diff --git a/src/auth/SignInForm.tsx b/src/auth/SignInForm.tsx index c7f840b4..d30ab0a4 100644 --- a/src/auth/SignInForm.tsx +++ b/src/auth/SignInForm.tsx @@ -4,12 +4,15 @@ import FieldSetWithStatus from '@/components/FieldSetWithStatus'; import InfoBlock from '@/components/InfoBlock'; import SubmitButtonWithStatus from '@/components/SubmitButtonWithStatus'; import { useLayoutEffect, useRef, useState } from 'react'; -import { signInAction } from './action'; +import { signInAction } from './actions'; import { useFormState } from 'react-dom'; import ErrorNote from '@/components/ErrorNote'; -import { CREDENTIALS_SIGN_IN_ERROR } from '.'; +import { KEY_CALLBACK_URL, KEY_CREDENTIALS_SIGN_IN_ERROR } from '.'; +import { useSearchParams } from 'next/navigation'; export default function SignInForm() { + const params = useSearchParams(); + const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [response, action] = useFormState(signInAction, undefined); @@ -27,7 +30,7 @@ export default function SignInForm() {
- {response === CREDENTIALS_SIGN_IN_ERROR && + {response === KEY_CREDENTIALS_SIGN_IN_ERROR && Invalid email/password } @@ -47,6 +50,11 @@ export default function SignInForm() { value={password} onChange={setPassword} /> +
Sign in diff --git a/src/auth/action.ts b/src/auth/action.ts deleted file mode 100644 index c16db0bd..00000000 --- a/src/auth/action.ts +++ /dev/null @@ -1,21 +0,0 @@ -'use server'; - -import { CREDENTIALS_SIGN_IN_ERROR, signIn, signOut } from '@/auth'; - -export const signInAction = async ( - _prevState: string | undefined, - formData: FormData, -) => { - try { - await signIn('credentials', Object.fromEntries(formData)); - } catch (error) { - if ((`${error}`).includes(CREDENTIALS_SIGN_IN_ERROR)) { - return CREDENTIALS_SIGN_IN_ERROR; - } - throw error; - } -}; - -export const signOutAction = async () => { - await signOut(); -}; diff --git a/src/auth/actions.ts b/src/auth/actions.ts new file mode 100644 index 00000000..cb14b725 --- /dev/null +++ b/src/auth/actions.ts @@ -0,0 +1,36 @@ +'use server'; + +import { + KEY_CALLBACK_URL, + KEY_CREDENTIALS_SIGN_IN_ERROR, + KEY_CREDENTIALS_SIGN_IN_ERROR_URL, + signIn, + signOut, +} from '@/auth'; +import { PATH_ADMIN_PHOTOS } from '@/site/paths'; +import { redirect } from 'next/navigation'; + +export const signInAction = async ( + _prevState: string | undefined, + formData: FormData, +) => { + try { + await signIn('credentials', Object.fromEntries(formData)); + } catch (error) { + if ( + `${error}`.includes(KEY_CREDENTIALS_SIGN_IN_ERROR) || + `${error}`.includes(KEY_CREDENTIALS_SIGN_IN_ERROR_URL) + ) { + // Rethrow credentials error to display on the sign in page. + return KEY_CREDENTIALS_SIGN_IN_ERROR; + } else if (!`${error}`.includes('NEXT_REDIRECT')) { + // Rethrow non-redirect errors + throw error; + } + } + redirect(formData.get(KEY_CALLBACK_URL) as string || PATH_ADMIN_PHOTOS); +}; + +export const signOutAction = async () => { + await signOut(); +}; diff --git a/src/auth/index.ts b/src/auth/index.ts index db3cc98d..0bf0d476 100644 --- a/src/auth/index.ts +++ b/src/auth/index.ts @@ -2,7 +2,10 @@ import { isPathProtected } from '@/site/paths'; import NextAuth, { User } from 'next-auth'; import Credentials from 'next-auth/providers/credentials'; -export const CREDENTIALS_SIGN_IN_ERROR = 'CredentialsSignin'; +export const KEY_CREDENTIALS_SIGN_IN_ERROR = 'CredentialsSignin'; +export const KEY_CREDENTIALS_SIGN_IN_ERROR_URL = + 'https://errors.authjs.dev#credentialssignin'; +export const KEY_CALLBACK_URL = 'callbackUrl'; export const { handlers: { GET, POST }, diff --git a/src/site/FooterClient.tsx b/src/site/FooterClient.tsx index c26e0134..ab114e7c 100644 --- a/src/site/FooterClient.tsx +++ b/src/site/FooterClient.tsx @@ -9,7 +9,7 @@ import RepoLink from '../components/RepoLink'; import { usePathname } from 'next/navigation'; import { isPathAdmin, isPathSignIn, pathForAdminPhotos } from './paths'; import SubmitButtonWithStatus from '@/components/SubmitButtonWithStatus'; -import { signOutAction } from '@/auth/action'; +import { signOutAction } from '@/auth/actions'; import Spinner from '@/components/Spinner'; import AnimateItems from '@/components/AnimateItems';