Skip to content

Commit

Permalink
Add resend confirmation link
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-bach committed May 20, 2024
1 parent 354e3c6 commit 5e7937f
Show file tree
Hide file tree
Showing 8 changed files with 43 additions and 74 deletions.
2 changes: 1 addition & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ X Style verify email
X Clean out route names (make components/home components/dashboard so app/home can be there)
X Add update password
X Add reset password - https://github.com/alexrusin/nextjs-cognito-auth/tree/5-reset-password-end
X Add resend verification email
- Clean up dashboard template
- Deploy to AWS (SST)
- Add resend verification email
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react';
import { Accounts } from '@/components/accounts';
import { Contacts } from '@/components/contacts';

const accounts = () => {
return <Accounts />;
return <Contacts />;
};

export default accounts;
3 changes: 1 addition & 2 deletions frontend/src/components/auth/reset-password.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { Button } from '@/components/ui/button';
import { useFormState, useFormStatus } from 'react-dom';
import { handleResetPassword } from '@/lib/cognitoActions';
import { AtSignIcon, CircleCheckIcon, TriangleAlertIcon } from 'lucide-react';
import { CircleCheckIcon, TriangleAlertIcon } from 'lucide-react';
import { Card, CardContent, CardHeader, CardDescription, CardTitle, CardFooter } from '../ui/card';
import { Label } from '../ui/label';
import { Input } from '../ui/input';
Expand All @@ -24,7 +24,6 @@ export default function ResetPasswordFrom() {
Email
</Label>
<Input id='email' type='email' name='email' placeholder='Enter your email address' required />
<AtSignIcon className='pointer-events-none absolute left-3 top-1/2 h-[18px] w-[18px] -translate-y-1/2 text-gray-500 peer-focus:text-gray-900' />
</CardContent>

{errorMessage && (
Expand Down
33 changes: 30 additions & 3 deletions frontend/src/components/auth/verify-form.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
'use client';

import { useFormState } from 'react-dom';
import { Card, CardContent, CardDescription, CardHeader, CardFooter, CardTitle } from '@/components/ui/card';
import { Button, buttonVariants } from '@/components/ui/button';
import Link from 'next/link';
import { cn } from '@/lib/utils';
import { handleSendEmailVerification } from '@/lib/cognitoActions';
import { Input } from '@nextui-org/react';
import { useSearchParams } from 'next/navigation';
import { TriangleAlertIcon } from 'lucide-react';

export default function VerifyForm() {
const [result, dispatch] = useFormState(handleSendEmailVerification, { message: '', errorMessage: '' });

const params = useSearchParams();
const email = params.get('email') ?? '';

return (
<div className='space-y-3 min-w-[400px]'>
<form action={dispatch} className='space-y-3 min-w-[400px]'>
<Card>
<CardHeader>
<CardTitle className='text-2xl'>Verify Email</CardTitle>
Expand All @@ -20,20 +30,37 @@ export default function VerifyForm() {
<p className='text-sm text-muted-foreground'>Please check your email and click on the verification link to proceed.</p>
</div>
<div className='space-y-2'>
<div>
<Input id='email' type='hidden' name='email' defaultValue={email} />
</div>
<p className='mt-4 text-center text-sm text-gray-500'>
Didn&#39;t receive an email?
<Button type='submit' variant='ghost' className='font-semibold hover:bg-transparent text-indigo-600 hover:text-indigo-600'>
Resend
</Button>
</p>
</div>
{(result.message || result.errorMessage) && (
<div className='flex h-8 items-end space-x-1' aria-live='polite' aria-atomic='true'>
{result.errorMessage && (
<>
<TriangleAlertIcon className='h-5 w-5 text-red-500' />
<p className='text-sm text-red-500'>Could not resend verification email.</p>
</>
)}
{result.message && <p className='text-sm text-green-500'>{result.message}</p>}
</div>
)}
</CardContent>
<CardFooter>
<Link href='/' className={cn(buttonVariants({ variant: 'default' }), 'w-full hover:bg-blue-500 transition-colors')}>
<Link
href='/'
className={cn(buttonVariants({ variant: 'default' }), 'w-full bg-indigo-500 hover:bg-indigo-600 transition-colors')}
>
Sign In
</Link>
</CardFooter>
</Card>
</div>
</form>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { SettingsIcon } from '@/components/icons/sidebar/settings-icon';
import { TableWrapper } from '@/components/table/table';
import { AddUser } from './add-user';

export const Accounts = () => {
export const Contacts = () => {
return (
<div className='my-14 lg:px-6 max-w-[95rem] mx-auto w-full flex flex-col gap-4'>
<ul className='flex'>
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/components/sidebar/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { FilterIcon } from '../icons/sidebar/filter-icon';
import { useSidebarContext } from '../layout/layout-context';
import { ChangeLogIcon } from '../icons/sidebar/changelog-icon';
import { usePathname } from 'next/navigation';
import { UserIcon } from 'lucide-react';

export const SidebarWrapper = () => {
const pathname = usePathname();
Expand All @@ -39,9 +40,9 @@ export const SidebarWrapper = () => {
<div className={Sidebar.Body()}>
<SidebarItem title='Home' icon={<HomeIcon />} isActive={pathname === '/dashboard'} href='/dashboard' />
<SidebarMenu title='Main Menu'>
<SidebarItem isActive={pathname === '/accounts'} title='Accounts' icon={<AccountsIcon />} href='accounts' />
<CollapseItems icon={<AccountsIcon />} items={['Banks Accounts', 'Credit Cards', 'Loans']} title='Balances' />
<SidebarItem isActive={pathname === '/investments'} title='Investments' icon={<PaymentsIcon />} />
<CollapseItems icon={<BalanceIcon />} items={['Banks Accounts', 'Credit Cards', 'Loans']} title='Balances' />
<SidebarItem isActive={pathname === '/contacts'} title='Contacts' icon={<UserIcon />} href='contacts' />
<SidebarItem isActive={pathname === '/customers'} title='Customers' icon={<CustomersIcon />} />
<SidebarItem isActive={pathname === '/products'} title='Products' icon={<ProductsIcon />} />
<SidebarItem isActive={pathname === '/reports'} title='Reports' icon={<ReportsIcon />} />
Expand Down
68 changes: 5 additions & 63 deletions frontend/src/lib/cognitoActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,19 @@ export async function handleSignUp(prevState: string | undefined, formData: Form
} catch (error) {
return getErrorMessage(error);
}
redirect('/auth/verify');
redirect('/auth/verify?email=' + encodeURIComponent(String(formData.get('email'))));
}

export async function handleSendEmailVerificationCode(prevState: { message: string; errorMessage: string }, formData: FormData) {
export async function handleSendEmailVerification(prevState: { message: string; errorMessage: string }, formData: FormData) {
let currentState;
try {
// Sends verificaiton email (despite the funciton name saying 'code')
await resendSignUpCode({
username: String(formData.get('email')),
});
currentState = {
...prevState,
message: 'Code sent successfully',
message: 'Verification email sent successfully',
};
} catch (error) {
currentState = {
Expand All @@ -55,20 +56,6 @@ export async function handleSendEmailVerificationCode(prevState: { message: stri
return currentState;
}

export async function handleConfirmSignUp(prevState: string | undefined, formData: FormData) {
try {
const { isSignUpComplete, nextStep } = await confirmSignUp({
username: String(formData.get('email')),
confirmationCode: String(formData.get('code')),
});

autoSignIn();
} catch (error) {
return getErrorMessage(error);
}
redirect('/auth/login');
}

export async function handleSignIn(prevState: string | undefined, formData: FormData) {
let redirectLink = '/dashboard';
try {
Expand All @@ -85,6 +72,7 @@ export async function handleSignIn(prevState: string | undefined, formData: Form
} catch (error) {
return getErrorMessage(error);
}

nextRedirect(redirectLink);
}

Expand All @@ -101,52 +89,6 @@ export async function handleSignOut() {
nextRedirect('/');
}

export async function handleUpdateUserAttribute(prevState: string, formData: FormData) {
let attributeKey = 'given_name';
let attributeValue;
let currentAttributeValue;

if (formData.get('email')) {
attributeKey = 'email';
attributeValue = formData.get('email');
currentAttributeValue = formData.get('current_email');
} else {
attributeValue = formData.get('name');
currentAttributeValue = formData.get('current_name');
}

console.log('AttributeValue', attributeValue);

if (attributeValue === currentAttributeValue) {
return '';
}

try {
const output = await updateUserAttribute({
userAttribute: {
attributeKey: String(attributeKey),
value: String(attributeValue),
},
});
return handleUpdateUserAttributeNextSteps(output);
} catch (error) {
console.log(error);
return 'error';
}
}

function handleUpdateUserAttributeNextSteps(output: UpdateUserAttributeOutput) {
const { nextStep } = output;

switch (nextStep.updateAttributeStep) {
case 'CONFIRM_ATTRIBUTE_WITH_CODE':
const codeDeliveryDetails = nextStep.codeDeliveryDetails;
return `Confirmation code was sent to ${codeDeliveryDetails?.deliveryMedium}.`;
case 'DONE':
return 'success';
}
}

export async function handleUpdatePassword(prevState: 'success' | 'error' | undefined, formData: FormData) {
const currentPassword = formData.get('current_password');
const newPassword = formData.get('new_password');
Expand Down

0 comments on commit 5e7937f

Please sign in to comment.