Skip to content

Commit

Permalink
Merge pull request #18 from MOVIEJOJO7/feature/#1
Browse files Browse the repository at this point in the history
Feat : 오픈채팅방 데이터 받아와서 리스트에 뿌려주기 pr
  • Loading branch information
LikeFireAndSky authored Nov 10, 2023
2 parents 51f047b + 16d1467 commit ea2874b
Show file tree
Hide file tree
Showing 22 changed files with 636 additions and 30 deletions.
123 changes: 123 additions & 0 deletions Components/Open/ChatGenerator/ChatGenerator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
'use client';

import {
Button,
Card,
Checkbox,
Input,
Typography,
} from '@material-tailwind/react';
import React, { useRef } from 'react';
import { useForm, SubmitHandler } from 'react-hook-form';
import ChatGeneratorMenu from './ChatGeneratorMenu/ChatGeneratorMenu';
import { chatModalAtom } from '@/atoms/chatModalAtom';
import { useRecoilState } from 'recoil';
import { Inputs } from './ChatGenerator.type';
import { useFetchPostNewChat } from '@/hooks/Open/useFetchPostNewChat';
import { useCurrentSearchParams } from '@/hooks/Open/useCurrentSearchParmas';

const ChatGenerator = () => {
const accessToken = process.env.NEXT_PUBLIC_ACCESS_TOKEN as string;
const mutation = useFetchPostNewChat(accessToken);
const params = useCurrentSearchParams('type');

const modalRef = useRef(null);
const [chatModal, setChatModal] = useRecoilState(chatModalAtom);
const {
register,
handleSubmit,
formState: { errors },
} = useForm<Inputs>();

const checkIsPrivateChat = () => {
if (params === 'private') {
return true;
}
return false;
};

const onSubmit: SubmitHandler<Inputs> = (data) => {
mutation.mutate({
name: data.name,
users: data.users,
isPrivate: checkIsPrivateChat(),
});
handleModalClose();
};

const handleModalClose = () => {
setChatModal(false);
};

return (
<>
{chatModal && (
<div
ref={modalRef}
className={`absolute w-full inset-0 flex flex-col items-center justify-center bg-white border-4 box-border`}
>
<button
type="button"
className="absolute w-8 h-8 rounded-xl bg-primary top-3 left-3 block"
onClick={handleModalClose}
>
X
</button>
<Card color="transparent" shadow={false}>
<Typography color="gray" className="mt-1 font-normal">
채팅방 주제 잘 정하고 만드세요!
</Typography>
<form
onSubmit={handleSubmit(onSubmit)}
className="mt-8 mb-2 w-full"
>
<div className="mb-1 flex flex-col gap-6">
<Typography variant="h6" color="blue-gray" className="-mb-3">
채팅방 이름
</Typography>
<Input
crossOrigin={'anonymous'}
size="lg"
placeholder="채팅방 이름을 입력해 주세요."
className=" !border-t-blue-gray-200 focus:!border-t-gray-900"
labelProps={{
className: 'before:content-none after:content-none',
}}
{...register('name', { required: true })}
/>
</div>
<p>{errors.name && <span>This field is required</span>}</p>
<div className="w-full">
<ChatGeneratorMenu register={register} />
</div>
<Checkbox
crossOrigin={'anonymous'}
label={
<Typography
variant="small"
color="gray"
className="flex items-center font-normal"
>
I agree the
<a
href="#"
className="font-medium transition-colors hover:text-gray-900"
>
&nbsp;Terms and Conditions
</a>
</Typography>
}
containerProps={{ className: '-ml-2.5' }}
/>
<Button type="submit" className="mt-6 bg-primary" fullWidth>
채팅방 만들기
</Button>
</form>
</Card>
</div>
)}
</>
);
};

export default ChatGenerator;
11 changes: 11 additions & 0 deletions Components/Open/ChatGenerator/ChatGenerator.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { UseFormRegister } from 'react-hook-form';

export type Inputs = {
name: string;
users: string[];
isPrivate?: boolean;
};

export type RegisterFn = {
register: UseFormRegister<Inputs>;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
'use client';

import React from 'react';
import {
Menu,
MenuHandler,
MenuList,
MenuItem,
Button,
Checkbox,
Typography,
} from '@material-tailwind/react';
import { useFetchAllUserHook } from '@/hooks/Open/useFetchAllUserHook';
import { User } from '@/types';
import { RegisterFn } from '../ChatGenerator.type';

const ChatGeneratorMenu = ({ register }: RegisterFn) => {
const accessToken = process.env.NEXT_PUBLIC_ACCESS_TOKEN;
const { data } = useFetchAllUserHook(accessToken as string);

return (
<Menu>
<MenuHandler>
<Button className="w-full">Menu</Button>
</MenuHandler>
<MenuList className="absolute z-40 max-h-64">
<MenuItem className="text-center text-xl font-bold">유저들</MenuItem>
{data?.map((user: User) => {
return (
<MenuItem key={user.id} color="blue">
<Checkbox
crossOrigin={'anonymous'}
label={
<Typography
variant="small"
color="gray"
className="flex items-center font-normal"
>
{user.name}
</Typography>
}
value={user.id}
{...register('users', { required: true })}
containerProps={{ className: '-ml-2.5' }}
/>
</MenuItem>
);
})}
</MenuList>
</Menu>
);
};

export default ChatGeneratorMenu;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const fetchAllUsers = async (tokens: string) => {
const res = await fetch('https://fastcampus-chat.net/users', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
serverId: process.env.NEXT_PUBLIC_SERVER_ID as string,
Authorization: `Bearer ${tokens}`,
},
});
const data = await res.json();
return data;
};
60 changes: 60 additions & 0 deletions Components/Open/ChatList/ChatItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
'use client';

