complete project using prettier!
This commit is contained in:
@@ -11,4 +11,4 @@ import * as apiClient from '../services/apiClient';
|
||||
*/
|
||||
export const ApiProvider = ({ children }: { children: ReactNode }) => {
|
||||
return <ApiContext.Provider value={apiClient}>{children}</ApiContext.Provider>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -26,4 +26,4 @@ export const AppProviders: React.FC<AppProvidersProps> = ({ children }) => {
|
||||
</AuthProvider>
|
||||
</ModalProvider>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -32,14 +32,15 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
|
||||
logger.info('[AuthProvider-Effect] Found auth token. Validating...');
|
||||
try {
|
||||
const fetchedProfile = await checkTokenApi();
|
||||
|
||||
|
||||
if (isMounted && fetchedProfile) {
|
||||
logger.info('[AuthProvider-Effect] Profile received, setting state to AUTHENTICATED.');
|
||||
setUserProfile(fetchedProfile);
|
||||
setAuthStatus('AUTHENTICATED');
|
||||
} else if (isMounted) {
|
||||
logger.warn('[AuthProvider-Effect] Token was present but validation returned no profile. Signing out.');
|
||||
logger.warn(
|
||||
'[AuthProvider-Effect] Token was present but validation returned no profile. Signing out.',
|
||||
);
|
||||
localStorage.removeItem('authToken');
|
||||
setUserProfile(null);
|
||||
setAuthStatus('SIGNED_OUT');
|
||||
@@ -61,7 +62,9 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
|
||||
}
|
||||
|
||||
if (isMounted) {
|
||||
logger.info('[AuthProvider-Effect] Initial auth check finished. Setting isLoading to false.');
|
||||
logger.info(
|
||||
'[AuthProvider-Effect] Initial auth check finished. Setting isLoading to false.',
|
||||
);
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
@@ -69,7 +72,7 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
|
||||
checkAuthToken();
|
||||
|
||||
return () => {
|
||||
logger.info('[AuthProvider-Effect] Component unmounting, cleaning up.');
|
||||
logger.info('[AuthProvider-Effect] Component unmounting, cleaning up.');
|
||||
isMounted = false;
|
||||
};
|
||||
}, [checkTokenApi]);
|
||||
@@ -81,53 +84,63 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
|
||||
setAuthStatus('SIGNED_OUT');
|
||||
}, []);
|
||||
|
||||
const login = useCallback(async (token: string, profileData?: UserProfile) => {
|
||||
logger.info(`[AuthProvider-Login] Attempting login.`);
|
||||
localStorage.setItem('authToken', token);
|
||||
const login = useCallback(
|
||||
async (token: string, profileData?: UserProfile) => {
|
||||
logger.info(`[AuthProvider-Login] Attempting login.`);
|
||||
localStorage.setItem('authToken', token);
|
||||
|
||||
if (profileData) {
|
||||
// If profile is provided (e.g., from credential login), use it directly.
|
||||
logger.info('[AuthProvider-Login] Profile data received directly.');
|
||||
setUserProfile(profileData);
|
||||
setAuthStatus('AUTHENTICATED');
|
||||
logger.info('[AuthProvider-Login] Login successful. State set to AUTHENTICATED.', { user: profileData.user });
|
||||
} else {
|
||||
// If no profile is provided (e.g., from OAuth or token refresh), fetch it.
|
||||
logger.info('[AuthProvider-Login] Auth token set in storage. Fetching profile...');
|
||||
try {
|
||||
const fetchedProfile = await fetchProfileApi();
|
||||
if (!fetchedProfile) {
|
||||
throw new Error('Received null or undefined profile from API.');
|
||||
}
|
||||
setUserProfile(fetchedProfile);
|
||||
if (profileData) {
|
||||
// If profile is provided (e.g., from credential login), use it directly.
|
||||
logger.info('[AuthProvider-Login] Profile data received directly.');
|
||||
setUserProfile(profileData);
|
||||
setAuthStatus('AUTHENTICATED');
|
||||
logger.info('[AuthProvider-Login] Profile fetch successful. State set to AUTHENTICATED.');
|
||||
} catch (e) {
|
||||
const errorMessage = e instanceof Error ? e.message : String(e);
|
||||
logger.error('Failed to fetch user data after login. Rolling back auth state.', { error: errorMessage });
|
||||
logout(); // Log the user out to prevent an inconsistent state.
|
||||
// Re-throw the error so the calling component can handle it (e.g., show a notification)
|
||||
throw new Error(`Login succeeded, but failed to fetch your data: ${errorMessage}`);
|
||||
logger.info('[AuthProvider-Login] Login successful. State set to AUTHENTICATED.', {
|
||||
user: profileData.user,
|
||||
});
|
||||
} else {
|
||||
// If no profile is provided (e.g., from OAuth or token refresh), fetch it.
|
||||
logger.info('[AuthProvider-Login] Auth token set in storage. Fetching profile...');
|
||||
try {
|
||||
const fetchedProfile = await fetchProfileApi();
|
||||
if (!fetchedProfile) {
|
||||
throw new Error('Received null or undefined profile from API.');
|
||||
}
|
||||
setUserProfile(fetchedProfile);
|
||||
setAuthStatus('AUTHENTICATED');
|
||||
logger.info('[AuthProvider-Login] Profile fetch successful. State set to AUTHENTICATED.');
|
||||
} catch (e) {
|
||||
const errorMessage = e instanceof Error ? e.message : String(e);
|
||||
logger.error('Failed to fetch user data after login. Rolling back auth state.', {
|
||||
error: errorMessage,
|
||||
});
|
||||
logout(); // Log the user out to prevent an inconsistent state.
|
||||
// Re-throw the error so the calling component can handle it (e.g., show a notification)
|
||||
throw new Error(`Login succeeded, but failed to fetch your data: ${errorMessage}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [fetchProfileApi, logout]);
|
||||
},
|
||||
[fetchProfileApi, logout],
|
||||
);
|
||||
|
||||
const updateProfile = useCallback((updatedProfileData: Partial<UserProfile>) => {
|
||||
logger.info('[AuthProvider-UpdateProfile] Updating profile state.', { updatedProfileData });
|
||||
setUserProfile(prevProfile => {
|
||||
setUserProfile((prevProfile) => {
|
||||
if (!prevProfile) return null;
|
||||
return { ...prevProfile, ...updatedProfileData };
|
||||
});
|
||||
}, []);
|
||||
|
||||
const value = useMemo(() => ({
|
||||
userProfile,
|
||||
authStatus,
|
||||
isLoading,
|
||||
login,
|
||||
logout,
|
||||
updateProfile
|
||||
}), [userProfile, authStatus, isLoading, login, logout, updateProfile]);
|
||||
const value = useMemo(
|
||||
() => ({
|
||||
userProfile,
|
||||
authStatus,
|
||||
isLoading,
|
||||
login,
|
||||
logout,
|
||||
updateProfile,
|
||||
}),
|
||||
[userProfile, authStatus, isLoading, login, logout, updateProfile],
|
||||
);
|
||||
|
||||
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -13,7 +13,7 @@ export const FlyersProvider: React.FC<{ children: ReactNode }> = ({ children })
|
||||
fetchNextPage: fetchNextFlyersPage,
|
||||
hasNextPage: hasNextFlyersPage,
|
||||
refetch: refetchFlyers,
|
||||
isRefetching: isRefetchingFlyers
|
||||
isRefetching: isRefetchingFlyers,
|
||||
} = useInfiniteQuery<Flyer>(apiClient.fetchFlyers);
|
||||
|
||||
const value: FlyersContextType = {
|
||||
@@ -27,4 +27,4 @@ export const FlyersProvider: React.FC<{ children: ReactNode }> = ({ children })
|
||||
};
|
||||
|
||||
return <FlyersContext.Provider value={value}>{children}</FlyersContext.Provider>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -6,15 +6,18 @@ import * as apiClient from '../services/apiClient';
|
||||
import { useApiOnMount } from '../hooks/useApiOnMount';
|
||||
|
||||
export const MasterItemsProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
|
||||
const { data, loading, error } = useApiOnMount<MasterGroceryItem[], []>(
|
||||
() => apiClient.fetchMasterItems()
|
||||
const { data, loading, error } = useApiOnMount<MasterGroceryItem[], []>(() =>
|
||||
apiClient.fetchMasterItems(),
|
||||
);
|
||||
|
||||
const value = useMemo(() => ({
|
||||
masterItems: data || [],
|
||||
isLoading: loading,
|
||||
error: error?.message || null,
|
||||
}), [data, loading, error]);
|
||||
const value = useMemo(
|
||||
() => ({
|
||||
masterItems: data || [],
|
||||
isLoading: loading,
|
||||
error: error?.message || null,
|
||||
}),
|
||||
[data, loading, error],
|
||||
);
|
||||
|
||||
return <MasterItemsContext.Provider value={value}>{children}</MasterItemsContext.Provider>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -14,13 +14,22 @@ export const ModalProvider: React.FC<{ children: React.ReactNode }> = ({ childre
|
||||
correctionTool: false,
|
||||
});
|
||||
|
||||
const openModal = useCallback((modal: ModalType) => setModalState(prev => ({ ...prev, [modal]: true })), []);
|
||||
const closeModal = useCallback((modal: ModalType) => setModalState(prev => ({ ...prev, [modal]: false })), []);
|
||||
const openModal = useCallback(
|
||||
(modal: ModalType) => setModalState((prev) => ({ ...prev, [modal]: true })),
|
||||
[],
|
||||
);
|
||||
const closeModal = useCallback(
|
||||
(modal: ModalType) => setModalState((prev) => ({ ...prev, [modal]: false })),
|
||||
[],
|
||||
);
|
||||
const isModalOpen = useCallback((modal: ModalType) => modalState[modal], [modalState]);
|
||||
|
||||
// useMemo ensures the context value object is stable across re-renders,
|
||||
// preventing unnecessary re-renders of consumer components.
|
||||
const value: ModalContextType = useMemo(() => ({ openModal, closeModal, isModalOpen }), [openModal, closeModal, isModalOpen]);
|
||||
const value: ModalContextType = useMemo(
|
||||
() => ({ openModal, closeModal, isModalOpen }),
|
||||
[openModal, closeModal, isModalOpen],
|
||||
);
|
||||
|
||||
return <ModalContext.Provider value={value}>{children}</ModalContext.Provider>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -8,13 +8,21 @@ import { useAuth } from '../hooks/useAuth';
|
||||
|
||||
export const UserDataProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
|
||||
const { userProfile } = useAuth();
|
||||
|
||||
const { data: watchedItemsData, loading: isLoadingWatched, error: watchedItemsError } = useApiOnMount<MasterGroceryItem[], []>(
|
||||
() => apiClient.fetchWatchedItems(), [userProfile], { enabled: !!userProfile }
|
||||
);
|
||||
const { data: shoppingListsData, loading: isLoadingShoppingLists, error: shoppingListsError } = useApiOnMount<ShoppingList[], []>(
|
||||
() => apiClient.fetchShoppingLists(), [userProfile], { enabled: !!userProfile }
|
||||
);
|
||||
|
||||
const {
|
||||
data: watchedItemsData,
|
||||
loading: isLoadingWatched,
|
||||
error: watchedItemsError,
|
||||
} = useApiOnMount<MasterGroceryItem[], []>(() => apiClient.fetchWatchedItems(), [userProfile], {
|
||||
enabled: !!userProfile,
|
||||
});
|
||||
const {
|
||||
data: shoppingListsData,
|
||||
loading: isLoadingShoppingLists,
|
||||
error: shoppingListsError,
|
||||
} = useApiOnMount<ShoppingList[], []>(() => apiClient.fetchShoppingLists(), [userProfile], {
|
||||
enabled: !!userProfile,
|
||||
});
|
||||
|
||||
const [watchedItems, setWatchedItems] = useState<MasterGroceryItem[]>([]);
|
||||
const [shoppingLists, setShoppingLists] = useState<ShoppingList[]>([]);
|
||||
@@ -34,14 +42,25 @@ export const UserDataProvider: React.FC<{ children: ReactNode }> = ({ children }
|
||||
if (shoppingListsData) setShoppingLists(shoppingListsData);
|
||||
}, [userProfile, watchedItemsData, shoppingListsData]);
|
||||
|
||||
const value = useMemo(() => ({
|
||||
watchedItems,
|
||||
shoppingLists,
|
||||
setWatchedItems,
|
||||
setShoppingLists,
|
||||
isLoading: !!userProfile && (isLoadingWatched || isLoadingShoppingLists),
|
||||
error: watchedItemsError?.message || shoppingListsError?.message || null,
|
||||
}), [watchedItems, shoppingLists, userProfile, isLoadingWatched, isLoadingShoppingLists, watchedItemsError, shoppingListsError]);
|
||||
const value = useMemo(
|
||||
() => ({
|
||||
watchedItems,
|
||||
shoppingLists,
|
||||
setWatchedItems,
|
||||
setShoppingLists,
|
||||
isLoading: !!userProfile && (isLoadingWatched || isLoadingShoppingLists),
|
||||
error: watchedItemsError?.message || shoppingListsError?.message || null,
|
||||
}),
|
||||
[
|
||||
watchedItems,
|
||||
shoppingLists,
|
||||
userProfile,
|
||||
isLoadingWatched,
|
||||
isLoadingShoppingLists,
|
||||
watchedItemsError,
|
||||
shoppingListsError,
|
||||
],
|
||||
);
|
||||
|
||||
return <UserDataContext.Provider value={value}>{children}</UserDataContext.Provider>;
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user