Skip to content

Commit 8422d91

Browse files
committed
Enhance chat functionality: add onClick handler to ChatItem, update ChatList to manage active chat, and implement getChatById in chatSlice for improved chat loading
1 parent 24ce777 commit 8422d91

5 files changed

Lines changed: 98 additions & 12 deletions

File tree

frontend/src/components/chats/ChatItem.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
} from "@/lib/utils";
77

88
interface ChatItemProps {
9+
id: string;
910
name: string;
1011
lastMessage: string;
1112
avatar: {
@@ -14,6 +15,7 @@ interface ChatItemProps {
1415
};
1516
timestamp: string;
1617
unread: number;
18+
onClick: (chatId: string) => void;
1719
}
1820

1921
export default function ChatRooms({
@@ -22,9 +24,16 @@ export default function ChatRooms({
2224
avatar,
2325
timestamp,
2426
unread,
27+
id,
28+
onClick,
2529
}: ChatItemProps) {
2630
return (
27-
<div className="flex items-center space-x-4 p-4 hover:bg-gray-100 dark:hover:bg-slate-800 cursor-pointer">
31+
<div
32+
className="flex items-center space-x-4 p-4 hover:bg-gray-100 dark:hover:bg-slate-800 cursor-pointer"
33+
onClick={() => {
34+
onClick(id);
35+
}}
36+
>
2837
<Avatar>
2938
{avatar.image && <AvatarImage src={avatar.image} alt={name} />}
3039
<AvatarFallback

frontend/src/components/chats/ChatList.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import { useAppSelector } from "@/statemanagement/store";
22
import ChatRooms from "./ChatItem";
33

4-
export default function ChatList() {
4+
export default function ChatList({
5+
setChatId,
6+
}: {
7+
setChatId: (chatId: string) => void;
8+
}) {
59
const chats = useAppSelector((state) => {
610
const chats = state.chats.chats;
711
return chats.map((chat) => {
@@ -20,7 +24,7 @@ export default function ChatList() {
2024
return (
2125
<div>
2226
{chats.map((chat) => (
23-
<ChatRooms key={chat.id} {...chat} />
27+
<ChatRooms key={chat.id} {...chat} onClick={setChatId} />
2428
))}
2529
</div>
2630
);

frontend/src/components/chats/ChatSidebar.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,27 @@
1+
import {
2+
getChatById,
3+
setActiveChatId,
4+
} from "@/statemanagement/chats/chatSlice";
5+
import { useAppDispatch } from "@/statemanagement/store";
6+
import { useCallback } from "react";
17
import ChatList from "./ChatList";
28

39
export default function ChatSidebar() {
10+
const dispatch = useAppDispatch();
11+
const setChatId = useCallback(
12+
(chatId: string) => {
13+
dispatch(setActiveChatId(chatId));
14+
dispatch(getChatById({ chatId }));
15+
},
16+
[dispatch]
17+
);
418
return (
519
<div className="w-full h-full md:w-1/3 lg:w-1/4 border-r border-gray-200 dark:border-slate-800 flex flex-col">
620
<div className="p-4">
721
<h1 className="text-2xl font-bold mb-4">Chats</h1>
822
</div>
923
<div className="flex-1 overflow-y-auto">
10-
<ChatList />
24+
<ChatList setChatId={setChatId} />
1125
</div>
1226
</div>
1327
);

frontend/src/statemanagement/chats/chatSlice.ts

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
1+
import { ChatMessage } from "@/types/chatmessage.type";
12
import { ChatRoom } from "@/types/chatroom.type";
23
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
34
export interface ChatState {
45
chats: ChatRoom[];
5-
chatsLoading: boolean;
6+
chatsAreLoading: boolean;
7+
chatIsLoading: boolean;
68
messageSending: boolean;
79
activeChatId?: string;
810
}
911

1012
const initialState: ChatState = {
1113
chats: [],
12-
chatsLoading: false,
14+
chatsAreLoading: false,
15+
chatIsLoading: false,
1316
messageSending: false,
1417
};
1518

16-
export const getAllChats = createAsyncThunk("chats/getAll", async () => {
19+
export const getAllChats = createAsyncThunk("chats/getAll", async (_, s) => {
1720
let token = window.sessionStorage.getItem("token");
18-
1921
const response = await fetch(
2022
"https://" + window.envUrl + "/api/v1/chats/query/chats/",
2123
{
@@ -29,9 +31,42 @@ export const getAllChats = createAsyncThunk("chats/getAll", async () => {
2931
}
3032
const data = await response.json();
3133
console.log(data);
34+
if (data.length > 0) {
35+
s.dispatch(getChatById({ chatId: data[0].id }));
36+
}
37+
3238
return data;
3339
});
3440

41+
export const getChatById = createAsyncThunk(
42+
"chats/getById",
43+
async ({ chatId }: { chatId: string }, t) => {
44+
let token = window.sessionStorage.getItem("token");
45+
46+
const activeChatId = (t.getState() as { chats: ChatState }).chats
47+
.activeChatId;
48+
if (activeChatId == chatId) {
49+
return { messages: [], chatId };
50+
}
51+
t.dispatch(setActiveChatId(chatId));
52+
53+
const response = await fetch(
54+
"https://" + window.envUrl + `/api/v1/chats/query/chats/${chatId}`,
55+
{
56+
headers: {
57+
Authorization: `Bearer ${token}`,
58+
},
59+
}
60+
);
61+
if (response.status > 299) {
62+
throw new Error("Request failed with " + response.status);
63+
}
64+
const data = await response.json();
65+
console.log(data);
66+
return { messages: data.messages, chatId };
67+
}
68+
);
69+
3570
export const addMessage = createAsyncThunk(
3671
"chats/add",
3772
async (payload: { text?: string; imageBase64?: string }) => {
@@ -68,18 +103,41 @@ export const chatSlice = createSlice({
68103
addChatSync: (state, action) => {
69104
state.chats.unshift(action.payload);
70105
},
106+
setActiveChatId: (state, action: { payload: string }) => {
107+
state.activeChatId = action.payload;
108+
},
71109
},
72110
extraReducers: (builder) => {
73111
builder.addCase(getAllChats.pending, (state) => {
74-
state.chatsLoading = true;
112+
state.chatsAreLoading = true;
75113
});
76114
builder.addCase(getAllChats.rejected, (state) => {
77-
state.chatsLoading = false;
115+
state.chatsAreLoading = false;
78116
});
79117
builder.addCase(getAllChats.fulfilled, (state, action) => {
80-
state.chatsLoading = false;
118+
state.chatsAreLoading = false;
81119
state.chats = action.payload;
82120
});
121+
builder.addCase(getChatById.pending, (state) => {
122+
state.chatIsLoading = true;
123+
});
124+
builder.addCase(getChatById.rejected, (state) => {
125+
state.chatIsLoading = false;
126+
});
127+
builder.addCase(
128+
getChatById.fulfilled,
129+
(
130+
state,
131+
action: { payload: { chatId: string; messages: ChatMessage[] } }
132+
) => {
133+
state.chatIsLoading = false;
134+
const chat = state.chats.find((x) => x.id == action.payload.chatId);
135+
if (chat != null) {
136+
const prevMessages = chat.messages ?? [];
137+
chat.messages = [...prevMessages, ...action.payload.messages];
138+
}
139+
}
140+
);
83141
builder.addCase(addMessage.pending, (state) => {
84142
state.messageSending = true;
85143
});
@@ -93,6 +151,6 @@ export const chatSlice = createSlice({
93151
},
94152
});
95153

96-
export const { addChatSync } = chatSlice.actions;
154+
export const { addChatSync, setActiveChatId } = chatSlice.actions;
97155

98156
export default chatSlice.reducer;

frontend/src/types/chatroom.type.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { ChatMessage } from "./chatmessage.type";
33
export interface ChatRoom {
44
id: string;
55
name: string;
6+
users: string[];
67
messages?: ChatMessage[];
78
isLoading?: boolean;
89
}

0 commit comments

Comments
 (0)