You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

chat-slice.js 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
  2. import roomService from "../services/roomService";
  3. import notificationService from "../services/notificationService";
  4. const initialState = {
  5. status: "idle",
  6. rooms: [],
  7. activeRoom: null,
  8. error: null,
  9. connection: null,
  10. messages: [],
  11. connections: [],
  12. notifications: [],
  13. typings: [],
  14. };
  15. export const fetchChatRoomsAsync = createAsyncThunk(
  16. "chat/fetchChatRoomsAsync",
  17. async (payload, thunkAPI) => {
  18. try {
  19. return await roomService.getRooms(payload);
  20. } catch (error) {
  21. return thunkAPI.rejectWithValue({ error });
  22. }
  23. }
  24. );
  25. export const fetchSupportRoomsAsync = createAsyncThunk(
  26. "chat/fetchSupportRooms",
  27. async (payload, thunkAPI) => {
  28. try {
  29. return await roomService.getSupportRooms(payload);
  30. } catch (error) {
  31. return thunkAPI.rejectWithValue({ error });
  32. }
  33. }
  34. );
  35. export const createChatRoomAsync = createAsyncThunk(
  36. "chat/createChatRoomAsync",
  37. async (payload, thunkAPI) => {
  38. try {
  39. return await roomService.createRoom(payload);
  40. } catch (error) {
  41. return thunkAPI.rejectWithValue({ error });
  42. }
  43. }
  44. );
  45. export const loadNotifications = createAsyncThunk(
  46. "chat/loadNotifications",
  47. async (payload, thunkAPI) => {
  48. try {
  49. return await notificationService.loadNotifications(payload);
  50. } catch (error) {
  51. return thunkAPI.rejectWithValue({ error });
  52. }
  53. }
  54. );
  55. export const readNotificationsAsync = createAsyncThunk(
  56. "chat/deleteNotificationsAsync",
  57. async (payload, thunkAPI) => {
  58. try {
  59. return await notificationService.readNotifications(payload);
  60. } catch (error) {
  61. return thunkAPI.rejectWithValue({ error });
  62. }
  63. }
  64. );
  65. const chatSlice = createSlice({
  66. name: "chat",
  67. initialState,
  68. reducers: {
  69. setAllChats: (state, action) => {
  70. state.rooms = action.payload;
  71. },
  72. setRoom: (state, action) => {
  73. state.activeRoom = action.payload;
  74. },
  75. deleteActiveRoom: (state, action) => {
  76. state.activeRoom = null;
  77. },
  78. // Set hub connection
  79. setConnection: (state, action) => {
  80. state.connection = action.payload;
  81. },
  82. // New message sent from user
  83. newMessage: (state, action) => {
  84. if (action.payload.changedRoom) {
  85. state.messages = [];
  86. } else {
  87. state.messages = [...state.messages, action.payload];
  88. }
  89. },
  90. saveContextId: (state, action) => {
  91. // Check is empty array
  92. // If array is not empty, check is connection for specific room and specific user already added
  93. if (state.connections.length > 0) {
  94. if (
  95. !state.connections.some(
  96. (e) => e.connId === action.payload && e.roomId === state.activeRoom
  97. )
  98. ) {
  99. state.connections.push({
  100. connId: action.payload.connId,
  101. roomId: state.activeRoom.id,
  102. userId: action.payload.userId,
  103. });
  104. }
  105. } else {
  106. // If array is empty, add connection
  107. state.connections.push({
  108. connId: action.payload.connId,
  109. roomId: state.activeRoom.id,
  110. userId: action.payload.userId,
  111. });
  112. }
  113. },
  114. // Set messages fetched from backend for specific room
  115. setMessages: (state, action) => {
  116. state.messages = action.payload;
  117. },
  118. addNotification: (state, action) => {
  119. if (state.notifications.length !== 0) {
  120. const room = state.notifications.find(
  121. (notification) => notification.roomId === action.payload
  122. );
  123. if (room) {
  124. room.notificationCount++;
  125. } else {
  126. state.notifications.push({
  127. roomId: action.payload,
  128. notificationCount: 1,
  129. });
  130. }
  131. } else {
  132. state.notifications.push({
  133. roomId: action.payload,
  134. notificationCount: 1,
  135. });
  136. }
  137. },
  138. readNotifications: (state, action) => {
  139. state.notifications = state.notifications.filter(
  140. (notification) => notification.roomId !== action.payload
  141. );
  142. },
  143. leaveRoom: (state, action) => {
  144. state.activeRoom = null;
  145. const room = state.rooms.find(
  146. (room) => room.id === action.payload.roomId
  147. );
  148. room.customers = room.customers.filter(
  149. (customer) => customer.customerId !== action.payload.customerId
  150. );
  151. },
  152. addTyping: (state, action) => {
  153. if (
  154. !state.typings.some(
  155. (n) =>
  156. n.message === action.payload.message &&
  157. n.roomId === action.payload.roomId
  158. )
  159. )
  160. state.typings = [...state.typings, action.payload];
  161. else console.log("ima vec");
  162. },
  163. removeTyping: (state, action) => {
  164. if (state.typings.length >= 1) {
  165. let f = state.typings[0];
  166. state.typings = state.typings.filter((n) => n.message !== f.message);
  167. }
  168. },
  169. },
  170. extraReducers: (builder) => {
  171. // Fetch chat rooms
  172. builder.addCase(fetchChatRoomsAsync.pending, (state) => {
  173. state.status = "pendingFetchRooms";
  174. state.error = null;
  175. });
  176. builder.addCase(fetchChatRoomsAsync.fulfilled, (state, action) => {
  177. state.rooms = action.payload;
  178. state.status = "idle";
  179. state.error = null;
  180. });
  181. builder.addCase(fetchChatRoomsAsync.rejected, (state, action) => {
  182. state.status = "idle";
  183. state.error = "Fetch error" + action.payload;
  184. });
  185. // fetch rooms that support created
  186. builder.addCase(fetchSupportRoomsAsync.pending, (state) => {
  187. state.status = "pendingFetchRooms";
  188. state.error = null;
  189. });
  190. builder.addCase(fetchSupportRoomsAsync.fulfilled, (state, action) => {
  191. state.rooms = action.payload;
  192. state.status = "idle";
  193. state.error = null;
  194. });
  195. builder.addCase(fetchSupportRoomsAsync.rejected, (state, action) => {
  196. state.status = "idle";
  197. state.error = "Fetch error" + action.payload;
  198. });
  199. // Add chat room
  200. builder.addCase(createChatRoomAsync.pending, (state) => {
  201. state.status = "pendingAddRoom";
  202. state.error = null;
  203. });
  204. builder.addCase(createChatRoomAsync.fulfilled, (state, action) => {
  205. state.status = "idle";
  206. state.rooms = [...state.rooms, action.payload];
  207. state.error = null;
  208. });
  209. builder.addCase(createChatRoomAsync.rejected, (state, action) => {
  210. state.status = "idle";
  211. state.error = action.payload;
  212. });
  213. builder.addCase(loadNotifications.pending, (state) => {
  214. state.status = "pendingLoadingNotification";
  215. state.error = null;
  216. });
  217. builder.addCase(loadNotifications.fulfilled, (state, action) => {
  218. state.status = "idle";
  219. if (action.payload.length === 0) {
  220. state.notifications = [];
  221. } else {
  222. state.notifications = action.payload.map((n) => {
  223. return { roomId: n.roomId, notificationCount: n.count };
  224. });
  225. }
  226. state.error = null;
  227. });
  228. builder.addCase(loadNotifications.rejected, (state, action) => {
  229. state.status = "idle";
  230. state.error = action.payload;
  231. });
  232. // Read notifications
  233. builder.addCase(readNotificationsAsync.pending, (state) => {
  234. state.status = "pendingReadingNotifications";
  235. state.error = null;
  236. });
  237. builder.addCase(readNotificationsAsync.fulfilled, (state) => {
  238. state.status = "idle";
  239. state.error = null;
  240. });
  241. builder.addCase(readNotificationsAsync.rejected, (state, action) => {
  242. state.status = "idle";
  243. state.error = action.payload;
  244. });
  245. },
  246. });
  247. export const chatActions = chatSlice.actions;
  248. export const chatReducers = chatSlice.reducer;