160 lines
4.0 KiB
TypeScript
160 lines
4.0 KiB
TypeScript
/**
|
|
* User Profile Query Hooks
|
|
*
|
|
* This module provides React Query hooks for fetching and updating user profile.
|
|
* It integrates with the existing CalComAPIService and provides:
|
|
* - Automatic caching with configurable stale times
|
|
* - Profile update mutations with cache invalidation
|
|
*/
|
|
|
|
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
|
import { CalComAPIService, UserProfile } from "../services/calcom";
|
|
import { CACHE_CONFIG, queryKeys } from "../config/cache.config";
|
|
|
|
/**
|
|
* User profile update input type
|
|
*/
|
|
export interface UpdateUserProfileInput {
|
|
email?: string;
|
|
name?: string;
|
|
timeFormat?: number;
|
|
defaultScheduleId?: number;
|
|
weekStart?: string;
|
|
timeZone?: string;
|
|
locale?: string;
|
|
avatarUrl?: string;
|
|
bio?: string;
|
|
metadata?: Record<string, unknown>;
|
|
}
|
|
|
|
/**
|
|
* Hook to fetch the current user profile
|
|
*
|
|
* @returns Query result with user profile data, loading state, error, and refetch function
|
|
*
|
|
* @example
|
|
* ```tsx
|
|
* const { data: profile, isLoading } = useUserProfile();
|
|
*
|
|
* if (profile) {
|
|
* console.log(profile.username, profile.email);
|
|
* }
|
|
* ```
|
|
*/
|
|
export function useUserProfile() {
|
|
return useQuery({
|
|
queryKey: queryKeys.userProfile.current(),
|
|
queryFn: () => CalComAPIService.getUserProfile(),
|
|
staleTime: CACHE_CONFIG.userProfile.staleTime,
|
|
// Keep previous data while fetching new data (smoother UX)
|
|
placeholderData: (previousData) => previousData,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Hook to get the current username
|
|
*
|
|
* @returns Query result with username
|
|
*
|
|
* @example
|
|
* ```tsx
|
|
* const { data: username } = useUsername();
|
|
* ```
|
|
*/
|
|
export function useUsername() {
|
|
const { data: profile, ...rest } = useUserProfile();
|
|
|
|
return {
|
|
...rest,
|
|
data: profile?.username,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Hook to update the user profile
|
|
*
|
|
* @returns Mutation function and state
|
|
*
|
|
* @example
|
|
* ```tsx
|
|
* const { mutate: updateProfile, isPending } = useUpdateUserProfile();
|
|
*
|
|
* updateProfile({
|
|
* name: 'New Name',
|
|
* timeZone: 'America/New_York'
|
|
* });
|
|
* ```
|
|
*/
|
|
export function useUpdateUserProfile() {
|
|
const queryClient = useQueryClient();
|
|
|
|
return useMutation({
|
|
mutationFn: (updates: UpdateUserProfileInput) => CalComAPIService.updateUserProfile(updates),
|
|
onMutate: async (newData) => {
|
|
// Cancel any outgoing refetches
|
|
await queryClient.cancelQueries({ queryKey: queryKeys.userProfile.current() });
|
|
|
|
// Snapshot the previous value
|
|
const previousProfile = queryClient.getQueryData<UserProfile>(
|
|
queryKeys.userProfile.current()
|
|
);
|
|
|
|
// Optimistically update to the new value
|
|
if (previousProfile) {
|
|
queryClient.setQueryData(queryKeys.userProfile.current(), {
|
|
...previousProfile,
|
|
...newData,
|
|
});
|
|
}
|
|
|
|
return { previousProfile };
|
|
},
|
|
onError: (error, _newData, context) => {
|
|
// Rollback on error
|
|
if (context?.previousProfile) {
|
|
queryClient.setQueryData(queryKeys.userProfile.current(), context.previousProfile);
|
|
}
|
|
console.error("Failed to update user profile:", error);
|
|
},
|
|
onSettled: () => {
|
|
// Always refetch after error or success
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.userProfile.current() });
|
|
},
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Hook to prefetch user profile (useful for app initialization)
|
|
*
|
|
* @returns Function to prefetch user profile
|
|
*/
|
|
export function usePrefetchUserProfile() {
|
|
const queryClient = useQueryClient();
|
|
|
|
return () => {
|
|
queryClient.prefetchQuery({
|
|
queryKey: queryKeys.userProfile.current(),
|
|
queryFn: () => CalComAPIService.getUserProfile(),
|
|
staleTime: CACHE_CONFIG.userProfile.staleTime,
|
|
});
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Hook to invalidate user profile cache
|
|
*
|
|
* @returns Function to invalidate user profile cache
|
|
*/
|
|
export function useInvalidateUserProfile() {
|
|
const queryClient = useQueryClient();
|
|
|
|
return () => {
|
|
queryClient.invalidateQueries({ queryKey: queryKeys.userProfile.all });
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Type exports for consumers
|
|
*/
|
|
export type { UserProfile };
|