refactor: Set default colorScheme to purple

Took 1 hour 12 minutes
This commit is contained in:
Lucàs
2023-05-06 12:51:28 +02:00
parent 0c7c3081b5
commit e0dbda70a8
32 changed files with 811 additions and 1152 deletions
+3 -15
View File
@@ -1,27 +1,15 @@
import { Box, Flex, Text, Button, Image } from "@chakra-ui/react"; import { Box, Flex, Text, Button, Image } from "@chakra-ui/react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
export default function BottomBar(props) { export default function BottomBar(props: { variant: any; saveData: any; }) {
const router = useRouter(); const router = useRouter();
const { variant, saveData } = props; const { variant, saveData } = props;
return ( return (
<Box <Box position={variant} zIndex={0} bottom={0} backdropFilter={"auto"} px={10} py={2}>
position={variant}
zIndex={0}
bottom={0}
backdropFilter={"auto"}
px={10}
py={2}
>
<Flex align={"center"}> <Flex align={"center"}>
<Button <Button onClick={() => saveData()}>
colorScheme={"purple"}
onClick={() => {
saveData();
}}
>
Sauvegarder les modifications Sauvegarder les modifications
</Button> </Button>
</Flex> </Flex>
+11 -30
View File
@@ -1,6 +1,6 @@
import { useState } from "react"; import {useState} from 'react';
import { Flex, IconButton } from "@chakra-ui/react"; import {Flex, IconButton} from '@chakra-ui/react';
import { BiLeftArrowAlt, BiRightArrowAlt } from "react-icons/bi"; import {BiLeftArrowAlt, BiRightArrowAlt} from 'react-icons/bi';
interface Props { interface Props {
images: string[]; images: string[];
@@ -18,38 +18,19 @@ const Carousel = ({ images, borderRadius: bRadius }: Props) => {
setCurrentIndex(currentIndex === images.length - 1 ? 0 : currentIndex + 1); setCurrentIndex(currentIndex === images.length - 1 ? 0 : currentIndex + 1);
}; };
if (images.length === 0) images = ["blank_profile_picture.webp"]; if (images.length === 0) images = ['blank_profile_picture.webp'];
return ( return (
<Flex <Flex px={2} align="center" borderRadius={bRadius} overflow={'hidden'}
px={2} justify={'space-between'} bgColor={'purple.50'} height={500}
align="center" bgImage={images[currentIndex]} bgSize={'contain'}
borderRadius={bRadius} bgRepeat={'no-repeat'} bgPosition={'center'} width={'100%'}>
overflow={"hidden"} <IconButton aria-label="left-arrow" borderRadius="full"
justify={"space-between"} onClick={handleClickPrevious}>
bgColor={"purple.50"}
bgImage={images[currentIndex]}
bgSize={"contain"}
bgRepeat={"no-repeat"}
bgPosition={"center"}
width={"100%"}
height={500}
>
<IconButton
aria-label="left-arrow"
colorScheme="purple"
borderRadius="full"
onClick={handleClickPrevious}
>
<BiLeftArrowAlt/> <BiLeftArrowAlt/>
</IconButton> </IconButton>
<IconButton <IconButton aria-label="left-arrow" borderRadius="full" onClick={handleClickNext}>
aria-label="left-arrow"
colorScheme="purple"
borderRadius="full"
onClick={handleClickNext}
>
<BiRightArrowAlt/> <BiRightArrowAlt/>
</IconButton> </IconButton>
</Flex> </Flex>
+3 -10
View File
@@ -6,20 +6,13 @@ export default function LoadingPage() {
const router = useRouter(); const router = useRouter();
return ( return (
<VStack <VStack justifyContent="center" alignItems="center" height="100vh"
justifyContent="center" width="100vw" bg="gray.100">
alignItems="center"
height="100vh"
width="100vw"
bg="gray.100"
>
<MdError color="purple.500" size="50%" /> <MdError color="purple.500" size="50%" />
<Text color="purple.500" fontSize="2xl" fontWeight="bold"> <Text color="purple.500" fontSize="2xl" fontWeight="bold">
Veillez à autoriser la géolocalisation Veillez à autoriser la géolocalisation
</Text> </Text>
<Button colorScheme={"purple"} onClick={() => router.push("/")}> <Button onClick={() => router.push("/")}>Page d'accueil</Button>
Page d'accueuil
</Button>
</VStack> </VStack>
); );
} }
+3 -10
View File
@@ -6,20 +6,13 @@ export default function LoadingPage() {
const router = useRouter(); const router = useRouter();
return ( return (
<VStack <VStack justifyContent="center" alignItems="center" height="100vh"
justifyContent="center" width="100vw" bg="gray.100">
alignItems="center"
height="100vh"
width="100vw"
bg="gray.100"
>
<MdError color="purple.500" size="50%" /> <MdError color="purple.500" size="50%" />
<Text color="purple.500" fontSize="2xl" fontWeight="bold"> <Text color="purple.500" fontSize="2xl" fontWeight="bold">
Une erreur est survenue Une erreur est survenue
</Text> </Text>
<Button colorScheme={"purple"} onClick={() => router.push("/")}> <Button onClick={() => router.push("/")}>Page d'accueil</Button>
Page d'accueuil
</Button>
</VStack> </VStack>
); );
} }
+3 -14
View File
@@ -2,20 +2,9 @@ import { Flex, Spinner } from "@chakra-ui/react";
export default function LoadingPage() { export default function LoadingPage() {
return ( return (
<Flex <Flex justifyContent="center" alignItems="center" height="100vh"
justifyContent="center" width="100vw" bg="gray.100">
alignItems="center" <Spinner thickness="4px" speed="0.65s" emptyColor="gray.200" size="xl"/>
height="100vh"
width="100vw"
bg="gray.100"
>
<Spinner
thickness="4px"
speed="0.65s"
emptyColor="gray.200"
color="purple.500"
size="xl"
/>
</Flex> </Flex>
); );
} }
+45 -59
View File
@@ -6,85 +6,71 @@ import {
Button, Button,
Image, Image,
Link, Link,
} from "@chakra-ui/react"; } from '@chakra-ui/react';
import { useRouter } from "next/router"; import {useRouter} from 'next/router';
import { signOut, useSession } from "next-auth/react"; import {signOut, useSession} from 'next-auth/react';
type Props = { type Props = {
variant: "static" | "fixed"; variant: 'static' | 'fixed';
}; };
export default function Navbar({ variant = "fixed" }: Props) { export default function Navbar({variant = 'fixed'}: Props) {
const router = useRouter(); const router = useRouter();
const {data: session, status} = useSession(); const {data: session, status} = useSession();
const RightSection = () => { const MiddleSection = () => {
if (status === "authenticated" && session.user) const authenticatedLinks = (
<>
<Link href={'/dashboard'}>Tableau de bord</Link>
<Link href={'/profile'}>Profile</Link>
<Link href={'/map'}>Carte</Link>
</>
);
return ( return (
<Flex justify={"right"} flexBasis={"100%"}> <Flex gap={5} justify={'center'} flexBasis={'100%'}>
<ButtonGroup> {status === 'authenticated'
<Button colorScheme={"purple"} onClick={() => signOut()}> ? authenticatedLinks
Déconnexion : <></>
</Button> }
</ButtonGroup>
</Flex> </Flex>
); );
else };
const RightSection = () => {
const authenticatedButtons = (
<Button onClick={() => signOut()}>Déconnexion</Button>
);
const unauthenticatedButtons = (
<>
<Button onClick={() => router.push('/register')}>Inscription</Button>
<Button onClick={() => router.push('/login')}>Connexion</Button>
</>
);
return ( return (
<Flex justify={"right"} flexBasis={"100%"}> <Flex justify={'right'} flexBasis={'100%'}>
<ButtonGroup> <ButtonGroup>
<Button onClick={() => router.push("/register")}> {status === 'authenticated'
Inscription ? authenticatedButtons
</Button> : unauthenticatedButtons
<Button }
colorScheme={"purple"}
onClick={() => router.push("/login")}
>
Connexion
</Button>
</ButtonGroup> </ButtonGroup>
</Flex> </Flex>
); );
}; };
return ( return (
<Box <Box position={variant} zIndex={9999} top={0} width={'100vw'}
position={variant} backdropFilter={'auto'} backdropBlur={'20px'} px={10} py={2}>
zIndex={9999} <Flex align={'center'}>
top={0} <Box flexBasis={'100%'}>
width={"100vw"} <Image src={'/logo.svg'} h={'3rem'} objectFit={'contain'}/>
backdropFilter={"auto"}
backdropBlur={"20px"}
px={10}
py={2}
>
<Flex align={"center"}>
<Box flexBasis={"100%"}>
<Image src={"/logo.svg"} h={"3rem"} objectFit={"contain"} />
</Box> </Box>
<Flex gap={5} justify={"center"} flexBasis={"100%"}> <MiddleSection/>
{status === "authenticated" ? (
<>
<Link href={"/dashboard"} color={"purple.500"}>
Tableau de bord
</Link>
<Link href={"/profile"} color={"purple.500"}>
Profile
</Link>
<Link href={"/map"} color={"purple.500"}>
Carte
</Link>
</>
) : (
<>
<Text>A propos</Text>
<Text>Contact</Text>
<Text>Aide</Text>
</>
)}
</Flex>
<RightSection/> <RightSection/>
</Flex> </Flex>
</Box> </Box>
+2 -2
View File
@@ -32,8 +32,8 @@ export default function FormMessage(props: Props) {
return ( return (
<Flex gap={5} mt={5}> <Flex gap={5} mt={5}>
<Input type={text} colorScheme={'purple'} onChange={(evt) => setText(evt.target.value) } value={text} /> <Input type={text} onChange={evt => setText(evt.target.value) } value={text}/>
<Button colorScheme={'purple'} onClick={handleSubmit} >Envoyer</Button> <Button onClick={handleSubmit}>Envoyer</Button>
</Flex> </Flex>
) )
} }
+31 -39
View File
@@ -8,13 +8,13 @@ import {
Input, Input,
Container, Container,
FormErrorMessage, FormErrorMessage,
} from "@chakra-ui/react"; } from '@chakra-ui/react';
import { useState } from "react"; import {useState} from 'react';
import { useRouter } from "next/router"; import {useRouter} from 'next/router';
import { signIn, SignInResponse } from "next-auth/react"; import {signIn, SignInResponse} from 'next-auth/react';
import { LoginData } from "@/models/form/LoginData"; import {LoginData} from '@/models/form/LoginData';
import { useForm } from "react-hook-form"; import {useForm} from 'react-hook-form';
export default function LoginForm() { export default function LoginForm() {
const router = useRouter(); const router = useRouter();
@@ -27,84 +27,76 @@ export default function LoginForm() {
formState: {errors, isSubmitting}, formState: {errors, isSubmitting},
} = useForm(); } = useForm();
const buttonWidth = { base: "100%", md: "unset" }; const buttonWidth = {base: '100%', md: 'unset'};
const errorPassword = "Mot de passe incorrect"; const errorPassword = 'Mot de passe incorrect';
const loginUser = async (value: LoginData) => { const loginUser = async (value: LoginData) => {
setIsLoading(true); setIsLoading(true);
signIn("credentials", { ...value, redirect: false }).then( signIn('credentials', {...value, redirect: false}).then(
(res: unknown) => { (res: unknown) => {
const {ok: connexionSuccess} = res as SignInResponse; const {ok: connexionSuccess} = res as SignInResponse;
setIsLoading(false); setIsLoading(false);
if (connexionSuccess) router.push("/dashboard"); if (connexionSuccess) router.push('/dashboard');
else setWrongPasswordError(true); else setWrongPasswordError(true);
} },
); );
}; };
return ( return (
<Box flexBasis={"100%"}> <Box flexBasis={'100%'}>
<Container> <Container>
<form id="login_form" onSubmit={handleSubmit(loginUser)}> <form id="login_form" onSubmit={handleSubmit(loginUser)}>
<Heading textAlign={"center"} size={"2xl"}> <Heading textAlign={'center'} size={'2xl'}>
Connexion Connexion
</Heading> </Heading>
{/*Email*/} {/*Email*/}
<FormControl mb={"1rem"} id={"email"} isInvalid={errors.email}> <FormControl mb={'1rem'} id={'email'}
isInvalid={errors.email as boolean | undefined}>
<FormLabel>Adresse email</FormLabel> <FormLabel>Adresse email</FormLabel>
<Input <Input
type="text" type="text"
{...register("email", { {...register('email', {
required: { value: true, message: "Adresse email requise" }, required: {value: true, message: 'Adresse email requise'},
pattern: { pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i, value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: "Adresse email invalide", message: 'Adresse email invalide',
}, },
})} })}
placeholder="adresse@email.com" placeholder="adresse@email.com"
/> />
<FormErrorMessage>{errors.email?.message}</FormErrorMessage> <FormErrorMessage>{errors.email?.message as string}</FormErrorMessage>
</FormControl> </FormControl>
{/*Mot de passe*/} {/*Mot de passe*/}
<FormControl <FormControl
mb={"1rem"} mb={'1rem'}
id="password" id="password"
isInvalid={errors.password || wrongPasswordError} isInvalid={errors.password as boolean | undefined ||
wrongPasswordError}
> >
<FormLabel>Mot de passe</FormLabel> <FormLabel>Mot de passe</FormLabel>
<Input <Input
type="password" type="password"
placeholder="Mot de passe" placeholder="Mot de passe"
{...register("password", { {...register('password', {
required: { value: true, message: "Mot de passe requis" }, required: {value: true, message: 'Mot de passe requis'},
})} })}
/> />
<FormErrorMessage>{errors.password?.message}</FormErrorMessage> <FormErrorMessage>{errors.password?.message as string}</FormErrorMessage>
<FormErrorMessage> <FormErrorMessage>{wrongPasswordError &&
{wrongPasswordError && errorPassword} errorPassword}</FormErrorMessage>
</FormErrorMessage>
</FormControl> </FormControl>
{/*Boutons*/} {/*Boutons*/}
<Flex <Flex justify={'center'} mt={'50px'} gap={5}
justify={"center"} justifyContent={'space-between'}>
mt={"50px"} <Button onClick={() => router.push('/')} w={buttonWidth}>
gap={5}
justifyContent={"space-between"}
>
<Button onClick={() => router.push("/")} w={buttonWidth}>
Retour Retour
</Button> </Button>
<Button <Button isLoading={isLoading} w={buttonWidth} type="submit">
isLoading={isLoading}
w={buttonWidth}
colorScheme="purple"
type="submit"
>
Connexion Connexion
</Button> </Button>
</Flex> </Flex>
+43 -68
View File
@@ -10,7 +10,6 @@ import {
FormErrorMessage, FormErrorMessage,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import {useRouter} from 'next/router'; import {useRouter} from 'next/router';
import {useState} from 'react';
import {signIn, SignInResponse} from 'next-auth/react'; import {signIn, SignInResponse} from 'next-auth/react';
import {RegisterData} from '@/models/form/RegisterData'; import {RegisterData} from '@/models/form/RegisterData';
import {SubmitHandler, useForm} from 'react-hook-form'; import {SubmitHandler, useForm} from 'react-hook-form';
@@ -48,137 +47,113 @@ export default function RegisterForm() {
}), }),
}; };
fetch('/api/users', options).then(() => { fetch('/api/users', options)
signIn('credentials', {email, password, redirect: false}).then( .then(() => signIn('credentials', {email, password, redirect: false}))
(res: unknown) => { .then((res: unknown) => {
const {ok: connexionSuccess} = res as SignInResponse; const {ok: connexionSuccess} = res as SignInResponse;
router.push(connexionSuccess ? '/getting-start' : '/');
// TODO If success -> goto interactive form else login
router.push(connexionSuccess ? '/dashboard' : '/');
}, },
); )
}).catch((err) => console.error(err)); .catch(err => console.error(err));
}; };
return ( return (
<Box flexBasis={'100%'}> <Box flexBasis={'100%'}>
<Container> <Container>
<form id="register_form" onSubmit={handleSubmit(submitHandler)}> <form id="register_form" onSubmit={handleSubmit(submitHandler)}>
<Heading textAlign={'center'} size={'2xl'}> <Heading textAlign={'center'} size={'2xl'}>Inscription</Heading>
Inscription
</Heading>
<Flex mt={'100px'} mb={'1rem'} gap={5}> <Flex mt={'100px'} mb={'1rem'} gap={5}>
{/*Prénom*/} {/*Prénom*/}
<FormControl id="firstName" isInvalid={errors.firstName as boolean|undefined}> <FormControl id="firstName"
isInvalid={errors.firstName as boolean | undefined}>
<FormLabel>Prénom</FormLabel> <FormLabel>Prénom</FormLabel>
<Input <Input type="text" placeholder="Prénom"
type="text"
placeholder="Prénom"
{...register('firstName', { {...register('firstName', {
required: {value: true, message: 'Prénom requis'}, required: {value: true, message: 'Prénom requis'},
})} })}/>
/>
<FormErrorMessage>{errors.firstName?.message as string}</FormErrorMessage> <FormErrorMessage>{errors.firstName?.message as string}</FormErrorMessage>
</FormControl> </FormControl>
{/*Nom*/} {/*Nom*/}
<FormControl id="lastName" isInvalid={errors.lastName as boolean|undefined}> <FormControl id="lastName"
isInvalid={errors.lastName as boolean | undefined}>
<FormLabel>Nom</FormLabel> <FormLabel>Nom</FormLabel>
<Input <Input type="text" placeholder="Nom"
type="text"
placeholder="Nom"
{...register('lastName', { {...register('lastName', {
required: {value: true, message: 'Nom requis'}, required: {value: true, message: 'Nom requis'},
})} })}/>
/>
<FormErrorMessage>{errors.lastName?.message as string}</FormErrorMessage> <FormErrorMessage>{errors.lastName?.message as string}</FormErrorMessage>
</FormControl> </FormControl>
</Flex> </Flex>
{/*Email*/} {/*Email*/}
<FormControl mb={'1rem'} id={'email'} isInvalid={errors.email as boolean|undefined}> <FormControl mb={'1rem'} id={'email'}
isInvalid={errors.email as boolean | undefined}>
<FormLabel>Adresse email</FormLabel> <FormLabel>Adresse email</FormLabel>
<Input <Input type="text" placeholder="adresse@email.com"
type="text"
{...register('email', { {...register('email', {
required: {value: true, message: 'Adresse email requise'}, required: {
value: true,
message: 'Adresse email requise',
},
pattern: { pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i, value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: 'Adresse email invalide', message: 'Adresse email invalide',
}, },
})} })}/>
placeholder="adresse@email.com"
/>
<FormErrorMessage>{errors.email?.message as string}</FormErrorMessage> <FormErrorMessage>{errors.email?.message as string}</FormErrorMessage>
</FormControl> </FormControl>
{/*Date de naissance*/} {/*Date de naissance*/}
<FormControl <FormControl mb={'1rem'} id={'birthdate'}
mb={'1rem'} isInvalid={errors.birthdate as boolean | undefined}>
id={'birthdate'}
isInvalid={errors.birthdate as boolean|undefined}
>
<FormLabel>Date de naissance</FormLabel> <FormLabel>Date de naissance</FormLabel>
<Input <Input type="date"
type="date"
{...register('birthdate', { {...register('birthdate', {
required: { required: {
value: true, value: true,
message: 'Date de naissance requise', message: 'Date de naissance requise',
}, },
validate: validateDate, validate: validateDate,
})} })}/>
/> {(errors.birthdate) &&
{ (errors.birthdate) ? <FormErrorMessage>{errors.birthdate.message as string}</FormErrorMessage> : "" } <FormErrorMessage>{errors.birthdate.message as string}</FormErrorMessage>}
</FormControl> </FormControl>
{/*Mot de passe*/} {/*Mot de passe*/}
<FormControl mb={'1rem'} id="password" isInvalid={errors.password as boolean|undefined}> <FormControl mb={'1rem'} id="password"
isInvalid={errors.password as boolean | undefined}>
<FormLabel>Mot de passe</FormLabel> <FormLabel>Mot de passe</FormLabel>
<Input <Input type="password" placeholder="Mot de passe"
type="password"
placeholder="Mot de passe"
{...register('password', { {...register('password', {
required: {value: true, message: 'Mot de passe requis'}, required: {value: true, message: 'Mot de passe requis'},
})} })}/>
/>
<FormErrorMessage>{errors.password?.message as string}</FormErrorMessage> <FormErrorMessage>{errors.password?.message as string}</FormErrorMessage>
</FormControl> </FormControl>
{/*Mot de passe (2)*/} {/*Mot de passe (2)*/}
<FormControl <FormControl mb={'1rem'} id="confirmPassword"
mb={'1rem'} isInvalid={errors.confirmPassword as boolean | undefined}>
id="confirmPassword"
isInvalid={errors.confirmPassword as boolean|undefined}
>
<FormLabel>Confirmation du mot de passe</FormLabel> <FormLabel>Confirmation du mot de passe</FormLabel>
<Input <Input type="password" placeholder="Mot de passe"
type="password"
placeholder="Mot de passe"
{...register('confirmPassword', { {...register('confirmPassword', {
required: {value: true, message: 'Confirmation requise'}, required: {value: true, message: 'Confirmation requise'},
validate: (value: string) => { validate: (value: string) => (
return (
watch('password') === value || watch('password') === value ||
'Les mots de passe ne correspondent pas' 'Les mots de passe ne correspondent pas'
); ),
}, })}/>
})}
/>
<FormErrorMessage>{errors.confirmPassword?.message as string}</FormErrorMessage> <FormErrorMessage>{errors.confirmPassword?.message as string}</FormErrorMessage>
</FormControl> </FormControl>
<Flex mt={'50px'} w={'100%'} justify={'space-between'} gap={5}> <Flex mt={'50px'} w={'100%'} justify={'space-between'} gap={5}>
<Button onClick={() => router.push('/')} w={{base: '100%', md: 'unset'}}> <Button onClick={() => router.push('/')}
w={{base: '100%', md: 'unset'}}>
Retour Retour
</Button> </Button>
<Button <Button isLoading={isSubmitting} w={{base: '100%', md: 'unset'}}
isLoading={isSubmitting} type="submit">
w={{base: '100%', md: 'unset'}}
colorScheme="purple"
type="submit"
>
Je m&apos;inscris Je m&apos;inscris
</Button> </Button>
</Flex> </Flex>
@@ -8,19 +8,20 @@ import {
Box, Box,
CardHeader, CardHeader,
useToast, useToast,
} from "@chakra-ui/react"; } from '@chakra-ui/react';
import Carousel from "../../../Carousel"; import Carousel from '../../../Carousel';
import { BiHeart } from "react-icons/bi"; import {BiHeart} from 'react-icons/bi';
import { RxCross1 } from "react-icons/rx"; import {RxCross1} from 'react-icons/rx';
import { useMutation, useQuery } from "@tanstack/react-query"; import {useMutation, useQuery} from '@tanstack/react-query';
import PassionTagList from "@/components/layout/dashboard/card_user/PassionTagList"; import PassionTagList
import { useState } from "react"; from '@/components/layout/dashboard/card_user/PassionTagList';
import SearchFailCard from "./SearchFailCard"; import {useState} from 'react';
import LoadingPage from "@/components/LoadingPage"; import SearchFailCard from './SearchFailCard';
import LoadingPage from '@/components/LoadingPage';
export default function CardUser({users, loggedUser, setMatch}) { export default function CardUser({users, loggedUser, setMatch}) {
const toast = useToast({ const toast = useToast({
position: "top", position: 'top',
duration: 2000, duration: 2000,
isClosable: true, isClosable: true,
}); });
@@ -29,8 +30,8 @@ export default function CardUser({ users, loggedUser, setMatch }) {
const likeMutation = useMutation({ const likeMutation = useMutation({
mutationFn: async (id) => { mutationFn: async (id) => {
const likePostOptions = { const likePostOptions = {
method: "POST", method: 'POST',
headers: { "Content-Type": "application/json" }, headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ body: JSON.stringify({
idUser: loggedUser.id, idUser: loggedUser.id,
idUserLiked: id, idUserLiked: id,
@@ -48,9 +49,9 @@ export default function CardUser({ users, loggedUser, setMatch }) {
onSuccess: (data) => { onSuccess: (data) => {
if (data.error) { if (data.error) {
toast({ toast({
title: "Erreur", title: 'Erreur',
description: "Une erreur est survenue", description: 'Une erreur est survenue',
status: "error", status: 'error',
}); });
return; return;
} }
@@ -59,9 +60,9 @@ export default function CardUser({ users, loggedUser, setMatch }) {
} }
setListUsers(listUsers.slice(1)); setListUsers(listUsers.slice(1));
toast({ toast({
title: "J'aime", title: 'J\'aime',
description: "Votre action a bien été prise en compte", description: 'Votre action a bien été prise en compte',
status: "success", status: 'success',
}); });
//tester si match et afficher un truc //tester si match et afficher un truc
@@ -71,8 +72,8 @@ export default function CardUser({ users, loggedUser, setMatch }) {
const dislikeMutation = useMutation({ const dislikeMutation = useMutation({
mutationFn: async (id) => { mutationFn: async (id) => {
const dislikePostOptions = { const dislikePostOptions = {
method: "POST", method: 'POST',
headers: { "Content-Type": "application/json" }, headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ body: JSON.stringify({
idUser: loggedUser.id, idUser: loggedUser.id,
idUserDisliked: id, idUserDisliked: id,
@@ -90,18 +91,18 @@ export default function CardUser({ users, loggedUser, setMatch }) {
onSuccess: (data) => { onSuccess: (data) => {
if (data.error) { if (data.error) {
toast({ toast({
title: "Erreur", title: 'Erreur',
description: "Une erreur est survenue", description: 'Une erreur est survenue',
status: "error", status: 'error',
duration: 2000, duration: 2000,
}); });
return; return;
} }
setListUsers(listUsers.slice(1)); setListUsers(listUsers.slice(1));
toast({ toast({
title: "J'aime pas", title: 'J\'aime pas',
description: "Votre action a bien été prise en compte", description: 'Votre action a bien été prise en compte',
status: "success", status: 'success',
duration: 2000, duration: 2000,
}); });
}, },
@@ -113,91 +114,70 @@ export default function CardUser({ users, loggedUser, setMatch }) {
data: listPassions, data: listPassions,
error: passionError, error: passionError,
} = useQuery({ } = useQuery({
queryKey: ["passions"], queryKey: ['passions'],
queryFn: async () => { queryFn: async () => {
return fetch(`/api/passions/`) return fetch(`/api/passions/`)
.then((res) => res.json()) .then(res => res.json())
.catch((err) => { .catch(err => err);
return err;
});
}, },
}); });
const formateDateToAge = (birthdate: Date) => { const formateDateToAge = (birthdate: Date) => {
const date = new Date(birthdate); const date = new Date(birthdate);
var ageDifMs = Date.now() - date.getTime(); const ageDifMs = Date.now() - date.getTime();
var ageDate = new Date(ageDifMs); // miliseconds from epoch const ageDate = new Date(ageDifMs); // miliseconds from epoch
return Math.abs(ageDate.getUTCFullYear() - 1970); return Math.abs(ageDate.getUTCFullYear() - 1970);
}; };
if (listUsers.length === 0) { if (listUsers.length === 0) return <SearchFailCard/>;
return <SearchFailCard />; if (likeMutation.isLoading ||
} dislikeMutation.isLoading) return <LoadingPage/>;
if (likeMutation.isLoading || dislikeMutation.isLoading) {
return <LoadingPage />;
}
return ( return (
<Card w={"100%"} h={"100%"} borderRadius={"1rem"} overflow={"hidden"}> <Card w={'100%'} h={'100%'} borderRadius={'1rem'} overflow={'hidden'}>
<CardHeader> <CardHeader>
<Carousel borderRadius={"1rem"} images={listUsers?.[0].images} /> <Carousel borderRadius={'1rem'} images={listUsers?.[0].images}/>
</CardHeader> </CardHeader>
<CardBody> <CardBody>
<Flex justify={"space-between"} mb={"20px"}> <Flex justify={'space-between'} mb={'20px'}>
<Heading fontSize={"1.5rem"} fontWeight={"bold"} flexBasis={"70%"}> <Heading fontSize={'1.5rem'} fontWeight={'bold'} flexBasis={'70%'}>
{listUsers[0].firstName} {listUsers[0].lastName},{" "} {listUsers[0].firstName} {listUsers[0].lastName},{' '}
{formateDateToAge(listUsers[0].birthdate)} ans {formateDateToAge(listUsers[0].birthdate)} ans
</Heading> </Heading>
<Flex gap={1}> <Flex gap={1}>
<IconButton <IconButton icon={<BiHeart/>} aria-label="like"
aria-label="like" borderRadius={'1rem'}
borderRadius={"1rem"} onClick={() => likeMutation.mutate(listUsers[0].id)
colorScheme={"purple"} }/>
onClick={() => { <IconButton icon={<RxCross1/>} aria-label="dislike"
likeMutation.mutate(listUsers[0].id); borderRadius={'1rem'} variant={'outline'}
}} onClick={() => dislikeMutation.mutate(
> listUsers[0].id)}/>
<BiHeart />
</IconButton>
<IconButton
aria-label="dislike"
borderRadius={"1rem"}
colorScheme={"purple"}
variant={"outline"}
onClick={() => {
dislikeMutation.mutate(listUsers[0].id);
}}
>
<RxCross1 />
</IconButton>
</Flex> </Flex>
</Flex> </Flex>
<Box mb={"20px"}> <Box mb={'20px'}>
<Heading size={"sm"} fontWeight={"bold"} mb="0.5rem"> <Heading size={'sm'} fontWeight={'bold'} mb="0.5rem">
A propos : A propos :
</Heading> </Heading>
<Text as="i">&quot;{listUsers[0].bio}&quot;</Text> <Text as="i">&quot;{listUsers[0].bio}&quot;</Text>
</Box> </Box>
<Box> <Box>
<Heading size={"sm"} fontWeight={"bold"}> <Heading size={'sm'} fontWeight={'bold'}>
Passions : Passions :
</Heading> </Heading>
{passionLoading ? ( {passionLoading
<Text>Chargement des passions...</Text> ? <Text>Chargement des passions...</Text>
) : passionIsError ? ( : passionIsError
<Text>Erreur lors du chargement des passions</Text> ? <Text>Erreur lors du chargement des passions</Text>
) : ( :
<PassionTagList <PassionTagList passions={listUsers[0].PassionID}
passions={listUsers[0].PassionID}
userPassions={loggedUser.PassionID} userPassions={loggedUser.PassionID}
listPassions={listPassions} listPassions={listPassions}/>
/> }
)}
</Box> </Box>
</CardBody> </CardBody>
</Card> </Card>
@@ -1,4 +1,4 @@
import { Badge, Flex, Tag } from "@chakra-ui/react"; import {Flex, Tag} from '@chakra-ui/react';
type Props = { type Props = {
passions: string[]; passions: string[];
@@ -6,22 +6,15 @@ type Props = {
listPassions?: Object[]; listPassions?: Object[];
}; };
export default function PassionTagList({ const PassionTagList = ({passions, userPassions = [], listPassions}: Props) => (
passions, <Flex gap={'0.5rem'} mt={'1vh'} flexWrap="wrap">
userPassions = [],
listPassions,
}: Props) {
return (
<Flex gap={"0.5rem"} mt={"1vh"} flexWrap="wrap">
{passions.map((passionID, index) => ( {passions.map((passionID, index) => (
<Tag <Tag variant={userPassions.includes(passionID) ? 'subtle' : 'outline'}
key={index} key={index}>
variant={userPassions.includes(passionID) ? "subtle" : "outline"}
colorScheme={"purple"}
>
{listPassions?.find((passion) => passion.id === passionID)?.name} {listPassions?.find((passion) => passion.id === passionID)?.name}
</Tag> </Tag>
))} ))}
</Flex> </Flex>
); );
}
export default PassionTagList;
@@ -1,8 +1,7 @@
import { Card, Text, CardBody, CardHeader } from "@chakra-ui/react"; import {Card, Text, CardBody, CardHeader} from '@chakra-ui/react';
export default function SearchFailCard(props) { const SearchFailCard = () => (
return ( <Card w={'100%'} h={'100%'} borderRadius={'1rem'} overflow={'hidden'}>
<Card w={"100%"} h={"100%"} borderRadius={"1rem"} overflow={"hidden"}>
<CardHeader> Aucun profil correspondant à vos critères </CardHeader> <CardHeader> Aucun profil correspondant à vos critères </CardHeader>
<CardBody> <CardBody>
<Text as="b"> <Text as="b">
@@ -11,4 +10,5 @@ export default function SearchFailCard(props) {
</CardBody> </CardBody>
</Card> </Card>
); );
}
export default SearchFailCard;
@@ -1,90 +1,64 @@
import {Card, Flex, Box, Image, Text, Spacer, Divider} from "@chakra-ui/react"; import {Card, Flex, Box, Image, Text, Spacer, Divider} from '@chakra-ui/react';
import { useRouter } from "next/router"; import {useRouter} from 'next/router';
import { AiFillMessage } from "react-icons/ai"; import {AiFillMessage} from 'react-icons/ai';
import { BsFillPersonFill } from "react-icons/bs"; import {BsFillPersonFill} from 'react-icons/bs';
import { BiLogOut } from "react-icons/bi"; import {BiLogOut} from 'react-icons/bi';
import { FaMapMarkedAlt } from "react-icons/fa"; import {FaMapMarkedAlt} from 'react-icons/fa';
import LeftPanelButton from "@/components/layout/dashboard/left_panel/LeftPanelButton"; import LeftPanelButton
import { signOut } from "next-auth/react"; from '@/components/layout/dashboard/left_panel/LeftPanelButton';
import {signOut} from 'next-auth/react';
export default function LeftPanel(props) { export default function LeftPanel(props) {
const router = useRouter(); const router = useRouter();
const {user} = props; const {user} = props;
const formateDate = (dateString) => { const formateDate = (dateString) => {
var options = { year: "numeric", month: "long", day: "numeric" }; const options = {year: 'numeric', month: 'long', day: 'numeric'};
return new Date(dateString).toLocaleDateString([], options); return new Date(dateString).toLocaleDateString([], options);
}; };
return ( return (
<Card <Card width={'20vw'} height={'100%'} borderRadius={0} padding={'0px'}
width={"20vw"} bg={'#faf9ff'}>
height={"100%"} <Flex direction={'column'} height={'100%'} margin={'10%'}>
borderRadius={0}
padding={"0px"}
bg={"#faf9ff"}
>
<Flex direction={"column"} height={"100%"} margin={"10%"}>
<Box> <Box>
{user.images.length === 0 ? ( <Image src={user.images[0] ?? '/blank_profile_picture.webp'}
<Image src={"/blank_profile_picture.webp"} borderRadius={"1rem"} /> objectFit={'contain'} borderRadius={'1rem'}/>
) : ( <Box mt={'2rem'}>
<Image <Flex align={'center'} justifyContent="space-between" mb={'1rem'}>
src={user.images[0]} <Text fontSize={'1.5rem'} fontWeight={'bold'}>
borderRadius={"1rem"}
objectFit={"contain"}
width={"100%"}
/>
)}
<Box mt={"2rem"}>
<Flex align={"center"} justifyContent="space-between" mb={"1rem"}>
<Text fontSize={"1.5rem"} fontWeight={"bold"}>
{user.firstName} {user.lastName} {user.firstName} {user.lastName}
</Text> </Text>
<Text fontSize={"1rem"} fontWeight={"bold"}> <Text fontSize={'1rem'} fontWeight={'bold'}>
{formateDate(user.birthdate)} {formateDate(user.birthdate)}
</Text> </Text>
</Flex> </Flex>
<Divider colorScheme={"purple"} mb={"1rem"} /> <Divider mb={'1rem'}/>
<Text as="i" fontWeight={"bold"}> <Text as="i" fontWeight={'bold'}>&quot;{user.bio}&quot;</Text>
&quot;{user.bio}&quot;
</Text>
</Box> </Box>
</Box> </Box>
<Spacer/> <Spacer/>
<Flex <Flex gap={2} direction={'column'} mt={'1vh'}
gap={2} spacing={3.5} alignContent={'bottom'}>
direction={"column"} <LeftPanelButton leftIcon={<FaMapMarkedAlt/>}
mt={"1vh"} onClickHandler={() => router.push('/map')}>
spacing={3.5}
alignContent={"bottom"}
>
<LeftPanelButton
leftIcon={<FaMapMarkedAlt />}
onClickHandler={() => router.push("/map")}
>
Carte Carte
</LeftPanelButton> </LeftPanelButton>
<LeftPanelButton
leftIcon={<AiFillMessage />} <LeftPanelButton leftIcon={<AiFillMessage/>}
onClickHandler={() => router.push("/dashboard")} onClickHandler={() => router.push('/dashboard')}>
>
Messages Messages
</LeftPanelButton> </LeftPanelButton>
<LeftPanelButton
leftIcon={<BsFillPersonFill />} <LeftPanelButton leftIcon={<BsFillPersonFill/>}
onClickHandler={() => router.push("/profile")} onClickHandler={() => router.push('/profile')}>
> Profil
Profile
</LeftPanelButton> </LeftPanelButton>
<LeftPanelButton <LeftPanelButton variant={'outline'} leftIcon={<BiLogOut/>}
variant={"outline"} onClickHandler={() => signOut({callbackUrl: '/'})}>
leftIcon={<BiLogOut />} Déconnexion
onClickHandler={() => signOut({ callbackUrl: "/" })}
>
Deconnexion
</LeftPanelButton> </LeftPanelButton>
</Flex> </Flex>
</Flex> </Flex>
@@ -2,25 +2,20 @@ import {Button, ResponsiveValue} from '@chakra-ui/react';
import {ReactJSXElement} from '@emotion/react/types/jsx-namespace'; import {ReactJSXElement} from '@emotion/react/types/jsx-namespace';
type Props = { type Props = {
children?: ReactJSXElement children?: ReactJSXElement | string
onClickHandler: () => void onClickHandler: () => void
leftIcon?: ReactJSXElement, leftIcon?: ReactJSXElement,
variant?: ResponsiveValue<'link' | 'outline' | string | 'ghost' | 'solid' | 'unstyled'> variant?: ResponsiveValue<'link' | 'outline' | string | 'ghost' | 'solid' | 'unstyled'>
} }
export default function LeftPanelButton(props: Props) { export default function LeftPanelButton(props: Props) {
const {children, onClickHandler, leftIcon: icon, variant = "ghost"} = props; const {children, onClickHandler, leftIcon: icon, variant = 'ghost'} = props;
return ( return (
<Button <Button variant={variant} width={'100%'} justifyContent={'left'}
colorScheme={'purple'} onClick={onClickHandler} leftIcon={icon} fontWeight={'bold'}
variant={variant} fontSize={'1.2rem'}>
width={'100%'} {children}
justifyContent={'left'} </Button>
onClick={onClickHandler}
leftIcon={icon}
fontWeight={'bold'}
fontSize={'1.2rem'}
>{children}</Button>
); );
} }
+9 -17
View File
@@ -13,37 +13,29 @@ export default function HeroBanner() {
const router = useRouter(); const router = useRouter();
return ( return (
<Flex <Flex bg={'#FAF9FF'} p={150} minH={{base: 'unset', md: '100vh'}}
bg={'#FAF9FF'} align={'center'} justify={'center'}>
p={150}
minH={{base: 'unset', md: '100vh'}}
align={'center'}
justify={'center'}
>
<Flex gap={10}> <Flex gap={10}>
<Flex justify={'center'} direction={'column'} flexBasis={'100%'}> <Flex justify={'center'} direction={'column'} flexBasis={'100%'}>
<Heading mb={'2.5rem'}>Prêt(e) à trouver votre âme sœur ?</Heading> <Heading mb={'2.5rem'}>Prêt(e) à trouver votre âme sœur ?</Heading>
<Text mb={'2rem'} maxW={{md: "500px"}}> <Text mb={'2rem'} maxW={{md: '500px'}}>
Notre site de rencontre vous offre la possibilité de rencontrer Notre site de rencontre vous offre la possibilité de rencontrer
des personnes intéressantes et de trouver l&apos;amour. Inscrivez-vous des personnes intéressantes et de trouver l&apos;amour.
Inscrivez-vous
dès maintenant pour découvrir toutes nos fonctionnalités ! dès maintenant pour découvrir toutes nos fonctionnalités !
</Text> </Text>
<ButtonGroup> <ButtonGroup>
<Button colorScheme={'purple'} <Button onClick={() => router.push('/register')}>
onClick={() => router.push('/register')}>
S&apos;inscrire S&apos;inscrire
</Button> </Button>
</ButtonGroup> </ButtonGroup>
</Flex> </Flex>
<Box flexBasis={'100%'} display={{base: "none", md: "block"}}> <Box flexBasis={'100%'} display={{base: 'none', md: 'block'}}>
<Image borderRadius={20} <Image borderRadius={20} boxShadow={'lg'} src={'/couple_img.jpg'}
boxShadow={'lg'} alt="happy couple"/>
src={'/couple_img.jpg'}
alt="happy couple"
/>
</Box> </Box>
</Flex> </Flex>
</Flex> </Flex>
@@ -4,8 +4,7 @@ export default function PresentationSection() {
return ( return (
<Flex justify={{base: 'center', md: 'right'}} alignItems={'center'} <Flex justify={{base: 'center', md: 'right'}} alignItems={'center'}
bg={{base: '#805AD5'}} bgImage={'/couple_funny.png'} bg={{base: '#805AD5'}} bgImage={'/couple_funny.png'}
bgSize={'cover'} bgSize={'cover'} bgPos={'center'}
bgPos={'center'}
bgAttachment={'fixed'} minH={{base: 'initial', md: '80vh'}}> bgAttachment={'fixed'} minH={{base: 'initial', md: '80vh'}}>
<Box p={50} width={{base: '100%', md: '50%'}} maxW={{md: "500px"}} bg={'#805AD5'}> <Box p={50} width={{base: '100%', md: '50%'}} maxW={{md: "500px"}} bg={'#805AD5'}>
+19 -28
View File
@@ -1,21 +1,22 @@
import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet"; import {MapContainer, TileLayer, Marker, Popup} from 'react-leaflet';
import { Flex, Text, useToast } from "@chakra-ui/react"; import {Flex, Text, useToast} from '@chakra-ui/react';
import MarkerClusterGroup from "@christopherpickering/react-leaflet-markercluster"; import MarkerClusterGroup
from '@christopherpickering/react-leaflet-markercluster';
import "@christopherpickering/react-leaflet-markercluster/dist/styles.min.css"; import '@christopherpickering/react-leaflet-markercluster/dist/styles.min.css';
import MarkerBar from "./MarkerBar"; import MarkerBar from './MarkerBar';
import "leaflet/dist/leaflet.css"; import 'leaflet/dist/leaflet.css';
export default function MapComponent(props: any) { export default function MapComponent(props: any) {
const {location, listBars} = props; const {location, listBars} = props;
const toast = useToast({ position: "bottom" }); const toast = useToast({position: 'bottom'});
const idToastError = "error_location"; const idToastError = 'error_location';
const userIcon = new L.Icon({ const userIcon = new L.Icon({
iconUrl: "logo.svg", iconUrl: 'logo.svg',
iconSize: [35, 35], iconSize: [35, 35],
}); });
@@ -23,32 +24,24 @@ export default function MapComponent(props: any) {
<> <>
{location[0] === null || location[1] === null ? ( {location[0] === null || location[1] === null ? (
<> <>
{!toast.isActive(idToastError) {!toast.isActive(idToastError) &&
? toast({ toast({
title: "Erreur", title: 'Erreur',
id: idToastError, id: idToastError,
description: "Veuillez autoriser la localisation", description: 'Veuillez autoriser la localisation',
status: "error", status: 'error',
isClosable: false, isClosable: false,
duration: 100000, duration: 100000,
}) })}
: null}
<Text color="purple.500" fontSize="2xl" fontWeight="bold"> <Text color="purple.500" fontSize="2xl" fontWeight="bold">
Veuillez autoriser la localisation Veuillez autoriser la localisation
</Text> </Text>
</> </>
) : ( ) : (
<Flex> <Flex>
<MapContainer <MapContainer center={location} zoom={13} minZoom={8}
center={location}
zoom={13}
minZoom={8}
zoomControl={false} zoomControl={false}
style={{ style={{width: '100vw', height: '100vw'}}>
width: "100vw",
height: "100vw",
}}
>
<TileLayer <TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
@@ -57,9 +50,7 @@ export default function MapComponent(props: any) {
<Marker icon={userIcon} position={location}></Marker> <Marker icon={userIcon} position={location}></Marker>
<MarkerClusterGroup chunkedLoading showCoverageOnHover={false}> <MarkerClusterGroup chunkedLoading showCoverageOnHover={false}>
{listBars.map((bar, index) => { {listBars.map((bar: any, index: number) => <MarkerBar key={index} bar={bar}/>)}
return <MarkerBar key={index} bar={bar} />;
})}
</MarkerClusterGroup> </MarkerClusterGroup>
</MapContainer> </MapContainer>
</Flex> </Flex>
+2 -4
View File
@@ -1,6 +1,6 @@
import { Marker, Popup } from "react-leaflet"; import { Marker, Popup } from "react-leaflet";
import "leaflet/dist/leaflet.css"; import "leaflet/dist/leaflet.css";
import { Box, Button, Card, CardBody, Text } from "@chakra-ui/react"; import { Box, Button, Text } from "@chakra-ui/react";
export default function MarkerBar(props) { export default function MarkerBar(props) {
const { bar } = props; const { bar } = props;
@@ -23,9 +23,7 @@ export default function MarkerBar(props) {
<Text fontSize={"1rem"} fontWeight={"bold"} align={"center"}> <Text fontSize={"1rem"} fontWeight={"bold"} align={"center"}>
{bar.name || '"Nom du bar"'} {bar.name || '"Nom du bar"'}
</Text> </Text>
<Button colorScheme={"purple"} variant={"outline"}> <Button variant={"outline"}>Inviter un match</Button>
Inviter un match
</Button>
</Box> </Box>
</Popup> </Popup>
</Marker> </Marker>
@@ -4,9 +4,9 @@ import {
Tag, Tag,
TagLeftIcon, TagLeftIcon,
TagLabel, TagLabel,
} from "@chakra-ui/react"; } from '@chakra-ui/react';
import { IoAdd, IoRemove } from "react-icons/io5"; import {IoAdd, IoRemove} from 'react-icons/io5';
export default function CustomCheckbox(props) { export default function CustomCheckbox(props) {
const {text} = props; const {text} = props;
@@ -14,33 +14,17 @@ export default function CustomCheckbox(props) {
useCheckbox(props); useCheckbox(props);
return ( return (
<chakra.label <chakra.label variant={state.isChecked ? 'solid' : 'outline'}
// colorScheme={"purple"} cursor="pointer" {...htmlProps}>
variant={state.isChecked ? "solid" : "outline"}
cursor="pointer"
{...htmlProps}
>
<input {...getInputProps()} hidden/> <input {...getInputProps()} hidden/>
{state.isChecked ? (
<Tag <Tag {...getCheckboxProps()} variant={state.isChecked ? "solid" : "outline"} {...getLabelProps()}>
{...getCheckboxProps()} {state.isChecked
colorScheme={"purple"} ? <TagLeftIcon as={IoRemove}/>
{...getLabelProps()} : <TagLeftIcon as={IoAdd}/>
> }
<TagLeftIcon as={IoRemove} />
<TagLabel>{text}</TagLabel> <TagLabel>{text}</TagLabel>
</Tag> </Tag>
) : (
<Tag
{...getCheckboxProps()}
colorScheme={"purple"}
variant={"outline"}
{...getLabelProps()}
>
<TagLeftIcon as={IoAdd} />
<TagLabel>{text}</TagLabel>
</Tag>
)}
</chakra.label> </chakra.label>
); );
} }
@@ -6,52 +6,40 @@ import {
FormErrorMessage, FormErrorMessage,
FormHelperText, FormHelperText,
FormLabel, FormLabel,
} from "@chakra-ui/react"; } from '@chakra-ui/react';
import { Controller, ControllerProps } from "react-hook-form"; import {Controller, ControllerProps} from 'react-hook-form';
type CustomEditableProps = { type CustomEditableProps = {
label: string; label: string;
isDisabled?: boolean; isDisabled?: boolean;
helperText?: string; helperText?: string;
} & Omit<ControllerProps, "render">; } & Omit<ControllerProps, 'render'>;
export default function CustomEditable(props: CustomEditableProps) { export default function CustomEditable(props: CustomEditableProps) {
const { const {
defaultValue, defaultValue,
label, label,
name, name,
helperText = "", helperText = '',
isDisabled = false, isDisabled = false,
...controllerProps ...controllerProps
} = props; } = props;
return ( return (
<Controller <Controller{...controllerProps} name={name} defaultValue={defaultValue}
{...controllerProps} render={({field, fieldState: {invalid, error}}) => (
name={name}
defaultValue={defaultValue}
render={({ field, fieldState: { invalid, error } }) => {
return (
<FormControl id={name} isInvalid={invalid}> <FormControl id={name} isInvalid={invalid}>
<FormLabel as="legend" htmlFor={name}> <FormLabel as="legend" htmlFor={name}>{label}</FormLabel>
{label} <Editable{...field} id={name} fontWeight="bold"
</FormLabel>
<Editable
{...field}
id={name}
fontWeight="bold"
isDisabled={isDisabled} isDisabled={isDisabled}
placeholder={"Non renseigné"} placeholder={'Non renseigné'}
color={isDisabled ? "gray.500" : undefined} color={isDisabled ? 'gray.500' : undefined}>
>
<EditablePreview/> <EditablePreview/>
<EditableInput/> <EditableInput/>
</Editable> </Editable>
<FormHelperText>{helperText}</FormHelperText> <FormHelperText>{helperText}</FormHelperText>
<FormErrorMessage as="b">{error?.message}</FormErrorMessage> <FormErrorMessage as="b">{error?.message}</FormErrorMessage>
</FormControl> </FormControl>
); )}/>
}}
/>
); );
} }
@@ -5,13 +5,13 @@ import {
FormControl, FormControl,
FormErrorMessage, FormErrorMessage,
FormLabel, FormLabel,
} from "@chakra-ui/react"; } from '@chakra-ui/react';
import { Controller, ControllerProps } from "react-hook-form"; import {Controller, ControllerProps} from 'react-hook-form';
type CustomEditableProps = { type CustomEditableProps = {
label: string; label: string;
isDisabled?: boolean; isDisabled?: boolean;
} & Omit<ControllerProps, "render">; } & Omit<ControllerProps, 'render'>;
export default function CustomEditableArea(props: CustomEditableProps) { export default function CustomEditableArea(props: CustomEditableProps) {
const { const {
@@ -23,32 +23,19 @@ export default function CustomEditableArea(props: CustomEditableProps) {
} = props; } = props;
return ( return (
<Controller <Controller{...controllerProps} name={name} defaultValue={defaultValue}
{...controllerProps} render={({field, fieldState: {invalid, error}}) => (
name={name}
defaultValue={defaultValue}
render={({ field, fieldState: { invalid, error } }) => {
return (
<FormControl id={name} isInvalid={invalid}> <FormControl id={name} isInvalid={invalid}>
<FormLabel as="legend" htmlFor={name}> <FormLabel as="legend" htmlFor={name}>{label}</FormLabel>
{label} <Editable{...field} id={name} fontWeight="bold"
</FormLabel> width={'100%'} isDisabled={isDisabled}
<Editable placeholder={'Non renseigné'}
{...field} color={isDisabled ? 'gray.500' : undefined}>
id={name}
fontWeight="bold"
width={"100%"}
isDisabled={isDisabled}
placeholder={"Non renseigné"}
color={isDisabled ? "gray.500" : undefined}
>
<EditablePreview/> <EditablePreview/>
<EditableTextarea/> <EditableTextarea/>
</Editable> </Editable>
<FormErrorMessage as="b">{error?.message}</FormErrorMessage> <FormErrorMessage as="b">{error?.message}</FormErrorMessage>
</FormControl> </FormControl>
); )}/>
}}
/>
); );
} }
@@ -5,7 +5,7 @@ import {
FormHelperText, FormHelperText,
FormLabel, FormLabel,
UseEditableProps, UseEditableProps,
} from "@chakra-ui/react"; } from '@chakra-ui/react';
type CustomEditableProps = { type CustomEditableProps = {
id: string; id: string;
@@ -14,20 +14,13 @@ type CustomEditableProps = {
} & UseEditableProps; } & UseEditableProps;
export default function CustomEditable(props: CustomEditableProps) { export default function CustomEditable(props: CustomEditableProps) {
const { label, id, helperText = "", ...UseEditableProps } = props; const {label, id, helperText = '', ...UseEditableProps} = props;
return ( return (
<FormControl> <FormControl>
<FormLabel as="legend" htmlFor={id}> <FormLabel as="legend" htmlFor={id}>{label}</FormLabel>
{label} <Editable{...UseEditableProps} fontWeight="bold" isDisabled={true}
</FormLabel> placeholder={'Non renseigné'} color={'gray.500'}>
<Editable
{...UseEditableProps}
fontWeight="bold"
isDisabled={true}
placeholder={"Non renseigné"}
color={"gray.500"}
>
<EditablePreview/> <EditablePreview/>
</Editable> </Editable>
<FormHelperText>{helperText}</FormHelperText> <FormHelperText>{helperText}</FormHelperText>
@@ -1,60 +1,35 @@
import { FormLabel, HStack, Radio, RadioGroup } from "@chakra-ui/react"; import {FormLabel, HStack, Radio, RadioGroup} from '@chakra-ui/react';
import { Gender } from "@prisma/client"; import {Gender} from '@prisma/client';
import { Controller, ControllerProps } from "react-hook-form"; import {Controller, ControllerProps} from 'react-hook-form';
type CustomRadioGenderProps = { type CustomRadioGenderProps = {
label: string; label: string;
} & Omit<ControllerProps, "render">; } & Omit<ControllerProps, 'render'>;
export default function CustomRadioGender(props: CustomRadioGenderProps) { export default function CustomRadioGender(props: CustomRadioGenderProps) {
const {defaultValue, label, name, ...controllerProps} = props; const {defaultValue, label, name, ...controllerProps} = props;
const getTextGender = (gender: string) => { const genders = [
switch (gender) { {label: 'Homme', gender: Gender.MALE},
case Gender.MALE: {label: 'Femme', gender: Gender.FEMALE},
return "Homme"; {label: 'Autre', gender: Gender.OTHER},
case Gender.FEMALE: {label: 'Non renseigné', gender: Gender.UNKNOWN},
return "Femme"; ];
case Gender.OTHER:
return "Autre";
case Gender.UNKNOWN:
return "Non renseigné";
}
};
return ( return (
<> <>
<FormLabel as={"legend"} htmlFor={name}> <FormLabel as={'legend'} htmlFor={name}>{label}</FormLabel>
{label} <Controller{...controllerProps} name={name}
</FormLabel> render={({field}) => (
<Controller <RadioGroup{...field} id={name} as="b"
{...controllerProps} defaultValue={defaultValue}>
name={name} <HStack spacing={'0.5rem'}>
render={({ field }) => { {genders.map(({label, gender}, index) => (
return ( <Radio key={index} value={gender}>{label}</Radio>
<RadioGroup ))}
{...field}
colorScheme={"purple"}
id={name}
as="b"
defaultValue={defaultValue}
>
<HStack spacing={"0.5rem"}>
<Radio value={Gender.MALE}>{getTextGender(Gender.MALE)}</Radio>
<Radio value={Gender.FEMALE}>
{getTextGender(Gender.FEMALE)}
</Radio>
<Radio value={Gender.OTHER}>
{getTextGender(Gender.OTHER)}
</Radio>
<Radio value={Gender.UNKNOWN}>
{getTextGender(Gender.UNKNOWN)}
</Radio>
</HStack> </HStack>
</RadioGroup> </RadioGroup>
); )}/>
}}
/>
</> </>
); );
} }
@@ -6,10 +6,10 @@ import {
RangeSliderThumb, RangeSliderThumb,
RangeSliderTrack, RangeSliderTrack,
Tooltip, Tooltip,
} from "@chakra-ui/react"; } from '@chakra-ui/react';
import { Controller, ControllerProps } from "react-hook-form"; import {Controller, ControllerProps} from 'react-hook-form';
import { FaGreaterThan, FaLessThan } from "react-icons/fa"; import {FaGreaterThan, FaLessThan} from 'react-icons/fa';
type CustomRangeSliderProps = { type CustomRangeSliderProps = {
label: string; label: string;
@@ -19,7 +19,7 @@ type CustomRangeSliderProps = {
showTooltipAge: boolean; showTooltipAge: boolean;
setShowTooltipAge: React.Dispatch<React.SetStateAction<boolean>>; setShowTooltipAge: React.Dispatch<React.SetStateAction<boolean>>;
name: string; name: string;
} & Omit<ControllerProps, "render">; } & Omit<ControllerProps, 'render'>;
export default function CustomRangeSlider(props: CustomRangeSliderProps) { export default function CustomRangeSlider(props: CustomRangeSliderProps) {
const { const {
@@ -35,59 +35,39 @@ export default function CustomRangeSlider(props: CustomRangeSliderProps) {
return ( return (
<> <>
<FormLabel as={"legend"} htmlFor={name}> <FormLabel as={'legend'} htmlFor={name}>{label}</FormLabel>
{label} <Controller{...controllerProps} name={name}
</FormLabel>
<Controller
{...controllerProps}
name={name}
render={({field: {onChange}}) => ( render={({field: {onChange}}) => (
<RangeSlider <RangeSlider aria-label={['min', 'max']} min={18}
aria-label={["min", "max"]}
colorScheme={"purple"}
min={18}
max={99} max={99}
id={name} id={name} color={'pink.500'}
color={"pink.500"}
defaultValue={defaultValue} defaultValue={defaultValue}
onChange={(v: [number, number]) => { onChange={(v: [number, number]) => {
setSliderAgeValue(v); setSliderAgeValue(v);
onChange(v); onChange(v);
}} }}
onMouseEnter={() => setShowTooltipAge(true)} onMouseEnter={() => setShowTooltipAge(true)}
onMouseLeave={() => setShowTooltipAge(false)} onMouseLeave={() => setShowTooltipAge(false)}>
>
<RangeSliderTrack> <RangeSliderTrack>
<RangeSliderFilledTrack bgColor={"purple.500"} /> <RangeSliderFilledTrack bgColor={'purple.500'}/>
</RangeSliderTrack> </RangeSliderTrack>
<Tooltip <Tooltip hasArrow bg="purple.500" color="white"
hasArrow placement="top" isOpen={showTooltipAge}
bg="purple.500" label={`${sliderAgeValue[0]}`}>
color="white"
placement="top"
isOpen={showTooltipAge}
label={`${sliderAgeValue[0]}`}
>
<RangeSliderThumb boxSize={6} index={0}> <RangeSliderThumb boxSize={6} index={0}>
<Box color={"purple.500"} as={FaLessThan} /> <Box color={'purple.500'} as={FaLessThan}/>
</RangeSliderThumb> </RangeSliderThumb>
</Tooltip> </Tooltip>
<Tooltip <Tooltip hasArrow bg="purple.500" color="white"
hasArrow placement="top" isOpen={showTooltipAge}
bg="purple.500" label={`${sliderAgeValue[1]}`}>
color="white"
placement="top"
isOpen={showTooltipAge}
label={`${sliderAgeValue[1]}`}
>
<RangeSliderThumb boxSize={6} index={1}> <RangeSliderThumb boxSize={6} index={1}>
<Box color={"purple.500"} as={FaGreaterThan} /> <Box color={'purple.500'} as={FaGreaterThan}/>
</RangeSliderThumb> </RangeSliderThumb>
</Tooltip> </Tooltip>
</RangeSlider> </RangeSlider>
)} )}/>
/>
</> </>
); );
} }
+16 -32
View File
@@ -6,10 +6,10 @@ import {
SliderThumb, SliderThumb,
SliderTrack, SliderTrack,
Tooltip, Tooltip,
} from "@chakra-ui/react"; } from '@chakra-ui/react';
import { Controller, ControllerProps } from "react-hook-form"; import {Controller, ControllerProps} from 'react-hook-form';
import { FaWalking } from "react-icons/fa"; import {FaWalking} from 'react-icons/fa';
type CustomSliderProps = { type CustomSliderProps = {
label: string; label: string;
@@ -19,7 +19,7 @@ type CustomSliderProps = {
showTooltipDistance: boolean; showTooltipDistance: boolean;
setShowTooltipDistance: React.Dispatch<React.SetStateAction<boolean>>; setShowTooltipDistance: React.Dispatch<React.SetStateAction<boolean>>;
name: string; name: string;
} & Omit<ControllerProps, "render">; } & Omit<ControllerProps, 'render'>;
export default function CustomSlider(props: CustomSliderProps) { export default function CustomSlider(props: CustomSliderProps) {
const { const {
@@ -35,46 +35,30 @@ export default function CustomSlider(props: CustomSliderProps) {
return ( return (
<> <>
<FormLabel as={"legend"} htmlFor={name}> <FormLabel as={'legend'} htmlFor={name}>{label}</FormLabel>
{label} <Controller{...controllerProps} name={name}
</FormLabel>
<Controller
{...controllerProps}
name={name}
render={({field: {onChange}}) => ( render={({field: {onChange}}) => (
<Slider <Slider aria-label={'distance'} min={20} max={250}
aria-label={"distance"} id={'distance'} color={'pink.500'}
colorScheme={"purple"}
min={20}
max={250}
id={"distance"}
color={"pink.500"}
defaultValue={defaultValue} defaultValue={defaultValue}
onChange={(v) => { onChange={v => {
setSliderDistanceValue(v); setSliderDistanceValue(v);
onChange(v); onChange(v);
}} }}
onMouseEnter={() => setShowTooltipDistance(true)} onMouseEnter={() => setShowTooltipDistance(true)}
onMouseLeave={() => setShowTooltipDistance(false)} onMouseLeave={() => setShowTooltipDistance(false)}>
>
<SliderTrack> <SliderTrack>
<SliderFilledTrack bgColor={"purple.500"} /> <SliderFilledTrack bgColor={'purple.500'}/>
</SliderTrack> </SliderTrack>
<Tooltip <Tooltip hasArrow bg="purple.500" color="white"
hasArrow placement="top" isOpen={showTooltipDistance}
bg="purple.500" label={`${sliderDistanceValue} km`}>
color="white"
placement="top"
isOpen={showTooltipDistance}
label={`${sliderDistanceValue} km`}
>
<SliderThumb boxSize={6}> <SliderThumb boxSize={6}>
<Box color={"purple.500"} as={FaWalking} /> <Box color={'purple.500'} as={FaWalking}/>
</SliderThumb> </SliderThumb>
</Tooltip> </Tooltip>
</Slider> </Slider>
)} )}/>
/>
</> </>
); );
} }
@@ -13,15 +13,16 @@ import {
useCheckboxGroup, useCheckboxGroup,
useDisclosure, useDisclosure,
useToast, useToast,
} from "@chakra-ui/react"; } from '@chakra-ui/react';
import { useQueryClient } from "@tanstack/react-query"; import {useQueryClient} from '@tanstack/react-query';
import { RiEditBoxLine } from "react-icons/ri"; import {RiEditBoxLine} from 'react-icons/ri';
import CustomCheckbox from "./CustomCheckbox"; import CustomCheckbox from './CustomCheckbox';
import {Passion} from '@prisma/client';
export default function ModalChoosePassion(props) { export default function ModalChoosePassion(props) {
const {isOpen, onOpen, onClose} = useDisclosure(); const {isOpen, onOpen, onClose} = useDisclosure();
const {user, passions} = props; const {user, passions} = props;
const toast = useToast({ position: "top", isClosable: true }); const toast = useToast({position: 'top', isClosable: true});
const client = useQueryClient(); const client = useQueryClient();
const {value, getCheckboxProps} = useCheckboxGroup({ const {value, getCheckboxProps} = useCheckboxGroup({
@@ -36,76 +37,51 @@ export default function ModalChoosePassion(props) {
}); });
const options = { const options = {
method: "PATCH", method: 'PATCH',
headers: { headers: {'Content-Type': 'application/json'},
"Content-Type": "application/json",
},
body: JSON.stringify(jsonPassions), body: JSON.stringify(jsonPassions),
}; };
fetch(`/api/users/${user.id}`, options) fetch(`/api/users/${user.id}`, options)
.then((res) => res.json()) .then(res => res.json())
.then((data) => { .then(() => {
toast({ toast({
title: "Centres d'intérêts mis à jour", title: 'Centres d\'intérêts mis à jour',
status: "success", status: 'success',
duration: 9000, duration: 9000,
}); });
client.invalidateQueries("user"); client.invalidateQueries('user');
onClose(); onClose();
}) })
.catch((err) => { .catch(err => console.log(err));
console.log(err);
});
}; };
return ( return (
<> <>
<Button <Button onClick={onOpen} leftIcon={<RiEditBoxLine/>}>
colorScheme={"purple"} Choisir les centres d'intérêts
onClick={onOpen}
leftIcon={<RiEditBoxLine />}
>
Choisir les centres d'intérèts
</Button> </Button>
<Modal <Modal blockScrollOnMount={false} size={'4xl'} isOpen={isOpen}
blockScrollOnMount={false} onClose={onClose} scrollBehavior={'inside'}>
size={"4xl"}
isOpen={isOpen}
onClose={onClose}
scrollBehavior={"inside"}
>
<ModalOverlay/> <ModalOverlay/>
<ModalContent> <ModalContent>
<ModalHeader>Choix des centres d'intérèts</ModalHeader> <ModalHeader>Choix des centres d'intérêts</ModalHeader>
<ModalCloseButton/> <ModalCloseButton/>
<ModalBody> <ModalBody>
<Flex gap={"1rem"} flexWrap="wrap"> <Flex gap={'1rem'} flexWrap="wrap">
{passions !== null ? ( {passions && (
passions.map((passion, index) => { passions.map((passion: Passion) => (
return ( <CustomCheckbox key={passion.id} text={passion.name}
<CustomCheckbox {...getCheckboxProps({value: passion.id})}/>
{...getCheckboxProps({ value: passion.id })} )
key={passion.id} )
text={passion.name}
/>
);
})
) : (
<></>
)} )}
</Flex> </Flex>
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<Button <Button mr={3} onClick={() => savePassions(value)}>
colorScheme="purple"
mr={3}
onClick={() => {
savePassions(value);
}}
>
Save Save
</Button> </Button>
</ModalFooter> </ModalFooter>
@@ -13,44 +13,43 @@ import {
ModalHeader, ModalHeader,
ModalOverlay, ModalOverlay,
useDisclosure, useDisclosure,
useQuery,
useToast, useToast,
} from "@chakra-ui/react"; } from '@chakra-ui/react';
import { useQueryClient } from "@tanstack/react-query"; import {useQueryClient} from '@tanstack/react-query';
import { useState } from "react"; import {useState} from 'react';
import { RiEditBoxLine } from "react-icons/ri"; import {RiEditBoxLine} from 'react-icons/ri';
export default function ModalModifyImages(props) { export default function ModalModifyImages(props) {
const {isOpen, onOpen, onClose} = useDisclosure(); const {isOpen, onOpen, onClose} = useDisclosure();
const {images, user, userData, setUserData} = props; const {images, user, userData, setUserData} = props;
const [listImage, setlistImage] = useState(images); const [listImage, setlistImage] = useState(images);
const toast = useToast({ position: "top", isClosable: true }); const toast = useToast({position: 'top', isClosable: true});
const client = useQueryClient(); const client = useQueryClient();
const uploadImage = async (file) => { const uploadImage = async (file) => {
const body = new FormData(); const body = new FormData();
body.append("file", file); body.append('file', file);
const imagePostOptions = { const imagePostOptions = {
method: "POST", method: 'POST',
body, body,
}; };
const imagePatchOptions = { const imagePatchOptions = {
method: "PUT", method: 'PUT',
headers: { "Content-Type": "application/json" }, headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ body: JSON.stringify({
images: [...listImage, `imageUsers/${file.name}`], images: [...listImage, `imageUsers/${file.name}`],
}), }),
}; };
fetch(`/api/file/uploadFile`, imagePostOptions) fetch(`/api/file/uploadFile`, imagePostOptions)
.then((res) => { .then(res => {
fetch(`/api/users/${user.id}`, imagePatchOptions) fetch(`/api/users/${user.id}`, imagePatchOptions)
.then((res) => { .then(res => {
toast({ toast({
title: `Ajout d'image effectué`, title: `Ajout d'image effectué`,
status: "success", status: 'success',
isClosable: true, isClosable: true,
}); });
setlistImage([...listImage, `imageUsers/${file.name}`]); setlistImage([...listImage, `imageUsers/${file.name}`]);
@@ -60,15 +59,15 @@ export default function ModalModifyImages(props) {
setIsLoading(false); setIsLoading(false);
toast({ toast({
title: `Erreur lors de l'ajout des images`, title: `Erreur lors de l'ajout des images`,
status: "error", status: 'error',
isClosable: true, isClosable: true,
}); });
}); });
}) })
.catch((err) => { .catch(err => {
toast({ toast({
title: `Erreur lors de l'ajout des images`, title: `Erreur lors de l'ajout des images`,
status: "error", status: 'error',
isClosable: true, isClosable: true,
}); });
console.log(err); console.log(err);
@@ -85,14 +84,14 @@ export default function ModalModifyImages(props) {
} }
const imageDeleteOptions = { const imageDeleteOptions = {
method: "DELETE", method: 'DELETE',
body: JSON.stringify({ fileName: fileName.split("/").pop() }), body: JSON.stringify({fileName: fileName.split('/').pop()}),
}; };
fetch(`/api/file/deleteFile`, imageDeleteOptions).then((res) => { fetch(`/api/file/deleteFile`, imageDeleteOptions).then((res) => {
const imagePatchOptions = { const imagePatchOptions = {
method: "PUT", method: 'PUT',
headers: { "Content-Type": "application/json" }, headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ body: JSON.stringify({
images: [...listImage], images: [...listImage],
}), }),
@@ -101,14 +100,14 @@ export default function ModalModifyImages(props) {
.then((res) => { .then((res) => {
toast({ toast({
title: `Suppression d'image effectué`, title: `Suppression d'image effectué`,
status: "success", status: 'success',
isClosable: true, isClosable: true,
}); });
}) })
.catch(() => { .catch(() => {
toast({ toast({
title: `Erreur lors de la suppression des images`, title: `Erreur lors de la suppression des images`,
status: "error", status: 'error',
isClosable: true, isClosable: true,
}); });
}); });
@@ -117,84 +116,60 @@ export default function ModalModifyImages(props) {
return ( return (
<> <>
<Button <Button onClick={onOpen} leftIcon={<RiEditBoxLine/>}>
colorScheme={"purple"}
onClick={onOpen}
leftIcon={<RiEditBoxLine />}
>
Modifier les images Modifier les images
</Button> </Button>
<Modal <Modal blockScrollOnMount={false} size={'4xl'} isOpen={isOpen}
blockScrollOnMount={false} onClose={onClose} scrollBehavior={'inside'}>
size={"4xl"}
isOpen={isOpen}
onClose={onClose}
scrollBehavior={"inside"}
>
<ModalOverlay/> <ModalOverlay/>
<ModalContent> <ModalContent>
<ModalHeader>Modification des images</ModalHeader> <ModalHeader>Modification des images</ModalHeader>
<ModalCloseButton/> <ModalCloseButton/>
<ModalBody> <ModalBody>
<Grid <Grid templateColumns={`repeat(${listImage.length + 1}, 1fr)`}
templateColumns={`repeat(${listImage.length + 1}, 1fr)`} gap={5}>
gap={5}
>
{listImage.map((image, index) => ( {listImage.map((image, index) => (
<GridItem key={index}> <GridItem key={index}>
<Flex direction={"column"} gap={"1rem"}> <Flex direction={'column'} gap={'1rem'}>
<Image src={image}/> <Image src={image}/>
<Button <Button id={index.toString()} colorScheme={'red'}
id={"" + index} onClick={() =>
colorScheme={"red"} deleteImage(`${listImage[index]}`)}>
onClick={(e) => {
deleteImage(`${listImage[index]}`);
}}
>
Supprimer l'image Supprimer l'image
</Button> </Button>
</Flex> </Flex>
</GridItem> </GridItem>
))} ))}
{listImage.length < 5 ? ( {listImage.length < 5 && (
<GridItem width={"100%"}> <GridItem width={'100%'}>
<Input <Input type={'file'} height={'100%'}
type={"file"} accept={'image/png, image/jpeg, image/webp'}
height={"100%"}
accept={"image/png, image/jpeg, image/webp"}
onInput={({target}) => { onInput={({target}) => {
const date = new Date(); const date = new Date();
const time = date.getTime(); const time = date.getTime();
const file = target.files[0]; const file = target.files[0];
const extension = file.name.split(".").pop(); const extension = file.name.split('.').pop();
const newFile = new File( const newFile = new File(
[file], [file],
`${user.id}_${time}.${extension}`, `${user.id}_${time}.${extension}`,
{ {
type: file.type, type: file.type,
} },
); );
uploadImage(newFile); uploadImage(newFile);
}} }}/>
></Input>
</GridItem> </GridItem>
) : (
<></>
)} )}
</Grid> </Grid>
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<Button <Button mr={3} onClick={() => {
colorScheme="purple" client.invalidateQueries('user');
mr={3}
onClick={(e) => {
client.invalidateQueries("user");
onClose(); onClose();
}} }}>
>
Save Save
</Button> </Button>
</ModalFooter> </ModalFooter>
@@ -5,7 +5,7 @@ export default function ProfileBadgeList(props) {
return ( return (
<Flex gap={"0.5rem"} mt={"1vh"} flexWrap="wrap"> <Flex gap={"0.5rem"} mt={"1vh"} flexWrap="wrap">
{userPassions.map((idPassion, index) => ( {userPassions.map((idPassion, index) => (
<Tag key={index} colorScheme={"purple"}> <Tag key={index}>
{passions !== null && passions !== undefined && passions.length > 0 {passions !== null && passions !== undefined && passions.length > 0
? passions.find((element) => element.id === idPassion).name ? passions.find((element) => element.id === idPassion).name
: ""} : ""}
+2 -1
View File
@@ -3,6 +3,7 @@ import type { AppProps } from "next/app";
import { ChakraProvider } from "@chakra-ui/react"; import { ChakraProvider } from "@chakra-ui/react";
import { SessionProvider } from "next-auth/react"; import { SessionProvider } from "next-auth/react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import theme from '@/styles/theme';
const queryClient = new QueryClient(); const queryClient = new QueryClient();
@@ -12,7 +13,7 @@ export default function App({
}: AppProps) { }: AppProps) {
return ( return (
<QueryClientProvider client={queryClient}> <QueryClientProvider client={queryClient}>
<ChakraProvider> <ChakraProvider theme={theme}>
<SessionProvider session={session}> <SessionProvider session={session}>
<Component {...pageProps} /> <Component {...pageProps} />
</SessionProvider> </SessionProvider>
+27 -39
View File
@@ -1,21 +1,22 @@
import { import {
Box, Box,
Button, Button,
Flex,
FormControl, FormControl,
FormErrorMessage, FormErrorMessage,
FormLabel, FormLabel,
Input, Input,
useToast, useToast,
} from "@chakra-ui/react"; } from '@chakra-ui/react';
import { useSession } from "next-auth/react"; import {useSession} from 'next-auth/react';
import { useRouter } from "next/router"; import {useRouter} from 'next/router';
import { useState } from "react"; import {useState} from 'react';
import { useForm } from "react-hook-form"; import {useForm} from 'react-hook-form';
import LoadingPage from '@/components/LoadingPage';
import {Session} from '@/models/auth/Session';
export default function settings() { export default function settings() {
const router = useRouter(); const router = useRouter();
const toast = useToast({ position: "top", isClosable: true }); const toast = useToast({position: 'top', isClosable: true});
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
@@ -26,66 +27,53 @@ export default function settings() {
} = useForm(); } = useForm();
const [userData, setUserData] = useState({}); const [userData, setUserData] = useState({});
const {data: session, status} = useSession({required: true});
const { data: session, status } = useSession(); if (status === "loading") return <LoadingPage/>
if (status === "unauthenticated") router.push("/login"); if (status === 'authenticated') {
if (status === "authenticated") {
const {user} = session as unknown as Session; const {user} = session as unknown as Session;
if (user.role !== "ADMIN") router.push("/login"); if (user.role !== 'ADMIN') router.push('/login');
const savePassion = (passion: any) => { const savePassion = (passion: any) => {
const options = { const options = {
method: "POST", method: 'POST',
headers: { "Content-Type": "application/json" }, headers: {'Content-Type': 'application/json'},
body: JSON.stringify(passion), body: JSON.stringify(passion),
}; };
fetch(`/api/passions`, options) fetch(`/api/passions`, options)
.then((res) => { .then(res => {
setIsLoading(false); setIsLoading(false);
toast({ toast({
title: `Passion ajoutée`, title: `Passion ajoutée`,
status: "success", status: 'success',
}); });
}) })
.catch((err) => { .catch(err => {
setIsLoading(false); setIsLoading(false);
toast({ toast({
title: `Erreur lors de l'ajout`, title: `Erreur lors de l'ajout`,
status: "error", status: 'error',
}); });
}); });
}; };
return ( return (
<> <>
<Box <Box as="form" id="form_passion" width={'80%'}
as="form" onSubmit={handleSubmit(savePassion)}>
id="form_passion" <FormControl isInvalid={errors.name as boolean | undefined}>
width={"80%"}
onSubmit={handleSubmit(savePassion)}
>
<FormControl isInvalid={errors.name}>
<FormLabel htmlFor="passion">Passion</FormLabel> <FormLabel htmlFor="passion">Passion</FormLabel>
<Input <Input id="passion" placeholder="passion"
id="passion" {...register('name', {
placeholder="passion" required: 'This is required',
{...register("name", { })}/>
required: "This is required",
})}
/>
<FormErrorMessage> <FormErrorMessage>
{errors.name && errors.name.message} {errors.name && errors.name.message as string}
</FormErrorMessage> </FormErrorMessage>
</FormControl> </FormControl>
<Button <Button mt={4} isLoading={isSubmitting} type="submit">
mt={4}
colorScheme="purple"
isLoading={isSubmitting}
type="submit"
>
Submit Submit
</Button> </Button>
</Box> </Box>
+1 -1
View File
@@ -55,7 +55,7 @@ export default function ChatId() {
<MessageList user={session.user as User} messages={messages}/> <MessageList user={session.user as User} messages={messages}/>
<Flex gap={5} mt={5}> <Flex gap={5} mt={5}>
<Input type={"text"} colorScheme={'purple'} onChange={(evt) => setText(evt.target.value) } value={text} /> <Input type={"text"} colorScheme={'purple'} onChange={evt => setText(evt.target.value)} value={text} />
<Button colorScheme={'purple'} onClick={handleSubmit}>Envoyer</Button> <Button colorScheme={'purple'} onClick={handleSubmit}>Envoyer</Button>
</Flex> </Flex>
</Container> </Container>
+9
View File
@@ -0,0 +1,9 @@
import {extendTheme, withDefaultColorScheme} from '@chakra-ui/react';
const theme = extendTheme(
{},
withDefaultColorScheme({ colorScheme: 'purple' })
);
export default theme;