analytica-frontend-lib 1.2.52 → 1.2.53

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/ActivitiesHistory/index.css +33 -0
  2. package/dist/ActivitiesHistory/index.css.map +1 -1
  3. package/dist/ActivityCardQuestionBanks/index.css +33 -0
  4. package/dist/ActivityCardQuestionBanks/index.css.map +1 -1
  5. package/dist/ActivityCardQuestionPreview/index.css +33 -0
  6. package/dist/ActivityCardQuestionPreview/index.css.map +1 -1
  7. package/dist/ActivityDetails/index.css +33 -0
  8. package/dist/ActivityDetails/index.css.map +1 -1
  9. package/dist/ActivityFilters/index.css +33 -0
  10. package/dist/ActivityFilters/index.css.map +1 -1
  11. package/dist/ActivityPreview/index.css +33 -0
  12. package/dist/ActivityPreview/index.css.map +1 -1
  13. package/dist/AlertManager/index.css +33 -0
  14. package/dist/AlertManager/index.css.map +1 -1
  15. package/dist/RecommendedLessonsHistory/index.css +33 -0
  16. package/dist/RecommendedLessonsHistory/index.css.map +1 -1
  17. package/dist/SendActivityModal/SendActivityModal.css +33 -0
  18. package/dist/SendActivityModal/SendActivityModal.css.map +1 -1
  19. package/dist/SendActivityModal/index.css +33 -0
  20. package/dist/SendActivityModal/index.css.map +1 -1
  21. package/dist/TableProvider/index.css +33 -0
  22. package/dist/TableProvider/index.css.map +1 -1
  23. package/dist/hooks/useChat.d.ts +112 -0
  24. package/dist/hooks/useChat.d.ts.map +1 -0
  25. package/dist/hooks/useChatRooms.d.ts +76 -0
  26. package/dist/hooks/useChatRooms.d.ts.map +1 -0
  27. package/dist/index.css +33 -0
  28. package/dist/index.css.map +1 -1
  29. package/dist/index.d.ts +8 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +709 -0
  32. package/dist/index.js.map +1 -1
  33. package/dist/index.mjs +706 -0
  34. package/dist/index.mjs.map +1 -1
  35. package/dist/styles.css +33 -0
  36. package/dist/styles.css.map +1 -1
  37. package/dist/types/chat.d.ts +164 -0
  38. package/dist/types/chat.d.ts.map +1 -0
  39. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -54,6 +54,7 @@ __export(src_exports, {
54
54
  Badge: () => Badge_default,
55
55
  BreadcrumbMenu: () => BreadcrumbMenu,
56
56
  Button: () => Button_default,
57
+ CHAT_MESSAGE_TYPES: () => CHAT_MESSAGE_TYPES,
57
58
  CORRECTION_QUESTION_STATUS: () => QUESTION_STATUS2,
58
59
  Calendar: () => Calendar_default,
59
60
  CardAccordation: () => CardAccordation,
@@ -68,6 +69,7 @@ __export(src_exports, {
68
69
  CardStatus: () => CardStatus,
69
70
  CardTest: () => CardTest,
70
71
  CardTopic: () => CardTopic,
72
+ Chat: () => Chat,
71
73
  CheckBox: () => CheckBox_default,
72
74
  CheckboxGroup: () => CheckboxGroup,
73
75
  CheckboxList: () => CheckboxList_default,
@@ -114,6 +116,7 @@ __export(src_exports, {
114
116
  NotFound: () => NotFound_default,
115
117
  NotificationCard: () => NotificationCard_default,
116
118
  NotificationEntityType: () => NotificationEntityType,
119
+ PROFILE_ROLES: () => PROFILE_ROLES,
117
120
  ProfileMenuFooter: () => ProfileMenuFooter,
118
121
  ProfileMenuHeader: () => ProfileMenuHeader,
119
122
  ProfileMenuInfo: () => ProfileMenuInfo,
@@ -198,6 +201,7 @@ __export(src_exports, {
198
201
  Toast: () => Toast_default,
199
202
  Toaster: () => Toaster_default,
200
203
  VideoPlayer: () => VideoPlayer_default,
204
+ WS_STATES: () => WS_STATES,
201
205
  Whiteboard: () => Whiteboard_default,
202
206
  activitiesHistoryApiResponseSchema: () => activitiesHistoryApiResponseSchema,
203
207
  activityModelsApiResponseSchema: () => activityModelsApiResponseSchema,
@@ -214,6 +218,8 @@ __export(src_exports, {
214
218
  createUseActivitiesHistory: () => createUseActivitiesHistory,
215
219
  createUseActivityFiltersData: () => createUseActivityFiltersData,
216
220
  createUseActivityModels: () => createUseActivityModels,
221
+ createUseChat: () => createUseChat,
222
+ createUseChatRooms: () => createUseChatRooms,
217
223
  createUseNotificationStore: () => createUseNotificationStore,
218
224
  createUseNotifications: () => createUseNotifications,
219
225
  createUseQuestionsList: () => createUseQuestionsList,
@@ -281,6 +287,8 @@ __export(src_exports, {
281
287
  useAuthStore: () => useAuthStore,
282
288
  useBreadcrumb: () => useBreadcrumb,
283
289
  useBreadcrumbBuilder: () => useBreadcrumbBuilder,
290
+ useChat: () => useChat,
291
+ useChatRooms: () => useChatRooms,
284
292
  useInstitutionId: () => useInstitutionId,
285
293
  useMobile: () => useMobile,
286
294
  useQuestionFiltersStore: () => useQuestionFiltersStore,
@@ -25119,6 +25127,699 @@ var ActivitiesHistory = ({
25119
25127
  }
25120
25128
  );
25121
25129
  };
25130
+
25131
+ // src/hooks/useChat.ts
25132
+ var import_react86 = require("react");
25133
+ var WS_STATES = {
25134
+ CONNECTING: 0,
25135
+ OPEN: 1,
25136
+ CLOSING: 2,
25137
+ CLOSED: 3
25138
+ };
25139
+ function useChat({
25140
+ wsUrl,
25141
+ token,
25142
+ roomId,
25143
+ userId,
25144
+ onConnect,
25145
+ onDisconnect,
25146
+ onError,
25147
+ autoReconnect = true,
25148
+ reconnectInterval = 3e3,
25149
+ maxReconnectAttempts = 5
25150
+ }) {
25151
+ const [isConnected, setIsConnected] = (0, import_react86.useState)(false);
25152
+ const [messages, setMessages] = (0, import_react86.useState)([]);
25153
+ const [participants, setParticipants] = (0, import_react86.useState)([]);
25154
+ const [error, setError] = (0, import_react86.useState)(null);
25155
+ const wsRef = (0, import_react86.useRef)(null);
25156
+ const reconnectAttemptsRef = (0, import_react86.useRef)(0);
25157
+ const reconnectTimeoutRef = (0, import_react86.useRef)(
25158
+ null
25159
+ );
25160
+ const isManualDisconnectRef = (0, import_react86.useRef)(false);
25161
+ const sendWsMessage = (0, import_react86.useCallback)((message) => {
25162
+ if (wsRef.current?.readyState === WS_STATES.OPEN) {
25163
+ wsRef.current.send(JSON.stringify(message));
25164
+ }
25165
+ }, []);
25166
+ const sendMessage = (0, import_react86.useCallback)(
25167
+ (content) => {
25168
+ const trimmedContent = content.trim();
25169
+ if (!trimmedContent) return;
25170
+ sendWsMessage({
25171
+ type: "message",
25172
+ payload: { content: trimmedContent }
25173
+ });
25174
+ },
25175
+ [sendWsMessage]
25176
+ );
25177
+ const leave = (0, import_react86.useCallback)(() => {
25178
+ isManualDisconnectRef.current = true;
25179
+ sendWsMessage({ type: "leave" });
25180
+ wsRef.current?.close(1e3, "User left");
25181
+ }, [sendWsMessage]);
25182
+ const handleMessage = (0, import_react86.useCallback)(
25183
+ (event) => {
25184
+ try {
25185
+ const data = JSON.parse(event.data);
25186
+ switch (data.type) {
25187
+ case "history":
25188
+ if (data.payload.messages) {
25189
+ setMessages(data.payload.messages);
25190
+ }
25191
+ break;
25192
+ case "participants":
25193
+ if (data.payload.participants) {
25194
+ setParticipants(data.payload.participants);
25195
+ }
25196
+ break;
25197
+ case "new_message":
25198
+ if (data.payload.message) {
25199
+ setMessages((prev) => [...prev, data.payload.message]);
25200
+ }
25201
+ break;
25202
+ case "user_joined":
25203
+ if (data.payload.user) {
25204
+ const user = data.payload.user;
25205
+ setParticipants((prev) => {
25206
+ const exists = prev.some(
25207
+ (p) => p.userInstitutionId === user.userInstitutionId
25208
+ );
25209
+ if (exists) {
25210
+ return prev.map(
25211
+ (p) => p.userInstitutionId === user.userInstitutionId ? { ...p, isOnline: true } : p
25212
+ );
25213
+ }
25214
+ return [
25215
+ ...prev,
25216
+ {
25217
+ userInstitutionId: user.userInstitutionId,
25218
+ name: user.name,
25219
+ photo: user.photo,
25220
+ role: user.role,
25221
+ isOnline: true
25222
+ }
25223
+ ];
25224
+ });
25225
+ }
25226
+ break;
25227
+ case "user_left":
25228
+ if (data.payload.user) {
25229
+ const user = data.payload.user;
25230
+ setParticipants(
25231
+ (prev) => prev.map(
25232
+ (p) => p.userInstitutionId === user.userInstitutionId ? { ...p, isOnline: false } : p
25233
+ )
25234
+ );
25235
+ }
25236
+ break;
25237
+ case "error": {
25238
+ const errorMessage = data.payload.message_text || "Erro desconhecido";
25239
+ setError(new Error(errorMessage));
25240
+ onError?.(new Error(errorMessage));
25241
+ break;
25242
+ }
25243
+ }
25244
+ } catch (err) {
25245
+ console.error("Error parsing WebSocket message:", err);
25246
+ }
25247
+ },
25248
+ [onError]
25249
+ );
25250
+ const connect = (0, import_react86.useCallback)(() => {
25251
+ const url = new URL(wsUrl);
25252
+ url.searchParams.set("roomId", roomId);
25253
+ url.searchParams.set("token", token);
25254
+ if (wsRef.current) {
25255
+ wsRef.current.close();
25256
+ }
25257
+ const ws = new WebSocket(url.toString());
25258
+ wsRef.current = ws;
25259
+ ws.onopen = () => {
25260
+ setIsConnected(true);
25261
+ setError(null);
25262
+ reconnectAttemptsRef.current = 0;
25263
+ onConnect?.();
25264
+ };
25265
+ ws.onmessage = handleMessage;
25266
+ ws.onerror = () => {
25267
+ const error2 = new Error("Erro na conex\xE3o WebSocket");
25268
+ setError(error2);
25269
+ onError?.(error2);
25270
+ };
25271
+ ws.onclose = (event) => {
25272
+ setIsConnected(false);
25273
+ onDisconnect?.();
25274
+ if (autoReconnect && !isManualDisconnectRef.current && reconnectAttemptsRef.current < maxReconnectAttempts && event.code !== 4001 && // Unauthorized
25275
+ event.code !== 4002 && // Missing roomId
25276
+ event.code !== 4003) {
25277
+ reconnectAttemptsRef.current += 1;
25278
+ reconnectTimeoutRef.current = setTimeout(() => {
25279
+ connect();
25280
+ }, reconnectInterval);
25281
+ }
25282
+ };
25283
+ }, [
25284
+ wsUrl,
25285
+ roomId,
25286
+ token,
25287
+ handleMessage,
25288
+ onConnect,
25289
+ onDisconnect,
25290
+ onError,
25291
+ autoReconnect,
25292
+ reconnectInterval,
25293
+ maxReconnectAttempts
25294
+ ]);
25295
+ const reconnect = (0, import_react86.useCallback)(() => {
25296
+ isManualDisconnectRef.current = false;
25297
+ reconnectAttemptsRef.current = 0;
25298
+ connect();
25299
+ }, [connect]);
25300
+ (0, import_react86.useEffect)(() => {
25301
+ isManualDisconnectRef.current = false;
25302
+ connect();
25303
+ return () => {
25304
+ isManualDisconnectRef.current = true;
25305
+ if (reconnectTimeoutRef.current) {
25306
+ clearTimeout(reconnectTimeoutRef.current);
25307
+ }
25308
+ wsRef.current?.close(1e3, "Component unmounted");
25309
+ };
25310
+ }, [connect]);
25311
+ return {
25312
+ isConnected,
25313
+ messages,
25314
+ participants,
25315
+ sendMessage,
25316
+ leave,
25317
+ error,
25318
+ reconnect,
25319
+ currentUserId: userId
25320
+ };
25321
+ }
25322
+ function createUseChat(baseWsUrl) {
25323
+ return (options) => useChat({ ...options, wsUrl: baseWsUrl });
25324
+ }
25325
+
25326
+ // src/hooks/useChatRooms.ts
25327
+ var import_react87 = require("react");
25328
+ function useChatRooms({
25329
+ apiClient
25330
+ }) {
25331
+ const [rooms, setRooms] = (0, import_react87.useState)([]);
25332
+ const [availableUsers, setAvailableUsers] = (0, import_react87.useState)([]);
25333
+ const [loading, setLoading] = (0, import_react87.useState)(false);
25334
+ const [error, setError] = (0, import_react87.useState)(null);
25335
+ const fetchRooms = (0, import_react87.useCallback)(async () => {
25336
+ setLoading(true);
25337
+ setError(null);
25338
+ try {
25339
+ const response = await apiClient.get("/chat/rooms");
25340
+ setRooms(response.data.rooms);
25341
+ } catch (err) {
25342
+ const error2 = err instanceof Error ? err : new Error("Erro ao carregar salas");
25343
+ setError(error2);
25344
+ console.error("Error fetching chat rooms:", err);
25345
+ } finally {
25346
+ setLoading(false);
25347
+ }
25348
+ }, [apiClient]);
25349
+ const fetchAvailableUsers = (0, import_react87.useCallback)(async () => {
25350
+ setLoading(true);
25351
+ setError(null);
25352
+ try {
25353
+ const response = await apiClient.get(
25354
+ "/chat/available-users"
25355
+ );
25356
+ setAvailableUsers(response.data.users);
25357
+ } catch (err) {
25358
+ const error2 = err instanceof Error ? err : new Error("Erro ao carregar usu\xE1rios");
25359
+ setError(error2);
25360
+ console.error("Error fetching available users:", err);
25361
+ } finally {
25362
+ setLoading(false);
25363
+ }
25364
+ }, [apiClient]);
25365
+ const createRoom = (0, import_react87.useCallback)(
25366
+ async (participantIds) => {
25367
+ setLoading(true);
25368
+ setError(null);
25369
+ try {
25370
+ const response = await apiClient.post(
25371
+ "/chat/rooms",
25372
+ {
25373
+ participantIds
25374
+ }
25375
+ );
25376
+ await fetchRooms();
25377
+ return response.data.room;
25378
+ } catch (err) {
25379
+ const error2 = err instanceof Error ? err : new Error("Erro ao criar sala");
25380
+ setError(error2);
25381
+ console.error("Error creating chat room:", err);
25382
+ return null;
25383
+ } finally {
25384
+ setLoading(false);
25385
+ }
25386
+ },
25387
+ [apiClient, fetchRooms]
25388
+ );
25389
+ const clearError = (0, import_react87.useCallback)(() => {
25390
+ setError(null);
25391
+ }, []);
25392
+ return {
25393
+ rooms,
25394
+ availableUsers,
25395
+ loading,
25396
+ error,
25397
+ fetchRooms,
25398
+ fetchAvailableUsers,
25399
+ createRoom,
25400
+ clearError
25401
+ };
25402
+ }
25403
+ function createUseChatRooms(apiClient) {
25404
+ return () => useChatRooms({ apiClient });
25405
+ }
25406
+
25407
+ // src/types/chat.ts
25408
+ var PROFILE_ROLES = /* @__PURE__ */ ((PROFILE_ROLES2) => {
25409
+ PROFILE_ROLES2["SUPER_ADMIN"] = "SUPER_ADMIN";
25410
+ PROFILE_ROLES2["GENERAL_MANAGER"] = "GENERAL_MANAGER";
25411
+ PROFILE_ROLES2["REGIONAL_MANAGER"] = "REGIONAL_MANAGER";
25412
+ PROFILE_ROLES2["UNIT_MANAGER"] = "UNIT_MANAGER";
25413
+ PROFILE_ROLES2["TEACHER"] = "TEACHER";
25414
+ PROFILE_ROLES2["STUDENT"] = "STUDENT";
25415
+ return PROFILE_ROLES2;
25416
+ })(PROFILE_ROLES || {});
25417
+ var CHAT_MESSAGE_TYPES = {
25418
+ TEXT: "text",
25419
+ SYSTEM: "system"
25420
+ };
25421
+
25422
+ // src/components/Chat/Chat.tsx
25423
+ var import_react88 = require("react");
25424
+ var import_react89 = require("@phosphor-icons/react");
25425
+ var import_jsx_runtime104 = require("react/jsx-runtime");
25426
+ var RoomItem = ({
25427
+ room,
25428
+ onClick,
25429
+ isActive
25430
+ }) => /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(
25431
+ Button_default,
25432
+ {
25433
+ variant: "link",
25434
+ onClick,
25435
+ className: cn(
25436
+ "w-full p-3 rounded-lg text-left transition-colors justify-start h-auto",
25437
+ "hover:bg-background-100",
25438
+ isActive && "bg-primary-50 border-l-4 border-primary-500"
25439
+ ),
25440
+ children: /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "flex items-start gap-3 w-full", children: [
25441
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("div", { className: "w-10 h-10 rounded-full bg-primary-100 flex items-center justify-center flex-shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(import_react89.UsersIcon, { size: 20, className: "text-primary-600" }) }),
25442
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "flex-1 min-w-0", children: [
25443
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Text_default, { size: "sm", weight: "semibold", className: "text-text-900 truncate", children: room.name }),
25444
+ room.lastMessage && /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)(Text_default, { size: "xs", className: "text-text-500 truncate mt-1", children: [
25445
+ room.lastMessage.senderName,
25446
+ ": ",
25447
+ room.lastMessage.content
25448
+ ] }),
25449
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)(Text_default, { size: "xs", className: "text-text-400 mt-1", children: [
25450
+ room.participantCount,
25451
+ " participantes"
25452
+ ] })
25453
+ ] })
25454
+ ] })
25455
+ }
25456
+ );
25457
+ var MessageBubble = ({
25458
+ message,
25459
+ isOwn
25460
+ }) => /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: cn("flex gap-2 mb-3", isOwn && "flex-row-reverse"), children: [
25461
+ !isOwn && /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("div", { className: "w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center flex-shrink-0", children: message.senderPhoto ? /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(
25462
+ "img",
25463
+ {
25464
+ src: message.senderPhoto,
25465
+ alt: message.senderName,
25466
+ className: "w-8 h-8 rounded-full object-cover"
25467
+ }
25468
+ ) : /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Text_default, { size: "xs", weight: "bold", className: "text-gray-600", children: message.senderName.charAt(0).toUpperCase() }) }),
25469
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: cn("max-w-[70%]", isOwn && "items-end"), children: [
25470
+ !isOwn && /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Text_default, { size: "xs", className: "text-text-500 mb-1", children: message.senderName }),
25471
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(
25472
+ "div",
25473
+ {
25474
+ className: cn(
25475
+ "px-4 py-2 rounded-2xl",
25476
+ isOwn ? "bg-primary-500 text-white rounded-br-md" : "bg-background-100 text-text-900 rounded-bl-md"
25477
+ ),
25478
+ children: /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Text_default, { size: "sm", children: message.content })
25479
+ }
25480
+ ),
25481
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(
25482
+ Text_default,
25483
+ {
25484
+ size: "xs",
25485
+ className: cn("text-text-400 mt-1", isOwn && "text-right"),
25486
+ children: new Date(message.createdAt).toLocaleTimeString("pt-BR", {
25487
+ hour: "2-digit",
25488
+ minute: "2-digit"
25489
+ })
25490
+ }
25491
+ )
25492
+ ] })
25493
+ ] });
25494
+ var ParticipantItem = ({ participant }) => /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "flex items-center gap-2 py-2", children: [
25495
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "relative", children: [
25496
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("div", { className: "w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center", children: participant.photo ? /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(
25497
+ "img",
25498
+ {
25499
+ src: participant.photo,
25500
+ alt: participant.name,
25501
+ className: "w-8 h-8 rounded-full object-cover"
25502
+ }
25503
+ ) : /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Text_default, { size: "xs", weight: "bold", className: "text-gray-600", children: participant.name.charAt(0).toUpperCase() }) }),
25504
+ participant.isOnline && /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("div", { className: "absolute bottom-0 right-0 w-3 h-3 bg-green-500 rounded-full border-2 border-white" })
25505
+ ] }),
25506
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "flex-1 min-w-0", children: [
25507
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Text_default, { size: "sm", className: "text-text-900 truncate", children: participant.name }),
25508
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Text_default, { size: "xs", className: "text-text-500", children: participant.role })
25509
+ ] })
25510
+ ] });
25511
+ var UserSelector = ({
25512
+ users,
25513
+ selectedIds,
25514
+ onToggle
25515
+ }) => /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("div", { className: "space-y-2 max-h-64 overflow-y-auto", children: users.map((user) => /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)(
25516
+ Button_default,
25517
+ {
25518
+ variant: "link",
25519
+ onClick: () => onToggle(user.userInstitutionId),
25520
+ className: cn(
25521
+ "w-full flex items-center gap-3 p-3 rounded-lg transition-colors justify-start h-auto",
25522
+ selectedIds.has(user.userInstitutionId) ? "bg-primary-50 border border-primary-500" : "bg-background-50 hover:bg-background-100 border border-transparent"
25523
+ ),
25524
+ children: [
25525
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("div", { className: "w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center", children: user.photo ? /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(
25526
+ "img",
25527
+ {
25528
+ src: user.photo,
25529
+ alt: user.name,
25530
+ className: "w-10 h-10 rounded-full object-cover"
25531
+ }
25532
+ ) : /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Text_default, { size: "sm", weight: "bold", className: "text-gray-600", children: user.name.charAt(0).toUpperCase() }) }),
25533
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "flex-1 text-left", children: [
25534
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Text_default, { size: "sm", weight: "medium", className: "text-text-900", children: user.name }),
25535
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Text_default, { size: "xs", className: "text-text-500", children: user.profileName })
25536
+ ] }),
25537
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(
25538
+ "div",
25539
+ {
25540
+ className: cn(
25541
+ "w-5 h-5 rounded-full border-2 flex items-center justify-center",
25542
+ selectedIds.has(user.userInstitutionId) ? "bg-primary-500 border-primary-500" : "border-gray-300"
25543
+ ),
25544
+ children: selectedIds.has(user.userInstitutionId) && /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("div", { className: "w-2 h-2 bg-white rounded-full" })
25545
+ }
25546
+ )
25547
+ ]
25548
+ },
25549
+ user.userInstitutionId
25550
+ )) });
25551
+ function Chat({
25552
+ apiClient,
25553
+ wsUrl,
25554
+ token,
25555
+ userId,
25556
+ userName,
25557
+ userPhoto,
25558
+ userRole,
25559
+ className
25560
+ }) {
25561
+ const [view, setView] = (0, import_react88.useState)("list");
25562
+ const [selectedRoom, setSelectedRoom] = (0, import_react88.useState)(
25563
+ null
25564
+ );
25565
+ const [selectedUserIds, setSelectedUserIds] = (0, import_react88.useState)(
25566
+ /* @__PURE__ */ new Set()
25567
+ );
25568
+ const [messageInput, setMessageInput] = (0, import_react88.useState)("");
25569
+ const [showCreateModal, setShowCreateModal] = (0, import_react88.useState)(false);
25570
+ const {
25571
+ rooms,
25572
+ availableUsers,
25573
+ loading: roomsLoading,
25574
+ error: roomsError,
25575
+ fetchRooms,
25576
+ fetchAvailableUsers,
25577
+ createRoom
25578
+ } = useChatRooms({ apiClient });
25579
+ const {
25580
+ isConnected,
25581
+ messages,
25582
+ participants,
25583
+ sendMessage,
25584
+ error: chatError
25585
+ } = useChat({
25586
+ wsUrl,
25587
+ token,
25588
+ roomId: selectedRoom?.id || "",
25589
+ userId,
25590
+ onConnect: () => console.log("Connected to chat"),
25591
+ onDisconnect: () => console.log("Disconnected from chat"),
25592
+ onError: (err) => console.error("Chat error:", err)
25593
+ });
25594
+ const getRoleLabel = () => {
25595
+ return userRole === "TEACHER" /* TEACHER */ ? "Professor" : "Aluno";
25596
+ };
25597
+ (0, import_react88.useEffect)(() => {
25598
+ fetchRooms();
25599
+ }, [fetchRooms]);
25600
+ const handleSelectRoom = (0, import_react88.useCallback)((room) => {
25601
+ setSelectedRoom(room);
25602
+ setView("room");
25603
+ }, []);
25604
+ const handleOpenCreateModal = (0, import_react88.useCallback)(async () => {
25605
+ await fetchAvailableUsers();
25606
+ setSelectedUserIds(/* @__PURE__ */ new Set());
25607
+ setShowCreateModal(true);
25608
+ }, [fetchAvailableUsers]);
25609
+ const handleToggleUser = (0, import_react88.useCallback)((id) => {
25610
+ setSelectedUserIds((prev) => {
25611
+ const next = new Set(prev);
25612
+ if (next.has(id)) {
25613
+ next.delete(id);
25614
+ } else {
25615
+ next.add(id);
25616
+ }
25617
+ return next;
25618
+ });
25619
+ }, []);
25620
+ const handleCreateRoom = (0, import_react88.useCallback)(async () => {
25621
+ if (selectedUserIds.size === 0) return;
25622
+ const room = await createRoom(Array.from(selectedUserIds));
25623
+ if (room) {
25624
+ setShowCreateModal(false);
25625
+ setSelectedUserIds(/* @__PURE__ */ new Set());
25626
+ await fetchRooms();
25627
+ }
25628
+ }, [selectedUserIds, createRoom, fetchRooms]);
25629
+ const handleSendMessage = (0, import_react88.useCallback)(() => {
25630
+ if (!messageInput.trim()) return;
25631
+ sendMessage(messageInput);
25632
+ setMessageInput("");
25633
+ }, [messageInput, sendMessage]);
25634
+ const handleBackToList = (0, import_react88.useCallback)(() => {
25635
+ setSelectedRoom(null);
25636
+ setView("list");
25637
+ }, []);
25638
+ const renderMessagesContent = () => {
25639
+ if (chatError) {
25640
+ return /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "text-center", children: [
25641
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Text_default, { size: "sm", className: "text-red-500 mb-2", children: "Erro de conexao com o chat" }),
25642
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Text_default, { size: "xs", className: "text-text-500", children: "Tentando reconectar..." })
25643
+ ] }) });
25644
+ }
25645
+ if (messages.length === 0) {
25646
+ return /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Text_default, { size: "sm", className: "text-text-500", children: "Nenhuma mensagem ainda. Comece a conversa!" }) });
25647
+ }
25648
+ return messages.map((message) => /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(
25649
+ MessageBubble,
25650
+ {
25651
+ message,
25652
+ isOwn: message.senderId === userId
25653
+ },
25654
+ message.id
25655
+ ));
25656
+ };
25657
+ const renderRoomList = () => /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "flex flex-col h-full", children: [
25658
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "p-4 border-b border-background-200 flex items-center justify-between", children: [
25659
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "flex items-center gap-3", children: [
25660
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("div", { className: "w-10 h-10 rounded-full bg-primary-100 flex items-center justify-center flex-shrink-0", children: userPhoto ? /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(
25661
+ "img",
25662
+ {
25663
+ src: userPhoto,
25664
+ alt: userName,
25665
+ className: "w-10 h-10 rounded-full object-cover"
25666
+ }
25667
+ ) : /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Text_default, { size: "sm", weight: "bold", className: "text-primary-600", children: userName.charAt(0).toUpperCase() }) }),
25668
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { children: [
25669
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Text_default, { size: "lg", weight: "bold", className: "text-text-900", children: "Conversas" }),
25670
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)(Text_default, { size: "xs", className: "text-text-500", children: [
25671
+ userName,
25672
+ " - ",
25673
+ getRoleLabel()
25674
+ ] })
25675
+ ] })
25676
+ ] }),
25677
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(
25678
+ Button_default,
25679
+ {
25680
+ variant: "solid",
25681
+ size: "small",
25682
+ onClick: handleOpenCreateModal,
25683
+ iconLeft: /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(import_react89.PlusIcon, { size: 16 }),
25684
+ children: "Nova conversa"
25685
+ }
25686
+ )
25687
+ ] }),
25688
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "flex-1 overflow-y-auto p-2", children: [
25689
+ roomsError && /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "p-4 text-center", children: [
25690
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Text_default, { size: "sm", className: "text-red-500 mb-2", children: "Erro ao carregar conversas" }),
25691
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Button_default, { variant: "outline", size: "small", onClick: fetchRooms, children: "Tentar novamente" })
25692
+ ] }),
25693
+ !roomsError && roomsLoading && /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("div", { className: "space-y-3 p-2", children: [1, 2, 3].map((i) => /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "flex items-center gap-3", children: [
25694
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(SkeletonRounded, { className: "w-10 h-10" }),
25695
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "flex-1", children: [
25696
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(SkeletonText, { className: "w-3/4 h-4 mb-2" }),
25697
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(SkeletonText, { className: "w-1/2 h-3" })
25698
+ ] })
25699
+ ] }, i)) }),
25700
+ !roomsError && !roomsLoading && rooms.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(
25701
+ EmptyState_default,
25702
+ {
25703
+ title: "Nenhuma conversa",
25704
+ description: "Comece uma nova conversa clicando no botao acima"
25705
+ }
25706
+ ),
25707
+ !roomsError && !roomsLoading && rooms.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("div", { className: "space-y-1", children: rooms.map((room) => /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(
25708
+ RoomItem,
25709
+ {
25710
+ room,
25711
+ onClick: () => handleSelectRoom(room),
25712
+ isActive: selectedRoom?.id === room.id
25713
+ },
25714
+ room.id
25715
+ )) })
25716
+ ] })
25717
+ ] });
25718
+ const renderChatRoom = () => {
25719
+ if (!selectedRoom) return null;
25720
+ return /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "flex h-full", children: [
25721
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "flex-1 flex flex-col", children: [
25722
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "p-4 border-b border-background-200 flex items-center gap-3", children: [
25723
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Button_default, { variant: "link", size: "small", onClick: handleBackToList, children: /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(import_react89.XIcon, { size: 20 }) }),
25724
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "flex-1", children: [
25725
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Text_default, { size: "md", weight: "semibold", className: "text-text-900", children: selectedRoom.name }),
25726
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Text_default, { size: "xs", className: "text-text-500", children: isConnected ? "Conectado" : "Conectando..." })
25727
+ ] })
25728
+ ] }),
25729
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("div", { className: "flex-1 overflow-y-auto p-4", children: renderMessagesContent() }),
25730
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("div", { className: "p-4 border-t border-background-200", children: /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "flex gap-2", children: [
25731
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(
25732
+ Input_default,
25733
+ {
25734
+ placeholder: "Digite sua mensagem...",
25735
+ value: messageInput,
25736
+ onChange: (e) => setMessageInput(e.target.value),
25737
+ onKeyDown: (e) => {
25738
+ if (e.key === "Enter" && !e.shiftKey) {
25739
+ e.preventDefault();
25740
+ handleSendMessage();
25741
+ }
25742
+ },
25743
+ className: "flex-1"
25744
+ }
25745
+ ),
25746
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(
25747
+ Button_default,
25748
+ {
25749
+ variant: "solid",
25750
+ onClick: handleSendMessage,
25751
+ disabled: !messageInput.trim() || !isConnected,
25752
+ children: /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(import_react89.PaperPlaneTiltIcon, { size: 20 })
25753
+ }
25754
+ )
25755
+ ] }) })
25756
+ ] }),
25757
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "w-64 border-l border-background-200 p-4 hidden lg:block", children: [
25758
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)(Text_default, { size: "sm", weight: "semibold", className: "text-text-900 mb-3", children: [
25759
+ "Participantes (",
25760
+ participants.length,
25761
+ ")"
25762
+ ] }),
25763
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("div", { className: "space-y-1", children: participants.map((participant) => /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(
25764
+ ParticipantItem,
25765
+ {
25766
+ participant
25767
+ },
25768
+ participant.userInstitutionId
25769
+ )) })
25770
+ ] })
25771
+ ] });
25772
+ };
25773
+ return /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)(
25774
+ "div",
25775
+ {
25776
+ className: cn(
25777
+ "bg-background rounded-xl border border-background-200 h-[600px]",
25778
+ className
25779
+ ),
25780
+ children: [
25781
+ view === "list" && renderRoomList(),
25782
+ view === "room" && renderChatRoom(),
25783
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(
25784
+ Modal_default,
25785
+ {
25786
+ isOpen: showCreateModal,
25787
+ onClose: () => setShowCreateModal(false),
25788
+ title: "Nova conversa",
25789
+ children: /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "p-4", children: [
25790
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Text_default, { size: "sm", className: "text-text-600 mb-4", children: "Selecione os participantes para iniciar uma conversa" }),
25791
+ roomsLoading && /* @__PURE__ */ (0, import_jsx_runtime104.jsx)("div", { className: "space-y-3", children: [1, 2, 3].map((i) => /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "flex items-center gap-3", children: [
25792
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(SkeletonRounded, { className: "w-10 h-10" }),
25793
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(SkeletonText, { className: "flex-1 h-4" })
25794
+ ] }, i)) }),
25795
+ !roomsLoading && availableUsers.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Text_default, { size: "sm", className: "text-text-500 text-center py-4", children: "Nenhum usuario disponivel para chat" }),
25796
+ !roomsLoading && availableUsers.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(
25797
+ UserSelector,
25798
+ {
25799
+ users: availableUsers,
25800
+ selectedIds: selectedUserIds,
25801
+ onToggle: handleToggleUser
25802
+ }
25803
+ ),
25804
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsxs)("div", { className: "flex justify-end gap-2 mt-6", children: [
25805
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(Button_default, { variant: "outline", onClick: () => setShowCreateModal(false), children: "Cancelar" }),
25806
+ /* @__PURE__ */ (0, import_jsx_runtime104.jsx)(
25807
+ Button_default,
25808
+ {
25809
+ variant: "solid",
25810
+ onClick: handleCreateRoom,
25811
+ disabled: selectedUserIds.size === 0 || roomsLoading,
25812
+ children: "Criar conversa"
25813
+ }
25814
+ )
25815
+ ] })
25816
+ ] })
25817
+ }
25818
+ )
25819
+ ]
25820
+ }
25821
+ );
25822
+ }
25122
25823
  // Annotate the CommonJS export names for ESM import in node:
