mirror of
https://github.com/LucasVbr/meeting-app.git
synced 2026-05-13 17:21:53 +00:00
371 lines
12 KiB
TypeScript
371 lines
12 KiB
TypeScript
import { useSession } from "next-auth/react";
|
|
import { useRouter } from "next/router";
|
|
import type { Session } from "@/models/auth/Session";
|
|
import Carousel from "@/components/Carousel";
|
|
import { Gender } from "@prisma/client";
|
|
import {
|
|
Box,
|
|
Button,
|
|
Center,
|
|
Container,
|
|
Divider,
|
|
Flex,
|
|
FormLabel,
|
|
Text,
|
|
useToast,
|
|
VStack,
|
|
} from "@chakra-ui/react";
|
|
|
|
import { formateDate } from "@/lib/formateDate";
|
|
import ModalModifyImages from "@/components/layout/profile/ModalModifyImages";
|
|
import ModalChoosePassion from "@/components/layout/profile/ModalChoosePassion";
|
|
import ProfileTagList from "@/components/layout/profile/ProfileTagList";
|
|
import LoadingPage from "@/components/LoadingPage";
|
|
import CustomEditable from "@/components/layout/profile/CustomEditable";
|
|
import CustomFalseEditable from "@/components/layout/profile/CustomFalseEditable";
|
|
import CustomEditableArea from "@/components/layout/profile/CustomEditableArea";
|
|
import CustomRadioGender from "@/components/layout/profile/CustomRadioGender";
|
|
import CustomRangeSlider from "@/components/layout/profile/CustomRangeSlider";
|
|
import CustomSlider from "@/components/layout/profile/CustomSlider";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { useForm } from "react-hook-form";
|
|
import { useQuery } from "@tanstack/react-query";
|
|
|
|
export default function UserProfile() {
|
|
const router = useRouter();
|
|
const toast = useToast({ position: "top", isClosable: true });
|
|
|
|
const [currentlyLoading, setCurrentlyLoading] = useState(false);
|
|
const [passions, setPassions] = useState([] as any[]);
|
|
const [address, setAddress] = useState({} as any);
|
|
|
|
const [showTooltipAge, setShowTooltipAge] = useState(false);
|
|
const [sliderAgeValue, setSliderAgeValue] = useState([[] as number[]]);
|
|
const [showTooltipDistance, setShowTooltipDistance] = useState(false);
|
|
const [sliderDistanceValue, setSliderDistanceValue] = useState<number>(0);
|
|
|
|
const {
|
|
handleSubmit,
|
|
control,
|
|
formState: { errors },
|
|
} = useForm({ mode: "onBlur" });
|
|
|
|
useEffect(() => {
|
|
fetch(`/api/passions`)
|
|
.then((res) => res.json())
|
|
.then((data) => {
|
|
setPassions([...data]);
|
|
})
|
|
.catch((err) => {
|
|
console.log(err);
|
|
});
|
|
}, []);
|
|
|
|
const { data: session, status } = useSession();
|
|
|
|
const {
|
|
isLoading,
|
|
isError,
|
|
data: userData,
|
|
error,
|
|
} = useQuery({
|
|
queryKey: ["user"],
|
|
enabled: status === "authenticated",
|
|
queryFn: async () => {
|
|
const { user } = session as unknown as Session;
|
|
|
|
setSliderAgeValue([user.ageMin, user.ageMax]);
|
|
setSliderDistanceValue(user.distance);
|
|
|
|
return fetch(`/api/users/${user.id}`)
|
|
.then((res) => res.json())
|
|
.catch((err) => {
|
|
return err;
|
|
});
|
|
},
|
|
});
|
|
|
|
const { data: addressData, isSuccess: addressIsSuccess } = useQuery({
|
|
queryKey: ["address"],
|
|
enabled: Boolean(userData?.location),
|
|
queryFn: async () => {
|
|
const [lat, long] = userData.location.split(",");
|
|
|
|
return fetch(
|
|
`https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${lat}&lon=${long}`
|
|
)
|
|
.then((res) => res.json())
|
|
.catch((err) => {
|
|
return err;
|
|
});
|
|
},
|
|
});
|
|
|
|
if (isLoading) {
|
|
if (status === "unauthenticated") router.push("/login");
|
|
return <LoadingPage />;
|
|
}
|
|
|
|
if (isError) {
|
|
toast({
|
|
title: `Erreur lors de la récupération des données du profil`,
|
|
status: "error",
|
|
position: "top",
|
|
});
|
|
if (status === "unauthenticated") router.push("/");
|
|
}
|
|
|
|
const saveData = (values: any) => {
|
|
let trueValues = {};
|
|
|
|
for (const [key, value] of Object.entries(values)) {
|
|
if (value !== "" && value !== undefined) {
|
|
if (key === "age") {
|
|
trueValues["ageMin"] = value[0];
|
|
trueValues["ageMax"] = value[1];
|
|
} else {
|
|
trueValues[key] = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
const options = {
|
|
method: "PATCH",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify(trueValues),
|
|
};
|
|
|
|
if (Object.keys(trueValues).length > 0) {
|
|
setCurrentlyLoading(true);
|
|
fetch(`/api/users/${userData.id}`, options)
|
|
.then((res) => {
|
|
setCurrentlyLoading(false);
|
|
toast({
|
|
position: "top",
|
|
title: `Modifications effectuées`,
|
|
status: "success",
|
|
isClosable: true,
|
|
});
|
|
})
|
|
.catch((err) => {
|
|
setCurrentlyLoading(false);
|
|
toast({
|
|
title: `Erreur lors de l'envoi des modifications`,
|
|
position: "top",
|
|
status: "error",
|
|
isClosable: true,
|
|
});
|
|
console.log(err);
|
|
});
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Box height={"100%"}>
|
|
<Container justifyContent={"center"} maxW={"70rem"} mt={"1rem"}>
|
|
<Flex flexDirection={"column"} alignItems={"center"} gap={"1rem"}>
|
|
<Box width={"50%"}>
|
|
<Carousel
|
|
images={
|
|
userData.images
|
|
? userData.images
|
|
: ["blank_profile_picture.webp"]
|
|
}
|
|
borderRadius={"1rem"}
|
|
></Carousel>
|
|
</Box>
|
|
<ModalModifyImages
|
|
userData={userData}
|
|
user={userData}
|
|
images={userData.images}
|
|
/>
|
|
|
|
<Divider colorScheme={"purple"} />
|
|
<Text align={"center"} as="i" color={"grey"}>
|
|
Modifiez les champs en les selectionnants
|
|
</Text>
|
|
|
|
<Box
|
|
position={"relative"}
|
|
as="form"
|
|
onSubmit={handleSubmit(saveData)}
|
|
width={"80%"}
|
|
>
|
|
<Flex width={"100%"} justify={"space-between"} mb={"1rem"}>
|
|
<Box>
|
|
<CustomEditable
|
|
name="firstName"
|
|
defaultValue={
|
|
userData.firstName === null ? "" : userData.firstName
|
|
}
|
|
control={control}
|
|
rules={{
|
|
required: { value: true, message: "Prénom requis" },
|
|
}}
|
|
label={"Prénom :"}
|
|
/>
|
|
</Box>
|
|
<Box>
|
|
<CustomEditable
|
|
name="lastName"
|
|
defaultValue={
|
|
userData.lastName === null ? "" : userData.lastName
|
|
}
|
|
control={control}
|
|
rules={{
|
|
required: { value: true, message: "Nom requis" },
|
|
}}
|
|
label={"Nom :"}
|
|
/>
|
|
</Box>
|
|
<Box>
|
|
<CustomFalseEditable
|
|
id="birthdate"
|
|
value={
|
|
userData.birthdate === undefined ||
|
|
userData.birthdate === null
|
|
? "Non renseigné"
|
|
: formateDate(userData.birthdate.toString())
|
|
}
|
|
label={"Date de naissance :"}
|
|
/>
|
|
</Box>
|
|
</Flex>
|
|
<Divider colorScheme={"purple"} />
|
|
<Flex justify={"space-between"} my={"1rem"}>
|
|
<Box>
|
|
<CustomFalseEditable
|
|
id="location"
|
|
value={
|
|
!addressIsSuccess || addressData === undefined
|
|
? "Rendez vous sur la carte !"
|
|
: `${addressData.address.town}, ${addressData.address.county}, ${addressData.address.state}`
|
|
}
|
|
label={"Adresse :"}
|
|
helperText={
|
|
"Ce champ est automatiquement modifié depuis la carte"
|
|
}
|
|
/>
|
|
</Box>
|
|
<Box>
|
|
<CustomFalseEditable
|
|
id="email"
|
|
value={userData.email}
|
|
label={"Adresse mail :"}
|
|
/>
|
|
</Box>
|
|
</Flex>
|
|
<Divider colorScheme={"purple"} />
|
|
<Box my={"1rem"}>
|
|
<CustomEditableArea
|
|
name="bio"
|
|
defaultValue={userData.bio === null ? "" : userData.bio}
|
|
control={control}
|
|
rules={{
|
|
maxLength: {
|
|
value: 240,
|
|
message: "240 caractères maximum",
|
|
},
|
|
}}
|
|
label={"À propos :"}
|
|
/>
|
|
</Box>
|
|
<Divider colorScheme={"purple"} />
|
|
<Box my={"1rem"}>
|
|
<Box>
|
|
<CustomRadioGender
|
|
name={"gender"}
|
|
label={"Genre :"}
|
|
control={control}
|
|
defaultValue={
|
|
userData.gender === null ? Gender.UNKNOWN : userData.gender
|
|
}
|
|
/>
|
|
</Box>
|
|
</Box>
|
|
<Divider colorScheme={"purple"} />
|
|
<Box my={"1rem"}>
|
|
<Box>
|
|
<FormLabel as={"legend"} htmlFor={"passion"}>
|
|
Centre d'intéret :
|
|
</FormLabel>
|
|
<VStack gap={"1rem"} align="start">
|
|
<ProfileTagList
|
|
userPassions={
|
|
userData.PassionID !== undefined ? userData.PassionID : []
|
|
}
|
|
passions={passions}
|
|
/>
|
|
<ModalChoosePassion user={userData} passions={passions} />
|
|
</VStack>
|
|
</Box>
|
|
</Box>
|
|
<Divider colorScheme={"purple"} />
|
|
<Box my={"1rem"}>
|
|
<Center>
|
|
<Text as={"b"} fontSize={"1.5rem"} my={"1rem"}>
|
|
Préférences
|
|
</Text>
|
|
</Center>
|
|
<Box my={"1rem"}>
|
|
<CustomRadioGender
|
|
name={"prefGender"}
|
|
label={"Genre :"}
|
|
control={control}
|
|
defaultValue={
|
|
userData.prefGender === null
|
|
? Gender.UNKNOWN
|
|
: userData.prefGender
|
|
}
|
|
/>
|
|
</Box>
|
|
<Box>
|
|
<CustomRangeSlider
|
|
control={control}
|
|
label={"Age :"}
|
|
name={"age"}
|
|
defaultValue={[userData.ageMin, userData.ageMax]}
|
|
setSliderAgeValue={setSliderAgeValue}
|
|
setShowTooltipAge={setShowTooltipAge}
|
|
showTooltipAge={showTooltipAge}
|
|
sliderAgeValue={sliderAgeValue}
|
|
/>
|
|
</Box>
|
|
<CustomSlider
|
|
control={control}
|
|
label={"Distance des bars :"}
|
|
name={"distance"}
|
|
defaultValue={userData.distance}
|
|
setSliderDistanceValue={setSliderDistanceValue}
|
|
setShowTooltipDistance={setShowTooltipDistance}
|
|
showTooltipDistance={showTooltipDistance}
|
|
sliderDistanceValue={sliderDistanceValue}
|
|
/>
|
|
</Box>
|
|
<Divider colorScheme={"purple"} />
|
|
<Center position={"sticky"} bottom={0} gap={"1rem"} my={"1rem"}>
|
|
<Button
|
|
colorScheme={"purple"}
|
|
isLoading={currentlyLoading}
|
|
type="submit"
|
|
>
|
|
Sauvegarder les modifications
|
|
</Button>
|
|
<Button
|
|
colorScheme={"purple"}
|
|
variant="outline"
|
|
onClick={() => {
|
|
router.push("/dashboard");
|
|
}}
|
|
>
|
|
Retour
|
|
</Button>
|
|
</Center>
|
|
</Box>
|
|
</Flex>
|
|
</Container>
|
|
</Box>
|
|
);
|
|
}
|