mirror of
https://github.com/LucasVbr/meeting-app.git
synced 2026-05-13 17:21:53 +00:00
refactor: Set default colorScheme to purple
Took 1 hour 12 minutes
This commit is contained in:
@@ -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
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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'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">"{listUsers[0].bio}"</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"}>
|
||||
"{user.bio}"
|
||||
</Text>
|
||||
<Divider mb={'1rem'}/>
|
||||
<Text as="i" fontWeight={'bold'}>"{user.bio}"</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>
|
||||
);
|
||||
}
|
||||
@@ -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'amour. Inscrivez-vous
|
||||
des personnes intéressantes et de trouver l'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'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'}>
|
||||
|
||||
@@ -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='© <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>
|
||||
|
||||
@@ -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>
|
||||
)}
|
||||
/>
|
||||
)}/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import {extendTheme, withDefaultColorScheme} from '@chakra-ui/react';
|
||||
|
||||
|
||||
const theme = extendTheme(
|
||||
{},
|
||||
withDefaultColorScheme({ colorScheme: 'purple' })
|
||||
);
|
||||
|
||||
export default theme;
|
||||
Reference in New Issue
Block a user