Description
Describe the bug
Hi all, i have a weird bug with Amplify essentially not responding to sign in event until after i click the navbar or some other element on the screen. It seems to be stuck in a stale state, and only after updating the state some other way will the events fire.
Desktop (please complete the following information):
- NextJS 15
- @aws-amplify/adapter-nextjs 1.4.1
- Version 6.15.1
https://pastebin.com/tYmEqARM (syntax highlighting)
`import {
getCognitoUser,
getEVUser,
setEVUserAttributes,
} from '@/lib/schema/user/client-fetch';
import { CognitoUser, EVUser } from '@/lib/schema/user/types';
import { showToast } from '@/lib/toast';
import { useQuery } from '@tanstack/react-query';
import {
deleteUser as deleteCognitoUser,
updateUserAttributes,
} from 'aws-amplify/auth';
import { Hub, HubCapsule } from 'aws-amplify/utils';
import {
createContext,
FC,
PropsWithChildren,
useCallback,
useEffect,
useMemo,
useState,
} from 'react';
export interface AuthContextType {
user: CognitoUser | null;
evUser: EVUser | null;
updateEVUser: (newEVUser: EVUser) => Promise<{ ok: boolean }>;
deleteUser: () => Promise<{ ok: boolean }>;
error: boolean;
loading: boolean;
}
export const AuthContext = createContext<AuthContextType | null>(null);
interface AuthProviderProps {
ssrUser?: CognitoUser | null;
}
/**
-
Context that holds and controls the signed in state.
-
@param {AuthProviderProps} props - The properties for the AuthProvider component.
-
@param {ReactNode} props.children - The children components that require access to authentication context.
-
@param {User} [props.preloadedUser] - A user object that is preloaded, if available.
-
@param {User} [props.user] - The current authenticated Cognito user.
-
@param {EVUser} props.evUser - The user data stored in the database - used to render user info on client side.
-
@param {() => void} props.updateEVUser - Function to update the evUser - updates the database and will update the client render.
-
@param {boolean} props.isLoading - Loading state of the authentication context.
-
@param {boolean} props.isError - Error state of the authentication context.
-
@returns {JSX.Element} The AuthContext.Provider component with authentication context values.
*/
export const AuthProvider: FC<PropsWithChildren> = ({
children,
ssrUser,
}) => {
const [preloadedUser, setPreloadedUser] = useState(ssrUser);
const [evUser, setEVUser] = useState<EVUser | null>(null);
Hub.listen('auth', async (data: HubCapsule<'auth', any>) => {
switch (data.payload.event) {
case 'signedIn':
console.log('signedIn from auth provider');refetchUser(); setPreloadedUser(null); break;
case 'signedOut':
console.log('signed out from auth provider');
setPreloadedUser(null);
refetchUser();
break;
default:
break;
}
});
const updateUser = async () => {
const newUser = await getCognitoUser();
if (newUser) {
const newEVUser = await getEVUser();
setEVUser(newEVUser);
if (newEVUser) {
const updatedFields: { given_name?: string; family_name?: string } = {};
if (newEVUser.firstName) {
updatedFields.given_name = newEVUser.firstName;
}
if (newEVUser.lastName) {
updatedFields.family_name = newEVUser.lastName;
}
await updateUserAttributes({ userAttributes: updatedFields });
}
}
return newUser;
};
const updateEVUser = useCallback(async (newEVUser: EVUser) => {
try {
await setEVUserAttributes(newEVUser);
await updateUserAttributes({
userAttributes: {
given_name: newEVUser.firstName,
family_name: newEVUser.lastName,
},
});
setEVUser(newEVUser);
showToast('Successfully saved your profile!', { type: 'success' });
return { ok: true };
} catch (err) {
showToast('Something went wrong saving your profile. Please try again.', {
type: 'error',
});
return { ok: false };
}
}, []);
const deleteUser = useCallback(async () => {
try {
if (evUser) {
await setEVUserAttributes({
...evUser,
flaggedForDeletion: true,
});
await deleteCognitoUser();
setEVUser(null);
}
return { ok: true };
} catch (err) {
showToast(
'Something went wrong deleting your account. Please try again.',
{
type: 'error',
}
);
return { ok: false };
}
}, [evUser]);
const {
data: user,
refetch: refetchUser,
isLoading,
isError,
} = useQuery({
queryKey: ['cognito-user'],
queryFn: updateUser,
});
const value = useMemo(
() => ({
user: preloadedUser || user || null,
evUser,
updateEVUser,
deleteUser,
loading: isLoading,
error: isError,
}),
[preloadedUser, user, isLoading, isError, evUser, updateEVUser, deleteUser]
);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};
`
Additional context
Here is the code from my auth provider it wraps the entire application https://pastebin.com/tYmEqARM. Ive also tried implementing the hub listener at the root
Thank you