Skip to content

Commit a5723b5

Browse files
authored
Merge pull request #112 from SocialGouv/feat/forgot-password
feat: add forgot and reset password pages
2 parents c5ddc2c + 65845fc commit a5723b5

File tree

15 files changed

+980
-393
lines changed

15 files changed

+980
-393
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { AlertProps, createMultiStyleConfigHelpers } from "@chakra-ui/react";
2+
import { alertAnatomy } from "@chakra-ui/anatomy";
3+
4+
const { definePartsStyle, defineMultiStyleConfig } =
5+
createMultiStyleConfigHelpers(alertAnatomy.keys);
6+
7+
const baseStyle = definePartsStyle((props: AlertProps) => {
8+
const { status } = props;
9+
10+
const base = {
11+
container: {
12+
borderRadius: "lg",
13+
},
14+
description: {
15+
fontWeight: 500,
16+
},
17+
};
18+
19+
const statusBases = {
20+
success: base,
21+
info: base,
22+
warning: {
23+
container: {
24+
borderRadius: "lg",
25+
bg: "highlight.50",
26+
color: "orange.500",
27+
},
28+
icon: {
29+
bg: "highlight.50",
30+
color: "highlight.500",
31+
},
32+
description: {
33+
fontWeight: 500,
34+
},
35+
},
36+
error: base,
37+
};
38+
39+
const baseStyle = statusBases[status as keyof typeof statusBases];
40+
41+
return baseStyle;
42+
});
43+
44+
export const alertTheme = defineMultiStyleConfig({ baseStyle });

webapp-next/components/layouts/Menu.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@ import { UserCard } from './UserCard';
1212
import { FilterDates } from '../filters/Dates';
1313
import { FiltersDepartments } from '../filters/Departments';
1414
import cookie from 'js-cookie';
15-
import { hasAtLeastOneFilter, ELASTIC_API_KEY_NAME } from '@/utils/tools';
15+
import { hasAtLeastOneFilter, ELASTIC_API_KEY_NAME, swrPOSTFetch } from '@/utils/tools';
1616
import { FilterAssociateCauses } from '../filters/AssociateCauses';
1717
import { RegionFilter } from '../filters/Regions';
18-
import { auth } from '../login/FormLogin';
1918
import useSWRMutation from 'swr/mutation';
2019

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

4140
const { trigger: triggerInvalidateApiKey } = useSWRMutation(
4241
"/api/auth/invalidate-api-key",
43-
auth<{ username: string }>
42+
swrPOSTFetch<{ username: string }>
4443
);
4544

4645
const { filters, setFilters, user } = context;
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import { swrPOSTFetch } from "@/utils/tools";
2+
import { CheckCircleIcon } from "@chakra-ui/icons";
3+
import {
4+
Box,
5+
Button,
6+
Divider,
7+
FormControl,
8+
FormErrorMessage,
9+
FormLabel,
10+
Heading,
11+
Image,
12+
Input,
13+
InputGroup,
14+
InputLeftElement,
15+
Link,
16+
Text,
17+
} from "@chakra-ui/react";
18+
import NextLink from "next/link";
19+
import { useForm, type SubmitHandler } from "react-hook-form";
20+
import useSWRMutation from "swr/mutation";
21+
import { WrapperForm } from "./WrapperForm";
22+
23+
type FormForgotPassword = {
24+
username: string;
25+
};
26+
27+
export const FormForgotPassword = () => {
28+
const { trigger: triggerForgotPassword, isMutating } = useSWRMutation(
29+
"/api/auth/forgot-password",
30+
swrPOSTFetch<{ username: string }>
31+
);
32+
33+
const {
34+
handleSubmit,
35+
register,
36+
formState: { errors, isSubmitting, isSubmitSuccessful },
37+
} = useForm<FormForgotPassword>();
38+
39+
const onSubmit: SubmitHandler<FormForgotPassword> = ({ username }) => {
40+
triggerForgotPassword({ username });
41+
};
42+
43+
const displayForm = () => {
44+
return (
45+
<form onSubmit={handleSubmit(onSubmit)}>
46+
<FormControl mb={[4, 6]} isInvalid={!!errors.username}>
47+
<FormLabel
48+
htmlFor="username"
49+
fontSize={["2xs", "xs"]}
50+
fontWeight={500}
51+
>
52+
Identifiant
53+
</FormLabel>
54+
<InputGroup>
55+
<InputLeftElement pointerEvents="none">
56+
<Image
57+
src={"/icons/user.svg"}
58+
alt="User Icon"
59+
boxSize={9}
60+
pt={2}
61+
/>
62+
</InputLeftElement>
63+
<Input
64+
type="text"
65+
id="username"
66+
autoFocus
67+
placeholder="Saisissez votre adresse email"
68+
fontSize="xs"
69+
bg={"secondary.500"}
70+
{...register("username", {
71+
required: "Ce champ est obligatoire",
72+
})}
73+
/>
74+
</InputGroup>
75+
</FormControl>
76+
<FormErrorMessage>
77+
{errors.username && errors.username.message}
78+
</FormErrorMessage>
79+
<Button
80+
type="submit"
81+
isLoading={isSubmitting || isMutating}
82+
colorScheme="primary"
83+
loadingText="..."
84+
color="white"
85+
w="full"
86+
fontSize={["md", "lg", "xl"]}
87+
fontWeight={600}
88+
>
89+
Réinitialiser le mot de passe
90+
</Button>
91+
</form>
92+
);
93+
};
94+
95+
const displaySubmitSuccess = () => {
96+
return (
97+
<Text fontSize={["sm", "md"]} color="neutral.500">
98+
<CheckCircleIcon w={5} h={5} mb={1} color="green.500" /> Un email de
99+
réinitialisation de mot de passe a été envoyé à
100+
<br />
101+
l'adresse email associée à votre compte.
102+
</Text>
103+
);
104+
};
105+
106+
return (
107+
<WrapperForm title="Mot de passe oublié">
108+
<Box>{isSubmitSuccessful ? displaySubmitSuccess() : displayForm()}</Box>
109+
<Divider my={4} />
110+
<Text fontSize={["xs", "sm"]} color="neutral.500">
111+
<Link as={NextLink} href="/login">
112+
Retour à la connexion
113+
</Link>
114+
</Text>
115+
</WrapperForm>
116+
);
117+
};

