mirror of
https://github.com/LucasVbr/meeting-app.git
synced 2026-05-13 17:21:53 +00:00
feat(UserMatch): Logique des matchs et notifications
Affichage d'un modal lorsqu'une notification de match n'est pas consulté
This commit is contained in:
@@ -61,6 +61,8 @@ model User {
|
|||||||
Match Match[] @relation(fields: [MatchID], references: [id])
|
Match Match[] @relation(fields: [MatchID], references: [id])
|
||||||
|
|
||||||
Notification Notification[]
|
Notification Notification[]
|
||||||
|
|
||||||
|
NotificationMatchedUser Notification[] @relation("matchedUser")
|
||||||
}
|
}
|
||||||
|
|
||||||
model Notification {
|
model Notification {
|
||||||
@@ -71,6 +73,9 @@ model Notification {
|
|||||||
|
|
||||||
UserID String @db.ObjectId
|
UserID String @db.ObjectId
|
||||||
User User @relation(fields: [UserID], references: [id])
|
User User @relation(fields: [UserID], references: [id])
|
||||||
|
|
||||||
|
MatchedUserID String? @db.ObjectId
|
||||||
|
MatchedUser User? @relation("matchedUser", fields: [MatchedUserID], references: [id])
|
||||||
}
|
}
|
||||||
|
|
||||||
model Match {
|
model Match {
|
||||||
|
|||||||
@@ -8,20 +8,24 @@ import {
|
|||||||
Box,
|
Box,
|
||||||
CardHeader,
|
CardHeader,
|
||||||
useToast,
|
useToast,
|
||||||
} from '@chakra-ui/react';
|
} from "@chakra-ui/react";
|
||||||
import Carousel from '../../../Carousel';
|
import Carousel from "../../../Carousel";
|
||||||
import {BiHeart} from 'react-icons/bi';
|
import { BiHeart } from "react-icons/bi";
|
||||||
import {RxCross1} from 'react-icons/rx';
|
import { RxCross1 } from "react-icons/rx";
|
||||||
import {useMutation, useQuery} from '@tanstack/react-query';
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||||
import PassionTagList
|
import PassionTagList from "@/components/layout/dashboard/card_user/PassionTagList";
|
||||||
from '@/components/layout/dashboard/card_user/PassionTagList';
|
import { useState } from "react";
|
||||||
import {useState} from 'react';
|
import SearchFailCard from "./SearchFailCard";
|
||||||
import SearchFailCard from './SearchFailCard';
|
import LoadingPage from "@/components/LoadingPage";
|
||||||
import LoadingPage from '@/components/LoadingPage';
|
|
||||||
|
|
||||||
export default function CardUser({users, loggedUser, setMatch}) {
|
export default function CardUser({
|
||||||
|
users,
|
||||||
|
loggedUser,
|
||||||
|
setMatch,
|
||||||
|
refetchLoggedUser,
|
||||||
|
}) {
|
||||||
const toast = useToast({
|
const toast = useToast({
|
||||||
position: 'top',
|
position: "top",
|
||||||
duration: 2000,
|
duration: 2000,
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
});
|
});
|
||||||
@@ -30,8 +34,8 @@ export default function CardUser({users, loggedUser, setMatch}) {
|
|||||||
const likeMutation = useMutation({
|
const likeMutation = useMutation({
|
||||||
mutationFn: async (id) => {
|
mutationFn: async (id) => {
|
||||||
const likePostOptions = {
|
const likePostOptions = {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
idUser: loggedUser.id,
|
idUser: loggedUser.id,
|
||||||
idUserLiked: id,
|
idUserLiked: id,
|
||||||
@@ -49,20 +53,20 @@ export default function CardUser({users, loggedUser, setMatch}) {
|
|||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
if (data.error) {
|
if (data.error) {
|
||||||
toast({
|
toast({
|
||||||
title: 'Erreur',
|
title: "Erreur",
|
||||||
description: 'Une erreur est survenue',
|
description: "Une erreur est survenue",
|
||||||
status: 'error',
|
status: "error",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (data.match) {
|
if (data.match) {
|
||||||
setMatch(true);
|
refetchLoggedUser();
|
||||||
}
|
}
|
||||||
setListUsers(listUsers.slice(1));
|
setListUsers(listUsers.slice(1));
|
||||||
toast({
|
toast({
|
||||||
title: 'J\'aime',
|
title: "J'aime",
|
||||||
description: 'Votre action a bien été prise en compte',
|
description: "Votre action a bien été prise en compte",
|
||||||
status: 'success',
|
status: "success",
|
||||||
});
|
});
|
||||||
|
|
||||||
//tester si match et afficher un truc
|
//tester si match et afficher un truc
|
||||||
@@ -72,8 +76,8 @@ export default function CardUser({users, loggedUser, setMatch}) {
|
|||||||
const dislikeMutation = useMutation({
|
const dislikeMutation = useMutation({
|
||||||
mutationFn: async (id) => {
|
mutationFn: async (id) => {
|
||||||
const dislikePostOptions = {
|
const dislikePostOptions = {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
idUser: loggedUser.id,
|
idUser: loggedUser.id,
|
||||||
idUserDisliked: id,
|
idUserDisliked: id,
|
||||||
@@ -91,18 +95,18 @@ export default function CardUser({users, loggedUser, setMatch}) {
|
|||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
if (data.error) {
|
if (data.error) {
|
||||||
toast({
|
toast({
|
||||||
title: 'Erreur',
|
title: "Erreur",
|
||||||
description: 'Une erreur est survenue',
|
description: "Une erreur est survenue",
|
||||||
status: 'error',
|
status: "error",
|
||||||
duration: 2000,
|
duration: 2000,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setListUsers(listUsers.slice(1));
|
setListUsers(listUsers.slice(1));
|
||||||
toast({
|
toast({
|
||||||
title: 'J\'aime pas',
|
title: "J'aime pas",
|
||||||
description: 'Votre action a bien été prise en compte',
|
description: "Votre action a bien été prise en compte",
|
||||||
status: 'success',
|
status: "success",
|
||||||
duration: 2000,
|
duration: 2000,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -114,11 +118,11 @@ export default function CardUser({users, loggedUser, setMatch}) {
|
|||||||
data: listPassions,
|
data: listPassions,
|
||||||
error: passionError,
|
error: passionError,
|
||||||
} = useQuery({
|
} = useQuery({
|
||||||
queryKey: ['passions'],
|
queryKey: ["passions"],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
return fetch(`/api/passions/`)
|
return fetch(`/api/passions/`)
|
||||||
.then(res => res.json())
|
.then((res) => res.json())
|
||||||
.catch(err => err);
|
.catch((err) => err);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -129,57 +133,64 @@ export default function CardUser({users, loggedUser, setMatch}) {
|
|||||||
return Math.abs(ageDate.getUTCFullYear() - 1970);
|
return Math.abs(ageDate.getUTCFullYear() - 1970);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (listUsers.length === 0) return <SearchFailCard/>;
|
if (listUsers.length === 0) return <SearchFailCard />;
|
||||||
if (likeMutation.isLoading ||
|
if (likeMutation.isLoading || dislikeMutation.isLoading)
|
||||||
dislikeMutation.isLoading) return <LoadingPage/>;
|
return <LoadingPage />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card w={'100%'} h={'100%'} borderRadius={'1rem'} overflow={'hidden'}>
|
<Card w={"100%"} h={"100%"} borderRadius={"1rem"} overflow={"hidden"}>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<Carousel borderRadius={'1rem'} images={listUsers?.[0].images}/>
|
<Carousel borderRadius={"1rem"} images={listUsers?.[0].images} />
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|
||||||
<CardBody>
|
<CardBody>
|
||||||
<Flex justify={'space-between'} mb={'20px'}>
|
<Flex justify={"space-between"} mb={"20px"}>
|
||||||
<Heading fontSize={'1.5rem'} fontWeight={'bold'} flexBasis={'70%'}>
|
<Heading fontSize={"1.5rem"} fontWeight={"bold"} flexBasis={"70%"}>
|
||||||
{listUsers[0].firstName} {listUsers[0].lastName},{' '}
|
{listUsers[0].firstName} {listUsers[0].lastName},{" "}
|
||||||
{formateDateToAge(listUsers[0].birthdate)} ans
|
{formateDateToAge(listUsers[0].birthdate)} ans
|
||||||
</Heading>
|
</Heading>
|
||||||
|
|
||||||
<Flex gap={1}>
|
<Flex gap={1}>
|
||||||
<IconButton icon={<BiHeart/>} aria-label="like"
|
<IconButton
|
||||||
borderRadius={'1rem'}
|
icon={<BiHeart />}
|
||||||
onClick={() => likeMutation.mutate(listUsers[0].id)
|
aria-label="like"
|
||||||
}/>
|
borderRadius={"1rem"}
|
||||||
<IconButton icon={<RxCross1/>} aria-label="dislike"
|
onClick={() => likeMutation.mutate(listUsers[0].id)}
|
||||||
borderRadius={'1rem'} variant={'outline'}
|
/>
|
||||||
onClick={() => dislikeMutation.mutate(
|
<IconButton
|
||||||
listUsers[0].id)}/>
|
icon={<RxCross1 />}
|
||||||
</Flex>
|
aria-label="dislike"
|
||||||
|
borderRadius={"1rem"}
|
||||||
|
variant={"outline"}
|
||||||
|
onClick={() => dislikeMutation.mutate(listUsers[0].id)}
|
||||||
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
<Box mb={'20px'}>
|
<Box mb={"20px"}>
|
||||||
<Heading size={'sm'} fontWeight={'bold'} mb="0.5rem">
|
<Heading size={"sm"} fontWeight={"bold"} mb="0.5rem">
|
||||||
A propos :
|
A propos :
|
||||||
</Heading>
|
</Heading>
|
||||||
<Text as="i">"{listUsers[0].bio}"</Text>
|
<Text as="i">"{listUsers[0].bio}"</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Heading size={'sm'} fontWeight={'bold'}>
|
<Heading size={"sm"} fontWeight={"bold"}>
|
||||||
Passions :
|
Passions :
|
||||||
</Heading>
|
</Heading>
|
||||||
{passionLoading
|
{passionLoading ? (
|
||||||
? <Text>Chargement des passions...</Text>
|
<Text>Chargement des passions...</Text>
|
||||||
: passionIsError
|
) : passionIsError ? (
|
||||||
? <Text>Erreur lors du chargement des passions</Text>
|
<Text>Erreur lors du chargement des passions</Text>
|
||||||
:
|
) : (
|
||||||
<PassionTagList passions={listUsers[0].PassionID}
|
<PassionTagList
|
||||||
userPassions={loggedUser.PassionID}
|
passions={listUsers[0].PassionID}
|
||||||
listPassions={listPassions}/>
|
userPassions={loggedUser.PassionID}
|
||||||
}
|
listPassions={listPassions}
|
||||||
</Box>
|
/>
|
||||||
</CardBody>
|
)}
|
||||||
</Card>
|
</Box>
|
||||||
|
</CardBody>
|
||||||
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,67 +1,95 @@
|
|||||||
import {Card, Flex, Box, Image, Text, Spacer, Divider} from '@chakra-ui/react';
|
import {
|
||||||
import {useRouter} from 'next/router';
|
Card,
|
||||||
|
Flex,
|
||||||
|
Box,
|
||||||
|
Image,
|
||||||
|
Text,
|
||||||
|
Spacer,
|
||||||
|
Divider,
|
||||||
|
} from "@chakra-ui/react";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
import {AiFillMessage} from 'react-icons/ai';
|
import { AiFillMessage } from "react-icons/ai";
|
||||||
import {BsFillPersonFill} from 'react-icons/bs';
|
import { BsFillPersonFill } from "react-icons/bs";
|
||||||
import {BiLogOut} from 'react-icons/bi';
|
import { BiLogOut } from "react-icons/bi";
|
||||||
import {FaMapMarkedAlt} from 'react-icons/fa';
|
import { FaMapMarkedAlt } from "react-icons/fa";
|
||||||
|
|
||||||
import LeftPanelButton
|
import LeftPanelButton from "@/components/layout/dashboard/left_panel/LeftPanelButton";
|
||||||
from '@/components/layout/dashboard/left_panel/LeftPanelButton';
|
import { signOut } from "next-auth/react";
|
||||||
import {signOut} from 'next-auth/react';
|
|
||||||
|
import { formateDate } from "@/lib/formateDate";
|
||||||
|
|
||||||
export default function LeftPanel(props) {
|
export default function LeftPanel(props) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const {user} = props;
|
const { user } = props;
|
||||||
|
|
||||||
const formateDate = (dateString) => {
|
|
||||||
const options = {year: 'numeric', month: 'long', day: 'numeric'};
|
|
||||||
return new Date(dateString).toLocaleDateString([], options);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card width={'20vw'} height={'100%'} borderRadius={0} padding={'0px'}
|
<Card
|
||||||
bg={'#faf9ff'}>
|
width={"20vw"}
|
||||||
<Flex direction={'column'} height={'100%'} margin={'10%'}>
|
height={"100%"}
|
||||||
<Box>
|
borderRadius={0}
|
||||||
<Image src={user.images[0] ?? '/blank_profile_picture.webp'}
|
padding={"0px"}
|
||||||
objectFit={'contain'} borderRadius={'1rem'}/>
|
bg={"#faf9ff"}
|
||||||
<Box mt={'2rem'}>
|
>
|
||||||
<Flex align={'center'} justifyContent="space-between" mb={'1rem'}>
|
<Flex direction={"column"} height={"100%"} margin={"10%"}>
|
||||||
<Text fontSize={'1.5rem'} fontWeight={'bold'}>
|
<Box>
|
||||||
{user.firstName} {user.lastName}
|
<Image
|
||||||
</Text>
|
src={user.images[0] ?? "/blank_profile_picture.webp"}
|
||||||
<Text fontSize={'1rem'} fontWeight={'bold'}>
|
objectFit={"contain"}
|
||||||
{formateDate(user.birthdate)}
|
borderRadius={"1rem"}
|
||||||
</Text>
|
/>
|
||||||
</Flex>
|
<Box mt={"2rem"}>
|
||||||
<Divider mb={'1rem'}/>
|
<Flex align={"center"} justifyContent="space-between" mb={"1rem"}>
|
||||||
<Text as="i" fontWeight={'bold'}>"{user.bio}"</Text>
|
<Text fontSize={"1.5rem"} fontWeight={"bold"}>
|
||||||
</Box>
|
{user.firstName} {user.lastName}
|
||||||
|
</Text>
|
||||||
|
<Text fontSize={"1rem"} fontWeight={"bold"}>
|
||||||
|
{formateDate(user.birthdate)}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
<Divider mb={"1rem"} />
|
||||||
|
<Text as="i" fontWeight={"bold"}>
|
||||||
|
"{user.bio}"
|
||||||
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Spacer/>
|
</Box>
|
||||||
<Flex gap={2} direction={'column'} mt={'1vh'}
|
<Spacer />
|
||||||
spacing={3.5} alignContent={'bottom'}>
|
<Flex
|
||||||
<LeftPanelButton leftIcon={<FaMapMarkedAlt/>}
|
gap={2}
|
||||||
onClickHandler={() => router.push('/map')}>
|
direction={"column"}
|
||||||
Carte
|
mt={"1vh"}
|
||||||
</LeftPanelButton>
|
spacing={3.5}
|
||||||
|
alignContent={"bottom"}
|
||||||
|
>
|
||||||
|
<LeftPanelButton
|
||||||
|
leftIcon={<FaMapMarkedAlt />}
|
||||||
|
onClickHandler={() => router.push("/map")}
|
||||||
|
>
|
||||||
|
Carte
|
||||||
|
</LeftPanelButton>
|
||||||
|
|
||||||
<LeftPanelButton leftIcon={<AiFillMessage/>}
|
<LeftPanelButton
|
||||||
onClickHandler={() => router.push('/dashboard')}>
|
leftIcon={<AiFillMessage />}
|
||||||
Messages
|
onClickHandler={() => router.push("/dashboard")}
|
||||||
</LeftPanelButton>
|
>
|
||||||
|
Messages
|
||||||
|
</LeftPanelButton>
|
||||||
|
|
||||||
<LeftPanelButton leftIcon={<BsFillPersonFill/>}
|
<LeftPanelButton
|
||||||
onClickHandler={() => router.push('/profile')}>
|
leftIcon={<BsFillPersonFill />}
|
||||||
Profil
|
onClickHandler={() => router.push("/profile")}
|
||||||
</LeftPanelButton>
|
>
|
||||||
<LeftPanelButton variant={'outline'} leftIcon={<BiLogOut/>}
|
Profil
|
||||||
onClickHandler={() => signOut({callbackUrl: '/'})}>
|
</LeftPanelButton>
|
||||||
Déconnexion
|
<LeftPanelButton
|
||||||
</LeftPanelButton>
|
variant={"outline"}
|
||||||
</Flex>
|
leftIcon={<BiLogOut />}
|
||||||
|
onClickHandler={() => signOut({ callbackUrl: "/" })}
|
||||||
|
>
|
||||||
|
Déconnexion
|
||||||
|
</LeftPanelButton>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Card>
|
</Flex>
|
||||||
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,147 @@
|
|||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Divider,
|
||||||
|
Flex,
|
||||||
|
Heading,
|
||||||
|
Modal,
|
||||||
|
ModalBody,
|
||||||
|
ModalCloseButton,
|
||||||
|
ModalContent,
|
||||||
|
ModalFooter,
|
||||||
|
ModalHeader,
|
||||||
|
ModalOverlay,
|
||||||
|
Text,
|
||||||
|
useDisclosure,
|
||||||
|
} from "@chakra-ui/react";
|
||||||
|
import { SetStateAction } from "react";
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { User } from "@prisma/client";
|
||||||
|
import Carousel from "@/components/Carousel";
|
||||||
|
import { MdWavingHand } from "react-icons/md";
|
||||||
|
import { formateDate } from "@/lib/formateDate";
|
||||||
|
import { Notification } from "@prisma/client";
|
||||||
|
import PassionTagList from "../card_user/PassionTagList";
|
||||||
|
|
||||||
|
type modalMatchProps = {
|
||||||
|
key: string;
|
||||||
|
loggedUser: User;
|
||||||
|
notif: Notification;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function ModalMatch({ notif, loggedUser }: modalMatchProps) {
|
||||||
|
const handleClose = () => {
|
||||||
|
const options = {
|
||||||
|
method: "PATCH",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ notificationId: notif.id }),
|
||||||
|
};
|
||||||
|
fetch(`/api/user/consultNotification`, options)
|
||||||
|
.then((res) => res.json())
|
||||||
|
.catch((err) => console.log(err));
|
||||||
|
};
|
||||||
|
|
||||||
|
const { isOpen, onClose } = useDisclosure({
|
||||||
|
defaultIsOpen: true,
|
||||||
|
onClose: () => {
|
||||||
|
handleClose();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
isLoading,
|
||||||
|
isError,
|
||||||
|
data: matchedUser,
|
||||||
|
error,
|
||||||
|
} = useQuery({
|
||||||
|
enabled: notif !== undefined,
|
||||||
|
queryKey: ["matchUser"],
|
||||||
|
queryFn: async () => {
|
||||||
|
return fetch(`/api/users/${notif.MatchedUserID}`)
|
||||||
|
.then((res) => {
|
||||||
|
return res.json();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
return err;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
isLoading: passionLoading,
|
||||||
|
isError: passionIsError,
|
||||||
|
data: listPassions,
|
||||||
|
error: passionError,
|
||||||
|
} = useQuery({
|
||||||
|
queryKey: ["passions"],
|
||||||
|
queryFn: async () => {
|
||||||
|
return fetch(`/api/passions/`)
|
||||||
|
.then((res) => res.json())
|
||||||
|
.catch((err) => err);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{matchedUser && (
|
||||||
|
<Modal isOpen={isOpen} onClose={onClose}>
|
||||||
|
<ModalOverlay backdropBlur="2px" />
|
||||||
|
<ModalContent>
|
||||||
|
<ModalHeader>Vous avez un nouveau match</ModalHeader>
|
||||||
|
<ModalBody>
|
||||||
|
<Carousel borderRadius={"1rem"} images={matchedUser.images} />
|
||||||
|
<Box mt={"2rem"}>
|
||||||
|
<Flex
|
||||||
|
align={"center"}
|
||||||
|
justifyContent="space-between"
|
||||||
|
mb={"1rem"}
|
||||||
|
>
|
||||||
|
<Text fontSize={"1.5rem"} fontWeight={"bold"}>
|
||||||
|
{matchedUser.firstName} {matchedUser.lastName}
|
||||||
|
</Text>
|
||||||
|
<Text fontSize={"1rem"} fontWeight={"bold"}>
|
||||||
|
{formateDate(matchedUser.birthdate)}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
<Divider mb={"1rem"} />
|
||||||
|
<Text as="i" fontWeight={"bold"}>
|
||||||
|
"{matchedUser.bio}"
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<Heading size={"sm"} fontWeight={"bold"}>
|
||||||
|
Passions :
|
||||||
|
</Heading>
|
||||||
|
{passionLoading ? (
|
||||||
|
<Text>Chargement des passions...</Text>
|
||||||
|
) : passionIsError ? (
|
||||||
|
<Text>Erreur lors du chargement des passions</Text>
|
||||||
|
) : (
|
||||||
|
<PassionTagList
|
||||||
|
passions={matchedUser.PassionID}
|
||||||
|
userPassions={loggedUser.PassionID}
|
||||||
|
listPassions={listPassions}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</ModalBody>
|
||||||
|
<ModalFooter>
|
||||||
|
<Flex gap={"1rem"}>
|
||||||
|
<Button onClick={onClose}>Fermer</Button>
|
||||||
|
<Button
|
||||||
|
leftIcon={<MdWavingHand />}
|
||||||
|
variant={"ghost"}
|
||||||
|
onClick={onClose}
|
||||||
|
>
|
||||||
|
Saluer
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
</ModalFooter>
|
||||||
|
</ModalContent>
|
||||||
|
</Modal>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export const formateDate = (dateString: Date) => {
|
||||||
|
const options = { year: "numeric", month: "long", day: "numeric" };
|
||||||
|
return new Date(dateString).toLocaleDateString([], options);
|
||||||
|
};
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
const { PrismaClient } = require("@prisma/client");
|
||||||
|
|
||||||
|
const patch = async (req: any, res: any) => {
|
||||||
|
const prisma = new PrismaClient();
|
||||||
|
|
||||||
|
const { notificationId } = req.body;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const notification = await prisma.notification.update({
|
||||||
|
where: {
|
||||||
|
id: notificationId,
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
hasBeenConsulted: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(200).json(notification);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(400).json({ message: "Something went wrong" });
|
||||||
|
} finally {
|
||||||
|
await prisma.$disconnect();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default (req: any, res: any) => {
|
||||||
|
req.method === "PATCH"
|
||||||
|
? patch(req, res)
|
||||||
|
: res.status(404).send({ message: "Wrong method, please use POST" });
|
||||||
|
};
|
||||||
@@ -21,23 +21,33 @@ const post = async (req, res) => {
|
|||||||
if (match) {
|
if (match) {
|
||||||
await prisma.notification.create({
|
await prisma.notification.create({
|
||||||
data: {
|
data: {
|
||||||
type: NotificationType.MATCH,
|
type: NotificationType.NEW_MATCH,
|
||||||
user: {
|
User: {
|
||||||
connect: {
|
connect: {
|
||||||
id: idUser,
|
id: idUser,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
MatchedUser: {
|
||||||
|
connect: {
|
||||||
|
id: idUserLiked,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await prisma.notification.create({
|
await prisma.notification.create({
|
||||||
data: {
|
data: {
|
||||||
type: NotificationType.MATCH,
|
type: NotificationType.NEW_MATCH,
|
||||||
user: {
|
User: {
|
||||||
connect: {
|
connect: {
|
||||||
id: idUserLiked,
|
id: idUserLiked,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
MatchedUser: {
|
||||||
|
connect: {
|
||||||
|
id: idUser,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-17
@@ -1,4 +1,4 @@
|
|||||||
import { Grid, GridItem, Text, Box, useToast } from "@chakra-ui/react";
|
import { Grid, GridItem, Box, useToast, useDisclosure } from "@chakra-ui/react";
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from "next-auth/react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
@@ -8,15 +8,16 @@ import CardUser from "../components/layout/dashboard/card_user/CardUser";
|
|||||||
import SearchFailCard from "../components/layout/dashboard/card_user/SearchFailCard";
|
import SearchFailCard from "../components/layout/dashboard/card_user/SearchFailCard";
|
||||||
|
|
||||||
import LeftPanel from "../components/layout/dashboard/left_panel/LeftPanel";
|
import LeftPanel from "../components/layout/dashboard/left_panel/LeftPanel";
|
||||||
|
import ModalMatch from "@/components/layout/dashboard/match_notification/ModalMatch";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import { websiteName } from "@/lib/constants";
|
import { websiteName } from "@/lib/constants";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import LoadingPage from "@/components/LoadingPage";
|
import LoadingPage from "@/components/LoadingPage";
|
||||||
|
import { Notification, NotificationType } from "@prisma/client";
|
||||||
|
|
||||||
export default function Dashboard() {
|
export default function Dashboard() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const toast = useToast({ position: "top", isClosable: true });
|
const toast = useToast({ position: "top", isClosable: true });
|
||||||
const [newMatch, setNewMatch] = useState(false);
|
|
||||||
|
|
||||||
const { data: session, status } = useSession();
|
const { data: session, status } = useSession();
|
||||||
|
|
||||||
@@ -25,13 +26,14 @@ export default function Dashboard() {
|
|||||||
isError,
|
isError,
|
||||||
data: loggedUser,
|
data: loggedUser,
|
||||||
error,
|
error,
|
||||||
|
refetch: refetchLoggedUser,
|
||||||
} = useQuery({
|
} = useQuery({
|
||||||
queryKey: ["LoggedUser"],
|
queryKey: ["LoggedUser"],
|
||||||
enabled: status === "authenticated",
|
enabled: status === "authenticated",
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const { user } = session as unknown as Session;
|
const { user } = session as unknown as Session;
|
||||||
|
|
||||||
return fetch(`/api/users/${user.id}`)
|
return fetch(`/api/users/${user.id}?include=Notification`)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
@@ -72,21 +74,25 @@ export default function Dashboard() {
|
|||||||
if (status === "unauthenticated") router.push("/");
|
if (status === "unauthenticated") router.push("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
let modal;
|
||||||
* UTILISER refetch (image sur discord)
|
|
||||||
* https://tanstack.com/query/v3/docs/react/reference/useQuery ---> tout en bas
|
if (loggedUser?.Notification?.length > 0) {
|
||||||
*
|
const matchNotification = loggedUser.Notification.filter(
|
||||||
* dans onSuccess de useQuery
|
(notif: Notification) =>
|
||||||
* on filtre l'objet Notification de loggedUser par le type (match)
|
notif.type === NotificationType.NEW_MATCH &&
|
||||||
* setMatchNotification = [...filteredNotification],
|
notif.hasBeenConsulted === false
|
||||||
*
|
);
|
||||||
* et on passe dans le modal la premiere notif de type match
|
modal = matchNotification.map((notif: Notification) => {
|
||||||
* et on enleve au fur et a mesure (sur la BD aussi)
|
return (
|
||||||
*
|
<ModalMatch notif={notif} key={notif.id} loggedUser={loggedUser} />
|
||||||
*/
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
{modal}
|
||||||
|
|
||||||
<Head>
|
<Head>
|
||||||
<title>{websiteName} | Dashboard</title>
|
<title>{websiteName} | Dashboard</title>
|
||||||
</Head>
|
</Head>
|
||||||
@@ -110,11 +116,10 @@ export default function Dashboard() {
|
|||||||
listUsers.users.length === 0 ? (
|
listUsers.users.length === 0 ? (
|
||||||
<SearchFailCard />
|
<SearchFailCard />
|
||||||
) : (
|
) : (
|
||||||
// dans cardUser, mettre une liste de user, utiliser le user[0] et quand like ou dislike, supprimer le user[0] de la liste
|
|
||||||
<CardUser
|
<CardUser
|
||||||
users={listUsers.users}
|
users={listUsers.users}
|
||||||
loggedUser={loggedUser}
|
loggedUser={loggedUser}
|
||||||
setMatch={setNewMatch}
|
refetchLoggedUser={refetchLoggedUser}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
Reference in New Issue
Block a user