Skip to content

Commit 39f6f3d

Browse files
committed
Merge branch 'develop'
2 parents ff195df + 45dc5eb commit 39f6f3d

51 files changed

Lines changed: 1964 additions & 906 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/App.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ const StudentIdStep = lazy(() => import('./pages/Auth/SignUp/StudentIdStep'));
1717
const TermStep = lazy(() => import('./pages/Auth/SignUp/TermStep'));
1818
const UniversityStep = lazy(() => import('./pages/Auth/SignUp/UniversityStep'));
1919
const ChatListPage = lazy(() => import('./pages/Chat'));
20+
const ChatSearch = lazy(() => import('./pages/Chat/ChatSearch'));
21+
const ChatAdd = lazy(() => import('./pages/Chat/AddChatRoom'));
2022
const ChatRoom = lazy(() => import('./pages/Chat/ChatRoom'));
23+
const ChatRoomInfo = lazy(() => import('./pages/Chat/ChatRoomInfo'));
2124
const ApplicationPage = lazy(() => import('./pages/Club/Application'));
2225
const ApplyCompletePage = lazy(() => import('./pages/Club/Application/applyCompletePage'));
2326
const ClubFeePage = lazy(() => import('./pages/Club/Application/clubFeePage'));
@@ -36,7 +39,6 @@ const ManagedApplicationDetail = lazy(() => import('./pages/Manager/ManagedAppli
3639
const ManagedApplicationList = lazy(() => import('./pages/Manager/ManagedApplicationList'));
3740
const ManagedClubDetail = lazy(() => import('./pages/Manager/ManagedClubDetail'));
3841
const ManagedClubInfo = lazy(() => import('./pages/Manager/ManagedClubProfile'));
39-
const ManagedClubList = lazy(() => import('./pages/Manager/ManagedClubList'));
4042
const ManagedMemberApplicationDetail = lazy(() => import('./pages/Manager/ManagedMemberApplicationDetail'));
4143
const ManagedMemberList = lazy(() => import('./pages/Manager/ManagedMemberList'));
4244
const ManagedRecruitment = lazy(() => import('./pages/Manager/ManagedRecruitment'));
@@ -87,14 +89,15 @@ function App() {
8789
<Route element={<Layout showBottomNav />}>
8890
<Route path="home" element={<Home />} />
8991
<Route path="notifications" element={<NotificationsPage />} />
92+
<Route path="chats/search" element={<ChatSearch />} />
93+
<Route path="chats/add" element={<ChatAdd />} />
9094
<Route path="council">
9195
<Route index element={<CouncilDetail />} />
9296
<Route path="notice/:noticeId" element={<CouncilNotice />} />
9397
</Route>
9498
<Route path="mypage">
9599
<Route index element={<MyPage />} />
96100
<Route path="manager">
97-
<Route index element={<ManagedClubList />} />
98101
<Route path=":clubId" element={<ManagedClubDetail />} />
99102
<Route path=":clubId/members" element={<ManagedMemberList />} />
100103
<Route path=":clubId/members/:userId/application" element={<ManagedMemberApplicationDetail />} />
@@ -123,6 +126,7 @@ function App() {
123126
<Route path="mypage/manager/:clubId/members/sheet/preview" element={<ManagedSheetImportPreview />} />
124127
<Route path="profile" element={<Profile />} />
125128
<Route path="chats/:chatRoomId" element={<ChatRoom />} />
129+
<Route path="chats/:chatRoomId/info" element={<ChatRoomInfo />} />
126130
</Route>
127131
</Route>
128132

src/apis/chat/entity.ts

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import type { PaginationParams, PaginationResponse } from '../common/pagination';
1+
import type { PaginationParams, PaginationResponse } from '@/apis/common/pagination';
22

33
export type ChatType = 'DIRECT' | 'CLUB_GROUP' | 'GROUP' | 'INQUIRY';
4+
export type SortBy = 'CLUB' | 'NAME';
45

56
export interface Room {
67
roomId: number;
@@ -35,6 +36,7 @@ export interface SendChatMessageRequest {
3536

3637
export interface ChatMessageRequestParam extends PaginationParams {
3738
chatRoomId: number;
39+
messageId?: number;
3840
}
3941

4042
export interface ChatMessagesResponse extends PaginationResponse {
@@ -45,3 +47,70 @@ export interface ChatMessagesResponse extends PaginationResponse {
4547
export interface CreateChatRoomResponse {
4648
chatRoomId: number;
4749
}
50+
51+
export interface Messages {
52+
roomId: number;
53+
chatType: ChatType;
54+
roomName: string;
55+
roomImageUrl: string;
56+
matchedMessage: string;
57+
matchedMessageSentAt: string;
58+
matchedMessageId: number;
59+
unreadCount: number;
60+
isMuted: boolean;
61+
}
62+
63+
export interface RoomMatched extends PaginationResponse {
64+
rooms?: Room[];
65+
}
66+
67+
export interface MessageMatched extends PaginationResponse {
68+
messages?: Messages[];
69+
}
70+
71+
export interface MatchedRequestParams extends PaginationParams {
72+
keyword: string;
73+
}
74+
75+
export interface MatchResponse {
76+
roomMatches?: RoomMatched;
77+
messageMatches?: MessageMatched;
78+
}
79+
80+
export interface InvitableUser {
81+
userId: number;
82+
name: string;
83+
imageUrl: string;
84+
studentNumber: string;
85+
}
86+
87+
export interface InvitableSection {
88+
clubId: number;
89+
clubName: string;
90+
users: InvitableUser[];
91+
}
92+
93+
export interface InvitableFriendsRequestParams extends PaginationParams {
94+
query: string;
95+
sortBy: SortBy;
96+
}
97+
98+
interface InvitableFriendsBase extends PaginationResponse {
99+
sortBy: SortBy;
100+
}
101+
102+
export interface GroupedInvitableFriendsResponse extends InvitableFriendsBase {
103+
sortBy: 'CLUB';
104+
grouped: true;
105+
users: [];
106+
sections: InvitableSection[];
107+
}
108+
109+
export interface FlatInvitableFriendsResponse extends InvitableFriendsBase {
110+
sortBy: 'NAME';
111+
grouped: false;
112+
users: InvitableUser[];
113+
sections: [];
114+
}
115+
116+
export type InvitableFriendsResponse = GroupedInvitableFriendsResponse | FlatInvitableFriendsResponse;

src/apis/chat/index.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ import type {
66
ChatRoomsResponse,
77
CreateChatRoomResponse,
88
SendChatMessageRequest,
9+
InvitableFriendsRequestParams,
10+
InvitableFriendsResponse,
11+
MatchResponse,
12+
MatchedRequestParams,
913
} from './entity';
1014

1115
export const getChatRooms = async () => {
@@ -23,6 +27,14 @@ export const postChatRooms = async (userId: number) => {
2327
return response;
2428
};
2529

30+
export const postChatRoomsGroup = async (userIds: number[]) => {
31+
const response = await apiClient.post<CreateChatRoomResponse>('chats/rooms/group', {
32+
body: { userIds },
33+
requiresAuth: true,
34+
});
35+
return response;
36+
};
37+
2638
export const postChatMessage = async ({ chatRoomId, content }: SendChatMessageRequest) => {
2739
return apiClient.post<ChatMessage>(`chats/rooms/${chatRoomId}/messages`, {
2840
body: { content },
@@ -64,3 +76,19 @@ export const deleteChatRoom = async (chatRoomId: number) => {
6476
});
6577
return response;
6678
};
79+
80+
export const getSearchChat = async ({ ...query }: MatchedRequestParams) => {
81+
const response = await apiClient.get<MatchResponse>(`chats/rooms/search`, {
82+
params: query,
83+
requiresAuth: true,
84+
});
85+
return response;
86+
};
87+
88+
export const getInvitableFriends = async ({ ...query }: InvitableFriendsRequestParams) => {
89+
const response = await apiClient.get<InvitableFriendsResponse>('chats/rooms/invitables', {
90+
params: query,
91+
requiresAuth: true,
92+
});
93+
return response;
94+
};

src/apis/chat/mutations.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { mutationOptions } from '@tanstack/react-query';
22
import {
33
patchChatRoomName,
4+
postChatRoomsGroup,
45
postAdminChatRoom,
56
postChatMessage,
67
postChatMute,
@@ -11,6 +12,7 @@ import {
1112
export const chatMutationKeys = {
1213
createRoom: () => ['chat', 'createRoom'] as const,
1314
createAdminRoom: () => ['chat', 'createAdminRoom'] as const,
15+
createRoomGroup: () => ['chat', 'createRoomGroup'] as const,
1416
sendMessage: () => ['chat', 'sendMessage'] as const,
1517
toggleMute: (chatRoomId?: number) => ['chat', 'toggleMute', chatRoomId ?? 'unknown'] as const,
1618
updateRoomName: () => ['chat', 'updateRoomName'] as const,
@@ -28,6 +30,11 @@ export const chatMutations = {
2830
mutationKey: chatMutationKeys.createAdminRoom(),
2931
mutationFn: postAdminChatRoom,
3032
}),
33+
createRoomGroup: () =>
34+
mutationOptions({
35+
mutationKey: chatMutationKeys.createRoomGroup(),
36+
mutationFn: postChatRoomsGroup,
37+
}),
3138
sendMessage: () =>
3239
mutationOptions({
3340
mutationKey: chatMutationKeys.sendMessage(),

src/apis/chat/queries.ts

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
import { infiniteQueryOptions, queryOptions } from '@tanstack/react-query';
2-
import type { ChatMessagesResponse } from './entity';
3-
import { getChatMessages, getChatRooms } from '.';
2+
import { getChatMessages, getChatRooms, getSearchChat, getInvitableFriends } from '@/apis/chat';
3+
import type { ChatMessagesResponse, SortBy } from '@/apis/chat/entity';
4+
5+
interface ChatMessagesPageParam {
6+
page: number;
7+
useMessageId: boolean;
8+
}
49

510
export const chatQueryKeys = {
611
all: ['chat'] as const,
712
rooms: () => [...chatQueryKeys.all, 'rooms'] as const,
8-
messages: (chatRoomId: number) => [...chatQueryKeys.all, 'messages', chatRoomId] as const,
13+
messagesByRoom: (chatRoomId: number) => [...chatQueryKeys.all, 'messages', chatRoomId] as const,
14+
messages: (chatRoomId: number, messageId?: number) =>
15+
[...chatQueryKeys.messagesByRoom(chatRoomId), messageId ?? 'latest'] as const,
916
disabledMessages: () => [...chatQueryKeys.all, 'messages', 'disabled'] as const,
17+
search: (keyword: string) => [...chatQueryKeys.all, 'search', keyword],
18+
invite: (query: string, sortBy: SortBy) => [...chatQueryKeys.all, 'invite', query, sortBy],
1019
};
1120

1221
export const chatQueries = {
@@ -15,18 +24,35 @@ export const chatQueries = {
1524
queryKey: chatQueryKeys.rooms(),
1625
queryFn: getChatRooms,
1726
}),
18-
messages: (chatRoomId?: number, limit = 20) =>
27+
messages: (chatRoomId?: number, messageId?: number, limit = 20) =>
1928
infiniteQueryOptions({
20-
queryKey: chatRoomId ? chatQueryKeys.messages(chatRoomId) : chatQueryKeys.disabledMessages(),
29+
queryKey: chatRoomId ? chatQueryKeys.messages(chatRoomId, messageId) : chatQueryKeys.disabledMessages(),
2130
queryFn: ({ pageParam }) =>
2231
getChatMessages({
2332
chatRoomId: chatRoomId!,
24-
page: pageParam,
33+
messageId: pageParam.useMessageId ? messageId : undefined,
34+
page: pageParam.page,
2535
limit,
2636
}),
27-
initialPageParam: 1,
37+
initialPageParam: { page: 1, useMessageId: Boolean(messageId) } satisfies ChatMessagesPageParam,
2838
getNextPageParam: (lastPage: ChatMessagesResponse) =>
29-
lastPage.currentPage < lastPage.totalPage ? lastPage.currentPage + 1 : undefined,
39+
lastPage.currentPage < lastPage.totalPage
40+
? ({ page: lastPage.currentPage + 1, useMessageId: false } satisfies ChatMessagesPageParam)
41+
: undefined,
42+
getPreviousPageParam: (firstPage: ChatMessagesResponse) =>
43+
firstPage.currentPage > 1
44+
? ({ page: firstPage.currentPage - 1, useMessageId: false } satisfies ChatMessagesPageParam)
45+
: undefined,
3046
enabled: Boolean(chatRoomId),
3147
}),
48+
search: (keyword: string) =>
49+
queryOptions({
50+
queryKey: chatQueryKeys.search(keyword),
51+
queryFn: () => getSearchChat({ keyword, page: 1, limit: 20 }),
52+
}),
53+
invite: (query: string, sortBy: SortBy) =>
54+
queryOptions({
55+
queryKey: chatQueryKeys.invite(query, sortBy),
56+
queryFn: () => getInvitableFriends({ query, sortBy, page: 1, limit: 20 }),
57+
}),
3258
};

src/apis/upload/mutations.ts

Lines changed: 0 additions & 15 deletions
This file was deleted.

src/assets/svg/check_color.svg

Lines changed: 3 additions & 0 deletions
Loading

src/components/common/Card.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import type { HTMLAttributes, ReactNode } from 'react';
2-
import clsx from 'clsx';
3-
import { twMerge } from 'tailwind-merge';
2+
import { cn } from '@/utils/ts/cn';
43

54
interface CardProps extends HTMLAttributes<HTMLDivElement> {
65
children: ReactNode;
76
}
87

98
function Card({ children, className, ...props }: CardProps) {
10-
const base = 'border-indigo-5 flex w-full flex-col gap-3 rounded-lg border bg-white p-3';
11-
129
return (
13-
<div className={twMerge(clsx(base, className))} {...props}>
10+
<div
11+
className={cn('border-indigo-5 flex w-full flex-col gap-3 rounded-lg border bg-white p-3', className)}
12+
{...props}
13+
>
1414
{children}
1515
</div>
1616
);

src/components/common/Dropdown.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ interface DropdownProps<T extends string> extends Omit<HTMLAttributes<HTMLDivEle
1313
value: T;
1414
onChange: (value: T) => void;
1515
menuClassName?: string;
16+
triggerClassName?: string;
1617
}
1718

1819
export default function Dropdown<T extends string>({
@@ -21,6 +22,7 @@ export default function Dropdown<T extends string>({
2122
onChange,
2223
className,
2324
menuClassName,
25+
triggerClassName,
2426
...props
2527
}: DropdownProps<T>) {
2628
const [isOpen, setIsOpen] = useState(false);
@@ -29,10 +31,6 @@ export default function Dropdown<T extends string>({
2931
useClickTouchOutside(dropdownRef, () => setIsOpen(false));
3032

3133
const selectedOption = options.find((opt) => opt.value === value);
32-
const orderedOptions = [
33-
...options.filter((option) => option.value !== value),
34-
...options.filter((option) => option.value === value),
35-
];
3634

3735
const handleSelect = (optionValue: T) => {
3836
onChange(optionValue);
@@ -45,8 +43,9 @@ export default function Dropdown<T extends string>({
4543
type="button"
4644
onClick={() => setIsOpen(!isOpen)}
4745
className={cn(
48-
'inline-flex h-7.25 items-center justify-center overflow-hidden rounded-full bg-[#69BFDF] px-2.5 text-[13px] leading-[1.6] font-medium text-white transition-opacity active:opacity-90',
49-
isOpen && 'opacity-95'
46+
'bg-primary-500 inline-flex h-7.25 items-center justify-evenly overflow-hidden rounded-full px-2.5 text-[13px] leading-[1.6] font-medium text-white transition-opacity active:opacity-90',
47+
isOpen && 'opacity-95',
48+
triggerClassName
5049
)}
5150
>
5251
<span>{selectedOption?.label}</span>
@@ -64,7 +63,7 @@ export default function Dropdown<T extends string>({
6463
)}
6564
>
6665
<div className="flex min-w-14 flex-col gap-1">
67-
{orderedOptions.map((option) => (
66+
{options.map((option) => (
6867
<button
6968
key={option.value}
7069
type="button"

0 commit comments

Comments
 (0)