import { Avatar, Typography } from '@material-tailwind/react';
import Image from 'next/image';
import OpenPeopleSvg from '@/public/OpenPeopleSvg.svg';
import { ChatItemProps } from './ChatList.type';

const ChatItem = ({ chat }: ChatItemProps) => {
const firstUserImage = chat.users[0].picture;

return (
<div
key={chat.id}
className="border-4 border-primary hover:bg-gray-300 cursor-pointer rounded-xl ease-in transition-all duration-300 p-5"
>
<div className="flex gap-5 h-full">
<Avatar
src={firstUserImage}
alt="candice"
width={5}
height={5}
className="rounded-full w-8 h-8"
/>
<div>
<Typography
variant="h6"
color="blue-gray"
className="whitespace-normal"
>
{chat.name}
</Typography>
<Typography
variant="small"
color="gray"
className="font-normal flex gap-1 items-center"
>
<Image
src={OpenPeopleSvg}
alt="candice"
width={10}
height={10}
className="rounded-full w-4 h-4 object-cover"
/>
{`${chat.users.length}명 참여중`}
</Typography>
<Typography variant="small" color="gray" className="font-normal">
{chat.messages
? chat.messages[chat.messages.length]?.text
: '아직 채팅이 없습니다.'}
</Typography>
<Typography variant="small" color="gray" className="font-normal">
{`${chat.updatedAt}`}
</Typography>
</div>
</div>
</div>
);
};

export default ChatItem;
29 changes: 29 additions & 0 deletions Components/Open/ChatList/ChatList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use client';

import React from 'react';
import { ChatListProps } from './ChatList.type';
import { Chat } from '@/app/open/open.type';
import { filterChat } from '@/app/open/open.utils';
import ChatItem from './ChatItem';
import { useQuery } from '@tanstack/react-query';
import { fetchAllChat } from '@/app/open/open.utils';

const ChatList = ({ myChatList }: ChatListProps) => {
const { data: chatList } = useQuery({
queryKey: ['myChatList'],
queryFn: () => fetchAllChat(process.env.NEXT_PUBLIC_ACCESS_TOKEN as string),
initialData: myChatList,
staleTime: 1000 * 60,
refetchInterval: 1000 * 120,
});
const filteredChatList = filterChat(chatList.chats);
return (
<div className="h-full overflow-y-scroll gap-5">
{filteredChatList.map((chat: Chat) => {
return <ChatItem chat={chat} key={chat.id} />;
})}
</div>
);
};

export default ChatList;
9 changes: 9 additions & 0 deletions Components/Open/ChatList/ChatList.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Chat } from '@/app/open/open.type';

export type ChatListProps = {
myChatList: Chat[];
};

export type ChatItemProps = {
chat: Chat;
};
61 changes: 61 additions & 0 deletions Components/Open/SpeedDial/SpeedDial.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
'use client';

import {
SpeedDial,
SpeedDialHandler,
SpeedDialContent,
SpeedDialAction,
Typography,
} from '@material-tailwind/react';
import { chatModalAtom } from '@/atoms/chatModalAtom';
import { useSetRecoilState } from 'recoil';
import Link from 'next/link';
import { useRouter } from 'next/navigation';

const SpeedDialWithTextInside = () => {
const setModalOpen = useSetRecoilState(chatModalAtom);
const router = useRouter();

const handleOpenModal = (query: string) => {
router.replace(`/open?${new URLSearchParams({ type: query })}`);
setModalOpen(true);
};

return (
<div className="absolute bottom-3 right-3">
<SpeedDial>
<SpeedDialHandler>
<div className="flex flex-col justify-center items-center text-center text-sm rounded-full shadow-2xl hover:scale-105 transition-all duration-500 ease-in-out w-16 h-16 bg-primary cursor-pointer">
채팅
<br />
만들기
</div>
</SpeedDialHandler>
<SpeedDialContent>
<SpeedDialAction
className="h-16 w-16"
onClick={() => handleOpenModal('open')}
>
<Link href={`?${new URLSearchParams({ type: 'open' })}`}>
<Typography color="blue-gray" className="text-xs font-normal">
오픈채팅
</Typography>
</Link>
</SpeedDialAction>
<SpeedDialAction
className="h-16 w-16"
onClick={() => handleOpenModal('private')}
>
<Link href={`?${new URLSearchParams({ type: 'private' })}`}>
<Typography color="blue-gray" className="text-xs font-normal">
비밀채팅
</Typography>
</Link>
</SpeedDialAction>
</SpeedDialContent>
</SpeedDial>
</div>
);
};

export default SpeedDialWithTextInside;
8 changes: 7 additions & 1 deletion Components/Search/OpenChatPicture.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import { User } from '@/app/search/search.type';
import Image from 'next/image';

const OpenChatPicture = ({ openChatUsers }: { openChatUsers: User[] }) => {
let userCount = 0;
Expand All @@ -16,7 +17,12 @@ const OpenChatPicture = ({ openChatUsers }: { openChatUsers: User[] }) => {

return (
<li key={user.id}>
<img src={user.picture} alt="user picture" />
<Image
width={100}
height={100}
src={user.picture}
alt="user picture"
/>
</li>
);
})}
Expand Down
7 changes: 7 additions & 0 deletions app/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from 'react';

const Loading = () => {
return <div>Loading</div>;
};

export default Loading;
Loading

0 comments on commit ea2874b

Please sign in to comment.