Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: 채팅 팝업 기능 추가 #73

Merged
merged 1 commit into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions components/ActivityDetails/ActivityDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@ import { usePopup } from '@/hooks/usePopup';
import { darkModeState } from '@/states/themeState';
import SendChat from '../Chat/SendChat';
import { ShareButton } from '../ShareButton/ShareButton';
import { loginState } from '@/states/loginState';
import { ViewedActivitiesState } from '@/states/ViewedState';
import { ViewedActivityProps } from '../ViewedActivities/ViewedActivities.type';

export default function ActivityDetails({ id }: ActivityDetailsProps) {
const router = useRouter();
const [isOpen, setIsOpen] = useState(false);
const isDarkMode = useRecoilValue(darkModeState);
const isLogined = useRecoilValue(loginState);
const [currentPage, setCurrentPage] = useState<number>(
router.query.page ? parseInt(router.query.page as string, 10) : 1
);
Expand Down Expand Up @@ -203,12 +205,14 @@ export default function ActivityDetails({ id }: ActivityDetailsProps) {
</div>
</div>
</div>
<div className="flex items-center t:items-center m:items-end">
<div className="flex items-center t:items-center m:items-center">
<div className="flex gap-[12px]">
{!isAuthor && (
{isLogined && !isAuthor && (
<SendChat
receiver={Number(activityData?.userId)}
activityId={Number(activityData?.id)}
activityTitle={String(activityData?.title)}
activityImage={String(activityData?.bannerImageUrl)}
/>
)}
<ShareButton
Expand Down
37 changes: 19 additions & 18 deletions components/Chat/SendChat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ import { useState } from 'react';
import ChatPopup from '../Popup/ChatPopup';
import { SendChatProps } from './SendChat.types';

function SendChat({ receiver, activityId }: SendChatProps) {
function SendChat({
receiver,
activityId,
activityTitle,
activityImage,
}: SendChatProps) {
const isDarkMode = useRecoilValue(darkModeState);
const { userData } = useUserData();
const [isPopupOpen, setIsPopupOpen] = useState(false);
Expand Down Expand Up @@ -41,25 +46,21 @@ function SendChat({ receiver, activityId }: SendChatProps) {

return (
<>
<button type="button" onClick={handleClick}>
{isDarkMode ? (
<Image
src="/icon/live_help_gray.svg"
alt="채팅 아이콘"
width={34}
height={34}
/>
) : (
<Image
src="/icon/live_help.svg"
alt="채팅 아이콘"
width={34}
height={34}
/>
)}
<button type="button" onClick={handleClick} className="w-[34px] h-[34px]">
<Image
src={isDarkMode ? '/icon/live_help_gray.svg' : '/icon/live_help.svg'}
alt="채팅 아이콘"
width={34}
height={34}
/>
</button>
{isPopupOpen && (
<ChatPopup closePopup={closePopup} activityId={activityId} />
<ChatPopup
closePopup={closePopup}
activityId={activityId}
activityTitle={activityTitle}
activityImage={activityImage}
/>
)}
</>
);
Expand Down
2 changes: 2 additions & 0 deletions components/Chat/SendChat.types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export interface SendChatProps {
receiver: number;
activityId: number;
activityTitle: string;
activityImage: string;
}
12 changes: 10 additions & 2 deletions components/MyActivity/Card/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import Link from 'next/link';
import ChatPopup from '@/components/Popup/ChatPopup';
import { useUserData } from '@/hooks/useUserData';
import socket from '@/server/server';
import { useRecoilValue } from 'recoil';
import { darkModeState } from '@/states/themeState';

function PopoverButton({ children, onClick }: PopoverButtonProps) {
return (
Expand Down Expand Up @@ -69,7 +71,7 @@ function Card({
}: CardProps) {
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
const [isPopupOpen, setIsPopupOpen] = useState(false);
const { userData } = useUserData();
const isDarkMode = useRecoilValue(darkModeState);

const handleClickMeatball = () => {
setIsPopoverOpen(!isPopoverOpen);
Expand Down Expand Up @@ -132,7 +134,11 @@ function Card({
<div className="m:w-[32px] m:h-[32px] flex items-center">
<button onClick={handleClickChat}>
<Image
src="/icon/chat_bubble.svg"
src={
isDarkMode
? '/icon/chat_bubble_gray.svg'
: '/icon/chat_bubble.svg'
}
alt="문의 내역"
width={30}
height={30}
Expand All @@ -144,6 +150,8 @@ function Card({
<ChatPopup
closePopup={closePopup}
activityId={activityId}
activityTitle={title}
activityImage={activityImage}
isAdmin
/>
)}
Expand Down
83 changes: 69 additions & 14 deletions components/Popup/ChatPopup.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { useState, useEffect } from 'react';
import { CloseButtonBold } from '../Button/Button';
import {
ChatListProps,
ChatPopupProps,
Expand All @@ -13,11 +12,23 @@ import Image from 'next/image';
function ChatPopup({
closePopup,
activityId,
activityTitle,
activityImage,
isAdmin = false,
}: ChatPopupProps) {
const [message, setMessage] = useState('');
const [senderId, setSenderId] = useState(0);
const [nickname, setNickName] = useState('문의 하기');
const [profile, setProfile] = useState(activityImage);
const [isSendEnabled, setIsSendEnabled] = useState(true);
const [isEnter, setIsEnter] = useState(false);

const handleClickPrev = () => {
setIsEnter(false);
setIsSendEnabled(false);
setNickName('문의 내역');
setProfile(activityImage);
};

const sendMessage = (event: any) => {
event.preventDefault();
Expand All @@ -43,15 +54,50 @@ function ChatPopup({

useEffect(() => {
setIsSendEnabled(!isAdmin);
if (isAdmin) {
setNickName('문의 내역');
}
}, []);

return (
<div className="flex items-center justify-center fixed w-[400px] bottom-[30px] right-[30px] z-50">
<div className="flex flex-col bg-var-gray2 w-full rounded-[20px]">
<div className="flex justify-between pt-[7px] pb-[3px] px-[20px] items-center bg-var-gray3 rounded-t-[20px]">
<p>문의 채팅</p>
<div className="flex items-center justify-center fixed w-[400px] bottom-[30px] right-[30px] z-50 m:inset-0 m:w-full m:bg-black m:bg-opacity-70">
<div className="flex flex-col bg-var-gray2 w-full rounded-[20px] dark:bg-var-dark2 dark:border-4 dark:border-solid dark:border-var-dark3">
<div className="flex justify-between h-[64px] pt-[10px] pb-[3px] px-[20px] items-center bg-var-gray3 rounded-t-[15px] dark:bg-var-dark3">
<div className="flex gap-[10px]">
<div className="w-[40px] h-[40px] rounded-full">
<Image
src={profile}
alt="프로필"
width={40}
height={40}
className="w-[40px] h-[40px] rounded-full"
/>
</div>
<div>
<p className="font-[500] line-clamp-1">{activityTitle}</p>
<p className="text-var-gray6">{`@${nickname}`}</p>
</div>
</div>

<div className="flex items-center h-[30px]">
<CloseButtonBold onClick={closePopup} />
{isEnter && (
<button onClick={handleClickPrev}>
<Image
src="/icon/prev_arrow.svg"
alt="이전"
width={20}
height={20}
/>
</button>
)}
<button onClick={closePopup}>
<Image
src="/icon/chat_close.svg"
alt="닫기"
width={24}
height={24}
/>
</button>
</div>
</div>
<div className="flex flex-col h-[500px]">
Expand All @@ -60,6 +106,10 @@ function ChatPopup({
activityId={activityId}
handleSenderId={setSenderId}
handleSendEnable={setIsSendEnabled}
isEnter={isEnter}
handleIsEnter={setIsEnter}
handleNickName={setNickName}
handleProfile={setProfile}
/>
) : (
<ShowChatList />
Expand Down Expand Up @@ -91,18 +141,23 @@ function ShowChatRoomList({
activityId,
handleSenderId,
handleSendEnable,
isEnter,
handleIsEnter,
handleNickName,
handleProfile,
}: ChatRoomPopupProps) {
const [rooms, setRooms] = useState<ChatRoomProps[]>([]);
const [isEnter, setIsEnter] = useState(false);
const { userData } = useUserData();

const handleClickRoom = (userId: number) => {
const handleClickRoom = (userId: number, index: number) => {
socket.emit('inquiryAdmin', userData.id, activityId, userId, (res: any) => {
console.log('inquiryAdmin res', res);
});
setIsEnter(true);
handleIsEnter(true);
handleSenderId(userId);
handleSendEnable(true);
handleNickName(rooms[index].user.name);
handleProfile(rooms[index].user.profile);
};

useEffect(() => {
Expand All @@ -129,8 +184,8 @@ function ShowChatRoomList({
<div key={room.user.id} className="flex justify-center">
<button
type="button"
onClick={() => handleClickRoom(room.user.id)}
className={`flex items-center gap-[15px] p-[15px] h-[75px] bg-var-gray2 w-full max-w-[400px] border-b border-solid border-b-var-gray4`}
onClick={() => handleClickRoom(room.user.id, index)}
className={`flex items-center gap-[15px] p-[15px] h-[75px] bg-var-gray2 w-full max-w-[400px] border-b border-solid border-b-var-gray4 dark:bg-var-dark2`}
>
<div className="w-[50px] h-[50px] rounded-full overflow-hidden">
<Image
Expand All @@ -141,7 +196,7 @@ function ShowChatRoomList({
/>
</div>
<div className="flex flex-col items-start">
<div className="font-[500] text-nomad-black">
<div className="font-[500] text-nomad-black dark:text-var-gray2">
{room.user.name}
</div>
<div className="text-var-gray6">
Expand All @@ -153,7 +208,7 @@ function ShowChatRoomList({
))}
</div>
) : (
<div className="flex justify-center items-center">
<div className="flex justify-center items-center mt-[20px]">
<p>아직 문의 채팅이 없습니다.</p>
</div>
))}
Expand Down Expand Up @@ -200,7 +255,7 @@ function ShowChatList({ isAdmin = false }: ChatListProps) {
className={`inline-block max-w-max rounded-[10px] p-[8px] pl-[10px] ${
sender[index] === 'user'
? 'bg-var-green2 text-white'
: 'bg-var-gray3'
: 'bg-var-gray3 text-var-dark1'
}`}
>
{message}
Expand Down
6 changes: 6 additions & 0 deletions components/Popup/ChatPopup.types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { Dispatch, SetStateAction } from 'react';
export interface ChatPopupProps {
closePopup: () => void;
activityId: number;
activityTitle: string;
activityImage: string;
isAdmin?: boolean;
}

Expand All @@ -21,6 +23,10 @@ export interface ChatRoomPopupProps {
activityId: number;
handleSenderId: Dispatch<SetStateAction<number>>;
handleSendEnable: Dispatch<SetStateAction<boolean>>;
isEnter: boolean;
handleIsEnter: Dispatch<SetStateAction<boolean>>;
handleNickName: Dispatch<SetStateAction<string>>;
handleProfile: Dispatch<SetStateAction<string>>;
}

export interface ChatListProps {
Expand Down
1 change: 1 addition & 0 deletions public/icon/chat_close.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/icon/prev_arrow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions server/server.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import io from 'socket.io-client';
const socket = io('https://rear-ninnetta-codeitsprinter-6a0e09e4.koyeb.app/');
// const socket = io('http://localhost:5001');

export default socket;