25123
25824
  0 && (module.exports = {
25124
25825
  ACTIVITY_AVAILABILITY,
@@ -25145,6 +25846,7 @@ var ActivitiesHistory = ({
25145
25846
  Badge,
25146
25847
  BreadcrumbMenu,
25147
25848
  Button,
25849
+ CHAT_MESSAGE_TYPES,
25148
25850
  CORRECTION_QUESTION_STATUS,
25149
25851
  Calendar,
25150
25852
  CardAccordation,
@@ -25159,6 +25861,7 @@ var ActivitiesHistory = ({
25159
25861
  CardStatus,
25160
25862
  CardTest,
25161
25863
  CardTopic,
25864
+ Chat,
25162
25865
  CheckBox,
25163
25866
  CheckboxGroup,
25164
25867
  CheckboxList,
@@ -25205,6 +25908,7 @@ var ActivitiesHistory = ({
25205
25908
  NotFound,
25206
25909
  NotificationCard,
25207
25910
  NotificationEntityType,
25911
+ PROFILE_ROLES,
25208
25912
  ProfileMenuFooter,
25209
25913
  ProfileMenuHeader,
25210
25914
  ProfileMenuInfo,
@@ -25289,6 +25993,7 @@ var ActivitiesHistory = ({
25289
25993
  Toast,
25290
25994
  Toaster,
25291
25995
  VideoPlayer,
25996
+ WS_STATES,
25292
25997
  Whiteboard,
25293
25998
  activitiesHistoryApiResponseSchema,
25294
25999
  activityModelsApiResponseSchema,
@@ -25305,6 +26010,8 @@ var ActivitiesHistory = ({
25305
26010
  createUseActivitiesHistory,
25306
26011
  createUseActivityFiltersData,
25307
26012
  createUseActivityModels,
26013
+ createUseChat,
26014
+ createUseChatRooms,
25308
26015
  createUseNotificationStore,
25309
26016
  createUseNotifications,
25310
26017
  createUseQuestionsList,
@@ -25372,6 +26079,8 @@ var ActivitiesHistory = ({
25372
26079
  useAuthStore,
25373
26080
  useBreadcrumb,
25374
26081
  useBreadcrumbBuilder,
26082
+ useChat,
26083
+ useChatRooms,
25375
26084
  useInstitutionId,
25376
26085
  useMobile,
25377
26086
  useQuestionFiltersStore,