webapp-next/components/login/FormLogin.tsx

Lines changed: 35 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
AlertTitle,
66
Box,
77
Button,
8+
Divider,
89
FormControl,
910
FormLabel,
1011
Heading,
@@ -26,19 +27,13 @@ import {
2627
useDisclosure,
2728
} from "@chakra-ui/react";
2829
import cookie from "js-cookie";
30+
import NextLink from "next/link";
2931
import { useRouter } from "next/router";
3032
import { useEffect, useRef, useState } from "react";
3133
import useSWRMutation from "swr/mutation";
32-
import { ELASTIC_API_KEY_NAME } from "@/utils/tools";
34+
import { ELASTIC_API_KEY_NAME, swrPOSTFetch } from "@/utils/tools";
3335
import { ContentCGU } from "@/pages/legals/cgu";
34-
35-
export async function auth<T>(url: string, { arg }: { arg: T }) {
36-
return fetch(url, {
37-
method: "POST",
38-
body: JSON.stringify(arg),
39-
headers: { "Content-Type": "application/json" },
40-
});
41-
}
36+
import { WrapperForm } from "./WrapperForm";
4237

4338
export const FormLogin = () => {
4439
const router = useRouter();
@@ -68,15 +63,15 @@ export const FormLogin = () => {
6863

6964
const { trigger: triggerLogin } = useSWRMutation(
7065
"/api/auth",
71-
auth<{ username: string; password: string }>
66+
swrPOSTFetch<{ username: string; password: string }>
7267
);
7368
const { trigger: triggerVerify } = useSWRMutation(
7469
"/api/auth/verify-code",
75-
auth<{ username: string; code: string }>
70+
swrPOSTFetch<{ username: string; code: string }>
7671
);
7772
const { trigger: triggerCreateUser } = useSWRMutation(
7873
"/api/auth/create-user",
79-
auth<{ username: string; versionCGU: string }>
74+
swrPOSTFetch<{ username: string; versionCGU: string }>
8075
);
8176

8277
const startTimer = () => {
@@ -192,7 +187,7 @@ export const FormLogin = () => {
192187
}}
193188
>
194189
<FormControl mb={[4, 6]}>
195-
<FormLabel htmlFor="code" fontSize={["10px", "12px"]} fontWeight={500}>
190+
<FormLabel htmlFor="code" fontSize={["2xs", "xs"]} fontWeight={500}>
196191
Code
197192
</FormLabel>
198193
<InputGroup mb={2}>
@@ -204,7 +199,7 @@ export const FormLogin = () => {
204199
id="code"
205200
autoFocus
206201
placeholder="Saisissez votre code"
207-
fontSize={"12px"}
202+
fontSize="xs"
208203
bg={"secondary.500"}
209204
value={code}
210205
onChange={handleCodeChange}
@@ -253,12 +248,11 @@ export const FormLogin = () => {
253248
<Button
254249
type="submit"
255250
isDisabled={isLoading}
256-
bg="primary.500"
257-
_hover={{}}
251+
colorScheme="primary"
258252
loadingText="Connexion en cours..."
259253
color={"white"}
260254
w={"full"}
261-
fontSize={["14px", "16px", "18px"]}
255+
fontSize={["md", "lg", "xl"]}
262256
fontWeight={600}
263257
>
264258
{isLoading ? <Spinner color="primary.500" /> : <>Je valide -&gt;</>}
@@ -276,7 +270,7 @@ export const FormLogin = () => {
276270
<FormControl mb={[4, 6]}>
277271
<FormLabel
278272
htmlFor="username"
279-
fontSize={["10px", "12px"]}
273+
fontSize={["2xs", "xs"]}
280274
fontWeight={500}
281275
>
282276
Identifiant
@@ -290,7 +284,7 @@ export const FormLogin = () => {
290284
id="username"
291285
autoFocus
292286
placeholder="Saisissez votre adresse email"
293-
fontSize={"12px"}
287+
fontSize="xs"
294288
bg={"secondary.500"}
295289
value={username}
296290
onChange={handleUsernameChange}
@@ -301,7 +295,7 @@ export const FormLogin = () => {
301295
<FormControl mb={[4, 6]}>
302296
<FormLabel
303297
htmlFor="password"
304-
fontSize={["10px", "12px"]}
298+
fontSize={["2xs", "xs"]}
305299
fontWeight={500}
306300
>
307301
Mot de passe
@@ -314,7 +308,7 @@ export const FormLogin = () => {
314308
type={isOpen ? "text" : "password"}
315309
id="password"
316310
placeholder="Saisissez votre mot de passe"
317-
fontSize={"12px"}
311+
fontSize="xs"
318312
bg={"secondary.500"}
319313
value={password}
320314
onChange={handlePasswordChange}
@@ -369,12 +363,11 @@ export const FormLogin = () => {
369363
<Button
370364
type="submit"
371365
isDisabled={isLoading}
372-
bg="primary.500"
373-
_hover={{}}
366+
colorScheme="primary"
374367
loadingText="Connexion en cours..."
375368
color={"white"}
376369
w={"full"}
377-
fontSize={["14px", "16px", "18px"]}
370+
fontSize={["md", "lg", "xl"]}
378371
fontWeight={600}
379372
>
380373
{isLoading ? (
@@ -383,41 +376,30 @@ export const FormLogin = () => {
383376
<>Je me connecte -&gt;</>
384377
)}
385378
</Button>
379+
<Divider my={4} />
380+
<Text fontSize={["xs", "sm"]} color="neutral.500">
381+
<Link as={NextLink} href="/login/forgot-password">
382+
Mot de passe oublié ?
383+
</Link>
384+
</Text>
386385
</form>
387386
);
388387

389388
return (
390389
<>
391-
<Box
392-
display="flex"
393-
justifyContent="center"
394-
alignItems="center"
395-
mx={"auto"}
396-
mt={[8, 0]}
390+
<WrapperForm title="Connexion 👋">
391+
<Text
392+
mb={6}
393+
fontSize={["md", "lg"]}
394+
fontWeight={400}
395+
color={"neutral.500"}
397396
>
398-
<Box maxW="sm" mx={[10, 20]} p={[0, 2]} bgColor="white">
399-
<Heading
400-
as="h1"
401-
size="lg"
402-
mb={6}
403-
fontSize={["32px", "48px"]}
404-
fontWeight={700}
405-
>
406-
Connexion 👋
407-
</Heading>
408-
<Text
409-
mb={6}
410-
fontSize={["14px", "16px"]}
411-
fontWeight={400}
412-
color={"neutral.500"}
413-
>
414-
{showCodeForm
415-
? "Vous avez reçu un code par email, merci de le saisir ci-dessous."
416-
: "Veuillez vous connecter pour accéder à votre compte."}
417-
</Text>
418-
{showCodeForm ? CodeForm : EmailPasswordForm}
419-
</Box>
420-
</Box>
397+
{showCodeForm
398+
? "Vous avez reçu un code par email, merci de le saisir ci-dessous."
399+
: "Veuillez vous connecter pour accéder à votre compte."}
400+
</Text>
401+
{showCodeForm ? CodeForm : EmailPasswordForm}
402+
</WrapperForm>
421403
<Modal
422404
isOpen={isOpenTerms}
423405
onClose={onCloseTerms}

0 commit comments

Comments
 (0)