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.mjs CHANGED
@@ -19153,7 +19153,7 @@ import { useCallback as useCallback14, useEffect as useEffect38, useMemo as useM
19153
19153
  import { useNavigate as useNavigate2 } from "react-router-dom";
19154
19154
  function useAppContent(config) {
19155
19155
  const navigate = useNavigate2();
19156
- const { setTokens, setSessionInfo, setSelectedProfile } = useAuthStore();
19156
+ const { setTokens, setSessionInfo, setSelectedProfile, setUser } = useAuthStore();
19157
19157
  const {
19158
19158
  api,
19159
19159
  getInstitutionId,
@@ -19204,6 +19204,7 @@ function useAppContent(config) {
19204
19204
  setTokens,
19205
19205
  setSessionInfo,
19206
19206
  setSelectedProfile: handleSetSelectedProfile,
19207
+ setUser,
19207
19208
  api: apiConfig,
19208
19209
  endpoint,
19209
19210
  clearParamsFromURL: handleClearParamsFromURL,
@@ -19215,6 +19216,7 @@ function useAppContent(config) {
19215
19216
  setTokens,
19216
19217
  setSessionInfo,
19217
19218
  handleSetSelectedProfile,
19219
+ setUser,
19218
19220
  apiConfig,
19219
19221
  endpoint,
19220
19222
  handleClearParamsFromURL,
@@ -25003,6 +25005,704 @@ var ActivitiesHistory = ({
25003
25005
  }
25004
25006
  );
25005
25007
  };
25008
+
25009
+ // src/hooks/useChat.ts
25010
+ import { useState as useState50, useEffect as useEffect46, useCallback as useCallback27, useRef as useRef28 } from "react";
25011
+ var WS_STATES = {
25012
+ CONNECTING: 0,
25013
+ OPEN: 1,
25014
+ CLOSING: 2,
25015
+ CLOSED: 3
25016
+ };
25017
+ function useChat({
25018
+ wsUrl,
25019
+ token,
25020
+ roomId,
25021
+ userId,
25022
+ onConnect,
25023
+ onDisconnect,
25024
+ onError,
25025
+ autoReconnect = true,
25026
+ reconnectInterval = 3e3,
25027
+ maxReconnectAttempts = 5
25028
+ }) {
25029
+ const [isConnected, setIsConnected] = useState50(false);
25030
+ const [messages, setMessages] = useState50([]);
25031
+ const [participants, setParticipants] = useState50([]);
25032
+ const [error, setError] = useState50(null);
25033
+ const wsRef = useRef28(null);
25034
+ const reconnectAttemptsRef = useRef28(0);
25035
+ const reconnectTimeoutRef = useRef28(
25036
+ null
25037
+ );
25038
+ const isManualDisconnectRef = useRef28(false);
25039
+ const sendWsMessage = useCallback27((message) => {
25040
+ if (wsRef.current?.readyState === WS_STATES.OPEN) {
25041
+ wsRef.current.send(JSON.stringify(message));
25042
+ }
25043
+ }, []);
25044
+ const sendMessage = useCallback27(
25045
+ (content) => {
25046
+ const trimmedContent = content.trim();
25047
+ if (!trimmedContent) return;
25048
+ sendWsMessage({
25049
+ type: "message",
25050
+ payload: { content: trimmedContent }
25051
+ });
25052
+ },
25053
+ [sendWsMessage]
25054
+ );
25055
+ const leave = useCallback27(() => {
25056
+ isManualDisconnectRef.current = true;
25057
+ sendWsMessage({ type: "leave" });
25058
+ wsRef.current?.close(1e3, "User left");
25059
+ }, [sendWsMessage]);
25060
+ const handleMessage = useCallback27(
25061
+ (event) => {
25062
+ try {
25063
+ const data = JSON.parse(event.data);
25064
+ switch (data.type) {
25065
+ case "history":
25066
+ if (data.payload.messages) {
25067
+ setMessages(data.payload.messages);
25068
+ }
25069
+ break;
25070
+ case "participants":
25071
+ if (data.payload.participants) {
25072
+ setParticipants(data.payload.participants);
25073
+ }
25074
+ break;
25075
+ case "new_message":
25076
+ if (data.payload.message) {
25077
+ setMessages((prev) => [...prev, data.payload.message]);
25078
+ }
25079
+ break;
25080
+ case "user_joined":
25081
+ if (data.payload.user) {
25082
+ const user = data.payload.user;
25083
+ setParticipants((prev) => {
25084
+ const exists = prev.some(
25085
+ (p) => p.userInstitutionId === user.userInstitutionId
25086
+ );
25087
+ if (exists) {
25088
+ return prev.map(
25089
+ (p) => p.userInstitutionId === user.userInstitutionId ? { ...p, isOnline: true } : p
25090
+ );
25091
+ }
25092
+ return [
25093
+ ...prev,
25094
+ {
25095
+ userInstitutionId: user.userInstitutionId,
25096
+ name: user.name,
25097
+ photo: user.photo,
25098
+ role: user.role,
25099
+ isOnline: true
25100
+ }
25101
+ ];
25102
+ });
25103
+ }
25104
+ break;
25105
+ case "user_left":
25106
+ if (data.payload.user) {
25107
+ const user = data.payload.user;
25108
+ setParticipants(
25109
+ (prev) => prev.map(
25110
+ (p) => p.userInstitutionId === user.userInstitutionId ? { ...p, isOnline: false } : p
25111
+ )
25112
+ );
25113
+ }
25114
+ break;
25115
+ case "error": {
25116
+ const errorMessage = data.payload.message_text || "Erro desconhecido";
25117
+ setError(new Error(errorMessage));
25118
+ onError?.(new Error(errorMessage));
25119
+ break;
25120
+ }
25121
+ }
25122
+ } catch (err) {
25123
+ console.error("Error parsing WebSocket message:", err);
25124
+ }
25125
+ },
25126
+ [onError]
25127
+ );
25128
+ const connect = useCallback27(() => {
25129
+ const url = new URL(wsUrl);
25130
+ url.searchParams.set("roomId", roomId);
25131
+ url.searchParams.set("token", token);
25132
+ if (wsRef.current) {
25133
+ wsRef.current.close();
25134
+ }
25135
+ const ws = new WebSocket(url.toString());
25136
+ wsRef.current = ws;
25137
+ ws.onopen = () => {
25138
+ setIsConnected(true);
25139
+ setError(null);
25140
+ reconnectAttemptsRef.current = 0;
25141
+ onConnect?.();
25142
+ };
25143
+ ws.onmessage = handleMessage;
25144
+ ws.onerror = () => {
25145
+ const error2 = new Error("Erro na conex\xE3o WebSocket");
25146
+ setError(error2);
25147
+ onError?.(error2);
25148
+ };
25149
+ ws.onclose = (event) => {
25150
+ setIsConnected(false);
25151
+ onDisconnect?.();
25152
+ if (autoReconnect && !isManualDisconnectRef.current && reconnectAttemptsRef.current < maxReconnectAttempts && event.code !== 4001 && // Unauthorized
25153
+ event.code !== 4002 && // Missing roomId
25154
+ event.code !== 4003) {
25155
+ reconnectAttemptsRef.current += 1;
25156
+ reconnectTimeoutRef.current = setTimeout(() => {
25157
+ connect();
25158
+ }, reconnectInterval);
25159
+ }
25160
+ };
25161
+ }, [
25162
+ wsUrl,
25163
+ roomId,
25164
+ token,
25165
+ handleMessage,
25166
+ onConnect,
25167
+ onDisconnect,
25168
+ onError,
25169
+ autoReconnect,
25170
+ reconnectInterval,
25171
+ maxReconnectAttempts
25172
+ ]);
25173
+ const reconnect = useCallback27(() => {
25174
+ isManualDisconnectRef.current = false;
25175
+ reconnectAttemptsRef.current = 0;
25176
+ connect();
25177
+ }, [connect]);
25178
+ useEffect46(() => {
25179
+ isManualDisconnectRef.current = false;
25180
+ connect();
25181
+ return () => {
25182
+ isManualDisconnectRef.current = true;
25183
+ if (reconnectTimeoutRef.current) {
25184
+ clearTimeout(reconnectTimeoutRef.current);
25185
+ }
25186
+ wsRef.current?.close(1e3, "Component unmounted");
25187
+ };
25188
+ }, [connect]);
25189
+ return {
25190
+ isConnected,
25191
+ messages,
25192
+ participants,
25193
+ sendMessage,
25194
+ leave,
25195
+ error,
25196
+ reconnect,
25197
+ currentUserId: userId
25198
+ };
25199
+ }
25200
+ function createUseChat(baseWsUrl) {
25201
+ return (options) => useChat({ ...options, wsUrl: baseWsUrl });
25202
+ }
25203
+
25204
+ // src/hooks/useChatRooms.ts
25205
+ import { useState as useState51, useCallback as useCallback28 } from "react";
25206
+ function useChatRooms({
25207
+ apiClient
25208
+ }) {
25209
+ const [rooms, setRooms] = useState51([]);
25210
+ const [availableUsers, setAvailableUsers] = useState51([]);
25211
+ const [loading, setLoading] = useState51(false);
25212
+ const [error, setError] = useState51(null);
25213
+ const fetchRooms = useCallback28(async () => {
25214
+ setLoading(true);
25215
+ setError(null);
25216
+ try {
25217
+ const response = await apiClient.get("/chat/rooms");
25218
+ setRooms(response.data.rooms);
25219
+ } catch (err) {
25220
+ const error2 = err instanceof Error ? err : new Error("Erro ao carregar salas");
25221
+ setError(error2);
25222
+ console.error("Error fetching chat rooms:", err);
25223
+ } finally {
25224
+ setLoading(false);
25225
+ }
25226
+ }, [apiClient]);
25227
+ const fetchAvailableUsers = useCallback28(async () => {
25228
+ setLoading(true);
25229
+ setError(null);
25230
+ try {
25231
+ const response = await apiClient.get(
25232
+ "/chat/available-users"
25233
+ );
25234
+ setAvailableUsers(response.data.users);
25235
+ } catch (err) {
25236
+ const error2 = err instanceof Error ? err : new Error("Erro ao carregar usu\xE1rios");
25237
+ setError(error2);
25238
+ console.error("Error fetching available users:", err);
25239
+ } finally {
25240
+ setLoading(false);
25241
+ }
25242
+ }, [apiClient]);
25243
+ const createRoom = useCallback28(
25244
+ async (participantIds) => {
25245
+ setLoading(true);
25246
+ setError(null);
25247
+ try {
25248
+ const response = await apiClient.post(
25249
+ "/chat/rooms",
25250
+ {
25251
+ participantIds
25252
+ }
25253
+ );
25254
+ await fetchRooms();
25255
+ return response.data.room;
25256
+ } catch (err) {
25257
+ const error2 = err instanceof Error ? err : new Error("Erro ao criar sala");
25258
+ setError(error2);
25259
+ console.error("Error creating chat room:", err);
25260
+ return null;
25261
+ } finally {
25262
+ setLoading(false);
25263
+ }
25264
+ },
25265
+ [apiClient, fetchRooms]
25266
+ );
25267
+ const clearError = useCallback28(() => {
25268
+ setError(null);
25269
+ }, []);
25270
+ return {
25271
+ rooms,
25272
+ availableUsers,
25273
+ loading,
25274
+ error,
25275
+ fetchRooms,
25276
+ fetchAvailableUsers,
25277
+ createRoom,
25278
+ clearError
25279
+ };
25280
+ }
25281
+ function createUseChatRooms(apiClient) {
25282
+ return () => useChatRooms({ apiClient });
25283
+ }
25284
+
25285
+ // src/types/chat.ts
25286
+ var PROFILE_ROLES = /* @__PURE__ */ ((PROFILE_ROLES2) => {
25287
+ PROFILE_ROLES2["SUPER_ADMIN"] = "SUPER_ADMIN";
25288
+ PROFILE_ROLES2["GENERAL_MANAGER"] = "GENERAL_MANAGER";
25289
+ PROFILE_ROLES2["REGIONAL_MANAGER"] = "REGIONAL_MANAGER";
25290
+ PROFILE_ROLES2["UNIT_MANAGER"] = "UNIT_MANAGER";
25291
+ PROFILE_ROLES2["TEACHER"] = "TEACHER";
25292
+ PROFILE_ROLES2["STUDENT"] = "STUDENT";
25293
+ return PROFILE_ROLES2;
25294
+ })(PROFILE_ROLES || {});
25295
+ var CHAT_MESSAGE_TYPES = {
25296
+ TEXT: "text",
25297
+ SYSTEM: "system"
25298
+ };
25299
+
25300
+ // src/components/Chat/Chat.tsx
25301
+ import { useState as useState52, useEffect as useEffect47, useCallback as useCallback29 } from "react";
25302
+ import {
25303
+ PaperPlaneTiltIcon as PaperPlaneTiltIcon2,
25304
+ XIcon,
25305
+ PlusIcon,
25306
+ UsersIcon
25307
+ } from "@phosphor-icons/react";
25308
+ import { jsx as jsx104, jsxs as jsxs83 } from "react/jsx-runtime";
25309
+ var RoomItem = ({
25310
+ room,
25311
+ onClick,
25312
+ isActive
25313
+ }) => /* @__PURE__ */ jsx104(
25314
+ Button_default,
25315
+ {
25316
+ variant: "link",
25317
+ onClick,
25318
+ className: cn(
25319
+ "w-full p-3 rounded-lg text-left transition-colors justify-start h-auto",
25320
+ "hover:bg-background-100",
25321
+ isActive && "bg-primary-50 border-l-4 border-primary-500"
25322
+ ),
25323
+ children: /* @__PURE__ */ jsxs83("div", { className: "flex items-start gap-3 w-full", children: [
25324
+ /* @__PURE__ */ jsx104("div", { className: "w-10 h-10 rounded-full bg-primary-100 flex items-center justify-center flex-shrink-0", children: /* @__PURE__ */ jsx104(UsersIcon, { size: 20, className: "text-primary-600" }) }),
25325
+ /* @__PURE__ */ jsxs83("div", { className: "flex-1 min-w-0", children: [
25326
+ /* @__PURE__ */ jsx104(Text_default, { size: "sm", weight: "semibold", className: "text-text-900 truncate", children: room.name }),
25327
+ room.lastMessage && /* @__PURE__ */ jsxs83(Text_default, { size: "xs", className: "text-text-500 truncate mt-1", children: [
25328
+ room.lastMessage.senderName,
25329
+ ": ",
25330
+ room.lastMessage.content
25331
+ ] }),
25332
+ /* @__PURE__ */ jsxs83(Text_default, { size: "xs", className: "text-text-400 mt-1", children: [
25333
+ room.participantCount,
25334
+ " participantes"
25335
+ ] })
25336
+ ] })
25337
+ ] })
25338
+ }
25339
+ );
25340
+ var MessageBubble = ({
25341
+ message,
25342
+ isOwn
25343
+ }) => /* @__PURE__ */ jsxs83("div", { className: cn("flex gap-2 mb-3", isOwn && "flex-row-reverse"), children: [
25344
+ !isOwn && /* @__PURE__ */ jsx104("div", { className: "w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center flex-shrink-0", children: message.senderPhoto ? /* @__PURE__ */ jsx104(
25345
+ "img",
25346
+ {
25347
+ src: message.senderPhoto,
25348
+ alt: message.senderName,
25349
+ className: "w-8 h-8 rounded-full object-cover"
25350
+ }
25351
+ ) : /* @__PURE__ */ jsx104(Text_default, { size: "xs", weight: "bold", className: "text-gray-600", children: message.senderName.charAt(0).toUpperCase() }) }),
25352
+ /* @__PURE__ */ jsxs83("div", { className: cn("max-w-[70%]", isOwn && "items-end"), children: [
25353
+ !isOwn && /* @__PURE__ */ jsx104(Text_default, { size: "xs", className: "text-text-500 mb-1", children: message.senderName }),
25354
+ /* @__PURE__ */ jsx104(
25355
+ "div",
25356
+ {
25357
+ className: cn(
25358
+ "px-4 py-2 rounded-2xl",
25359
+ isOwn ? "bg-primary-500 text-white rounded-br-md" : "bg-background-100 text-text-900 rounded-bl-md"
25360
+ ),
25361
+ children: /* @__PURE__ */ jsx104(Text_default, { size: "sm", children: message.content })
25362
+ }
25363
+ ),
25364
+ /* @__PURE__ */ jsx104(
25365
+ Text_default,
25366
+ {
25367
+ size: "xs",
25368
+ className: cn("text-text-400 mt-1", isOwn && "text-right"),
25369
+ children: new Date(message.createdAt).toLocaleTimeString("pt-BR", {
25370
+ hour: "2-digit",
25371
+ minute: "2-digit"
25372
+ })
25373
+ }
25374
+ )
25375
+ ] })
25376
+ ] });
25377
+ var ParticipantItem = ({ participant }) => /* @__PURE__ */ jsxs83("div", { className: "flex items-center gap-2 py-2", children: [
25378
+ /* @__PURE__ */ jsxs83("div", { className: "relative", children: [
25379
+ /* @__PURE__ */ jsx104("div", { className: "w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center", children: participant.photo ? /* @__PURE__ */ jsx104(
25380
+ "img",
25381
+ {
25382
+ src: participant.photo,
25383
+ alt: participant.name,
25384
+ className: "w-8 h-8 rounded-full object-cover"
25385
+ }
25386
+ ) : /* @__PURE__ */ jsx104(Text_default, { size: "xs", weight: "bold", className: "text-gray-600", children: participant.name.charAt(0).toUpperCase() }) }),
25387
+ participant.isOnline && /* @__PURE__ */ jsx104("div", { className: "absolute bottom-0 right-0 w-3 h-3 bg-green-500 rounded-full border-2 border-white" })
25388
+ ] }),
25389
+ /* @__PURE__ */ jsxs83("div", { className: "flex-1 min-w-0", children: [
25390
+ /* @__PURE__ */ jsx104(Text_default, { size: "sm", className: "text-text-900 truncate", children: participant.name }),
25391
+ /* @__PURE__ */ jsx104(Text_default, { size: "xs", className: "text-text-500", children: participant.role })
25392
+ ] })
25393
+ ] });
25394
+ var UserSelector = ({
25395
+ users,
25396
+ selectedIds,
25397
+ onToggle
25398
+ }) => /* @__PURE__ */ jsx104("div", { className: "space-y-2 max-h-64 overflow-y-auto", children: users.map((user) => /* @__PURE__ */ jsxs83(
25399
+ Button_default,
25400
+ {
25401
+ variant: "link",
25402
+ onClick: () => onToggle(user.userInstitutionId),
25403
+ className: cn(
25404
+ "w-full flex items-center gap-3 p-3 rounded-lg transition-colors justify-start h-auto",
25405
+ selectedIds.has(user.userInstitutionId) ? "bg-primary-50 border border-primary-500" : "bg-background-50 hover:bg-background-100 border border-transparent"
25406
+ ),
25407
+ children: [
25408
+ /* @__PURE__ */ jsx104("div", { className: "w-10 h-10 rounded-full bg-gray-200 flex items-center justify-center", children: user.photo ? /* @__PURE__ */ jsx104(
25409
+ "img",
25410
+ {
25411
+ src: user.photo,
25412
+ alt: user.name,
25413
+ className: "w-10 h-10 rounded-full object-cover"
25414
+ }
25415
+ ) : /* @__PURE__ */ jsx104(Text_default, { size: "sm", weight: "bold", className: "text-gray-600", children: user.name.charAt(0).toUpperCase() }) }),
25416
+ /* @__PURE__ */ jsxs83("div", { className: "flex-1 text-left", children: [
25417
+ /* @__PURE__ */ jsx104(Text_default, { size: "sm", weight: "medium", className: "text-text-900", children: user.name }),
25418
+ /* @__PURE__ */ jsx104(Text_default, { size: "xs", className: "text-text-500", children: user.profileName })
25419
+ ] }),
25420
+ /* @__PURE__ */ jsx104(
25421
+ "div",
25422
+ {
25423
+ className: cn(
25424
+ "w-5 h-5 rounded-full border-2 flex items-center justify-center",
25425
+ selectedIds.has(user.userInstitutionId) ? "bg-primary-500 border-primary-500" : "border-gray-300"
25426
+ ),
25427
+ children: selectedIds.has(user.userInstitutionId) && /* @__PURE__ */ jsx104("div", { className: "w-2 h-2 bg-white rounded-full" })
25428
+ }
25429
+ )
25430
+ ]
25431
+ },
25432
+ user.userInstitutionId
25433
+ )) });
25434
+ function Chat({
25435
+ apiClient,
25436
+ wsUrl,
25437
+ token,
25438
+ userId,
25439
+ userName,
25440
+ userPhoto,
25441
+ userRole,
25442
+ className
25443
+ }) {
25444
+ const [view, setView] = useState52("list");
25445
+ const [selectedRoom, setSelectedRoom] = useState52(
25446
+ null
25447
+ );
25448
+ const [selectedUserIds, setSelectedUserIds] = useState52(
25449
+ /* @__PURE__ */ new Set()
25450
+ );
25451
+ const [messageInput, setMessageInput] = useState52("");
25452
+ const [showCreateModal, setShowCreateModal] = useState52(false);
25453
+ const {
25454
+ rooms,
25455
+ availableUsers,
25456
+ loading: roomsLoading,
25457
+ error: roomsError,
25458
+ fetchRooms,
25459
+ fetchAvailableUsers,
25460
+ createRoom
25461
+ } = useChatRooms({ apiClient });
25462
+ const {
25463
+ isConnected,
25464
+ messages,
25465
+ participants,
25466
+ sendMessage,
25467
+ error: chatError
25468
+ } = useChat({
25469
+ wsUrl,
25470
+ token,
25471
+ roomId: selectedRoom?.id || "",
25472
+ userId,
25473
+ onConnect: () => console.log("Connected to chat"),
25474
+ onDisconnect: () => console.log("Disconnected from chat"),
25475
+ onError: (err) => console.error("Chat error:", err)
25476
+ });
25477
+ const getRoleLabel = () => {
25478
+ return userRole === "TEACHER" /* TEACHER */ ? "Professor" : "Aluno";
25479
+ };
25480
+ useEffect47(() => {
25481
+ fetchRooms();
25482
+ }, [fetchRooms]);
25483
+ const handleSelectRoom = useCallback29((room) => {
25484
+ setSelectedRoom(room);
25485
+ setView("room");
25486
+ }, []);
25487
+ const handleOpenCreateModal = useCallback29(async () => {
25488
+ await fetchAvailableUsers();
25489
+ setSelectedUserIds(/* @__PURE__ */ new Set());
25490
+ setShowCreateModal(true);
25491
+ }, [fetchAvailableUsers]);
25492
+ const handleToggleUser = useCallback29((id) => {
25493
+ setSelectedUserIds((prev) => {
25494
+ const next = new Set(prev);
25495
+ if (next.has(id)) {
25496
+ next.delete(id);
25497
+ } else {
25498
+ next.add(id);
25499
+ }
25500
+ return next;
25501
+ });
25502
+ }, []);
25503
+ const handleCreateRoom = useCallback29(async () => {
25504
+ if (selectedUserIds.size === 0) return;
25505
+ const room = await createRoom(Array.from(selectedUserIds));
25506
+ if (room) {
25507
+ setShowCreateModal(false);
25508
+ setSelectedUserIds(/* @__PURE__ */ new Set());
25509
+ await fetchRooms();
25510
+ }
25511
+ }, [selectedUserIds, createRoom, fetchRooms]);
25512
+ const handleSendMessage = useCallback29(() => {
25513
+ if (!messageInput.trim()) return;
25514
+ sendMessage(messageInput);
25515
+ setMessageInput("");
25516
+ }, [messageInput, sendMessage]);
25517
+ const handleBackToList = useCallback29(() => {
25518
+ setSelectedRoom(null);
25519
+ setView("list");
25520
+ }, []);
25521
+ const renderMessagesContent = () => {
25522
+ if (chatError) {
25523
+ return /* @__PURE__ */ jsx104("div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ jsxs83("div", { className: "text-center", children: [
25524
+ /* @__PURE__ */ jsx104(Text_default, { size: "sm", className: "text-red-500 mb-2", children: "Erro de conexao com o chat" }),
25525
+ /* @__PURE__ */ jsx104(Text_default, { size: "xs", className: "text-text-500", children: "Tentando reconectar..." })
25526
+ ] }) });
25527
+ }
25528
+ if (messages.length === 0) {
25529
+ return /* @__PURE__ */ jsx104("div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ jsx104(Text_default, { size: "sm", className: "text-text-500", children: "Nenhuma mensagem ainda. Comece a conversa!" }) });
25530
+ }
25531
+ return messages.map((message) => /* @__PURE__ */ jsx104(
25532
+ MessageBubble,
25533
+ {
25534
+ message,
25535
+ isOwn: message.senderId === userId
25536
+ },
25537
+ message.id
25538
+ ));
25539
+ };
25540
+ const renderRoomList = () => /* @__PURE__ */ jsxs83("div", { className: "flex flex-col h-full", children: [
25541
+ /* @__PURE__ */ jsxs83("div", { className: "p-4 border-b border-background-200 flex items-center justify-between", children: [
25542
+ /* @__PURE__ */ jsxs83("div", { className: "flex items-center gap-3", children: [
25543
+ /* @__PURE__ */ jsx104("div", { className: "w-10 h-10 rounded-full bg-primary-100 flex items-center justify-center flex-shrink-0", children: userPhoto ? /* @__PURE__ */ jsx104(
25544
+ "img",
25545
+ {
25546
+ src: userPhoto,
25547
+ alt: userName,
25548
+ className: "w-10 h-10 rounded-full object-cover"
25549
+ }
25550
+ ) : /* @__PURE__ */ jsx104(Text_default, { size: "sm", weight: "bold", className: "text-primary-600", children: userName.charAt(0).toUpperCase() }) }),
25551
+ /* @__PURE__ */ jsxs83("div", { children: [
25552
+ /* @__PURE__ */ jsx104(Text_default, { size: "lg", weight: "bold", className: "text-text-900", children: "Conversas" }),
25553
+ /* @__PURE__ */ jsxs83(Text_default, { size: "xs", className: "text-text-500", children: [
25554
+ userName,
25555
+ " - ",
25556
+ getRoleLabel()
25557
+ ] })
25558
+ ] })
25559
+ ] }),
25560
+ /* @__PURE__ */ jsx104(
25561
+ Button_default,
25562
+ {
25563
+ variant: "solid",
25564
+ size: "small",
25565
+ onClick: handleOpenCreateModal,
25566
+ iconLeft: /* @__PURE__ */ jsx104(PlusIcon, { size: 16 }),
25567
+ children: "Nova conversa"
25568
+ }
25569
+ )
25570
+ ] }),
25571
+ /* @__PURE__ */ jsxs83("div", { className: "flex-1 overflow-y-auto p-2", children: [
25572
+ roomsError && /* @__PURE__ */ jsxs83("div", { className: "p-4 text-center", children: [
25573
+ /* @__PURE__ */ jsx104(Text_default, { size: "sm", className: "text-red-500 mb-2", children: "Erro ao carregar conversas" }),
25574
+ /* @__PURE__ */ jsx104(Button_default, { variant: "outline", size: "small", onClick: fetchRooms, children: "Tentar novamente" })
25575
+ ] }),
25576
+ !roomsError && roomsLoading && /* @__PURE__ */ jsx104("div", { className: "space-y-3 p-2", children: [1, 2, 3].map((i) => /* @__PURE__ */ jsxs83("div", { className: "flex items-center gap-3", children: [
25577
+ /* @__PURE__ */ jsx104(SkeletonRounded, { className: "w-10 h-10" }),
25578
+ /* @__PURE__ */ jsxs83("div", { className: "flex-1", children: [
25579
+ /* @__PURE__ */ jsx104(SkeletonText, { className: "w-3/4 h-4 mb-2" }),
25580
+ /* @__PURE__ */ jsx104(SkeletonText, { className: "w-1/2 h-3" })
25581
+ ] })
25582
+ ] }, i)) }),
25583
+ !roomsError && !roomsLoading && rooms.length === 0 && /* @__PURE__ */ jsx104(
25584
+ EmptyState_default,
25585
+ {
25586
+ title: "Nenhuma conversa",
25587
+ description: "Comece uma nova conversa clicando no botao acima"
25588
+ }
25589
+ ),
25590
+ !roomsError && !roomsLoading && rooms.length > 0 && /* @__PURE__ */ jsx104("div", { className: "space-y-1", children: rooms.map((room) => /* @__PURE__ */ jsx104(
25591
+ RoomItem,
25592
+ {
25593
+ room,
25594
+ onClick: () => handleSelectRoom(room),
25595
+ isActive: selectedRoom?.id === room.id
25596
+ },
25597
+ room.id
25598
+ )) })
25599
+ ] })
25600
+ ] });
25601
+ const renderChatRoom = () => {
25602
+ if (!selectedRoom) return null;
25603
+ return /* @__PURE__ */ jsxs83("div", { className: "flex h-full", children: [
25604
+ /* @__PURE__ */ jsxs83("div", { className: "flex-1 flex flex-col", children: [
25605
+ /* @__PURE__ */ jsxs83("div", { className: "p-4 border-b border-background-200 flex items-center gap-3", children: [
25606
+ /* @__PURE__ */ jsx104(Button_default, { variant: "link", size: "small", onClick: handleBackToList, children: /* @__PURE__ */ jsx104(XIcon, { size: 20 }) }),
25607
+ /* @__PURE__ */ jsxs83("div", { className: "flex-1", children: [
25608
+ /* @__PURE__ */ jsx104(Text_default, { size: "md", weight: "semibold", className: "text-text-900", children: selectedRoom.name }),
25609
+ /* @__PURE__ */ jsx104(Text_default, { size: "xs", className: "text-text-500", children: isConnected ? "Conectado" : "Conectando..." })
25610
+ ] })
25611
+ ] }),
25612
+ /* @__PURE__ */ jsx104("div", { className: "flex-1 overflow-y-auto p-4", children: renderMessagesContent() }),
25613
+ /* @__PURE__ */ jsx104("div", { className: "p-4 border-t border-background-200", children: /* @__PURE__ */ jsxs83("div", { className: "flex gap-2", children: [
25614
+ /* @__PURE__ */ jsx104(
25615
+ Input_default,
25616
+ {
25617
+ placeholder: "Digite sua mensagem...",
25618
+ value: messageInput,
25619
+ onChange: (e) => setMessageInput(e.target.value),
25620
+ onKeyDown: (e) => {
25621
+ if (e.key === "Enter" && !e.shiftKey) {
25622
+ e.preventDefault();
25623
+ handleSendMessage();
25624
+ }
25625
+ },
25626
+ className: "flex-1"
25627
+ }
25628
+ ),
25629
+ /* @__PURE__ */ jsx104(
25630
+ Button_default,
25631
+ {
25632
+ variant: "solid",
25633
+ onClick: handleSendMessage,
25634
+ disabled: !messageInput.trim() || !isConnected,
25635
+ children: /* @__PURE__ */ jsx104(PaperPlaneTiltIcon2, { size: 20 })
25636
+ }
25637
+ )
25638
+ ] }) })
25639
+ ] }),
25640
+ /* @__PURE__ */ jsxs83("div", { className: "w-64 border-l border-background-200 p-4 hidden lg:block", children: [
25641
+ /* @__PURE__ */ jsxs83(Text_default, { size: "sm", weight: "semibold", className: "text-text-900 mb-3", children: [
25642
+ "Participantes (",
25643
+ participants.length,
25644
+ ")"
25645
+ ] }),
25646
+ /* @__PURE__ */ jsx104("div", { className: "space-y-1", children: participants.map((participant) => /* @__PURE__ */ jsx104(
25647
+ ParticipantItem,
25648
+ {
25649
+ participant
25650
+ },
25651
+ participant.userInstitutionId
25652
+ )) })
25653
+ ] })
25654
+ ] });
25655
+ };
25656
+ return /* @__PURE__ */ jsxs83(
25657
+ "div",
25658
+ {
25659
+ className: cn(
25660
+ "bg-background rounded-xl border border-background-200 h-[600px]",
25661
+ className
25662
+ ),
25663
+ children: [
25664
+ view === "list" && renderRoomList(),
25665
+ view === "room" && renderChatRoom(),
25666
+ /* @__PURE__ */ jsx104(
25667
+ Modal_default,
25668
+ {
25669
+ isOpen: showCreateModal,
25670
+ onClose: () => setShowCreateModal(false),
25671
+ title: "Nova conversa",
25672
+ children: /* @__PURE__ */ jsxs83("div", { className: "p-4", children: [
25673
+ /* @__PURE__ */ jsx104(Text_default, { size: "sm", className: "text-text-600 mb-4", children: "Selecione os participantes para iniciar uma conversa" }),
25674
+ roomsLoading && /* @__PURE__ */ jsx104("div", { className: "space-y-3", children: [1, 2, 3].map((i) => /* @__PURE__ */ jsxs83("div", { className: "flex items-center gap-3", children: [
25675
+ /* @__PURE__ */ jsx104(SkeletonRounded, { className: "w-10 h-10" }),
25676
+ /* @__PURE__ */ jsx104(SkeletonText, { className: "flex-1 h-4" })
25677
+ ] }, i)) }),
25678
+ !roomsLoading && availableUsers.length === 0 && /* @__PURE__ */ jsx104(Text_default, { size: "sm", className: "text-text-500 text-center py-4", children: "Nenhum usuario disponivel para chat" }),
25679
+ !roomsLoading && availableUsers.length > 0 && /* @__PURE__ */ jsx104(
25680
+ UserSelector,
25681
+ {
25682
+ users: availableUsers,
25683
+ selectedIds: selectedUserIds,
25684
+ onToggle: handleToggleUser
25685
+ }
25686
+ ),
25687
+ /* @__PURE__ */ jsxs83("div", { className: "flex justify-end gap-2 mt-6", children: [
25688
+ /* @__PURE__ */ jsx104(Button_default, { variant: "outline", onClick: () => setShowCreateModal(false), children: "Cancelar" }),
25689
+ /* @__PURE__ */ jsx104(
25690
+ Button_default,
25691
+ {
25692
+ variant: "solid",
25693
+ onClick: handleCreateRoom,
25694
+ disabled: selectedUserIds.size === 0 || roomsLoading,
25695
+ children: "Criar conversa"
25696
+ }
25697
+ )
25698
+ ] })
25699
+ ] })
25700
+ }
25701
+ )
25702
+ ]
25703
+ }
25704
+ );
25705
+ }
25006
25706
  export {
25007
25707
  ACTIVITY_AVAILABILITY,
25008
25708
  ACTIVITY_FILTER_STATUS_OPTIONS,
@@ -25028,6 +25728,7 @@ export {
25028
25728
  Badge_default as Badge,
25029
25729
  BreadcrumbMenu,
25030
25730
  Button_default as Button,
25731
+ CHAT_MESSAGE_TYPES,
25031
25732
  QUESTION_STATUS2 as CORRECTION_QUESTION_STATUS,
25032
25733
  Calendar_default as Calendar,
25033
25734
  CardAccordation,
@@ -25042,6 +25743,7 @@ export {
25042
25743
  CardStatus,
25043
25744
  CardTest,
25044
25745
  CardTopic,
25746
+ Chat,
25045
25747
  CheckBox_default as CheckBox,
25046
25748
  CheckboxGroup,
25047
25749
  CheckboxList_default as CheckboxList,
@@ -25088,6 +25790,7 @@ export {
25088
25790
  NotFound_default as NotFound,
25089
25791
  NotificationCard_default as NotificationCard,
25090
25792
  NotificationEntityType,
25793
+ PROFILE_ROLES,
25091
25794
  ProfileMenuFooter,
25092
25795
  ProfileMenuHeader,
25093
25796
  ProfileMenuInfo,
@@ -25172,6 +25875,7 @@ export {
25172
25875
  Toast_default as Toast,
25173
25876
  Toaster_default as Toaster,
25174
25877
  VideoPlayer_default as VideoPlayer,
25878
+ WS_STATES,
25175
25879
  Whiteboard_default as Whiteboard,
25176
25880
  activitiesHistoryApiResponseSchema,
25177
25881
  activityModelsApiResponseSchema,
@@ -25188,6 +25892,8 @@ export {
25188
25892
  createUseActivitiesHistory,
25189
25893
  createUseActivityFiltersData,
25190
25894
  createUseActivityModels,
25895
+ createUseChat,
25896
+ createUseChatRooms,
25191
25897
  createUseNotificationStore,
25192
25898
  createUseNotifications,
25193
25899
  createUseQuestionsList,
@@ -25255,6 +25961,8 @@ export {
25255
25961
  useAuthStore,
25256
25962
  useBreadcrumb,
25257
25963
  useBreadcrumbBuilder,
25964
+ useChat,
25965
+ useChatRooms,
25258
25966
  useInstitutionId,
25259
25967
  useMobile,
25260
25968
  useQuestionFiltersStore,