mirror of
https://github.com/LucasVbr/meeting-app.git
synced 2026-05-13 17:21:53 +00:00
feat(Preferences): Choose preferences -- Fetch user from pref
This commit is contained in:
@@ -24,6 +24,13 @@ model User {
|
|||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
|
// Les préférences de l'utilisateur
|
||||||
|
distance Int @default(100)
|
||||||
|
ageMax Int @default(99)
|
||||||
|
ageMin Int @default(18)
|
||||||
|
prefGender Gender @default(UNKNOWN)
|
||||||
|
|
||||||
|
|
||||||
// Liste des chats de l'utilisateur
|
// Liste des chats de l'utilisateur
|
||||||
ChatID String[] @db.ObjectId
|
ChatID String[] @db.ObjectId
|
||||||
Chat Chat[] @relation(fields: [ChatID], references: [id])
|
Chat Chat[] @relation(fields: [ChatID], references: [id])
|
||||||
@@ -128,4 +135,4 @@ enum NotificationType {
|
|||||||
enum Role {
|
enum Role {
|
||||||
USER
|
USER
|
||||||
ADMIN
|
ADMIN
|
||||||
}
|
}
|
||||||
@@ -27,8 +27,11 @@ const Carousel = ({ images, borderRadius: bRadius }: Props) => {
|
|||||||
borderRadius={bRadius}
|
borderRadius={bRadius}
|
||||||
overflow={"hidden"}
|
overflow={"hidden"}
|
||||||
justify={"space-between"}
|
justify={"space-between"}
|
||||||
|
bgColor={"purple.50"}
|
||||||
bgImage={images[currentIndex]}
|
bgImage={images[currentIndex]}
|
||||||
bgSize={"cover"}
|
bgSize={"contain"}
|
||||||
|
bgRepeat={"no-repeat"}
|
||||||
|
bgPosition={"center"}
|
||||||
width={"100%"}
|
width={"100%"}
|
||||||
height={500}
|
height={500}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -28,12 +28,9 @@ export default function CardUser(props) {
|
|||||||
setUserDislikes,
|
setUserDislikes,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
console.log(userLikes);
|
|
||||||
console.log(userDislikes);
|
|
||||||
|
|
||||||
const toast = useToast({
|
const toast = useToast({
|
||||||
position: "top",
|
position: "top",
|
||||||
duration: 3000,
|
duration: 2000,
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
});
|
});
|
||||||
const [listUsers, setListUsers] = useState(users);
|
const [listUsers, setListUsers] = useState(users);
|
||||||
@@ -66,7 +63,6 @@ export default function CardUser(props) {
|
|||||||
title: "Erreur",
|
title: "Erreur",
|
||||||
description: "Une erreur est survenue",
|
description: "Une erreur est survenue",
|
||||||
status: "error",
|
status: "error",
|
||||||
duration: 2000,
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
@@ -74,7 +70,6 @@ export default function CardUser(props) {
|
|||||||
title: "J'aime",
|
title: "J'aime",
|
||||||
description: "Votre action a bien été prise en compte",
|
description: "Votre action a bien été prise en compte",
|
||||||
status: "success",
|
status: "success",
|
||||||
duration: 2000,
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -154,7 +149,7 @@ export default function CardUser(props) {
|
|||||||
return (
|
return (
|
||||||
<Card w={"100%"} h={"100%"} borderRadius={"1rem"} overflow={"hidden"}>
|
<Card w={"100%"} h={"100%"} borderRadius={"1rem"} overflow={"hidden"}>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<Carousel borderRadius={"1rem"} images={listUsers[0].images} />
|
<Carousel borderRadius={"1rem"} images={listUsers?.[0].images} />
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|
||||||
<CardBody>
|
<CardBody>
|
||||||
|
|||||||
@@ -39,7 +39,12 @@ export default function LeftPanel(props) {
|
|||||||
{user.images.length === 0 ? (
|
{user.images.length === 0 ? (
|
||||||
<Image src={"/blank_profile_picture.webp"} borderRadius={"1rem"} />
|
<Image src={"/blank_profile_picture.webp"} borderRadius={"1rem"} />
|
||||||
) : (
|
) : (
|
||||||
<Image src={user.images[0]} borderRadius={"1rem"} />
|
<Image
|
||||||
|
src={user.images[0]}
|
||||||
|
borderRadius={"1rem"}
|
||||||
|
objectFit={"contain"}
|
||||||
|
width={"100%"}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
<Box mt={"2rem"}>
|
<Box mt={"2rem"}>
|
||||||
<Flex align={"center"} justifyContent="space-between" mb={"1rem"}>
|
<Flex align={"center"} justifyContent="space-between" mb={"1rem"}>
|
||||||
|
|||||||
@@ -1,9 +1,26 @@
|
|||||||
import { error } from "console";
|
|
||||||
|
|
||||||
const { PrismaClient } = require("@prisma/client");
|
const { PrismaClient } = require("@prisma/client");
|
||||||
|
|
||||||
|
const birthDateFromAge = (age) => {
|
||||||
|
const ageMillis = age * 365 * 24 * 60 * 60 * 1000;
|
||||||
|
return new Date(new Date().getTime() - ageMillis);
|
||||||
|
};
|
||||||
|
|
||||||
const get = async (req, res) => {
|
const get = async (req, res) => {
|
||||||
const { preference, excludedId, userLikes, userDislikes } = req.query;
|
const {
|
||||||
|
preferences: preferencesList,
|
||||||
|
excludedId,
|
||||||
|
userLikes,
|
||||||
|
userDislikes,
|
||||||
|
} = req.query;
|
||||||
|
|
||||||
|
const preferences = preferencesList.split(",");
|
||||||
|
|
||||||
|
const prefGender = preferences[0];
|
||||||
|
const dateAgeMin = birthDateFromAge(preferences[1]);
|
||||||
|
const dateAgeMax = birthDateFromAge(preferences[2]);
|
||||||
|
|
||||||
|
// pas utilisé pour le moment
|
||||||
|
const distance = preferences[3];
|
||||||
|
|
||||||
let userLikesList = userLikes.split(",");
|
let userLikesList = userLikes.split(",");
|
||||||
let userDislikesList = userDislikes.split(",");
|
let userDislikesList = userDislikes.split(",");
|
||||||
@@ -21,16 +38,22 @@ const get = async (req, res) => {
|
|||||||
.findMany({
|
.findMany({
|
||||||
where: {
|
where: {
|
||||||
AND: [
|
AND: [
|
||||||
{ gender: { equals: preference } },
|
{ gender: { equals: prefGender } },
|
||||||
|
{
|
||||||
|
birthdate: {
|
||||||
|
lte: dateAgeMin.toISOString(),
|
||||||
|
gte: dateAgeMax.toISOString(),
|
||||||
|
},
|
||||||
|
},
|
||||||
{ images: { isEmpty: false } },
|
{ images: { isEmpty: false } },
|
||||||
{ id: { notIn: excludedIdArray } },
|
{ id: { notIn: excludedIdArray } },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
return e;
|
return [];
|
||||||
});
|
});
|
||||||
if (!users) {
|
if (users.length === 0 || users === undefined || users === null) {
|
||||||
return res.status(500).send({ error: "Aucun profil trouvé" });
|
return res.status(500).send({ error: "Aucun profil trouvé" });
|
||||||
}
|
}
|
||||||
return res.status(200).send({ users });
|
return res.status(200).send({ users });
|
||||||
|
|||||||
+15
-1
@@ -19,6 +19,8 @@ export default function Dashboard() {
|
|||||||
const [userLikes, setUserLikes] = useState();
|
const [userLikes, setUserLikes] = useState();
|
||||||
const [userDislikes, setUserDislikes] = useState();
|
const [userDislikes, setUserDislikes] = useState();
|
||||||
|
|
||||||
|
const [preferences, setPreferences] = useState(null);
|
||||||
|
|
||||||
const { data: session, status } = useSession();
|
const { data: session, status } = useSession();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -35,6 +37,13 @@ export default function Dashboard() {
|
|||||||
setUserDislikes([...user.UserDislikesID]);
|
setUserDislikes([...user.UserDislikesID]);
|
||||||
setUserLikes([...user.UserLikesID]);
|
setUserLikes([...user.UserLikesID]);
|
||||||
|
|
||||||
|
setPreferences([
|
||||||
|
user.prefGender,
|
||||||
|
user.ageMin,
|
||||||
|
user.ageMax,
|
||||||
|
user.distance,
|
||||||
|
]);
|
||||||
|
|
||||||
return fetch(`/api/users/${user.id}`)
|
return fetch(`/api/users/${user.id}`)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
return res.json();
|
return res.json();
|
||||||
@@ -45,6 +54,10 @@ export default function Dashboard() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
Erreur quand je retourn de userProfile à dashboard
|
||||||
|
*/
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: listUsers,
|
data: listUsers,
|
||||||
isError: isErrorListUsers,
|
isError: isErrorListUsers,
|
||||||
@@ -55,7 +68,7 @@ export default function Dashboard() {
|
|||||||
enabled: status === "authenticated" && !isLoading,
|
enabled: status === "authenticated" && !isLoading,
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
return fetch(
|
return fetch(
|
||||||
`/api/user/userDashboard?preference=${loggedUser.gender}&excludedId=${loggedUser.id}&userLikes=${loggedUser.UserLikesID}&userDislikes=${loggedUser.UserDislikesID}`
|
`/api/user/userDashboard?preferences=${preferences}&excludedId=${loggedUser.id}&userLikes=${loggedUser.UserLikesID}&userDislikes=${loggedUser.UserDislikesID}`
|
||||||
) //exclure les profils déjà like ou dislike
|
) //exclure les profils déjà like ou dislike
|
||||||
.then((res) => res.json())
|
.then((res) => res.json())
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
@@ -99,6 +112,7 @@ export default function Dashboard() {
|
|||||||
{isLoadingListUsers ? (
|
{isLoadingListUsers ? (
|
||||||
<LoadingPage />
|
<LoadingPage />
|
||||||
) : isErrorListUsers ||
|
) : isErrorListUsers ||
|
||||||
|
listUsers === undefined ||
|
||||||
listUsers.users === undefined ||
|
listUsers.users === undefined ||
|
||||||
listUsers.users.length === 0 ? (
|
listUsers.users.length === 0 ? (
|
||||||
<SearchFailCard />
|
<SearchFailCard />
|
||||||
|
|||||||
+175
-34
@@ -20,7 +20,16 @@ import {
|
|||||||
HStack,
|
HStack,
|
||||||
Radio,
|
Radio,
|
||||||
RadioGroup,
|
RadioGroup,
|
||||||
|
RangeSlider,
|
||||||
|
RangeSliderFilledTrack,
|
||||||
|
RangeSliderThumb,
|
||||||
|
RangeSliderTrack,
|
||||||
|
Slider,
|
||||||
|
SliderFilledTrack,
|
||||||
|
SliderThumb,
|
||||||
|
SliderTrack,
|
||||||
Text,
|
Text,
|
||||||
|
Tooltip,
|
||||||
useToast,
|
useToast,
|
||||||
VStack,
|
VStack,
|
||||||
} from "@chakra-ui/react";
|
} from "@chakra-ui/react";
|
||||||
@@ -30,6 +39,8 @@ import ModalChoosePassion from "@/components/layout/user_profile/ModalChoosePass
|
|||||||
import ProfileTagList from "@/components/layout/user_profile/ProfileTagList";
|
import ProfileTagList from "@/components/layout/user_profile/ProfileTagList";
|
||||||
import LoadingPage from "@/components/LoadingPage";
|
import LoadingPage from "@/components/LoadingPage";
|
||||||
|
|
||||||
|
import { FaGreaterThan, FaLessThan, FaWalking } from "react-icons/fa";
|
||||||
|
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useForm, Controller } from "react-hook-form";
|
import { useForm, Controller } from "react-hook-form";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
@@ -41,6 +52,11 @@ export default function UserProfile() {
|
|||||||
const [currentlyLoading, setCurrentlyLoading] = useState(false);
|
const [currentlyLoading, setCurrentlyLoading] = useState(false);
|
||||||
const [passions, setPassions] = useState(null);
|
const [passions, setPassions] = useState(null);
|
||||||
|
|
||||||
|
const [showTooltipAge, setShowTooltipAge] = useState(true);
|
||||||
|
const [sliderAgeValue, setSliderAgeValue] = useState([]);
|
||||||
|
const [showTooltipDistance, setShowTooltipDistance] = useState(true);
|
||||||
|
const [sliderDistanceValue, setSliderDistanceValue] = useState([]);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
control,
|
control,
|
||||||
@@ -71,6 +87,9 @@ export default function UserProfile() {
|
|||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const { user } = session as unknown as Session;
|
const { user } = session as unknown as Session;
|
||||||
|
|
||||||
|
setSliderAgeValue([user.ageMin, user.ageMax]);
|
||||||
|
setSliderDistanceValue(user.distance);
|
||||||
|
|
||||||
return fetch(`/api/users/${user.id}`)
|
return fetch(`/api/users/${user.id}`)
|
||||||
.then((res) => res.json())
|
.then((res) => res.json())
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
@@ -108,12 +127,19 @@ export default function UserProfile() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const saveData = (values: any) => {
|
const saveData = (values: any) => {
|
||||||
const trueValues = Object.keys(values).reduce((acc, key) => {
|
let trueValues = {};
|
||||||
if (values[key] !== "" && values[key] !== undefined) {
|
console.log(values);
|
||||||
acc[key] = values[key];
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return acc;
|
}
|
||||||
}, {});
|
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
@@ -392,35 +418,148 @@ export default function UserProfile() {
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</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"}>
|
||||||
|
<FormLabel as={"legend"} htmlFor={"prefGender"}>
|
||||||
|
Genre :
|
||||||
|
</FormLabel>
|
||||||
|
<Controller
|
||||||
|
name={"prefGender"}
|
||||||
|
control={control}
|
||||||
|
render={({ field }) => (
|
||||||
|
<RadioGroup
|
||||||
|
{...field}
|
||||||
|
colorScheme={"purple"}
|
||||||
|
id={"prefGender"}
|
||||||
|
as="b"
|
||||||
|
defaultValue={
|
||||||
|
userData.prefGender === null
|
||||||
|
? Gender.UNKNOWN
|
||||||
|
: userData.gender
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<HStack spacing={"0.5rem"}>
|
||||||
|
<Radio value={Gender.MALE}>
|
||||||
|
{getTextGender(Gender.MALE)}
|
||||||
|
</Radio>
|
||||||
|
<Radio value={Gender.FEMALE}>
|
||||||
|
{getTextGender(Gender.FEMALE)}
|
||||||
|
</Radio>
|
||||||
|
<Radio value={Gender.OTHER}>
|
||||||
|
{getTextGender(Gender.OTHER)}
|
||||||
|
</Radio>
|
||||||
|
<Radio value={Gender.UNKNOWN}>
|
||||||
|
{getTextGender(Gender.UNKNOWN)}
|
||||||
|
</Radio>
|
||||||
|
</HStack>
|
||||||
|
</RadioGroup>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<FormLabel as={"legend"} htmlFor={"prefGender"}>
|
||||||
|
Age :
|
||||||
|
</FormLabel>
|
||||||
|
<Controller
|
||||||
|
name={"age"}
|
||||||
|
control={control}
|
||||||
|
render={({ field: { onChange } }) => (
|
||||||
|
<RangeSlider
|
||||||
|
aria-label={["min", "max"]}
|
||||||
|
colorScheme={"purple"}
|
||||||
|
min={18}
|
||||||
|
max={99}
|
||||||
|
id={"age"}
|
||||||
|
color={"pink.500"}
|
||||||
|
defaultValue={[userData.ageMin, userData.ageMax]}
|
||||||
|
onChange={(v) => {
|
||||||
|
setSliderAgeValue(v);
|
||||||
|
onChange(v);
|
||||||
|
}}
|
||||||
|
onMouseEnter={() => setShowTooltipAge(true)}
|
||||||
|
onMouseLeave={() => setShowTooltipAge(false)}
|
||||||
|
>
|
||||||
|
<RangeSliderTrack>
|
||||||
|
<RangeSliderFilledTrack bgColor={"purple.500"} />
|
||||||
|
</RangeSliderTrack>
|
||||||
|
<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} />
|
||||||
|
</RangeSliderThumb>
|
||||||
|
</Tooltip>
|
||||||
|
|
||||||
|
<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} />
|
||||||
|
</RangeSliderThumb>
|
||||||
|
</Tooltip>
|
||||||
|
</RangeSlider>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
{/* <Box>
|
{/* <Box>
|
||||||
<FormLabel as={"legend"} htmlFor={"preference"}>
|
<FormLabel as={"legend"} htmlFor={"distance"}>
|
||||||
Préference :
|
Distance :
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<RadioGroup
|
<Controller
|
||||||
id={"preference"}
|
name={"distance"}
|
||||||
as="b"
|
control={control}
|
||||||
value={
|
render={({ field: { onChange } }) => (
|
||||||
userData.preference === null
|
<Slider
|
||||||
? Gender.UNKNOWN
|
aria-label={"distance"}
|
||||||
: userData.preference
|
colorScheme={"purple"}
|
||||||
}
|
min={20}
|
||||||
>
|
max={250}
|
||||||
<HStack spacing={"0.5rem"}>
|
id={"distance"}
|
||||||
<Radio value={Gender.MALE}>
|
color={"pink.500"}
|
||||||
{getTextGender(Gender.MALE)}
|
defaultValue={userData.distance}
|
||||||
</Radio>
|
onChange={(v) => {
|
||||||
<Radio value={Gender.FEMALE}>
|
setSliderDistanceValue(v);
|
||||||
{getTextGender(Gender.FEMALE)}
|
onChange(v);
|
||||||
</Radio>
|
}}
|
||||||
<Radio value={Gender.OTHER}>
|
onMouseEnter={() => setShowTooltipDistance(true)}
|
||||||
{getTextGender(Gender.OTHER)}
|
onMouseLeave={() => setShowTooltipDistance(false)}
|
||||||
</Radio>
|
>
|
||||||
<Radio value={Gender.UNKNOWN}>
|
<SliderTrack>
|
||||||
{getTextGender(Gender.UNKNOWN)}
|
<SliderFilledTrack bgColor={"purple.500"} />
|
||||||
</Radio>
|
</SliderTrack>
|
||||||
</HStack>
|
<Tooltip
|
||||||
</RadioGroup>
|
hasArrow
|
||||||
</Flex> */}
|
bg="purple.500"
|
||||||
|
color="white"
|
||||||
|
placement="top"
|
||||||
|
isOpen={showTooltipDistance}
|
||||||
|
label={`${sliderDistanceValue} km`}
|
||||||
|
>
|
||||||
|
<SliderThumb boxSize={6}>
|
||||||
|
<Box color={"purple.500"} as={FaWalking} />
|
||||||
|
</SliderThumb>
|
||||||
|
</Tooltip>
|
||||||
|
</Slider>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Box> */}
|
||||||
</Box>
|
</Box>
|
||||||
<Divider colorScheme={"purple"} />
|
<Divider colorScheme={"purple"} />
|
||||||
<Center gap={"1rem"} my={"1rem"}>
|
<Center gap={"1rem"} my={"1rem"}>
|
||||||
@@ -434,7 +573,9 @@ export default function UserProfile() {
|
|||||||
<Button
|
<Button
|
||||||
colorScheme={"purple"}
|
colorScheme={"purple"}
|
||||||
variant="outline"
|
variant="outline"
|
||||||
onClick={() => router.push("/dashboard")}
|
onClick={() => {
|
||||||
|
router.push("/dashboard");
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
Retour
|
Retour
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
Reference in New Issue
Block a user