diff --git a/src/app/(campaign)/campanha/(app)/layout.tsx b/src/app/(campaign)/campanha/(app)/layout.tsx index 640f0501..f0dbcd7e 100644 --- a/src/app/(campaign)/campanha/(app)/layout.tsx +++ b/src/app/(campaign)/campanha/(app)/layout.tsx @@ -26,13 +26,13 @@ import { import { Toaster } from '@/components/ui/Toaster' import { TooltipProvider } from '@/components/ui/tooltip' import { deviceLabelFromUserAgent } from '@/lib/deviceLabel' -import { getCampaignUser } from '@/utilities/campaignAuth' +import { getCampaignUserWithAvatar } from '@/utilities/campaignAuth' import { campaignUserShellView } from '@/utilities/campaignUserProfile' import { loadCampaignPasskeys } from '@/utilities/webauthn/campaignWebAuthnCeremony' import { resolveCampaignWebAuthnRelyingParty } from '@/utilities/webauthn/campaignWebAuthnConfig' export default async function CampaignAppLayout({ children }: { children: React.ReactNode }) { - const user = await getCampaignUser() + const user = await getCampaignUserWithAvatar() if (!user) { redirect('/campanha/login') diff --git a/src/app/(campaign)/campanha/(app)/perfil/page.tsx b/src/app/(campaign)/campanha/(app)/perfil/page.tsx index 0c731b03..772b9a69 100644 --- a/src/app/(campaign)/campanha/(app)/perfil/page.tsx +++ b/src/app/(campaign)/campanha/(app)/perfil/page.tsx @@ -1,14 +1,15 @@ import config from '@payload-config' import type { Metadata } from 'next' import { headers } from 'next/headers' +import { redirect } from 'next/navigation' import { getPayload } from 'payload' import { CampaignPasskeysCard } from '@/components/campaign/auth/CampaignPasskeysCard' import { CampaignProfileSettings } from '@/components/campaign/auth/CampaignProfileSettings' import { CampaignPushNotificationsCard } from '@/components/campaign/auth/CampaignPushNotificationsCard' import { deviceLabelFromUserAgent } from '@/lib/deviceLabel' +import { getCampaignUserWithAvatar } from '@/utilities/campaignAuth' import { getCampaignPushConsent } from '@/utilities/campaignConsent' -import { requireCampaignPageActor } from '@/utilities/campaignPageActor' import { campaignUserShellView } from '@/utilities/campaignUserProfile' import { getCampaignVapidPublicKey } from '@/utilities/notification/sendCampaignPush' import { loadCampaignPasskeys } from '@/utilities/webauthn/campaignWebAuthnCeremony' @@ -27,7 +28,8 @@ type CampaignProfilePageProps = { } export default async function CampaignProfilePage({ searchParams }: CampaignProfilePageProps) { - const [user, params] = await Promise.all([requireCampaignPageActor(), searchParams]) + const [user, params] = await Promise.all([getCampaignUserWithAvatar(), searchParams]) + if (!user) redirect('/campanha/login') const payload = await getPayload({ config }) const [passkeys, relyingParty, requestHeaders, pushConsent] = await Promise.all([ diff --git a/src/app/(campaign)/campanha/actions/auth.ts b/src/app/(campaign)/campanha/actions/auth.ts index fa5ebea8..11e567f4 100644 --- a/src/app/(campaign)/campanha/actions/auth.ts +++ b/src/app/(campaign)/campanha/actions/auth.ts @@ -18,8 +18,10 @@ import { revokeCampaignSession, setCampaignAuthCookie, } from '@/utilities/campaignAuth' - -export type LoginResult = { error?: string } +import { + mapCampaignFormActionError, + type CampaignFormActionState, +} from '@/utilities/campaignFormActionError' const isLockedAuthError = (error: unknown): boolean => typeof error === 'object' && @@ -27,11 +29,16 @@ const isLockedAuthError = (error: unknown): boolean => 'name' in error && (error as { name: unknown }).name === 'LockedAuth' -export const loginCampaign = async (input: CampaignLoginInput): Promise => { +export const loginCampaign = async ( + input: CampaignLoginInput, +): Promise => { const parsed = campaignLoginSchema.safeParse(input) if (!parsed.success) { - return { error: 'Dados inválidos.' } + return mapCampaignFormActionError({ + error: parsed.error, + genericMessage: 'Dados inválidos.', + }) } const payload = await getPayload({ config }) @@ -52,13 +59,13 @@ export const loginCampaign = async (input: CampaignLoginInput): Promise => { +): Promise => { try { - return loginCampaign({ + const result = await loginCampaign({ identifier: requiredFormText(formData, 'identifier'), password: requiredFormSecret(formData, 'password'), rememberMe: checkboxFormValue(formData, 'rememberMe'), }) - } catch { - return { error: 'Dados inválidos.' } + return result + } catch (error) { + if (error instanceof Error && error.message === 'NEXT_REDIRECT') throw error + return mapCampaignFormActionError({ + error, + genericMessage: 'Dados inválidos.', + }) } } diff --git a/src/app/(campaign)/campanha/convite/[token]/formActions.ts b/src/app/(campaign)/campanha/convite/[token]/formActions.ts index f415c348..7904f7dd 100644 --- a/src/app/(campaign)/campanha/convite/[token]/formActions.ts +++ b/src/app/(campaign)/campanha/convite/[token]/formActions.ts @@ -12,7 +12,7 @@ import { requiredFormSecret, requiredFormText, } from '@/lib/formData' -import { campaignInviteAutofillSchema, campaignInviteLoginSchema } from '@/lib/schemas/invite' +import { campaignInviteAutofillSchema, campaignInviteLoginFormSchema } from '@/lib/schemas/invite' import { mapCampaignFormActionError, runCampaignFormAction, @@ -67,24 +67,12 @@ export const redeemCampaignInviteLoginFormAction = async ( _state: CampaignInviteFormState, formData: FormData, ): Promise => { - let password: string try { - password = requiredFormSecret(formData, 'password') - if (password !== requiredFormSecret(formData, 'passwordConfirmation')) { - return { - fieldErrors: { - passwordConfirmation: ['As senhas não coincidem.'], - }, - } - } - } catch (error) { - return inviteFormError(error) - } - try { - const input = campaignInviteLoginSchema.parse({ + const input = campaignInviteLoginFormSchema.parse({ token, ...profileFromForm(formData), - password, + password: requiredFormSecret(formData, 'password'), + passwordConfirmation: requiredFormSecret(formData, 'passwordConfirmation'), consentAccepted: checkboxFormValue(formData, 'consentAccepted'), }) await redeemCampaignInviteLogin(input) diff --git a/src/app/(campaign)/campanha/esqueci-senha/page.tsx b/src/app/(campaign)/campanha/esqueci-senha/page.tsx index 995cf5c8..86ddb21e 100644 --- a/src/app/(campaign)/campanha/esqueci-senha/page.tsx +++ b/src/app/(campaign)/campanha/esqueci-senha/page.tsx @@ -3,7 +3,7 @@ import { redirect } from 'next/navigation' import { ForgotPasswordForm } from '@/app/(campaign)/campanha/esqueci-senha/ForgotPasswordForm' import { CampaignAuthPageShell } from '@/components/campaign/auth/CampaignAuthPageShell' -import { getCampaignUser } from '@/utilities/campaignAuth' +import { hasCampaignSession } from '@/utilities/campaignAuth' export const metadata: Metadata = { title: 'Esqueci a senha | Campanha', @@ -14,9 +14,9 @@ export const metadata: Metadata = { } export default async function CampaignForgotPasswordPage() { - const user = await getCampaignUser() + const hasSession = await hasCampaignSession() - if (user) { + if (hasSession) { redirect('/campanha/perfil') } diff --git a/src/app/(campaign)/campanha/login/LoginForm.tsx b/src/app/(campaign)/campanha/login/LoginForm.tsx index aef5fbb6..69c29920 100644 --- a/src/app/(campaign)/campanha/login/LoginForm.tsx +++ b/src/app/(campaign)/campanha/login/LoginForm.tsx @@ -3,7 +3,7 @@ import Link from 'next/link' import { useActionState, useState } from 'react' -import { loginCampaignFormAction, type LoginResult } from '@/app/(campaign)/campanha/actions/auth' +import { loginCampaignFormAction } from '@/app/(campaign)/campanha/actions/auth' import { CampaignAuthCardHeader } from '@/components/campaign/auth/CampaignAuthCardHeader' import { CampaignBiometricLoginButton } from '@/components/campaign/auth/CampaignBiometricLoginButton' import { Button } from '@/components/ui/button' @@ -28,6 +28,8 @@ import { campaignAuthTextLinkClassName, } from '@/lib/campaignAuthCopy' import { cn } from '@/lib/utils' +import type { CampaignFormActionState } from '@/utilities/campaignFormActionError' +import { firstFormActionMessage } from '@/utilities/campaignFormFields' const LOGIN_ERROR_ID = 'login-credentials-error' @@ -48,10 +50,11 @@ type LoginFormProps = { export const LoginForm = ({ biometricsConfigured }: LoginFormProps) => { const [state, formAction, pending] = useActionState( loginCampaignFormAction, - {} satisfies LoginResult, + {} satisfies CampaignFormActionState, ) const [identifier, setIdentifier] = useState('') - const hasAuthError = Boolean(state.error) + const authError = firstFormActionMessage(state) + const hasAuthError = Boolean(authError) return ( @@ -117,7 +120,7 @@ export const LoginForm = ({ biometricsConfigured }: LoginFormProps) => { ) : null} - {state.error ? {state.error} : null} + {authError ? {authError} : null}