analytica-frontend-lib 1.2.52 → 1.2.54

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