Skip to content

Commit

Permalink
Merge pull request #112 from SocialGouv/feat/forgot-password
Browse files Browse the repository at this point in the history
feat: add forgot and reset password pages
  • Loading branch information
HoreKk authored May 29, 2024
2 parents c5ddc2c + 65845fc commit a5723b5
Show file tree
Hide file tree
Showing 15 changed files with 980 additions and 393 deletions.
44 changes: 44 additions & 0 deletions webapp-next/components/chakra/Alert.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { AlertProps, createMultiStyleConfigHelpers } from "@chakra-ui/react";
import { alertAnatomy } from "@chakra-ui/anatomy";

const { definePartsStyle, defineMultiStyleConfig } =
createMultiStyleConfigHelpers(alertAnatomy.keys);

const baseStyle = definePartsStyle((props: AlertProps) => {
const { status } = props;

const base = {
container: {
borderRadius: "lg",
},
description: {
fontWeight: 500,
},
};

const statusBases = {
success: base,
info: base,
warning: {
container: {
borderRadius: "lg",
bg: "highlight.50",
color: "orange.500",
},
icon: {
bg: "highlight.50",
color: "highlight.500",
},
description: {
fontWeight: 500,
},
},
error: base,
};

const baseStyle = statusBases[status as keyof typeof statusBases];

return baseStyle;
});

export const alertTheme = defineMultiStyleConfig({ baseStyle });
5 changes: 2 additions & 3 deletions webapp-next/components/layouts/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@ import { UserCard } from './UserCard';
import { FilterDates } from '../filters/Dates';
import { FiltersDepartments } from '../filters/Departments';
import cookie from 'js-cookie';
import { hasAtLeastOneFilter, ELASTIC_API_KEY_NAME } from '@/utils/tools';
import { hasAtLeastOneFilter, ELASTIC_API_KEY_NAME, swrPOSTFetch } from '@/utils/tools';
import { FilterAssociateCauses } from '../filters/AssociateCauses';
import { RegionFilter } from '../filters/Regions';
import { auth } from '../login/FormLogin';
import useSWRMutation from 'swr/mutation';

