mirror of
https://github.com/LucasVbr/meeting-app.git
synced 2026-05-13 17:21:53 +00:00
Display Chats in dashboard + autoscroll chat to bottom
Took 1 hour 11 minutes
This commit is contained in:
@@ -23,7 +23,7 @@ const Carousel = ({images, borderRadius: bRadius}: Props) => {
|
|||||||
return (
|
return (
|
||||||
<Flex px={2} align="center" borderRadius={bRadius} overflow={'hidden'}
|
<Flex px={2} align="center" borderRadius={bRadius} overflow={'hidden'}
|
||||||
justify={'space-between'} bgColor={'purple.50'} height={500}
|
justify={'space-between'} bgColor={'purple.50'} height={500}
|
||||||
bgImage={images[currentIndex]} bgSize={'contain'}
|
bgImage={images[currentIndex]} bgSize={'cover'}
|
||||||
bgRepeat={'no-repeat'} bgPosition={'center'} width={'100%'}>
|
bgRepeat={'no-repeat'} bgPosition={'center'} width={'100%'}>
|
||||||
<IconButton aria-label="left-arrow" borderRadius="full"
|
<IconButton aria-label="left-arrow" borderRadius="full"
|
||||||
onClick={handleClickPrevious}>
|
onClick={handleClickPrevious}>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {Chat, User} from '@prisma/client';
|
import {Chat, User} from '@prisma/client';
|
||||||
import ChatListItem from '@/components/chat/ChatListItem';
|
import ChatListItem from '@/components/chat/ChatListItem';
|
||||||
import {useEffect, useState} from 'react';
|
import {useEffect, useState} from 'react';
|
||||||
|
import {Stack, StackDivider} from '@chakra-ui/react';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
user: User
|
user: User
|
||||||
@@ -18,11 +19,11 @@ export default function ChatList({user}: Props) {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Stack divider={<StackDivider/>} spacing={2}>
|
||||||
{chats.map(
|
{chats.map(
|
||||||
(chat: Chat & { User: User[] }, index: number) =>
|
(chat: Chat & { User: User[] }, index: number) =>
|
||||||
<ChatListItem key={index} chat={chat} user={user}/>)
|
<ChatListItem key={index} chat={chat} user={user}/>)
|
||||||
}
|
}
|
||||||
</>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,26 +1,24 @@
|
|||||||
import {Chat, User} from '@prisma/client';
|
import {Chat, User} from '@prisma/client';
|
||||||
import {Box, Flex, Image, Text} from '@chakra-ui/react';
|
import {Box, Button, Flex, Image, Text} from '@chakra-ui/react';
|
||||||
import {useRouter} from 'next/router';
|
import {useRouter} from 'next/router';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
user: User,
|
user: User,
|
||||||
chat: Chat & {User: User[]}
|
chat: Chat & { User: User[] }
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function ChatListItem({user, chat}: Props) {
|
export default function ChatListItem({user, chat}: Props) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const otherUser = chat.User.find((u: User) => u.id !== user.id) as User
|
const otherUser = chat.User.find((u: User) => u.id !== user.id) as User;
|
||||||
|
|
||||||
console.log(chat);
|
console.log(chat);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Flex alignItems={"center"} gap={5} cursor={'pointer'} onClick={() => router.push(`/chat/${chat.id}`)}>
|
||||||
<Flex cursor={"pointer"} onClick={() => router.push(`/chat/${chat.id}`)}>
|
<Image borderRadius={'full'} boxSize="50px" src={otherUser.images[0] ?? '/blank_profile_picture.webp'}/>
|
||||||
<Image borderRadius={'full'} boxSize='50px' src={otherUser.images[0] ?? "/blank_profile_picture.webp"}/>
|
<Box>
|
||||||
<Box>
|
<Text>{otherUser.firstName} {otherUser.lastName}</Text>
|
||||||
<Text>{otherUser.firstName} {otherUser.lastName}</Text>
|
</Box>
|
||||||
</Box>
|
</Flex>
|
||||||
</Flex>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import type {Message as MessageType, User} from '@prisma/client';
|
import type {Message as MessageType, User} from '@prisma/client';
|
||||||
import Message from '@/components/chat/Message';
|
import Message from '@/components/chat/Message';
|
||||||
import {Flex} from '@chakra-ui/react';
|
import {Flex, Box} from '@chakra-ui/react';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
user: User,
|
user: User,
|
||||||
@@ -9,12 +9,14 @@ type Props = {
|
|||||||
|
|
||||||
const MessageList = ({messages, user}: Props) => {
|
const MessageList = ({messages, user}: Props) => {
|
||||||
return (
|
return (
|
||||||
<Flex direction={'column'} gap={1}>
|
<Box w={'70vh'} overflow={'scroll'}>
|
||||||
{messages.map((message, index) => <Message
|
<Flex direction={'column'} gap={1} justifyContent={'flex-end'}>
|
||||||
align={user.id === message.UserID ? 'right' : 'left'} key={index}
|
{messages.map((message, index) => <Message
|
||||||
message={message}/>
|
align={user.id === message.UserID ? 'right' : 'left'} key={index}
|
||||||
)}
|
message={message}/>,
|
||||||
</Flex>
|
)}
|
||||||
|
</Flex>
|
||||||
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -17,13 +17,16 @@ import PassionTagList from "@/components/layout/dashboard/card_user/PassionTagLi
|
|||||||
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";
|
||||||
|
import {User} from '@prisma/client';
|
||||||
|
|
||||||
export default function CardUser({
|
type Props = {
|
||||||
users,
|
users: User[]
|
||||||
loggedUser,
|
loggedUser: User
|
||||||
setMatch,
|
setMatch: any
|
||||||
refetchLoggedUser,
|
refetchLoggedUser: any
|
||||||
}) {
|
}
|
||||||
|
|
||||||
|
export default function CardUser({users, loggedUser, setMatch, refetchLoggedUser}: Props) {
|
||||||
const toast = useToast({
|
const toast = useToast({
|
||||||
position: "top",
|
position: "top",
|
||||||
duration: 2000,
|
duration: 2000,
|
||||||
|
|||||||
@@ -68,13 +68,6 @@ export default function LeftPanel(props) {
|
|||||||
Carte
|
Carte
|
||||||
</LeftPanelButton>
|
</LeftPanelButton>
|
||||||
|
|
||||||
<LeftPanelButton
|
|
||||||
leftIcon={<AiFillMessage />}
|
|
||||||
onClickHandler={() => router.push("/chat")}
|
|
||||||
>
|
|
||||||
Messages
|
|
||||||
</LeftPanelButton>
|
|
||||||
|
|
||||||
<LeftPanelButton
|
<LeftPanelButton
|
||||||
leftIcon={<BsFillPersonFill />}
|
leftIcon={<BsFillPersonFill />}
|
||||||
onClickHandler={() => router.push("/profile")}
|
onClickHandler={() => router.push("/profile")}
|
||||||
|
|||||||
+27
-11
@@ -1,9 +1,9 @@
|
|||||||
import {Button, Container, Flex, Input} from '@chakra-ui/react';
|
import {Button, Container, Flex, FormControl, Input} from '@chakra-ui/react';
|
||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
import {websiteName} from '@/lib/constants';
|
import {websiteName} from '@/lib/constants';
|
||||||
import {useSession} from 'next-auth/react';
|
import {useSession} from 'next-auth/react';
|
||||||
import {useRouter} from 'next/router';
|
import {useRouter} from 'next/router';
|
||||||
import {useEffect, useState} from 'react';
|
import {useEffect, useRef, useState} from 'react';
|
||||||
|
|
||||||
import MessageList from '@/components/chat/MessageList';
|
import MessageList from '@/components/chat/MessageList';
|
||||||
|
|
||||||
@@ -30,19 +30,29 @@ export default function ChatId() {
|
|||||||
const soc = io();
|
const soc = io();
|
||||||
|
|
||||||
soc.on('connect', () => console.log('connected'));
|
soc.on('connect', () => console.log('connected'));
|
||||||
soc.on('allOldMessages', (allOldMessages: Message[]) => setMessages(allOldMessages));
|
soc.on('allOldMessages',
|
||||||
soc.on('newIncomingMessage', (newIncomingMessage: Message) => setMessages(messages => [...messages, newIncomingMessage]));
|
(allOldMessages: Message[]) => setMessages(allOldMessages));
|
||||||
|
soc.on('newIncomingMessage',
|
||||||
|
(newIncomingMessage: Message) => setMessages(
|
||||||
|
messages => [...messages, newIncomingMessage]));
|
||||||
setSocket(soc);
|
setSocket(soc);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = (evt) => {
|
||||||
|
evt.preventDefault()
|
||||||
if (text !== '' && socket && session?.user) {
|
if (text !== '' && socket && session?.user) {
|
||||||
socket.emit('createdMessage', {text, sender: session.user.id});
|
socket.emit('createdMessage', {text, sender: session.user.id});
|
||||||
setText('');
|
setText('');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const AlwaysScrollToBottom = () => {
|
||||||
|
const elementRef = useRef();
|
||||||
|
useEffect(() => elementRef.current.scrollIntoView());
|
||||||
|
return <div ref={elementRef}/>;
|
||||||
|
};
|
||||||
|
|
||||||
if (status === 'loading') return <LoadingPage/>;
|
if (status === 'loading') return <LoadingPage/>;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -51,12 +61,18 @@ export default function ChatId() {
|
|||||||
<Container>
|
<Container>
|
||||||
<MessageList user={session.user as User} messages={messages}/>
|
<MessageList user={session.user as User} messages={messages}/>
|
||||||
|
|
||||||
<Flex gap={5} mt={5}>
|
|
||||||
<Input type={'text'} colorScheme={'purple'}
|
<form onSubmit={handleSubmit}>
|
||||||
onChange={evt => setText(evt.target.value)} value={text}/>
|
<FormControl>
|
||||||
<Button colorScheme={'purple'}
|
<Flex gap={5} py={5}>
|
||||||
onClick={handleSubmit}>Envoyer</Button>
|
<Input type={'text'}
|
||||||
</Flex>
|
onChange={evt => setText(evt.target.value)}
|
||||||
|
value={text}/>
|
||||||
|
<Button type={'submit'} colorScheme={'purple'}>Envoyer</Button>
|
||||||
|
</Flex>
|
||||||
|
</FormControl>
|
||||||
|
</form>
|
||||||
|
<AlwaysScrollToBottom/>
|
||||||
</Container>
|
</Container>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -7,8 +7,5 @@ export default function Chat() {
|
|||||||
const {data: session, status} = useSession({required: true});
|
const {data: session, status} = useSession({required: true});
|
||||||
|
|
||||||
if (status === 'loading') return <LoadingPage/>;
|
if (status === 'loading') return <LoadingPage/>;
|
||||||
if (session)
|
return <ChatList user={session.user as User}/>;
|
||||||
return (
|
|
||||||
<ChatList user={session.user as User}/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
+91
-77
@@ -1,25 +1,34 @@
|
|||||||
import { Grid, GridItem, Box, useToast, useDisclosure } from "@chakra-ui/react";
|
import {
|
||||||
import { useSession } from "next-auth/react";
|
Grid,
|
||||||
import { useRouter } from "next/router";
|
GridItem,
|
||||||
import { useState } from "react";
|
Box,
|
||||||
|
useToast,
|
||||||
|
useDisclosure,
|
||||||
|
Card, CardBody, CardHeader, Heading,
|
||||||
|
} from '@chakra-ui/react';
|
||||||
|
import {useSession} from 'next-auth/react';
|
||||||
|
import {useRouter} from 'next/router';
|
||||||
|
|
||||||
import type { Session } from "@/models/auth/Session";
|
import type {Session} from '@/models/auth/Session';
|
||||||
import CardUser from "../components/layout/dashboard/card_user/CardUser";
|
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 ModalMatch
|
||||||
import Head from "next/head";
|
from '@/components/layout/dashboard/match_notification/ModalMatch';
|
||||||
import { websiteName } from "@/lib/constants";
|
import Head from 'next/head';
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import {websiteName} from '@/lib/constants';
|
||||||
import LoadingPage from "@/components/LoadingPage";
|
import {useQuery} from '@tanstack/react-query';
|
||||||
import { Notification, NotificationType } from "@prisma/client";
|
import LoadingPage from '@/components/LoadingPage';
|
||||||
|
import {Notification, NotificationType, User} from '@prisma/client';
|
||||||
|
import ChatList from '@/components/chat/ChatList';
|
||||||
|
|
||||||
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 { data: session, status } = useSession();
|
const {data: session, status} = useSession({required: true});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isLoading,
|
isLoading,
|
||||||
@@ -28,18 +37,18 @@ export default function Dashboard() {
|
|||||||
error,
|
error,
|
||||||
refetch: refetchLoggedUser,
|
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}?include=Notification`)
|
return fetch(`/api/users/${user.id}?include=Notification`)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
return err;
|
return err;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -49,84 +58,89 @@ export default function Dashboard() {
|
|||||||
isLoading: isLoadingListUsers,
|
isLoading: isLoadingListUsers,
|
||||||
error: errorListUsers,
|
error: errorListUsers,
|
||||||
} = useQuery({
|
} = useQuery({
|
||||||
queryKey: ["ListUsers"],
|
queryKey: ['ListUsers'],
|
||||||
enabled: status === "authenticated" && !isLoading,
|
enabled: status === 'authenticated' && !isLoading,
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
return fetch(`/api/user/userDashboard?userID=${loggedUser.id}`) //exclure les profils déjà like ou dislike
|
return fetch(
|
||||||
.then((res) => res.json())
|
`/api/user/userDashboard?userID=${loggedUser.id}`) //exclure les profils déjà like ou dislike
|
||||||
.catch((err) => {
|
.then((res) => res.json())
|
||||||
return err;
|
.catch((err) => {
|
||||||
});
|
return err;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
if (status === "unauthenticated") router.push("/login");
|
if (status === 'unauthenticated') router.push('/login');
|
||||||
return <LoadingPage />;
|
return <LoadingPage/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isError) {
|
if (isError) {
|
||||||
toast({
|
toast({
|
||||||
title: `Erreur lors de la récupération des données du profil`,
|
title: `Erreur lors de la récupération des données du profil`,
|
||||||
status: "error",
|
status: 'error',
|
||||||
position: "top",
|
position: 'top',
|
||||||
});
|
});
|
||||||
if (status === "unauthenticated") router.push("/");
|
if (status === 'unauthenticated') router.push('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
let modal;
|
let modal;
|
||||||
|
|
||||||
if (loggedUser?.Notification?.length > 0) {
|
if (loggedUser?.Notification?.length > 0) {
|
||||||
const matchNotification = loggedUser.Notification.filter(
|
const matchNotification = loggedUser.Notification.filter(
|
||||||
(notif: Notification) =>
|
(notif: Notification) =>
|
||||||
notif.type === NotificationType.NEW_MATCH &&
|
notif.type === NotificationType.NEW_MATCH &&
|
||||||
notif.hasBeenConsulted === false
|
notif.hasBeenConsulted === false,
|
||||||
);
|
);
|
||||||
modal = matchNotification.map((notif: Notification) => {
|
modal = matchNotification.map((notif: Notification) => {
|
||||||
return (
|
return (
|
||||||
<ModalMatch notif={notif} key={notif.id} loggedUser={loggedUser} />
|
<ModalMatch notif={notif} key={notif.id} loggedUser={loggedUser}/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (status === 'loading') return <LoadingPage/>;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{modal}
|
{modal}
|
||||||
|
|
||||||
<Head>
|
<Head>
|
||||||
<title>{websiteName} | Dashboard</title>
|
<title>{websiteName} | Dashboard</title>
|
||||||
</Head>
|
</Head>
|
||||||
|
|
||||||
<Grid
|
<Grid templateColumns={'repeat(5, 1fr)'}
|
||||||
templateColumns={"repeat(5, 1fr)"}
|
templateRows={'repeat(2, 1fr)'}
|
||||||
templateRows={"repeat(2, 1fr)"}
|
gap={5}
|
||||||
gap={5}
|
minH={'100vh'}>
|
||||||
minH={"100vh"}
|
<GridItem area={'1 / 1 / 3 / 2'}>
|
||||||
>
|
<LeftPanel user={loggedUser}/>
|
||||||
<GridItem area={"1 / 1 / 3 / 2"}>
|
</GridItem>
|
||||||
<LeftPanel user={loggedUser} />
|
<GridItem area={'1 / 2 / 3 / 4'}>
|
||||||
</GridItem>
|
<Box py={3}>
|
||||||
<GridItem area={"1 / 2 / 3 / 4"}>
|
{isLoadingListUsers
|
||||||
<Box py={3}>
|
? (<LoadingPage/>)
|
||||||
{isLoadingListUsers ? (
|
: (isErrorListUsers || !listUsers || !listUsers.users ||
|
||||||
<LoadingPage />
|
listUsers.users.length === 0)
|
||||||
) : isErrorListUsers ||
|
? <SearchFailCard/>
|
||||||
listUsers === undefined ||
|
: <CardUser users={listUsers.users} loggedUser={loggedUser}
|
||||||
listUsers.users === undefined ||
|
refetchLoggedUser={refetchLoggedUser}/>
|
||||||
listUsers.users.length === 0 ? (
|
}
|
||||||
<SearchFailCard />
|
</Box>
|
||||||
) : (
|
</GridItem>
|
||||||
<CardUser
|
<GridItem area={'1 / 4 / 2 / 6'}>
|
||||||
users={listUsers.users}
|
<Box py={3} pr={3}>
|
||||||
loggedUser={loggedUser}
|
<Card w={"100%"} h={"100%"} borderRadius={"1rem"}>
|
||||||
refetchLoggedUser={refetchLoggedUser}
|
<CardHeader>
|
||||||
/>
|
<Heading cursor={"pointer"} size='md' onClick={() => {router.push('/chat')}}>Conversations</Heading>
|
||||||
)}
|
</CardHeader>
|
||||||
</Box>
|
<CardBody>
|
||||||
</GridItem>
|
<ChatList user={session?.user as User}/>
|
||||||
<GridItem area={"1 / 4 / 2 / 6"}>{/*Right top*/}</GridItem>
|
</CardBody>
|
||||||
<GridItem area={"2 / 4 / 3 / 6"}>{/*Right Bottom*/}</GridItem>
|
</Card>
|
||||||
</Grid>
|
</Box>
|
||||||
</>
|
</GridItem>
|
||||||
|
<GridItem area={'2 / 4 / 3 / 6'}>{/*Right Bottom*/}</GridItem>
|
||||||
|
</Grid>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user