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