export const ageRanges = [
Expand All @@ -40,7 +39,7 @@ export function Menu() {

const { trigger: triggerInvalidateApiKey } = useSWRMutation(
"/api/auth/invalidate-api-key",
auth<{ username: string }>
swrPOSTFetch<{ username: string }>
);

const { filters, setFilters, user } = context;
Expand Down
117 changes: 117 additions & 0 deletions webapp-next/components/login/FormForgotPassword.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { swrPOSTFetch } from "@/utils/tools";
import { CheckCircleIcon } from "@chakra-ui/icons";
import {
Box,
Button,
Divider,
FormControl,
FormErrorMessage,
FormLabel,
Heading,
Image,
Input,
InputGroup,
InputLeftElement,
Link,
Text,
} from "@chakra-ui/react";
import NextLink from "next/link";
import { useForm, type SubmitHandler } from "react-hook-form";
import useSWRMutation from "swr/mutation";
import { WrapperForm } from "./WrapperForm";

type FormForgotPassword = {
username: string;
};

export const FormForgotPassword = () => {
const { trigger: triggerForgotPassword, isMutating } = useSWRMutation(
"/api/auth/forgot-password",
swrPOSTFetch<{ username: string }>
);

const {
handleSubmit,
register,
formState: { errors, isSubmitting, isSubmitSuccessful },
} = useForm<FormForgotPassword>();

const onSubmit: SubmitHandler<FormForgotPassword> = ({ username }) => {
triggerForgotPassword({ username });
};

const displayForm = () => {
return (
<form onSubmit={handleSubmit(onSubmit)}>
<FormControl mb={[4, 6]} isInvalid={!!errors.username}>
<FormLabel
htmlFor="username"
fontSize={["2xs", "xs"]}
fontWeight={500}
>
Identifiant
</FormLabel>
<InputGroup>
<InputLeftElement pointerEvents="none">
<Image
src={"/icons/user.svg"}
alt="User Icon"
boxSize={9}
pt={2}
/>
</InputLeftElement>
<Input
type="text"
id="username"
autoFocus
placeholder="Saisissez votre adresse email"
fontSize="xs"
bg={"secondary.500"}
{...register("username", {
required: "Ce champ est obligatoire",
})}
/>
</InputGroup>
</FormControl>
<FormErrorMessage>
{errors.username && errors.username.message}
</FormErrorMessage>
<Button
type="submit"
isLoading={isSubmitting || isMutating}
colorScheme="primary"
loadingText="..."
color="white"
w="full"
fontSize={["md", "lg", "xl"]}
fontWeight={600}
>
Réinitialiser le mot de passe
</Button>
</form>
);
};

const displaySubmitSuccess = () => {
return (
<Text fontSize={["sm", "md"]} color="neutral.500">
<CheckCircleIcon w={5} h={5} mb={1} color="green.500" /> Un email de
réinitialisation de mot de passe a été envoyé à
<br />
l'adresse email associée à votre compte.
</Text>
);
};

return (
<WrapperForm title="Mot de passe oublié">
<Box>{isSubmitSuccessful ? displaySubmitSuccess() : displayForm()}</Box>
<Divider my={4} />
<Text fontSize={["xs", "sm"]} color="neutral.500">
<Link as={NextLink} href="/login">
Retour à la connexion
</Link>
</Text>
</WrapperForm>
);
};
88 changes: 35 additions & 53 deletions webapp-next/components/login/FormLogin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
AlertTitle,
Box,
Button,
Divider,
FormControl,
FormLabel,
Heading,
Expand All @@ -26,19 +27,13 @@ import {
useDisclosure,
} from "@chakra-ui/react";
import cookie from "js-cookie";
import NextLink from "next/link";
import { useRouter } from "next/router";
import { useEffect, useRef, useState } from "react";
import useSWRMutation from "swr/mutation";
import { ELASTIC_API_KEY_NAME } from "@/utils/tools";
import { ELASTIC_API_KEY_NAME, swrPOSTFetch } from "@/utils/tools";
import { ContentCGU } from "@/pages/legals/cgu";

export async function auth<T>(url: string, { arg }: { arg: T }) {
return fetch(url, {
method: "POST",
body: JSON.stringify(arg),
headers: { "Content-Type": "application/json" },
});
}
import { WrapperForm } from "./WrapperForm";

export const FormLogin = () => {
const router = useRouter();
Expand Down Expand Up @@ -68,15 +63,15 @@ export const FormLogin = () => {

const { trigger: triggerLogin } = useSWRMutation(
"/api/auth",
auth<{ username: string; password: string }>
swrPOSTFetch<{ username: string; password: string }>
);
const { trigger: triggerVerify } = useSWRMutation(
"/api/auth/verify-code",
auth<{ username: string; code: string }>
swrPOSTFetch<{ username: string; code: string }>
);
const { trigger: triggerCreateUser } = useSWRMutation(
"/api/auth/create-user",
auth<{ username: string; versionCGU: string }>
swrPOSTFetch<{ username: string; versionCGU: string }>
);

const startTimer = () => {
Expand Down Expand Up @@ -192,7 +187,7 @@ export const FormLogin = () => {
}}
>
<FormControl mb={[4, 6]}>
<FormLabel htmlFor="code" fontSize={["10px", "12px"]} fontWeight={500}>
<FormLabel htmlFor="code" fontSize={["2xs", "xs"]} fontWeight={500}>
Code
</FormLabel>
<InputGroup mb={2}>
Expand All @@ -204,7 +199,7 @@ export const FormLogin = () => {
id="code"
autoFocus
placeholder="Saisissez votre code"
fontSize={"12px"}
fontSize="xs"
bg={"secondary.500"}
value={code}
onChange={handleCodeChange}
Expand Down Expand Up @@ -253,12 +248,11 @@ export const FormLogin = () => {
<Button
type="submit"
isDisabled={isLoading}
bg="primary.500"
_hover={{}}
colorScheme="primary"
loadingText="Connexion en cours..."
color={"white"}
w={"full"}
fontSize={["14px", "16px", "18px"]}
fontSize={["md", "lg", "xl"]}
fontWeight={600}
>
{isLoading ? <Spinner color="primary.500" /> : <>Je valide -&gt;</>}
Expand All @@ -276,7 +270,7 @@ export const FormLogin = () => {
<FormControl mb={[4, 6]}>
<FormLabel
htmlFor="username"
fontSize={["10px", "12px"]}
fontSize={["2xs", "xs"]}
fontWeight={500}
>
Identifiant
Expand All @@ -290,7 +284,7 @@ export const FormLogin = () => {
id="username"
autoFocus
placeholder="Saisissez votre adresse email"
fontSize={"12px"}
fontSize="xs"
bg={"secondary.500"}
value={username}
onChange={handleUsernameChange}
Expand All @@ -301,7 +295,7 @@ export const FormLogin = () => {
<FormControl mb={[4, 6]}>
<FormLabel
htmlFor="password"
fontSize={["10px", "12px"]}
fontSize={["2xs", "xs"]}
fontWeight={500}
>
Mot de passe
Expand All @@ -314,7 +308,7 @@ export const FormLogin = () => {
type={isOpen ? "text" : "password"}
id="password"
placeholder="Saisissez votre mot de passe"
fontSize={"12px"}
fontSize="xs"
bg={"secondary.500"}
value={password}
onChange={handlePasswordChange}
Expand Down Expand Up @@ -369,12 +363,11 @@ export const FormLogin = () => {
<Button
type="submit"
isDisabled={isLoading}
bg="primary.500"
_hover={{}}
colorScheme="primary"
loadingText="Connexion en cours..."
color={"white"}
w={"full"}
fontSize={["14px", "16px", "18px"]}
fontSize={["md", "lg", "xl"]}
fontWeight={600}
>
{isLoading ? (
Expand All @@ -383,41 +376,30 @@ export const FormLogin = () => {
<>Je me connecte -&gt;</>
)}
</Button>
<Divider my={4} />
<Text fontSize={["xs", "sm"]} color="neutral.500">
<Link as={NextLink} href="/login/forgot-password">
Mot de passe oublié ?
</Link>
</Text>
</form>
);

return (
<>
<Box
display="flex"
justifyContent="center"
alignItems="center"
mx={"auto"}
mt={[8, 0]}
<WrapperForm title="Connexion 👋">
<Text
mb={6}
fontSize={["md", "lg"]}
fontWeight={400}
color={"neutral.500"}
>
<Box maxW="sm" mx={[10, 20]} p={[0, 2]} bgColor="white">
<Heading
as="h1"
size="lg"
mb={6}
fontSize={["32px", "48px"]}
fontWeight={700}
>
Connexion 👋
</Heading>
<Text
mb={6}
fontSize={["14px", "16px"]}
fontWeight={400}
color={"neutral.500"}
>
{showCodeForm
? "Vous avez reçu un code par email, merci de le saisir ci-dessous."
: "Veuillez vous connecter pour accéder à votre compte."}
</Text>
{showCodeForm ? CodeForm : EmailPasswordForm}
</Box>
</Box>
{showCodeForm
? "Vous avez reçu un code par email, merci de le saisir ci-dessous."
: "Veuillez vous connecter pour accéder à votre compte."}
</Text>
{showCodeForm ? CodeForm : EmailPasswordForm}
</WrapperForm>
<Modal
isOpen={isOpenTerms}
onClose={onCloseTerms}
Expand Down
Loading

0 comments on commit a5723b5

Please sign in to comment.