Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
7 changes: 7 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
},
"dependencies": {
"@headlessui/react": "^2.2.0",
"@stomp/stompjs": "^7.0.0",
"@tanstack/react-query": "^5.61.5",
"@tanstack/react-query-devtools": "^5.61.5",
"@vercel/speed-insights": "^1.1.0",
Expand Down
7 changes: 2 additions & 5 deletions src/api/chat/chatApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,8 @@ export const uploadChatImages = async (
): Promise<UploadChatImagesResponse> => {
const formData = new FormData();
images.forEach((image) => {
formData.append('images', image);
formData.append('files', image);
});

return http.post<UploadChatImagesResponse>(
`/chat/${chatId}/images`,
formData,
);
return http.post<UploadChatImagesResponse>(`/chat/${chatId}/image`, formData);
};
10 changes: 10 additions & 0 deletions src/api/chat/chatRoomsApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,18 @@ interface RoomsResponse {
data: RoomResponse[];
}

interface LeaveChatResponse {
status: string;
data: null;
}

export const getChatRooms = async (
sortType: SortType,
): Promise<RoomsResponse> => {
return http.get<RoomsResponse>(`/chat?sortType=${sortType}`);
};

export const leaveChat = async (chatId: string): Promise<LeaveChatResponse> => {
return http.delete<LeaveChatResponse>(`/chat/${chatId}`);
};
// 나가기 기능
37 changes: 36 additions & 1 deletion src/app/(chat)/chat/page.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,49 @@
/* eslint-disable react-hooks/exhaustive-deps */

'use client';

import ChatRoomsContainer from '@/components/chat/chatRoomList/ChatRoomsContainer';
import ChatRoomContainer from '@/components/chat/chatRoom/ChatRoomContainer';
import { useState } from 'react';
import { useState, useEffect } from 'react';
import { useChatRooms } from '@/hooks/useChatRooms';
import { RoomResponse } from '@/@types/chat';
import MainNavigation from '@/components/nav/MainNavigation';
import PCHeader from '@/components/header/PCHeader';
import { useWebSocketStore } from '@/store/useWebSocketStore';
import useGetUser from '@/queries/user/useGetUser';

const ChatRoomsPage = () => {
const [chatRoomId, setChatRoomId] = useState<string | null>(null);
const {
connected,
connect,
disconnect,
subscribeToAlarm,
unsubscribeFromAlarm,
} = useWebSocketStore();
const { data } = useGetUser();
const userId = data?.userId;

useEffect(() => {
connect();

return () => {
disconnect();
};
}, [connect, disconnect]);

useEffect(() => {
if (connected && userId) {
subscribeToAlarm(`${userId}`);
} else {
console.warn('WebSocket is not connected yet');
}

return () => {
unsubscribeFromAlarm(`${userId}`);
};
}, [connected, subscribeToAlarm, unsubscribeFromAlarm, userId]);

const handleChatRoomId = (chatId: string) => {
setChatRoomId(chatId);
};
Expand Down Expand Up @@ -44,6 +78,7 @@ const ChatRoomsPage = () => {
className={`relative w-full ${chatRoomId === null ? 'block' : 'hidden'} md:block md:min-w-[383px] md:max-w-[450px] md:border-r md:border-[#D9D9D9] xl:mt-20 xl:h-[calc(100dvh-80px)]`}
>
<ChatRoomsContainer
chatRoomId={chatRoomId as string}
onChatRoomId={handleChatRoomId}
chatRoomsData={chatRoomsData}
/>
Expand Down
9 changes: 5 additions & 4 deletions src/app/travel/(tripRegister)/new/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
/* eslint-disable @next/next/no-img-element */

'use client';

import StepRenderer from '@/components/createTrip/steps/StepRenderer';
import Header from '@/components/common/header/Header';
import TripRegisterHeader from '@/components/createTrip/tripRegisterHeader/TripRegisterHeader';
import useTravelForm from '@/hooks/useTravelForm';
import LoadingOverlay from '@/components/common/loding/LoadingOverlay';

const MultiStepForm = () => {
const {
Expand All @@ -19,17 +22,15 @@ const MultiStepForm = () => {
} = useTravelForm();

return (
<div className="flex h-dvh flex-col">
<div className="relative flex h-dvh flex-col">
<Header
title="여행 만들기"
onRoute={currentStep === 0 ? undefined : goToPrevStep}
/>
<div className="mx-5">
<div className="mx-auto mt-[100px] flex w-full min-w-[335px] max-w-[500px] flex-col xl:mt-[120px]">
{isLoading ? (
<div className="flex h-1/2 items-center justify-center">
로딩중...
</div>
<LoadingOverlay />
) : (
<>
<TripRegisterHeader currentStep={currentStep} />
Expand Down
10 changes: 5 additions & 5 deletions src/components/chat/chatRoom/ChatImageViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ const ChatImageViewer = ({
if (!(isViewerOpen && currentGroup && groupedImages)) return null;

return (
<div className="fixed inset-0 z-40 bg-label-strong xl:bg-label-strong/[84%]">
<div className="fixed inset-0 z-[90] bg-label-strong xl:bg-label-strong/[84%]">
<header className="xl:border-b xl:border-label-neutral">
<div className="relative m-auto flex items-center justify-between p-5 xl:max-w-[1440px]">
<button
Expand Down Expand Up @@ -124,7 +124,7 @@ const ChatImageViewer = ({
<MenuButton onClick={handleClickDownload}>
<Download />
</MenuButton>
<MenuItems className="absolute right-5 top-[70px] z-50 flex flex-col">
<MenuItems className="z-100 absolute right-5 top-[70px] flex flex-col">
<MenuItem>
<button
type="button"
Expand Down Expand Up @@ -204,7 +204,7 @@ const ChatImageViewer = ({

<button
type="button"
className="prev-button absolute top-1/2 z-50 -translate-y-1/2 transform bg-black/40"
className="prev-button absolute top-1/2 z-[110] -translate-y-1/2 transform bg-black/40"
onClick={() => {
if (swiperRef.current && !swiperRef.current.animating) {
swiperRef.current.slidePrev();
Expand All @@ -215,7 +215,7 @@ const ChatImageViewer = ({
</button>
<button
type="button"
className="next-button absolute right-0 top-1/2 z-50 -translate-y-1/2 rotate-180 transform bg-black/40"
className="next-button absolute right-0 top-1/2 z-[110] -translate-y-1/2 rotate-180 transform bg-black/40"
onClick={() => {
if (swiperRef.current && !swiperRef.current.animating) {
swiperRef.current.slideNext();
Expand All @@ -227,7 +227,7 @@ const ChatImageViewer = ({
</div>

{currentGroup.images.length > 1 && (
<div className="body-1-r absolute bottom-10 left-1/2 z-50 -translate-x-1/2 transform rounded-[40px] bg-[#333333] px-2.5 py-0.5 text-primary-white xl:bottom-[216px]">
<div className="z-100 body-1-r absolute bottom-10 left-1/2 -translate-x-1/2 transform rounded-[40px] bg-[#333333] px-2.5 py-0.5 text-primary-white xl:bottom-[216px]">
{currentImageIndex + 1} / {currentGroup.images.length}
</div>
)}
Expand Down
11 changes: 6 additions & 5 deletions src/components/chat/chatRoom/ChatInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const ChatInput = ({ chatId, onSendMessage, onHeightChange }: Props) => {
message,
textareaRef,
fileInputRef,
modalData,
imageUrls,
isOpen,
setMessage,
Expand Down Expand Up @@ -50,13 +51,13 @@ const ChatInput = ({ chatId, onSendMessage, onHeightChange }: Props) => {
<div className="ml-2.5 flex max-w-full flex-1 flex-col gap-2.5 overflow-x-hidden rounded-3xl bg-gray-100 px-4 py-2">
{imageUrls.length > 0 && (
<div className="flex gap-4 overflow-x-auto custom-scrollbar">
{imageUrls.map((file, index) => (
{imageUrls.map(({ file, url }, index) => (
<div
key={URL.createObjectURL(file)}
key={url}
className="relative mt-[6px] h-[56px] w-[56px] flex-shrink-0"
>
<Image
src={URL.createObjectURL(file)}
src={url}
alt={`업로드된 이미지 미리보기 ${index + 1}`}
fill
className="rounded object-cover"
Expand Down Expand Up @@ -113,9 +114,9 @@ const ChatInput = ({ chatId, onSendMessage, onHeightChange }: Props) => {
</div>
</div>
<div className="text-center">
<h2 className="title-5-b mb-2">이미지 최대 등록 갯수 초과</h2>
<h2 className="title-5-b mb-2">{modalData.title}</h2>
<p className="body-2-r text-label-neutral">
이미지는 최대 9장 등록 가능합니다.
{modalData.description}
</p>
</div>
<div className="mt-9 flex justify-center">
Expand Down
5 changes: 3 additions & 2 deletions src/components/chat/chatRoom/ChatMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ const ChatMessage = ({
isLastInGroup ? 'bottom-[14px]' : 'bottom-0'
} text-label-neutral ${isMine ? 'right-0' : 'left-0'}`}
>
{message.unreadCount}
{/* {message.unreadCount} */}
</div>
{isLastInGroup && (
<div className="caption-1-r whitespace-nowrap text-label-alternative">
Expand Down Expand Up @@ -196,7 +196,7 @@ const ChatMessage = ({
isLastInGroup ? 'bottom-[14px]' : 'bottom-0'
} text-label-neutral ${isMine ? 'right-0' : 'left-0'}`}
>
{message.unreadCount}
{/* {message.unreadCount} */}
</div>
{isLastInGroup && (
<div className="caption-1-r whitespace-nowrap text-label-alternative">
Expand All @@ -214,3 +214,4 @@ const ChatMessage = ({
};

export default ChatMessage;
// 언리드 주석
33 changes: 19 additions & 14 deletions src/components/chat/chatRoom/ChatRoom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useChatOverview } from '@/hooks/useChatOverview';
import { useInView } from 'react-intersection-observer';
import useGetUser from '@/queries/user/useGetUser';
import ChatRoomSkeleton from '@/components/chat/skeleton/ChatRoomSkeleton';
import { useWebSocketStore } from '@/store/useWebSocketStore';

interface Props {
chatId: string;
Expand All @@ -26,8 +27,20 @@ const ChatRoom = ({ chatId, onCloseChatRoom }: Props) => {
const messagesContainerRef = useRef<HTMLUListElement | null>(null);
const previousScrollTopRef = useRef<number | null>(null);

const { data: user } = useGetUser();
const nickname = user?.nickname;
const { data } = useGetUser();
const nickname = data?.nickname;

const { chatUpdates } = useWebSocketStore();

const {
chatInfo,
isFetchingNextPage,
hasNextPage,
error,
isFetchingPreviousRef,
fetchNextPage,
handleSendMessage,
} = useChat(chatId);

const {
chatOverview,
Expand All @@ -45,17 +58,7 @@ const ChatRoom = ({ chatId, onCloseChatRoom }: Props) => {
handleCloseViewer,
setCurrentImageIndex,
setCurrentGroup,
} = useChatOverview(chatId);

const {
chatInfo,
isFetchingNextPage,
hasNextPage,
error,
isFetchingPreviousRef,
fetchNextPage,
handleSendMessage,
} = useChat(chatId, nickname as string, 5);
} = useChatOverview(chatId, chatInfo);

useEffect(() => {
if (inView && hasNextPage && !isFetchingNextPage) {
Expand Down Expand Up @@ -96,7 +99,9 @@ const ChatRoom = ({ chatId, onCloseChatRoom }: Props) => {
<div className="flex items-center justify-center gap-1 truncate">
<span className="truncate">{chatInfo?.chatTitle}</span>
<span className="title-5-sb text-primary-normal">
{chatOverview?.participants?.length}
{chatUpdates && chatUpdates[chatId]
? chatUpdates[chatId].currentMemberCount
: chatOverview?.participants?.length}
</span>
</div>
}
Expand Down
9 changes: 7 additions & 2 deletions src/components/chat/chatRoom/ChatRoomEntrance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { RoomResponse } from '@/@types/chat';
import { Button } from '@/components/common/button/Button';
import { useSetIsJoined } from '@/queries/chat/useSetChat';
import UserIcon from '@/components/common/user/UserIcon';
import { useWebSocketStore } from '@/store/useWebSocketStore';

interface Props {
chatId: string;
Expand All @@ -13,6 +14,7 @@ interface Props {

const ChatRoomEntrance = ({ chatId, chatRoomData, onCloseChatRoom }: Props) => {
const { mutate } = useSetIsJoined();
const { chatUpdates } = useWebSocketStore();

const handleJoinChat = () => {
mutate({ chatId });
Expand All @@ -32,7 +34,7 @@ const ChatRoomEntrance = ({ chatId, chatRoomData, onCloseChatRoom }: Props) => {
<>
<Header onRoute={onCloseChatRoom} title="채팅" isChatHeader />

<div className="mb-[120px] mt-[100px] flex h-full flex-1 flex-col items-center text-center xl:mt-[calc(60px+18%)]">
<div className="mb-[120px] mt-[100px] flex h-full flex-1 flex-col items-center text-center xl:mt-[12%]">
<div className="relative mb-6 h-[100px] w-[100px] overflow-hidden rounded-full">
<Image
src={image}
Expand All @@ -54,7 +56,10 @@ const ChatRoomEntrance = ({ chatId, chatRoomData, onCloseChatRoom }: Props) => {
{host}
</span>
<span className="body-2-m text-label-alternative">
{membersCount}/{totalMembersCount}명
{chatUpdates && chatUpdates[chatId]
? chatUpdates[chatId].currentMemberCount
: membersCount}
/{totalMembersCount}명
</span>
</div>
<Button
Expand Down
Loading
Loading