Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into alex/implement-adm…
Browse files Browse the repository at this point in the history
…in-league-operation
  • Loading branch information
alexappleget committed Nov 21, 2024
2 parents b26a582 + f92114f commit 7730fb5
Show file tree
Hide file tree
Showing 10 changed files with 328 additions and 137 deletions.
2 changes: 0 additions & 2 deletions app/(main)/account/recovery/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ const ResetPassword = (): React.JSX.Element => {
const password: string = useWatch({
control: form.control,
name: 'password',
defaultValue: '',
});

/**
Expand All @@ -116,7 +115,6 @@ const ResetPassword = (): React.JSX.Element => {
const confirmPassword: string = useWatch({
control: form.control,
name: 'confirmPassword',
defaultValue: '',
});

/**
Expand Down
51 changes: 38 additions & 13 deletions app/(main)/login/page.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ let continueButton: HTMLElement,
emailInput: HTMLInputElement,
passwordInput: HTMLInputElement;

const mockUseAuthContext = {
interface MockUseAuthContext {
getUser: jest.Mock;
isSignedIn: boolean | null;
login: jest.Mock;
}

const mockUseAuthContext: MockUseAuthContext = {
getUser,
isSignedIn: false,
login: mockLogin,
Expand Down Expand Up @@ -46,20 +52,45 @@ describe('Login', () => {
jest
.spyOn(React, 'useState')
.mockImplementation(() => [false, setIsLoading]);
});

it('should display GlobalSpinner while authenticating the user', async () => {
mockUseAuthContext.isSignedIn = null;

render(<Login />);

expect(screen.getByTestId('global-spinner')).toBeInTheDocument();
});

it('should not display GlobalSpinner once authentication is complete', async () => {
mockUseAuthContext.isSignedIn = false;

render(<Login />);

expect(screen.queryByTestId('global-spinner')).not.toBeInTheDocument();
});

it('should render the login page if the user is not logged in', () => {
mockUseAuthContext.isSignedIn = false;

render(<Login />);

continueButton = screen.getByTestId('continue-button');
emailInput = screen.getByTestId('email');
passwordInput = screen.getByTestId('password');
});
it('should render the login page', () => {

expect(continueButton).toBeInTheDocument();
expect(emailInput).toBeInTheDocument();
expect(passwordInput).toBeInTheDocument();
});

it('should update email and password fields and submit form', async () => {
mockUseAuthContext.isSignedIn = false;

render(<Login />);

const emailInput = screen.getByTestId('email');
const passwordInput = screen.getByTestId('password');
const form = screen.getByTestId('login-form');

await act(async () => {
Expand All @@ -80,16 +111,7 @@ describe('Login', () => {
});
});

it('redirects to /weeklyPicks when the button is clicked', () => {
mockUseAuthContext.isSignedIn = true;

render(<Login />);
expect(mockUseAuthContext.getUser).toHaveBeenCalled();

mockUseAuthContext.isSignedIn = false;
});

it('redirects to /league/all when user navigates to /login', async () => {
it('redirects to /league/all when user navigates to /login and is logged in', async () => {
mockUseAuthContext.isSignedIn = true;

act(() => {
Expand All @@ -106,6 +128,8 @@ describe('Login', () => {

describe('Login loading spinner', () => {
it('should show the loading spinner', async () => {
mockUseAuthContext.isSignedIn = false;

(useStateMock as jest.Mock).mockImplementation((init: boolean) => [
true,
setIsLoading,
Expand All @@ -117,6 +141,7 @@ describe('Login loading spinner', () => {
expect(screen.queryByTestId('loading-spinner')).toBeInTheDocument();
});
});

it('should not show the loading spinner', async () => {
(useStateMock as jest.Mock).mockImplementation((init: boolean) => [
false,
Expand Down
203 changes: 106 additions & 97 deletions app/(main)/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
FormItem,
FormMessage,
} from '../../../components/Form/Form';
import GlobalSpinner from '@/components/GlobalSpinner/GlobalSpinner';
import { Input } from '@/components/Input/Input';
import { useAuthContext } from '@/context/AuthContextProvider';
import { useRouter } from 'next/navigation';
Expand Down Expand Up @@ -51,31 +52,32 @@ type LoginUserSchemaType = z.infer<typeof LoginUserSchema>;
*/
const Login = (): React.JSX.Element => {
const router = useRouter();
const { login, isSignedIn, getUser } = useAuthContext();
const [isLoading, setIsLoading] = useState(false);
const { login, isSignedIn } = useAuthContext();
const [isLoading, setIsLoading] = useState<boolean>(false);

useEffect(() => {
if (isSignedIn) {
getUser();
if (isSignedIn === true) {
router.push('/league/all');
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isSignedIn, getUser]);
}, [isSignedIn]);

const form = useForm<LoginUserSchemaType>({
resolver: zodResolver(LoginUserSchema),
defaultValues: {
email: '',
password: '',
},
});

const email = useWatch({
control: form.control,
name: 'email',
defaultValue: '',
});

const password = useWatch({
control: form.control,
name: 'password',
defaultValue: '',
});

/**
Expand All @@ -97,98 +99,105 @@ const Login = (): React.JSX.Element => {
};

return (
<section className="grid xl:grid-cols-2 xl:grid-rows-none">
<div className="row-span-1 grid w-full place-items-center from-[#4E160E] to-zinc-950 bg-gradient-to-b xl:h-screen xl:bg-gradient-to-b">
<Logo className="mx-auto w-52 xl:w-64 xl:place-self-end" src={logo} />
<div className="mx-auto grid gap-4 place-self-end px-8 pb-8 text-foreground">
<p className="hidden leading-7 xl:block">
Thank you... fantasy football draft, for letting me know that even
in my fantasies, I am bad at sports.
</p>
<p className="hidden leading-7 xl:block">Jimmy Fallon</p>
<section className={`grid ${isSignedIn === null ? '' : 'xl:grid-cols-2'} xl:grid-rows-none`}>
{(isSignedIn === null || isSignedIn === true) &&
<GlobalSpinner data-testid="global-spinner" />
}
{isSignedIn === false &&
<>
<div className="row-span-1 grid w-full place-items-center from-[#4E160E] to-zinc-950 bg-gradient-to-b xl:h-screen xl:bg-gradient-to-b">
<Logo className="mx-auto w-52 xl:w-64 xl:place-self-end" src={logo} />
<div className="mx-auto grid gap-4 place-self-end px-8 pb-8 text-foreground">
<p className="hidden leading-7 xl:block">
Thank you... fantasy football draft, for letting me know that even
in my fantasies, I am bad at sports.
</p>
<p className="hidden leading-7 xl:block">Jimmy Fallon</p>
</div>
</div>
</div>
<div className="row-span-1 mx-auto grid max-w-sm justify-center space-y-4 px-4 xl:flex xl:flex-col">
<div>
<h1 className="text-5xl font-extrabold tracking-tight">
Join Gridiron Survivor
</h1>
<p className="pb-4 font-normal leading-7 text-muted-foreground">
Log in to your existing account or{' '}
<LinkCustom href="/register">sign up</LinkCustom> to get started
with a league
</p>
<div className="row-span-1 mx-auto grid max-w-sm justify-center space-y-4 px-4 xl:flex xl:flex-col">
<div>
<h1 className="text-5xl font-extrabold tracking-tight">
Join Gridiron Survivor
</h1>
<p className="pb-4 font-normal leading-7 text-muted-foreground">
Log in to your existing account or{' '}
<LinkCustom href="/register">sign up</LinkCustom> to get started
with a league
</p>
</div>
<Form {...form}>
<form
id="input-container"
className="grid gap-3"
data-testid="login-form"
onSubmit={form.handleSubmit(onSubmit)}
>
<FormField
control={form.control as Control<object>}
name="email"
render={({ field }) => (
<FormItem>
<FormControl>
<Input
data-testid="email"
type="email"
placeholder="Email"
{...field}
/>
</FormControl>
{form.formState.errors?.email && (
<FormMessage>
{form.formState.errors.email.message}
</FormMessage>
)}
</FormItem>
)}
/>
<FormField
control={form.control as Control<object>}
name="password"
render={({ field }) => (
<FormItem>
<FormControl>
<Input
data-testid="password"
type="password"
placeholder="Password"
{...field}
/>
</FormControl>
{form.formState.errors?.password && (
<FormMessage>
{form.formState.errors?.password.message}
</FormMessage>
)}
</FormItem>
)}
/>
<Button
data-testid="continue-button"
label={
isLoading ? (
<LoadingSpinner data-testid="loading-spinner" />
) : (
'Continue'
)
}
type="submit"
disabled={!email || !password || isLoading}
/>
<LinkCustom href="/register">
Sign up to get started with a league
</LinkCustom>
<LinkCustom href="/recover-password">
Forgot your password?
</LinkCustom>
</form>
</Form>
</div>
<Form {...form}>
<form
id="input-container"
className="grid gap-3"
data-testid="login-form"
onSubmit={form.handleSubmit(onSubmit)}
>
<FormField
control={form.control as Control<object>}
name="email"
render={({ field }) => (
<FormItem>
<FormControl>
<Input
data-testid="email"
type="email"
placeholder="Email"
{...field}
/>
</FormControl>
{form.formState.errors?.email && (
<FormMessage>
{form.formState.errors.email.message}
</FormMessage>
)}
</FormItem>
)}
/>
<FormField
control={form.control as Control<object>}
name="password"
render={({ field }) => (
<FormItem>
<FormControl>
<Input
data-testid="password"
type="password"
placeholder="Password"
{...field}
/>
</FormControl>
{form.formState.errors?.password && (
<FormMessage>
{form.formState.errors?.password.message}
</FormMessage>
)}
</FormItem>
)}
/>
<Button
data-testid="continue-button"
label={
isLoading ? (
<LoadingSpinner data-testid="loading-spinner" />
) : (
'Continue'
)
}
type="submit"
disabled={!email || !password || isLoading}
/>
<LinkCustom href="/register">
Sign up to get started with a league
</LinkCustom>
<LinkCustom href="/recover-password">
Forgot your password?
</LinkCustom>
</form>
</Form>
</div>
</>
}
</section>
);
};
Expand Down
1 change: 0 additions & 1 deletion app/(main)/recover-password/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ const RecoverPassword = (): React.JSX.Element => {
const email = useWatch({
control: form.control,
name: 'email',
defaultValue: '',
});

/**
Expand Down
Loading

0 comments on commit 7730fb5

Please sign in to comment.