organify-ui 0.2.0 → 0.2.2

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 (40) hide show
  1. package/dist/chat-mock-data-DST5Tn_H.d.ts +339 -0
  2. package/dist/chunk-2Y3W6JSG.js +4143 -0
  3. package/dist/chunk-2Y3W6JSG.js.map +1 -0
  4. package/dist/{chunk-7GFTSEVQ.js → chunk-5L6BWKVA.js} +2 -3
  5. package/dist/chunk-5L6BWKVA.js.map +1 -0
  6. package/dist/{chunk-YIVDY4T6.js → chunk-AHMA7OV3.js} +69 -4
  7. package/dist/chunk-AHMA7OV3.js.map +1 -0
  8. package/dist/chunk-B3N3YGMA.js +456 -0
  9. package/dist/chunk-B3N3YGMA.js.map +1 -0
  10. package/dist/chunk-DW4ZGEBH.js +930 -0
  11. package/dist/chunk-DW4ZGEBH.js.map +1 -0
  12. package/dist/{chunk-FWI3KZVO.js → chunk-FQA33MF4.js} +2 -4
  13. package/dist/chunk-FQA33MF4.js.map +1 -0
  14. package/dist/chunk-WONVWB5R.js +271 -0
  15. package/dist/chunk-WONVWB5R.js.map +1 -0
  16. package/dist/components/chat/index.d.ts +55 -0
  17. package/dist/components/chat/index.js +5 -0
  18. package/dist/components/chat/index.js.map +1 -0
  19. package/dist/components/notifications/index.d.ts +204 -0
  20. package/dist/components/notifications/index.js +5 -0
  21. package/dist/components/notifications/index.js.map +1 -0
  22. package/dist/i18n/index.js +1 -1
  23. package/dist/icons/index.d.ts +10 -1
  24. package/dist/icons/index.js +1 -1
  25. package/dist/index.d.ts +1018 -38
  26. package/dist/index.js +7858 -892
  27. package/dist/index.js.map +1 -1
  28. package/dist/providers/theme-provider.js +1 -1
  29. package/dist/tailwind-preset.d.ts +1 -2
  30. package/dist/tailwind-preset.js +102 -16
  31. package/dist/tailwind-preset.js.map +1 -1
  32. package/dist/tokens/index.d.ts +131 -69
  33. package/dist/tokens/index.js +1 -1
  34. package/package.json +25 -3
  35. package/src/globals.css +591 -257
  36. package/dist/chunk-7GFTSEVQ.js.map +0 -1
  37. package/dist/chunk-FWI3KZVO.js.map +0 -1
  38. package/dist/chunk-WPZJKIZT.js +0 -248
  39. package/dist/chunk-WPZJKIZT.js.map +0 -1
  40. package/dist/chunk-YIVDY4T6.js.map +0 -1
@@ -0,0 +1,4143 @@
1
+ import { cn, TooltipProvider, Tooltip, TooltipTrigger, TooltipContent, ScrollArea, Skeleton, Avatar, AvatarFallback, Badge, useOrganifyApi, useOrganifyUser, useOrganifyWorkspace, useOrganifyGql } from './chunk-B3N3YGMA.js';
2
+ import { OrgPlus, OrgSearch, OrgComment, OrgClose, OrgEdit, OrgTeam, OrgGlobe, OrgLock, OrgCheckCircle, OrgError, OrgWarning, OrgInfo, OrgChevronDown, OrgChevronRight, OrgDoor, OrgTrash, OrgCheck, OrgFolder, OrgChevronLeft } from './chunk-AHMA7OV3.js';
3
+ import * as React7 from 'react';
4
+ import React7__default, { useState, useCallback, useEffect } from 'react';
5
+ import { Slot } from '@radix-ui/react-slot';
6
+ import { cva } from 'class-variance-authority';
7
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
+ import { motion, AnimatePresence } from 'framer-motion';
9
+ import * as DialogPrimitive from '@radix-ui/react-dialog';
10
+ import { ChevronDown, ChevronUp, Check, XIcon } from 'lucide-react';
11
+ import { Drawer as Drawer$1 } from 'vaul';
12
+ import * as TabsPrimitive from '@radix-ui/react-tabs';
13
+ import * as SeparatorPrimitive from '@radix-ui/react-separator';
14
+ import * as SelectPrimitive from '@radix-ui/react-select';
15
+
16
+ var orgLoaderVariants = cva("relative inline-flex items-center justify-center", {
17
+ variants: {
18
+ size: {
19
+ xs: "h-4 w-4",
20
+ sm: "h-6 w-6",
21
+ default: "h-10 w-10",
22
+ lg: "h-16 w-16",
23
+ xl: "h-24 w-24",
24
+ full: "h-32 w-32"
25
+ }
26
+ },
27
+ defaultVariants: {
28
+ size: "default"
29
+ }
30
+ });
31
+ var diamondSizes = {
32
+ xs: 3,
33
+ sm: 4,
34
+ default: 6,
35
+ lg: 8,
36
+ xl: 10,
37
+ full: 14
38
+ };
39
+ var strokeWidths = {
40
+ xs: 1.5,
41
+ sm: 1.5,
42
+ default: 2,
43
+ lg: 2,
44
+ xl: 2.5,
45
+ full: 2.5
46
+ };
47
+ function OrgLoader({
48
+ size = "default",
49
+ caption,
50
+ overlay = false,
51
+ className,
52
+ ...props
53
+ }) {
54
+ const s = size ?? "default";
55
+ const d = diamondSizes[s];
56
+ const sw = strokeWidths[s];
57
+ const loader = /* @__PURE__ */ jsxs(
58
+ "div",
59
+ {
60
+ className: cn(
61
+ "flex flex-col items-center gap-3",
62
+ overlay && "pointer-events-none",
63
+ className
64
+ ),
65
+ role: "status",
66
+ "aria-label": "Loading",
67
+ ...props,
68
+ children: [
69
+ /* @__PURE__ */ jsx("div", { className: cn(orgLoaderVariants({ size })), children: /* @__PURE__ */ jsxs("svg", { className: "h-full w-full", viewBox: "0 0 48 48", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
70
+ /* @__PURE__ */ jsx(
71
+ "circle",
72
+ {
73
+ cx: "24",
74
+ cy: "24",
75
+ r: "18",
76
+ className: "stroke-current opacity-10 dark:opacity-[0.08]",
77
+ strokeWidth: sw
78
+ }
79
+ ),
80
+ /* @__PURE__ */ jsx(
81
+ "circle",
82
+ {
83
+ cx: "24",
84
+ cy: "24",
85
+ r: "18",
86
+ stroke: "url(#org-loader-gradient)",
87
+ strokeWidth: sw,
88
+ strokeLinecap: "round",
89
+ strokeDasharray: "85 28.27",
90
+ className: "origin-center",
91
+ style: { animation: "org-loader-spin 1.4s cubic-bezier(0.4, 0, 0.2, 1) infinite" }
92
+ }
93
+ ),
94
+ /* @__PURE__ */ jsx("g", { style: { animation: "org-loader-orbit 1.4s cubic-bezier(0.4, 0, 0.2, 1) infinite" }, className: "origin-center", children: /* @__PURE__ */ jsx(
95
+ "rect",
96
+ {
97
+ x: 24 - d / 2,
98
+ y: 6 - d / 2,
99
+ width: d,
100
+ height: d,
101
+ rx: d * 0.15,
102
+ transform: `rotate(45 24 6)`,
103
+ fill: "url(#org-loader-diamond)",
104
+ className: "drop-shadow-[0_0_6px_rgba(79,57,246,0.5)]"
105
+ }
106
+ ) }),
107
+ /* @__PURE__ */ jsx(
108
+ "circle",
109
+ {
110
+ cx: "24",
111
+ cy: "24",
112
+ r: "2",
113
+ className: "fill-current opacity-20",
114
+ style: { animation: "org-loader-pulse 1.4s ease-in-out infinite" }
115
+ }
116
+ ),
117
+ /* @__PURE__ */ jsxs("defs", { children: [
118
+ /* @__PURE__ */ jsxs("linearGradient", { id: "org-loader-gradient", x1: "6", y1: "6", x2: "42", y2: "42", gradientUnits: "userSpaceOnUse", children: [
119
+ /* @__PURE__ */ jsx("stop", { stopColor: "#4F39F6" }),
120
+ /* @__PURE__ */ jsx("stop", { offset: "0.5", stopColor: "#5b42f2" }),
121
+ /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#241979" })
122
+ ] }),
123
+ /* @__PURE__ */ jsxs("linearGradient", { id: "org-loader-diamond", x1: "0", y1: "0", x2: "1", y2: "1", children: [
124
+ /* @__PURE__ */ jsx("stop", { stopColor: "#4F39F6" }),
125
+ /* @__PURE__ */ jsx("stop", { offset: "1", stopColor: "#241979" })
126
+ ] })
127
+ ] })
128
+ ] }) }),
129
+ caption && /* @__PURE__ */ jsx("span", { className: cn(
130
+ "font-mono uppercase tracking-widest text-current opacity-40",
131
+ s === "xs" || s === "sm" ? "text-[8px]" : "text-[10px]"
132
+ ), children: caption })
133
+ ]
134
+ }
135
+ );
136
+ if (overlay) {
137
+ return /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40 backdrop-blur-sm dark:bg-black/60", children: loader });
138
+ }
139
+ return loader;
140
+ }
141
+ function OrgLoaderInline({ className, ...props }) {
142
+ return /* @__PURE__ */ jsxs(
143
+ "svg",
144
+ {
145
+ className: cn("h-4 w-4", className),
146
+ viewBox: "0 0 48 48",
147
+ fill: "none",
148
+ xmlns: "http://www.w3.org/2000/svg",
149
+ role: "status",
150
+ "aria-label": "Loading",
151
+ ...props,
152
+ children: [
153
+ /* @__PURE__ */ jsx("circle", { cx: "24", cy: "24", r: "18", className: "stroke-current opacity-10", strokeWidth: "2" }),
154
+ /* @__PURE__ */ jsx(
155
+ "circle",
156
+ {
157
+ cx: "24",
158
+ cy: "24",
159
+ r: "18",
160
+ stroke: "currentColor",
161
+ strokeWidth: "2",
162
+ strokeLinecap: "round",
163
+ strokeDasharray: "85 28.27",
164
+ className: "origin-center",
165
+ style: { animation: "org-loader-spin 1.4s cubic-bezier(0.4, 0, 0.2, 1) infinite" }
166
+ }
167
+ ),
168
+ /* @__PURE__ */ jsx("g", { style: { animation: "org-loader-orbit 1.4s cubic-bezier(0.4, 0, 0.2, 1) infinite" }, className: "origin-center", children: /* @__PURE__ */ jsx("rect", { x: "21", y: "3", width: "6", height: "6", rx: "1", transform: "rotate(45 24 6)", fill: "currentColor" }) })
169
+ ]
170
+ }
171
+ );
172
+ }
173
+ var buttonVariants = cva(
174
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap text-sm font-medium tracking-wide uppercase rounded-sm transition-all duration-[400ms] ease-[cubic-bezier(0.25,1,0.5,1)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-light disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
175
+ {
176
+ variants: {
177
+ variant: {
178
+ default: "bg-gradient-to-br from-primary-light to-primary !text-white hover:shadow-glow shadow-glow-primary",
179
+ secondary: "bg-transparent border border-glass-border-strong text-org-text hover:border-primary-light hover:bg-glass-highlight",
180
+ ghost: "bg-transparent text-org-text-secondary hover:bg-glass-highlight hover:text-org-text rounded-sm",
181
+ destructive: "bg-error !text-white hover:bg-error/90 shadow-glow-error",
182
+ outline: "bg-transparent border border-glass-border-strong text-org-text hover:bg-glass-highlight hover:border-primary-light",
183
+ link: "text-primary-light underline-offset-4 hover:underline rounded-none",
184
+ // ─── Cream Light theme buttons ─────────────
185
+ cream: "bg-primary text-white hover:shadow-cream-btn-primary hover:translate-y-[-1px] shadow-cream-btn",
186
+ "cream-secondary": "bg-transparent border border-primary text-primary hover:bg-primary/[0.03]"
187
+ },
188
+ size: {
189
+ default: "px-8 py-3",
190
+ sm: "px-4 py-2 text-xs",
191
+ lg: "px-10 py-4 text-base",
192
+ icon: "h-10 w-10",
193
+ "icon-sm": "h-8 w-8",
194
+ "icon-lg": "h-12 w-12"
195
+ }
196
+ },
197
+ defaultVariants: {
198
+ variant: "default",
199
+ size: "default"
200
+ }
201
+ }
202
+ );
203
+ var Button = React7.forwardRef(
204
+ ({ className, variant, size, asChild = false, loading = false, children, disabled, ...props }, ref) => {
205
+ const Comp = asChild ? Slot : "button";
206
+ return /* @__PURE__ */ jsx(
207
+ Comp,
208
+ {
209
+ className: cn(buttonVariants({ variant, size, className })),
210
+ ref,
211
+ disabled: disabled || loading,
212
+ ...props,
213
+ children: loading ? /* @__PURE__ */ jsxs(Fragment, { children: [
214
+ /* @__PURE__ */ jsx(OrgLoaderInline, { className: "shrink-0" }),
215
+ children
216
+ ] }) : children
217
+ }
218
+ );
219
+ }
220
+ );
221
+ Button.displayName = "Button";
222
+ var inputVariants = cva(
223
+ "flex w-full bg-glass-highlight backdrop-blur-md border border-glass-border rounded-sm px-4 py-3 text-sm font-light text-org-text transition-all duration-[400ms] ease-[cubic-bezier(0.25,1,0.5,1)] file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-org-text-muted focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50",
224
+ {
225
+ variants: {
226
+ variant: {
227
+ default: "focus:border-primary-light/50 focus:shadow-[0_0_0_3px_rgba(79,57,246,0.10),0_0_20px_rgba(79,57,246,0.08)]",
228
+ flat: "rounded-sm focus:border-primary-light/50 focus:shadow-[0_0_0_3px_rgba(79,57,246,0.10)]",
229
+ rounded: "rounded-sm focus:border-primary-light/50 focus:shadow-[0_0_0_3px_rgba(79,57,246,0.10)]",
230
+ error: "border-error/30 bg-error/5 text-red-100 placeholder:text-red-500/30 focus:border-error focus:shadow-[0_0_0_3px_rgba(224,17,95,0.10)]",
231
+ // ─── Cream Light theme (explicit light styling) ─────────────────────
232
+ cream: "bg-white/60 border-[rgba(36,25,121,0.06)] text-neutral-900 placeholder:text-neutral-400 focus:border-primary/40 focus:bg-white/80 focus:shadow-[0_0_0_3px_rgba(79,57,246,0.08)] backdrop-blur-sm"
233
+ }
234
+ },
235
+ defaultVariants: {
236
+ variant: "default"
237
+ }
238
+ }
239
+ );
240
+ var Input = React7.forwardRef(
241
+ ({ className, variant, type, label, error, labelPosition = "left", ...props }, ref) => {
242
+ const id = React7.useId();
243
+ const effectiveVariant = error ? "error" : variant;
244
+ return /* @__PURE__ */ jsxs("div", { className: "relative group", children: [
245
+ label && /* @__PURE__ */ jsx(
246
+ "label",
247
+ {
248
+ htmlFor: id,
249
+ className: cn(
250
+ "absolute -top-3 z-10 px-2 text-label uppercase tracking-widest",
251
+ effectiveVariant === "cream" ? "bg-cream-base" : "bg-surface",
252
+ labelPosition === "left" ? "left-0 ml-2" : "right-0 mr-2",
253
+ error ? "text-error" : "text-primary-light"
254
+ ),
255
+ children: label
256
+ }
257
+ ),
258
+ /* @__PURE__ */ jsx(
259
+ "input",
260
+ {
261
+ id,
262
+ type,
263
+ className: cn(inputVariants({ variant: effectiveVariant, className })),
264
+ ref,
265
+ "aria-invalid": !!error,
266
+ "aria-describedby": error ? `${id}-error` : void 0,
267
+ ...props
268
+ }
269
+ ),
270
+ error && /* @__PURE__ */ jsx("div", { id: `${id}-error`, className: "mt-2 flex items-center justify-end gap-2", children: /* @__PURE__ */ jsx("span", { className: "text-mono-xs text-error", children: error }) })
271
+ ] });
272
+ }
273
+ );
274
+ Input.displayName = "Input";
275
+ function getRoomIcon(room) {
276
+ if (room.type === "DIRECT") return /* @__PURE__ */ jsx(OrgComment, { className: "w-4 h-4" });
277
+ if (room.visibility === "PRIVATE") return /* @__PURE__ */ jsx(OrgLock, { className: "w-3.5 h-3.5" });
278
+ return /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "#" });
279
+ }
280
+ function ChatSidebar({
281
+ rooms,
282
+ activeRoomId,
283
+ loading,
284
+ onSelectRoom,
285
+ onCreateRoom,
286
+ onMobileClose
287
+ }) {
288
+ const [search, setSearch] = React7.useState("");
289
+ const [channelsOpen, setChannelsOpen] = React7.useState(true);
290
+ const [dmsOpen, setDmsOpen] = React7.useState(true);
291
+ const filtered = React7.useMemo(
292
+ () => search ? rooms.filter(
293
+ (r) => r.name?.toLowerCase().includes(search.toLowerCase()) || r.slug?.toLowerCase().includes(search.toLowerCase())
294
+ ) : rooms,
295
+ [rooms, search]
296
+ );
297
+ const channels = filtered.filter((r) => r.type === "CHANNEL");
298
+ const dms = filtered.filter((r) => r.type === "DIRECT");
299
+ const handleSelect = (roomId) => {
300
+ onSelectRoom(roomId);
301
+ onMobileClose?.();
302
+ };
303
+ const renderRoom = (room) => /* @__PURE__ */ jsxs(
304
+ "button",
305
+ {
306
+ onClick: () => handleSelect(room.id),
307
+ className: cn(
308
+ "flex items-center gap-2.5 w-full px-2.5 py-2 rounded-sm text-left text-sm transition-all duration-[400ms] ease-[cubic-bezier(0.25,1,0.5,1)]",
309
+ "active:scale-[0.98]",
310
+ room.id === activeRoomId ? "bg-primary/12 text-primary-light" : "text-theme-secondary hover:bg-theme-subtle hover:text-theme"
311
+ ),
312
+ children: [
313
+ /* @__PURE__ */ jsx(
314
+ "span",
315
+ {
316
+ className: cn(
317
+ "flex items-center justify-center h-7 w-7 rounded-sm text-sm shrink-0",
318
+ room.id === activeRoomId ? "bg-primary/20 text-primary-light" : "bg-theme-subtle-10 text-theme-muted"
319
+ ),
320
+ children: getRoomIcon(room)
321
+ }
322
+ ),
323
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx("div", { className: "font-medium text-[13px] truncate", children: room.name || "Sem nome" }) }),
324
+ room.unreadCount > 0 && /* @__PURE__ */ jsx(
325
+ Badge,
326
+ {
327
+ variant: "primary",
328
+ className: "text-[10px] px-1.5 py-0 min-w-[18px] h-[18px] flex items-center justify-center rounded-full animate-in zoom-in-50 duration-[400ms]",
329
+ children: room.unreadCount > 99 ? "99+" : room.unreadCount
330
+ }
331
+ )
332
+ ]
333
+ },
334
+ room.id
335
+ );
336
+ const renderSection = (title, items, isOpen, toggle) => /* @__PURE__ */ jsxs("div", { className: "mb-1", children: [
337
+ /* @__PURE__ */ jsxs(
338
+ "button",
339
+ {
340
+ onClick: toggle,
341
+ className: "flex items-center gap-1 w-full px-2.5 py-1.5 text-[11px] font-semibold uppercase tracking-wider text-theme-muted hover:text-theme-secondary transition-colors",
342
+ children: [
343
+ isOpen ? /* @__PURE__ */ jsx(OrgChevronDown, { className: "w-3 h-3" }) : /* @__PURE__ */ jsx(OrgChevronRight, { className: "w-3 h-3" }),
344
+ /* @__PURE__ */ jsx("span", { children: title }),
345
+ /* @__PURE__ */ jsx("span", { className: "ml-auto text-[10px] font-normal", children: items.length })
346
+ ]
347
+ }
348
+ ),
349
+ isOpen && /* @__PURE__ */ jsx("div", { className: "space-y-0.5 animate-in fade-in-0 slide-in-from-top-1 duration-[400ms]", children: items.map(renderRoom) })
350
+ ] });
351
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full border-r border-theme-subtle bg-theme-surface", children: [
352
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-theme-subtle", children: [
353
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-theme", children: "Chat" }),
354
+ /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
355
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
356
+ Button,
357
+ {
358
+ variant: "ghost",
359
+ size: "sm",
360
+ onClick: onCreateRoom,
361
+ className: "h-7 w-7 p-0 text-theme-muted hover:text-primary-light hover:bg-primary/10 transition-colors",
362
+ children: /* @__PURE__ */ jsx(OrgPlus, { className: "w-4 h-4" })
363
+ }
364
+ ) }),
365
+ /* @__PURE__ */ jsx(TooltipContent, { children: "Nova conversa" })
366
+ ] }) })
367
+ ] }),
368
+ /* @__PURE__ */ jsx("div", { className: "px-3 py-2", children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
369
+ /* @__PURE__ */ jsx(OrgSearch, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 w-3.5 h-3.5 text-theme-muted" }),
370
+ /* @__PURE__ */ jsx(
371
+ Input,
372
+ {
373
+ variant: "flat",
374
+ placeholder: "Pesquisar...",
375
+ value: search,
376
+ onChange: (e) => setSearch(e.target.value),
377
+ className: "h-8 text-xs bg-theme-subtle border-theme-subtle rounded-sm pl-8"
378
+ }
379
+ )
380
+ ] }) }),
381
+ /* @__PURE__ */ jsx(ScrollArea, { className: "flex-1", children: /* @__PURE__ */ jsx("div", { className: "px-2 pb-2", children: loading ? /* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 px-3 py-2", children: [
382
+ /* @__PURE__ */ jsx(Skeleton, { variant: "rounded", className: "h-7 w-7 shrink-0" }),
383
+ /* @__PURE__ */ jsx("div", { className: "flex-1 space-y-1.5", children: /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-24" }) })
384
+ ] }, i)) }) : filtered.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center py-8 text-theme-muted", children: [
385
+ /* @__PURE__ */ jsx(OrgSearch, { className: "w-6 h-6 mb-2 opacity-40" }),
386
+ /* @__PURE__ */ jsx("p", { className: "text-xs", children: search ? "Sem resultados" : "Sem conversas" }),
387
+ !search && /* @__PURE__ */ jsx(
388
+ "button",
389
+ {
390
+ onClick: onCreateRoom,
391
+ className: "mt-3 text-xs text-primary-light/70 hover:text-primary-light transition-colors",
392
+ children: "Criar primeira conversa \u2192"
393
+ }
394
+ )
395
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
396
+ channels.length > 0 && renderSection("Canais", channels, channelsOpen, () => setChannelsOpen(!channelsOpen)),
397
+ dms.length > 0 && renderSection("Mensagens Diretas", dms, dmsOpen, () => setDmsOpen(!dmsOpen))
398
+ ] }) }) })
399
+ ] });
400
+ }
401
+ var actionBarVariants = {
402
+ hidden: {
403
+ opacity: 0,
404
+ y: 8,
405
+ scale: 0.95
406
+ },
407
+ visible: {
408
+ opacity: 1,
409
+ y: 0,
410
+ scale: 1,
411
+ transition: {
412
+ type: "spring",
413
+ stiffness: 400,
414
+ damping: 25,
415
+ staggerChildren: 0.03
416
+ }
417
+ },
418
+ exit: {
419
+ opacity: 0,
420
+ y: 4,
421
+ scale: 0.98,
422
+ transition: { duration: 0.15 }
423
+ }
424
+ };
425
+ var actionItemVariants = {
426
+ hidden: { opacity: 0, scale: 0.8 },
427
+ visible: {
428
+ opacity: 1,
429
+ scale: 1,
430
+ transition: { type: "spring", stiffness: 500, damping: 30 }
431
+ }
432
+ };
433
+ var replyPreviewVariants = {
434
+ hidden: { opacity: 0, x: -10, height: 0 },
435
+ visible: {
436
+ opacity: 1,
437
+ x: 0,
438
+ height: "auto",
439
+ transition: { duration: 0.2, ease: "easeOut" }
440
+ }
441
+ };
442
+ var reactionVariants = {
443
+ hidden: { scale: 0, opacity: 0 },
444
+ visible: {
445
+ scale: 1,
446
+ opacity: 1,
447
+ transition: { type: "spring", stiffness: 500, damping: 25 }
448
+ },
449
+ tap: { scale: 1.2 }
450
+ };
451
+ function formatTime(iso) {
452
+ return new Date(iso).toLocaleTimeString("pt-BR", {
453
+ hour: "2-digit",
454
+ minute: "2-digit"
455
+ });
456
+ }
457
+ function getInitials(name) {
458
+ if (!name) return "??";
459
+ return name.split(" ").map((w) => w[0]).slice(0, 2).join("").toUpperCase();
460
+ }
461
+ function groupReactions(reactions) {
462
+ const map = /* @__PURE__ */ new Map();
463
+ reactions.forEach((r) => {
464
+ const existing = map.get(r.emoji);
465
+ if (existing) {
466
+ existing.count++;
467
+ existing.users.push(r.userId);
468
+ } else {
469
+ map.set(r.emoji, { count: 1, users: [r.userId] });
470
+ }
471
+ });
472
+ return Array.from(map.entries());
473
+ }
474
+ function truncate(str, len) {
475
+ if (str.length <= len) return str;
476
+ return str.slice(0, len) + "...";
477
+ }
478
+ var quickEmojis = ["\u{1F44D}", "\u2764\uFE0F", "\u{1F602}", "\u{1F62E}", "\u{1F622}", "\u{1F389}"];
479
+ function renderContent(content) {
480
+ const parts = content.split(/(@\w+)/g);
481
+ return parts.map((part, i) => {
482
+ if (part.startsWith("@")) {
483
+ return /* @__PURE__ */ jsx(
484
+ motion.span,
485
+ {
486
+ className: "text-primary-light font-medium hover:underline cursor-pointer",
487
+ whileHover: { scale: 1.02 },
488
+ whileTap: { scale: 0.98 },
489
+ children: part
490
+ },
491
+ i
492
+ );
493
+ }
494
+ return part;
495
+ });
496
+ }
497
+ function ActionBar({
498
+ show,
499
+ onClose,
500
+ onEdit,
501
+ onReply,
502
+ onDelete,
503
+ onReact,
504
+ canEdit,
505
+ canDelete,
506
+ position
507
+ }) {
508
+ return /* @__PURE__ */ jsx(AnimatePresence, { children: show && /* @__PURE__ */ jsxs(
509
+ motion.div,
510
+ {
511
+ variants: actionBarVariants,
512
+ initial: "hidden",
513
+ animate: "visible",
514
+ exit: "exit",
515
+ className: cn(
516
+ "absolute z-10 -top-12 flex items-center gap-1 p-1.5 rounded-sm",
517
+ "bg-theme-surface/95 backdrop-blur-md border border-theme-subtle shadow-lg",
518
+ position === "right" ? "right-0" : "left-0"
519
+ ),
520
+ children: [
521
+ onReact && /* @__PURE__ */ jsxs(Fragment, { children: [
522
+ quickEmojis.slice(0, 4).map((emoji) => /* @__PURE__ */ jsx(
523
+ motion.button,
524
+ {
525
+ variants: actionItemVariants,
526
+ whileHover: { scale: 1.15 },
527
+ whileTap: { scale: 0.9 },
528
+ onClick: () => {
529
+ onReact(emoji);
530
+ onClose();
531
+ },
532
+ className: "w-8 h-8 flex items-center justify-center rounded-sm hover:bg-theme-highlight text-base transition-colors",
533
+ children: emoji
534
+ },
535
+ emoji
536
+ )),
537
+ /* @__PURE__ */ jsx("div", { className: "w-px h-6 bg-theme-subtle mx-1" })
538
+ ] }),
539
+ onReply && /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
540
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
541
+ motion.button,
542
+ {
543
+ variants: actionItemVariants,
544
+ whileHover: { scale: 1.1 },
545
+ whileTap: { scale: 0.9 },
546
+ onClick: () => {
547
+ onReply();
548
+ onClose();
549
+ },
550
+ className: "p-2 rounded-sm text-theme-muted hover:text-theme hover:bg-theme-highlight transition-colors",
551
+ children: /* @__PURE__ */ jsx(OrgComment, { className: "w-4 h-4" })
552
+ }
553
+ ) }),
554
+ /* @__PURE__ */ jsx(TooltipContent, { side: "top", children: "Responder" })
555
+ ] }) }),
556
+ canEdit && onEdit && /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
557
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
558
+ motion.button,
559
+ {
560
+ variants: actionItemVariants,
561
+ whileHover: { scale: 1.1 },
562
+ whileTap: { scale: 0.9 },
563
+ onClick: () => {
564
+ onEdit();
565
+ onClose();
566
+ },
567
+ className: "p-2 rounded-sm text-theme-muted hover:text-theme hover:bg-theme-highlight transition-colors",
568
+ children: /* @__PURE__ */ jsx(OrgEdit, { className: "w-4 h-4" })
569
+ }
570
+ ) }),
571
+ /* @__PURE__ */ jsx(TooltipContent, { side: "top", children: "Editar" })
572
+ ] }) }),
573
+ canDelete && onDelete && /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
574
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
575
+ motion.button,
576
+ {
577
+ variants: actionItemVariants,
578
+ whileHover: { scale: 1.1 },
579
+ whileTap: { scale: 0.9 },
580
+ onClick: () => {
581
+ onDelete();
582
+ onClose();
583
+ },
584
+ className: "p-2 rounded-sm text-rose-400 hover:text-rose-300 hover:bg-rose-500/10 transition-colors",
585
+ children: /* @__PURE__ */ jsx(OrgTrash, { className: "w-4 h-4" })
586
+ }
587
+ ) }),
588
+ /* @__PURE__ */ jsx(TooltipContent, { side: "top", children: "Excluir" })
589
+ ] }) }),
590
+ /* @__PURE__ */ jsx(
591
+ motion.button,
592
+ {
593
+ variants: actionItemVariants,
594
+ whileHover: { scale: 1.1 },
595
+ whileTap: { scale: 0.9 },
596
+ onClick: onClose,
597
+ className: "p-2 rounded-sm text-theme-muted hover:text-theme hover:bg-theme-highlight transition-colors md:hidden",
598
+ children: /* @__PURE__ */ jsx(OrgClose, { className: "w-4 h-4" })
599
+ }
600
+ )
601
+ ]
602
+ }
603
+ ) });
604
+ }
605
+ function ReactionPill({ emoji, count, onClick }) {
606
+ return /* @__PURE__ */ jsxs(
607
+ motion.button,
608
+ {
609
+ variants: reactionVariants,
610
+ initial: "hidden",
611
+ animate: "visible",
612
+ whileHover: { scale: 1.05 },
613
+ whileTap: "tap",
614
+ onClick,
615
+ className: "inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs bg-theme-subtle border border-theme-subtle hover:bg-primary/10 hover:border-primary/20 transition-colors",
616
+ children: [
617
+ /* @__PURE__ */ jsx(
618
+ motion.span,
619
+ {
620
+ animate: { rotate: [0, -10, 10, 0] },
621
+ transition: { duration: 0.3, delay: 0.1 },
622
+ children: emoji
623
+ }
624
+ ),
625
+ /* @__PURE__ */ jsx("span", { className: "text-theme-muted font-medium", children: count })
626
+ ]
627
+ }
628
+ );
629
+ }
630
+ function MessageBubble({
631
+ message,
632
+ isCurrentUser,
633
+ replyToMessage,
634
+ onEdit,
635
+ onReply,
636
+ onDelete,
637
+ onReact,
638
+ onScrollToMessage,
639
+ canEdit = false,
640
+ canDelete = false
641
+ }) {
642
+ const [showActions, setShowActions] = React7.useState(false);
643
+ const bubbleRef = React7.useRef(null);
644
+ const isPending = message._status === "pending";
645
+ const isError = message._status === "error";
646
+ React7.useEffect(() => {
647
+ const handleClickOutside = (e) => {
648
+ if (bubbleRef.current && !bubbleRef.current.contains(e.target)) {
649
+ setShowActions(false);
650
+ }
651
+ };
652
+ if (showActions) {
653
+ document.addEventListener("mousedown", handleClickOutside);
654
+ return () => document.removeEventListener("mousedown", handleClickOutside);
655
+ }
656
+ }, [showActions]);
657
+ const handleMessageClick = (e) => {
658
+ if (e.target.closest("button")) return;
659
+ setShowActions((prev) => !prev);
660
+ };
661
+ if (isCurrentUser) {
662
+ return /* @__PURE__ */ jsxs(
663
+ motion.div,
664
+ {
665
+ ref: bubbleRef,
666
+ "data-message-id": message.id,
667
+ initial: { opacity: 0, y: 10, x: 20 },
668
+ animate: { opacity: 1, y: 0, x: 0 },
669
+ transition: { duration: 0.2, ease: "easeOut" },
670
+ className: cn(
671
+ "group flex flex-col items-end px-2 py-1.5 relative",
672
+ isPending && "opacity-60"
673
+ ),
674
+ children: [
675
+ /* @__PURE__ */ jsx(AnimatePresence, { children: replyToMessage && /* @__PURE__ */ jsxs(
676
+ motion.div,
677
+ {
678
+ variants: replyPreviewVariants,
679
+ initial: "hidden",
680
+ animate: "visible",
681
+ onClick: (e) => {
682
+ e.stopPropagation();
683
+ if (replyToMessage.id && onScrollToMessage) onScrollToMessage(replyToMessage.id);
684
+ },
685
+ className: cn(
686
+ "flex items-center gap-2 mb-1 mr-2 px-2 py-1 bg-theme-subtle/50 border-l-2 border-primary-light/50 rounded-r text-[11px] overflow-hidden",
687
+ onScrollToMessage && "cursor-pointer hover:bg-theme-subtle/80 transition-colors"
688
+ ),
689
+ children: [
690
+ /* @__PURE__ */ jsxs("span", { className: "text-theme-muted", children: [
691
+ "Respondendo a ",
692
+ /* @__PURE__ */ jsx("span", { className: "text-primary-light", children: replyToMessage.authorName || replyToMessage.authorId?.substring(0, 8) }),
693
+ ":"
694
+ ] }),
695
+ /* @__PURE__ */ jsx("span", { className: "text-theme-muted truncate", children: truncate(replyToMessage.content, 40) })
696
+ ]
697
+ }
698
+ ) }),
699
+ /* @__PURE__ */ jsxs("div", { className: "max-w-[75%] flex flex-col items-end relative", children: [
700
+ /* @__PURE__ */ jsx(
701
+ ActionBar,
702
+ {
703
+ show: showActions,
704
+ onClose: () => setShowActions(false),
705
+ onEdit: onEdit ? () => onEdit(message) : void 0,
706
+ onReply: onReply ? () => onReply(message) : void 0,
707
+ onDelete: onDelete ? () => onDelete(message.id) : void 0,
708
+ onReact: onReact ? (emoji) => onReact(message.id, emoji) : void 0,
709
+ canEdit,
710
+ canDelete,
711
+ position: "right"
712
+ }
713
+ ),
714
+ /* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2 mb-0.5 justify-end", children: [
715
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] text-theme-muted", children: formatTime(message.createdAt) }),
716
+ message.edited && /* @__PURE__ */ jsx(
717
+ motion.span,
718
+ {
719
+ initial: { opacity: 0 },
720
+ animate: { opacity: 1 },
721
+ className: "text-[10px] text-theme-muted italic",
722
+ children: "(editado)"
723
+ }
724
+ ),
725
+ isPending && /* @__PURE__ */ jsx(
726
+ motion.span,
727
+ {
728
+ animate: { opacity: [0.5, 1, 0.5] },
729
+ transition: { duration: 1.5, repeat: Infinity },
730
+ className: "text-[10px] text-theme-muted italic",
731
+ children: "enviando..."
732
+ }
733
+ ),
734
+ isError && /* @__PURE__ */ jsx(
735
+ motion.span,
736
+ {
737
+ initial: { scale: 0.8 },
738
+ animate: { scale: 1 },
739
+ className: "text-[10px] text-rose-400 font-medium",
740
+ children: "erro \u2014 toque para reenviar"
741
+ }
742
+ )
743
+ ] }),
744
+ /* @__PURE__ */ jsx(
745
+ motion.div,
746
+ {
747
+ onClick: handleMessageClick,
748
+ whileTap: { scale: 0.98 },
749
+ className: cn(
750
+ "rounded-sm rounded-br-none px-4 py-2.5 cursor-pointer select-none",
751
+ "bg-primary !text-white",
752
+ isError && "bg-rose-500/80",
753
+ showActions && "ring-2 ring-primary-light/30"
754
+ ),
755
+ children: /* @__PURE__ */ jsx("p", { className: "text-[13px] leading-relaxed break-words whitespace-pre-wrap !text-white", children: renderContent(message.content) })
756
+ }
757
+ ),
758
+ message.reactions.length > 0 && /* @__PURE__ */ jsx(
759
+ motion.div,
760
+ {
761
+ initial: { opacity: 0 },
762
+ animate: { opacity: 1 },
763
+ transition: { delay: 0.1 },
764
+ className: "flex flex-wrap gap-1 mt-1.5 justify-end",
765
+ children: groupReactions(message.reactions).map(([emoji, data]) => /* @__PURE__ */ jsx(
766
+ ReactionPill,
767
+ {
768
+ emoji,
769
+ count: data.count,
770
+ onClick: () => onReact?.(message.id, emoji)
771
+ },
772
+ emoji
773
+ ))
774
+ }
775
+ )
776
+ ] })
777
+ ]
778
+ }
779
+ );
780
+ }
781
+ return /* @__PURE__ */ jsxs(
782
+ motion.div,
783
+ {
784
+ ref: bubbleRef,
785
+ "data-message-id": message.id,
786
+ initial: { opacity: 0, y: 10, x: -20 },
787
+ animate: { opacity: 1, y: 0, x: 0 },
788
+ transition: { duration: 0.2, ease: "easeOut" },
789
+ onClick: handleMessageClick,
790
+ className: cn(
791
+ "group flex gap-3 px-2 py-1.5 rounded-sm cursor-pointer select-none relative",
792
+ "transition-colors",
793
+ isPending && "opacity-60",
794
+ isError && "border-l-2 border-rose-500/50",
795
+ showActions && "bg-theme-subtle"
796
+ ),
797
+ children: [
798
+ /* @__PURE__ */ jsx(motion.div, { whileHover: { scale: 1.05 }, whileTap: { scale: 0.95 }, children: /* @__PURE__ */ jsx(Avatar, { shape: "circle", size: "sm", className: "mt-0.5 shrink-0", children: /* @__PURE__ */ jsx(AvatarFallback, { className: "bg-primary/20 text-primary-light text-xs font-semibold", children: getInitials(message.authorName || message.authorId) }) }) }),
799
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0 relative", children: [
800
+ /* @__PURE__ */ jsx(
801
+ ActionBar,
802
+ {
803
+ show: showActions,
804
+ onClose: () => setShowActions(false),
805
+ onEdit: onEdit ? () => onEdit(message) : void 0,
806
+ onReply: onReply ? () => onReply(message) : void 0,
807
+ onDelete: onDelete ? () => onDelete(message.id) : void 0,
808
+ onReact: onReact ? (emoji) => onReact(message.id, emoji) : void 0,
809
+ canEdit,
810
+ canDelete,
811
+ position: "left"
812
+ }
813
+ ),
814
+ /* @__PURE__ */ jsx(AnimatePresence, { children: replyToMessage && /* @__PURE__ */ jsxs(
815
+ motion.div,
816
+ {
817
+ variants: replyPreviewVariants,
818
+ initial: "hidden",
819
+ animate: "visible",
820
+ onClick: (e) => {
821
+ e.stopPropagation();
822
+ if (replyToMessage.id && onScrollToMessage) onScrollToMessage(replyToMessage.id);
823
+ },
824
+ className: cn(
825
+ "flex items-center gap-2 mb-1 px-2 py-1 bg-theme-subtle/50 border-l-2 border-primary-light/50 rounded-r text-[11px] overflow-hidden",
826
+ onScrollToMessage && "cursor-pointer hover:bg-theme-subtle/80 transition-colors"
827
+ ),
828
+ children: [
829
+ /* @__PURE__ */ jsxs("span", { className: "text-theme-muted", children: [
830
+ "Respondendo a ",
831
+ /* @__PURE__ */ jsx("span", { className: "text-primary-light", children: replyToMessage.authorName }),
832
+ ":"
833
+ ] }),
834
+ /* @__PURE__ */ jsx("span", { className: "text-theme-muted truncate", children: truncate(replyToMessage.content, 40) })
835
+ ]
836
+ }
837
+ ) }),
838
+ /* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2 mb-0.5", children: [
839
+ /* @__PURE__ */ jsx("span", { className: "text-[13px] font-semibold text-theme", children: message.authorName || message.authorId.substring(0, 8) }),
840
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] text-theme-muted", children: formatTime(message.createdAt) }),
841
+ message.edited && /* @__PURE__ */ jsx(
842
+ motion.span,
843
+ {
844
+ initial: { opacity: 0 },
845
+ animate: { opacity: 1 },
846
+ className: "text-[10px] text-theme-muted italic",
847
+ children: "(editado)"
848
+ }
849
+ ),
850
+ isPending && /* @__PURE__ */ jsx(
851
+ motion.span,
852
+ {
853
+ animate: { opacity: [0.5, 1, 0.5] },
854
+ transition: { duration: 1.5, repeat: Infinity },
855
+ className: "text-[10px] text-theme-muted italic",
856
+ children: "enviando..."
857
+ }
858
+ ),
859
+ isError && /* @__PURE__ */ jsx(
860
+ motion.span,
861
+ {
862
+ initial: { scale: 0.8 },
863
+ animate: { scale: 1 },
864
+ className: "text-[10px] text-rose-400 font-medium",
865
+ children: "erro ao enviar"
866
+ }
867
+ )
868
+ ] }),
869
+ /* @__PURE__ */ jsx("p", { className: "text-[13px] text-theme-secondary leading-relaxed break-words whitespace-pre-wrap", children: renderContent(message.content) }),
870
+ message.reactions.length > 0 && /* @__PURE__ */ jsx(
871
+ motion.div,
872
+ {
873
+ initial: { opacity: 0 },
874
+ animate: { opacity: 1 },
875
+ transition: { delay: 0.1 },
876
+ className: "flex flex-wrap gap-1 mt-1.5",
877
+ children: groupReactions(message.reactions).map(([emoji, data]) => /* @__PURE__ */ jsx(
878
+ ReactionPill,
879
+ {
880
+ emoji,
881
+ count: data.count,
882
+ onClick: () => onReact?.(message.id, emoji)
883
+ },
884
+ emoji
885
+ ))
886
+ }
887
+ )
888
+ ] })
889
+ ]
890
+ }
891
+ );
892
+ }
893
+ MessageBubble.displayName = "MessageBubble";
894
+ function getInitials2(name) {
895
+ if (!name) return "?";
896
+ return name.split(" ").map((w) => w[0]).slice(0, 2).join("").toUpperCase();
897
+ }
898
+ function getMentionIcon(type) {
899
+ switch (type) {
900
+ case "user":
901
+ return /* @__PURE__ */ jsx(OrgTeam, { className: "w-4 h-4" });
902
+ case "project":
903
+ return /* @__PURE__ */ jsx(OrgFolder, { className: "w-4 h-4" });
904
+ case "task":
905
+ return /* @__PURE__ */ jsx(OrgCheck, { className: "w-4 h-4" });
906
+ default:
907
+ return null;
908
+ }
909
+ }
910
+ function getMentionLabel(type) {
911
+ switch (type) {
912
+ case "user":
913
+ return "Usu\xE1rio";
914
+ case "project":
915
+ return "Projeto";
916
+ case "task":
917
+ return "Tarefa";
918
+ default:
919
+ return "";
920
+ }
921
+ }
922
+ function MentionPopover({
923
+ open,
924
+ query,
925
+ options,
926
+ loading = false,
927
+ onSelect,
928
+ onClose,
929
+ position,
930
+ selectedIndex = 0
931
+ }) {
932
+ const listRef = React7.useRef(null);
933
+ const groupedOptions = React7.useMemo(() => {
934
+ const groups = {
935
+ user: [],
936
+ project: [],
937
+ task: []
938
+ };
939
+ options.forEach((opt) => {
940
+ if (groups[opt.type]) {
941
+ groups[opt.type].push(opt);
942
+ }
943
+ });
944
+ return groups;
945
+ }, [options]);
946
+ React7.useEffect(() => {
947
+ if (listRef.current && selectedIndex >= 0) {
948
+ const items = listRef.current.querySelectorAll("[data-mention-item]");
949
+ const item = items[selectedIndex];
950
+ if (item) {
951
+ item.scrollIntoView({ block: "nearest" });
952
+ }
953
+ }
954
+ }, [selectedIndex]);
955
+ if (!open) return null;
956
+ const hasResults = options.length > 0;
957
+ let flatIndex = -1;
958
+ return /* @__PURE__ */ jsx(
959
+ "div",
960
+ {
961
+ className: cn(
962
+ "absolute z-50 w-72 max-h-64 overflow-y-auto",
963
+ "bg-theme-surface border border-theme-subtle rounded-sm shadow-lg",
964
+ "animate-in fade-in-0 zoom-in-95 duration-[400ms]"
965
+ ),
966
+ style: position ? { top: position.top, left: position.left } : void 0,
967
+ children: loading ? /* @__PURE__ */ jsx("div", { className: "px-3 py-4 flex items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "flex gap-1", children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx(
968
+ "span",
969
+ {
970
+ className: "w-2 h-2 rounded-full bg-primary-light/50 animate-bounce",
971
+ style: { animationDelay: `${i * 100}ms` }
972
+ },
973
+ i
974
+ )) }) }) : !hasResults ? /* @__PURE__ */ jsx("div", { className: "px-3 py-4 text-center", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-theme-muted", children: query ? `Nenhum resultado para "${query}"` : "Digite para pesquisar" }) }) : /* @__PURE__ */ jsx("div", { ref: listRef, className: "py-1", children: ["user", "project", "task"].map((type) => {
975
+ const typeOptions = groupedOptions[type];
976
+ if (typeOptions.length === 0) return null;
977
+ return /* @__PURE__ */ jsxs("div", { children: [
978
+ /* @__PURE__ */ jsxs("div", { className: "px-3 py-1.5 flex items-center gap-2", children: [
979
+ /* @__PURE__ */ jsx("span", { className: "text-theme-muted", children: getMentionIcon(type) }),
980
+ /* @__PURE__ */ jsxs("span", { className: "text-[11px] font-medium text-theme-muted uppercase tracking-wide", children: [
981
+ getMentionLabel(type),
982
+ "s"
983
+ ] })
984
+ ] }),
985
+ typeOptions.map((option) => {
986
+ flatIndex++;
987
+ const isSelected = flatIndex === selectedIndex;
988
+ return /* @__PURE__ */ jsxs(
989
+ "button",
990
+ {
991
+ "data-mention-item": true,
992
+ onClick: () => onSelect(option),
993
+ className: cn(
994
+ "w-full flex items-center gap-3 px-3 py-2 text-left transition-colors",
995
+ "hover:bg-theme-highlight focus:bg-theme-highlight focus:outline-none",
996
+ isSelected && "bg-theme-highlight"
997
+ ),
998
+ children: [
999
+ type === "user" ? /* @__PURE__ */ jsx(Avatar, { shape: "circle", size: "sm", className: "w-7 h-7", children: /* @__PURE__ */ jsx(AvatarFallback, { className: "bg-primary/20 text-primary-light text-[10px] font-semibold", children: getInitials2(option.display) }) }) : /* @__PURE__ */ jsx(
1000
+ "span",
1001
+ {
1002
+ className: cn(
1003
+ "w-7 h-7 rounded flex items-center justify-center",
1004
+ type === "project" && "bg-purple-500/20 text-purple-400",
1005
+ type === "task" && "bg-emerald-500/20 text-emerald-400"
1006
+ ),
1007
+ children: getMentionIcon(type)
1008
+ }
1009
+ ),
1010
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
1011
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-theme truncate", children: option.display }),
1012
+ option.subtitle && /* @__PURE__ */ jsx("p", { className: "text-[11px] text-theme-muted truncate", children: option.subtitle })
1013
+ ] })
1014
+ ]
1015
+ },
1016
+ option.id
1017
+ );
1018
+ })
1019
+ ] }, type);
1020
+ }) })
1021
+ }
1022
+ );
1023
+ }
1024
+ MentionPopover.displayName = "MentionPopover";
1025
+ var bannerVariants = {
1026
+ initial: { opacity: 0, y: -8, height: 0 },
1027
+ animate: { opacity: 1, y: 0, height: "auto" },
1028
+ exit: { opacity: 0, y: -8, height: 0 }
1029
+ };
1030
+ var bannerTransition = {
1031
+ duration: 0.2,
1032
+ ease: [0.4, 0, 0.2, 1]
1033
+ };
1034
+ function truncate2(str, len) {
1035
+ if (str.length <= len) return str;
1036
+ return str.slice(0, len) + "...";
1037
+ }
1038
+ function MessageInput({
1039
+ value,
1040
+ onChange,
1041
+ onSend,
1042
+ onTyping,
1043
+ onStopTyping,
1044
+ disabled = false,
1045
+ placeholder = "Escreva uma mensagem...",
1046
+ editingMessage,
1047
+ onCancelEdit,
1048
+ replyTo,
1049
+ onCancelReply,
1050
+ mentionOptions = [],
1051
+ onMentionSearch,
1052
+ mentionLoading = false
1053
+ }) {
1054
+ const inputRef = React7.useRef(null);
1055
+ const [showMentions, setShowMentions] = React7.useState(false);
1056
+ const [mentionQuery, setMentionQuery] = React7.useState("");
1057
+ const [mentionIndex, setMentionIndex] = React7.useState(0);
1058
+ const [caretPosition, setCaretPosition] = React7.useState(null);
1059
+ const detectMention = (text, cursorPos) => {
1060
+ const beforeCursor = text.slice(0, cursorPos);
1061
+ const match = beforeCursor.match(/@(\w*)$/);
1062
+ if (match) {
1063
+ setShowMentions(true);
1064
+ setMentionQuery(match[1]);
1065
+ setMentionIndex(0);
1066
+ onMentionSearch?.(match[1], null);
1067
+ if (inputRef.current) {
1068
+ inputRef.current.getBoundingClientRect();
1069
+ setCaretPosition({
1070
+ top: -200,
1071
+ // Above input
1072
+ left: 0
1073
+ });
1074
+ }
1075
+ } else {
1076
+ setShowMentions(false);
1077
+ setMentionQuery("");
1078
+ }
1079
+ };
1080
+ const handleChange = (e) => {
1081
+ const newValue = e.target.value;
1082
+ onChange(newValue);
1083
+ onTyping?.();
1084
+ detectMention(newValue, e.target.selectionStart || 0);
1085
+ };
1086
+ const handleKeyDown = (e) => {
1087
+ if (showMentions && mentionOptions.length > 0) {
1088
+ if (e.key === "ArrowDown") {
1089
+ e.preventDefault();
1090
+ setMentionIndex((i) => Math.min(i + 1, mentionOptions.length - 1));
1091
+ return;
1092
+ }
1093
+ if (e.key === "ArrowUp") {
1094
+ e.preventDefault();
1095
+ setMentionIndex((i) => Math.max(i - 1, 0));
1096
+ return;
1097
+ }
1098
+ if (e.key === "Enter" || e.key === "Tab") {
1099
+ e.preventDefault();
1100
+ handleMentionSelect(mentionOptions[mentionIndex]);
1101
+ return;
1102
+ }
1103
+ if (e.key === "Escape") {
1104
+ e.preventDefault();
1105
+ setShowMentions(false);
1106
+ return;
1107
+ }
1108
+ }
1109
+ if (e.key === "Enter" && !e.shiftKey) {
1110
+ e.preventDefault();
1111
+ if (value.trim()) {
1112
+ onSend();
1113
+ }
1114
+ }
1115
+ };
1116
+ const handleMentionSelect = (option) => {
1117
+ const cursorPos = inputRef.current?.selectionStart || 0;
1118
+ const beforeCursor = value.slice(0, cursorPos);
1119
+ const afterCursor = value.slice(cursorPos);
1120
+ const match = beforeCursor.match(/@(\w*)$/);
1121
+ if (match) {
1122
+ const mentionStart = beforeCursor.length - match[0].length;
1123
+ const newValue = beforeCursor.slice(0, mentionStart) + `@${option.display} ` + afterCursor;
1124
+ onChange(newValue);
1125
+ }
1126
+ setShowMentions(false);
1127
+ setMentionQuery("");
1128
+ inputRef.current?.focus();
1129
+ };
1130
+ const handleBlur = () => {
1131
+ setTimeout(() => {
1132
+ setShowMentions(false);
1133
+ onStopTyping?.();
1134
+ }, 200);
1135
+ };
1136
+ React7.useEffect(() => {
1137
+ if (inputRef.current) {
1138
+ inputRef.current.style.height = "auto";
1139
+ inputRef.current.style.height = `${Math.min(inputRef.current.scrollHeight, 120)}px`;
1140
+ }
1141
+ }, [value]);
1142
+ React7.useEffect(() => {
1143
+ if (editingMessage && inputRef.current) {
1144
+ inputRef.current.focus();
1145
+ }
1146
+ }, [editingMessage]);
1147
+ const isEditing = !!editingMessage;
1148
+ const isReplying = !!replyTo;
1149
+ return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
1150
+ /* @__PURE__ */ jsx(
1151
+ MentionPopover,
1152
+ {
1153
+ open: showMentions,
1154
+ query: mentionQuery,
1155
+ options: mentionOptions,
1156
+ loading: mentionLoading,
1157
+ onSelect: handleMentionSelect,
1158
+ onClose: () => setShowMentions(false),
1159
+ position: caretPosition ?? void 0,
1160
+ selectedIndex: mentionIndex
1161
+ }
1162
+ ),
1163
+ /* @__PURE__ */ jsx(AnimatePresence, { children: isReplying && replyTo && /* @__PURE__ */ jsx(
1164
+ motion.div,
1165
+ {
1166
+ variants: bannerVariants,
1167
+ initial: "initial",
1168
+ animate: "animate",
1169
+ exit: "exit",
1170
+ transition: bannerTransition,
1171
+ className: "overflow-hidden",
1172
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-3 py-2 mb-2 bg-theme-subtle border border-theme-subtle rounded-sm", children: [
1173
+ /* @__PURE__ */ jsx(OrgComment, { className: "w-4 h-4 text-primary-light shrink-0" }),
1174
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
1175
+ /* @__PURE__ */ jsxs("p", { className: "text-[11px] font-medium text-primary-light", children: [
1176
+ "Respondendo a ",
1177
+ replyTo.authorName
1178
+ ] }),
1179
+ /* @__PURE__ */ jsx("p", { className: "text-[12px] text-theme-muted truncate", children: truncate2(replyTo.content, 60) })
1180
+ ] }),
1181
+ /* @__PURE__ */ jsx(
1182
+ "button",
1183
+ {
1184
+ onClick: onCancelReply,
1185
+ className: "p-1 rounded hover:bg-theme-highlight text-theme-muted hover:text-theme transition-colors",
1186
+ children: /* @__PURE__ */ jsx(OrgClose, { className: "w-4 h-4" })
1187
+ }
1188
+ )
1189
+ ] })
1190
+ },
1191
+ "reply-banner"
1192
+ ) }),
1193
+ /* @__PURE__ */ jsx(AnimatePresence, { children: isEditing && /* @__PURE__ */ jsx(
1194
+ motion.div,
1195
+ {
1196
+ variants: bannerVariants,
1197
+ initial: "initial",
1198
+ animate: "animate",
1199
+ exit: "exit",
1200
+ transition: bannerTransition,
1201
+ className: "overflow-hidden",
1202
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-3 py-2 mb-2 bg-amber-500/10 border border-amber-500/30 rounded-sm", children: [
1203
+ /* @__PURE__ */ jsx(OrgEdit, { className: "w-4 h-4 text-amber-400 shrink-0" }),
1204
+ /* @__PURE__ */ jsx("p", { className: "text-[12px] text-amber-300 flex-1", children: "Editando mensagem" }),
1205
+ /* @__PURE__ */ jsx(
1206
+ "button",
1207
+ {
1208
+ onClick: onCancelEdit,
1209
+ className: "p-1 rounded hover:bg-amber-500/20 text-amber-400 hover:text-amber-300 transition-colors",
1210
+ children: /* @__PURE__ */ jsx(OrgClose, { className: "w-4 h-4" })
1211
+ }
1212
+ )
1213
+ ] })
1214
+ },
1215
+ "edit-banner"
1216
+ ) }),
1217
+ /* @__PURE__ */ jsxs(
1218
+ "div",
1219
+ {
1220
+ className: cn(
1221
+ "flex items-end gap-2 bg-theme-subtle border border-theme-subtle rounded-sm px-3 py-2 transition-colors",
1222
+ "focus-within:border-primary/50",
1223
+ isEditing && "border-amber-500/30 focus-within:border-amber-500/50"
1224
+ ),
1225
+ children: [
1226
+ /* @__PURE__ */ jsx(
1227
+ "textarea",
1228
+ {
1229
+ ref: inputRef,
1230
+ value,
1231
+ onChange: handleChange,
1232
+ onKeyDown: handleKeyDown,
1233
+ onBlur: handleBlur,
1234
+ placeholder,
1235
+ disabled,
1236
+ rows: 1,
1237
+ className: cn(
1238
+ "flex-1 bg-transparent border-none outline-none resize-none",
1239
+ "text-[13px] text-theme placeholder:text-theme-muted",
1240
+ "min-h-[24px] max-h-[120px]"
1241
+ )
1242
+ }
1243
+ ),
1244
+ /* @__PURE__ */ jsx(
1245
+ Button,
1246
+ {
1247
+ variant: isEditing ? "secondary" : "default",
1248
+ size: "sm",
1249
+ onClick: onSend,
1250
+ disabled: disabled || !value.trim(),
1251
+ className: "h-7 px-3 text-xs shrink-0",
1252
+ children: isEditing ? "Salvar" : "Enviar"
1253
+ }
1254
+ )
1255
+ ]
1256
+ }
1257
+ ),
1258
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-1 mt-1", children: [
1259
+ /* @__PURE__ */ jsxs("p", { className: "text-[10px] text-theme-muted", children: [
1260
+ /* @__PURE__ */ jsx("kbd", { className: "px-1 py-0.5 rounded bg-theme-subtle text-[10px]", children: "@" }),
1261
+ " para mencionar"
1262
+ ] }),
1263
+ /* @__PURE__ */ jsxs("p", { className: "text-[10px] text-theme-muted", children: [
1264
+ /* @__PURE__ */ jsx("kbd", { className: "px-1 py-0.5 rounded bg-theme-subtle text-[10px]", children: "Enter" }),
1265
+ " para enviar"
1266
+ ] })
1267
+ ] })
1268
+ ] });
1269
+ }
1270
+ MessageInput.displayName = "MessageInput";
1271
+ var chatPanelVariants = {
1272
+ hidden: { opacity: 0, x: 20 },
1273
+ visible: {
1274
+ opacity: 1,
1275
+ x: 0,
1276
+ transition: {
1277
+ type: "spring",
1278
+ stiffness: 300,
1279
+ damping: 30
1280
+ }
1281
+ },
1282
+ exit: {
1283
+ opacity: 0,
1284
+ x: -20,
1285
+ transition: {
1286
+ duration: 0.2
1287
+ }
1288
+ }
1289
+ };
1290
+ function formatDateSeparator(iso) {
1291
+ const date = new Date(iso);
1292
+ const today = /* @__PURE__ */ new Date();
1293
+ const yesterday = new Date(today);
1294
+ yesterday.setDate(yesterday.getDate() - 1);
1295
+ if (date.toDateString() === today.toDateString()) return "Hoje";
1296
+ if (date.toDateString() === yesterday.toDateString()) return "Ontem";
1297
+ return date.toLocaleDateString("pt-BR", { day: "numeric", month: "long" });
1298
+ }
1299
+ function shouldShowDateSeparator(messages, index) {
1300
+ if (index === 0) return true;
1301
+ const curr = new Date(messages[index].createdAt).toDateString();
1302
+ const prev = new Date(messages[index - 1].createdAt).toDateString();
1303
+ return curr !== prev;
1304
+ }
1305
+ function TypingIndicator({ users }) {
1306
+ if (users.length === 0) return null;
1307
+ const text = users.length === 1 ? `${users[0].substring(0, 8)} est\xE1 digitando` : users.length === 2 ? `${users[0].substring(0, 8)} e ${users[1].substring(0, 8)} est\xE3o digitando` : `${users.length} pessoas est\xE3o digitando`;
1308
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-5 py-1 animate-in fade-in-0 duration-[400ms]", children: [
1309
+ /* @__PURE__ */ jsx("div", { className: "flex gap-0.5", children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx(
1310
+ "span",
1311
+ {
1312
+ className: "w-1.5 h-1.5 rounded-full bg-primary-light/50 animate-bounce",
1313
+ style: { animationDelay: `${i * 150}ms` }
1314
+ },
1315
+ i
1316
+ )) }),
1317
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] text-theme-muted", children: text })
1318
+ ] });
1319
+ }
1320
+ function ChatMessages({
1321
+ room,
1322
+ messages,
1323
+ loading,
1324
+ typingUsers = [],
1325
+ currentUserId,
1326
+ permissions,
1327
+ onSendMessage,
1328
+ onEditMessage,
1329
+ onDeleteMessage,
1330
+ onReactToMessage,
1331
+ onTyping,
1332
+ onStopTyping,
1333
+ onOpenManagement,
1334
+ onBack,
1335
+ isMobile,
1336
+ mentionUsers = [],
1337
+ mentionProjects = [],
1338
+ hasMore = false,
1339
+ onLoadMore,
1340
+ loadingMore = false
1341
+ }) {
1342
+ const [inputValue, setInputValue] = React7.useState("");
1343
+ const [editingMessage, setEditingMessage] = React7.useState(null);
1344
+ const [replyTo, setReplyTo] = React7.useState(null);
1345
+ const [mentionOptions, setMentionOptions] = React7.useState([]);
1346
+ const scrollRef = React7.useRef(null);
1347
+ const messagesById = React7.useMemo(() => {
1348
+ const map = /* @__PURE__ */ new Map();
1349
+ messages.forEach((m) => map.set(m.id, m));
1350
+ return map;
1351
+ }, [messages]);
1352
+ const isInitialLoad = React7.useRef(true);
1353
+ const prevMessageCount = React7.useRef(messages.length);
1354
+ React7.useEffect(() => {
1355
+ const el = scrollRef.current;
1356
+ if (!el) return;
1357
+ if (isInitialLoad.current || messages.length > prevMessageCount.current) {
1358
+ const nearBottom = isInitialLoad.current || el.scrollHeight - el.scrollTop - el.clientHeight < 120;
1359
+ if (nearBottom) {
1360
+ requestAnimationFrame(() => {
1361
+ el.scrollTop = el.scrollHeight;
1362
+ });
1363
+ }
1364
+ isInitialLoad.current = false;
1365
+ }
1366
+ prevMessageCount.current = messages.length;
1367
+ }, [messages]);
1368
+ React7.useEffect(() => {
1369
+ isInitialLoad.current = true;
1370
+ }, [room?.id]);
1371
+ const handleScroll = React7.useCallback(() => {
1372
+ const el = scrollRef.current;
1373
+ if (!el || !hasMore || loadingMore || !onLoadMore) return;
1374
+ if (el.scrollTop < 60) {
1375
+ onLoadMore();
1376
+ }
1377
+ }, [hasMore, loadingMore, onLoadMore]);
1378
+ React7.useEffect(() => {
1379
+ if (editingMessage) {
1380
+ setInputValue(editingMessage.content);
1381
+ }
1382
+ }, [editingMessage]);
1383
+ const handleSend = () => {
1384
+ if (!inputValue.trim()) return;
1385
+ if (editingMessage) {
1386
+ onEditMessage?.(editingMessage.id, inputValue.trim());
1387
+ setEditingMessage(null);
1388
+ } else {
1389
+ onSendMessage(inputValue.trim(), replyTo?.id);
1390
+ setReplyTo(null);
1391
+ }
1392
+ setInputValue("");
1393
+ };
1394
+ const handleCancelEdit = () => {
1395
+ setEditingMessage(null);
1396
+ setInputValue("");
1397
+ };
1398
+ const handleCancelReply = () => {
1399
+ setReplyTo(null);
1400
+ };
1401
+ const handleEditMessage = (message) => {
1402
+ setEditingMessage(message);
1403
+ setReplyTo(null);
1404
+ };
1405
+ const handleReplyToMessage = (message) => {
1406
+ setReplyTo({
1407
+ id: message.id,
1408
+ authorName: message.authorName || message.authorId.substring(0, 8),
1409
+ content: message.content
1410
+ });
1411
+ setEditingMessage(null);
1412
+ };
1413
+ const handleScrollToMessage = React7.useCallback((messageId) => {
1414
+ const el = scrollRef.current?.querySelector(`[data-message-id="${messageId}"]`);
1415
+ if (el) {
1416
+ el.scrollIntoView({ behavior: "smooth", block: "center" });
1417
+ el.classList.add("bg-primary/10");
1418
+ setTimeout(() => el.classList.remove("bg-primary/10"), 1500);
1419
+ }
1420
+ }, []);
1421
+ const handleMentionSearch = (query) => {
1422
+ const q = query.toLowerCase();
1423
+ const options = [];
1424
+ mentionUsers.filter((u) => u.displayName.toLowerCase().includes(q) || u.email?.toLowerCase().includes(q)).slice(0, 5).forEach((u) => {
1425
+ options.push({
1426
+ id: u.id,
1427
+ type: "user",
1428
+ display: u.displayName,
1429
+ avatarUrl: u.avatarUrl,
1430
+ subtitle: u.email
1431
+ });
1432
+ });
1433
+ mentionProjects.filter((p) => p.name.toLowerCase().includes(q) || p.key?.toLowerCase().includes(q)).slice(0, 3).forEach((p) => {
1434
+ options.push({
1435
+ id: p.id,
1436
+ type: "project",
1437
+ display: p.name,
1438
+ subtitle: p.key
1439
+ });
1440
+ });
1441
+ setMentionOptions(options);
1442
+ };
1443
+ if (!room) {
1444
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col items-center justify-center text-center px-6", children: [
1445
+ /* @__PURE__ */ jsx("div", { className: "w-16 h-16 rounded-sm bg-primary/10 flex items-center justify-center mb-4", children: /* @__PURE__ */ jsx(OrgComment, { className: "w-8 h-8 text-primary-light/60" }) }),
1446
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-medium text-theme mb-2", children: "Selecione uma conversa" }),
1447
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-theme-muted max-w-[240px]", children: "Escolha um canal ou mensagem direta para come\xE7ar a conversar." })
1448
+ ] });
1449
+ }
1450
+ return /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: /* @__PURE__ */ jsxs(
1451
+ motion.div,
1452
+ {
1453
+ variants: chatPanelVariants,
1454
+ initial: "hidden",
1455
+ animate: "visible",
1456
+ exit: "exit",
1457
+ className: "flex flex-col h-full overflow-hidden relative",
1458
+ children: [
1459
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 px-4 md:px-5 py-3 border-b border-theme-subtle", children: [
1460
+ isMobile && onBack && /* @__PURE__ */ jsx(
1461
+ "button",
1462
+ {
1463
+ onClick: onBack,
1464
+ className: "p-1.5 rounded-sm text-theme-muted hover:text-theme hover:bg-theme-subtle transition-colors",
1465
+ children: /* @__PURE__ */ jsx("svg", { className: "w-5 h-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) })
1466
+ }
1467
+ ),
1468
+ /* @__PURE__ */ jsx(
1469
+ "span",
1470
+ {
1471
+ className: cn(
1472
+ "flex items-center justify-center h-8 w-8 rounded-sm text-sm",
1473
+ "bg-primary/15 text-primary-light"
1474
+ ),
1475
+ children: room.type === "DIRECT" ? /* @__PURE__ */ jsx(OrgComment, { className: "w-4 h-4" }) : "#"
1476
+ }
1477
+ ),
1478
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
1479
+ /* @__PURE__ */ jsx("h3", { className: "text-[15px] font-semibold text-theme truncate", children: room.name || "Sem nome" }),
1480
+ /* @__PURE__ */ jsxs("p", { className: "text-[11px] text-theme-muted truncate", children: [
1481
+ room.memberCount,
1482
+ " membro",
1483
+ room.memberCount !== 1 ? "s" : ""
1484
+ ] })
1485
+ ] }),
1486
+ onOpenManagement && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", children: /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
1487
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
1488
+ Button,
1489
+ {
1490
+ variant: "ghost",
1491
+ size: "sm",
1492
+ onClick: onOpenManagement,
1493
+ className: "h-8 w-8 p-0 text-theme-muted hover:text-theme",
1494
+ children: /* @__PURE__ */ jsx(OrgTeam, { className: "w-4 h-4" })
1495
+ }
1496
+ ) }),
1497
+ /* @__PURE__ */ jsx(TooltipContent, { children: "Detalhes do canal" })
1498
+ ] }) }) })
1499
+ ] }),
1500
+ /* @__PURE__ */ jsxs(
1501
+ "div",
1502
+ {
1503
+ ref: scrollRef,
1504
+ onScroll: handleScroll,
1505
+ className: "flex-1 overflow-y-auto px-3 md:px-5 py-4 space-y-0.5",
1506
+ children: [
1507
+ loadingMore && /* @__PURE__ */ jsx("div", { className: "flex justify-center py-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-theme-muted", children: [
1508
+ /* @__PURE__ */ jsx("div", { className: "w-4 h-4 border-2 border-primary-light/30 border-t-primary-light rounded-full animate-spin" }),
1509
+ "Carregando mensagens anteriores..."
1510
+ ] }) }),
1511
+ hasMore && !loadingMore && /* @__PURE__ */ jsx("div", { className: "flex justify-center py-2", children: /* @__PURE__ */ jsx(
1512
+ "button",
1513
+ {
1514
+ onClick: onLoadMore,
1515
+ className: "text-xs text-primary-light hover:text-primary transition-colors",
1516
+ children: "\u2191 Carregar mais mensagens"
1517
+ }
1518
+ ) }),
1519
+ loading ? /* @__PURE__ */ jsx("div", { className: "space-y-4 py-4", children: Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ jsxs("div", { className: "flex gap-3", children: [
1520
+ /* @__PURE__ */ jsx(Skeleton, { variant: "circular", className: "h-8 w-8 shrink-0" }),
1521
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-1.5", children: [
1522
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-32" }),
1523
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-full" }),
1524
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-3/4" })
1525
+ ] })
1526
+ ] }, i)) }) : messages.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center h-full", children: [
1527
+ /* @__PURE__ */ jsx("div", { className: "w-12 h-12 rounded-sm bg-primary/10 flex items-center justify-center mb-3", children: /* @__PURE__ */ jsx(OrgComment, { className: "w-6 h-6 text-primary-light/50" }) }),
1528
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-theme-muted", children: "Ainda sem mensagens." }),
1529
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-theme-muted mt-1", children: "Comece a conversa!" })
1530
+ ] }) : messages.map((msg, idx) => {
1531
+ const isCurrentUser = msg.authorId === currentUserId;
1532
+ const replyToMessage = msg.replyToId || msg.parentId ? messagesById.get(msg.replyToId || msg.parentId || "") : null;
1533
+ return /* @__PURE__ */ jsxs(React7.Fragment, { children: [
1534
+ shouldShowDateSeparator(messages, idx) && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 py-3", children: [
1535
+ /* @__PURE__ */ jsx("div", { className: "flex-1 h-px bg-theme-subtle-10" }),
1536
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] text-theme-muted font-medium", children: formatDateSeparator(msg.createdAt) }),
1537
+ /* @__PURE__ */ jsx("div", { className: "flex-1 h-px bg-theme-subtle-10" })
1538
+ ] }),
1539
+ /* @__PURE__ */ jsx(
1540
+ MessageBubble,
1541
+ {
1542
+ message: msg,
1543
+ isCurrentUser,
1544
+ replyToMessage,
1545
+ onEdit: isCurrentUser ? handleEditMessage : void 0,
1546
+ onReply: handleReplyToMessage,
1547
+ onDelete: isCurrentUser ? (id) => onDeleteMessage?.(id) : void 0,
1548
+ onReact: (id, emoji) => onReactToMessage?.(id, emoji),
1549
+ onScrollToMessage: handleScrollToMessage,
1550
+ canEdit: isCurrentUser,
1551
+ canDelete: isCurrentUser
1552
+ }
1553
+ )
1554
+ ] }, msg.id);
1555
+ })
1556
+ ]
1557
+ }
1558
+ ),
1559
+ /* @__PURE__ */ jsx(TypingIndicator, { users: typingUsers }),
1560
+ /* @__PURE__ */ jsx("div", { className: "px-3 md:px-5 py-3 border-t border-theme-subtle", children: /* @__PURE__ */ jsx(
1561
+ MessageInput,
1562
+ {
1563
+ value: inputValue,
1564
+ onChange: setInputValue,
1565
+ onSend: handleSend,
1566
+ onTyping,
1567
+ onStopTyping,
1568
+ editingMessage,
1569
+ onCancelEdit: handleCancelEdit,
1570
+ replyTo,
1571
+ onCancelReply: handleCancelReply,
1572
+ mentionOptions,
1573
+ onMentionSearch: handleMentionSearch,
1574
+ placeholder: "Escreva uma mensagem..."
1575
+ }
1576
+ ) })
1577
+ ]
1578
+ },
1579
+ room.id
1580
+ ) });
1581
+ }
1582
+ ChatMessages.displayName = "ChatMessages";
1583
+ function Label({ className, ...props }) {
1584
+ return /* @__PURE__ */ jsx(
1585
+ "label",
1586
+ {
1587
+ "data-slot": "label",
1588
+ className: cn(
1589
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
1590
+ className
1591
+ ),
1592
+ ...props
1593
+ }
1594
+ );
1595
+ }
1596
+ var textareaVariants = cva(
1597
+ "flex w-full min-h-[100px] bg-glass-highlight backdrop-blur-md border border-glass-border rounded-sm px-4 py-3 text-sm font-light text-org-text transition-all duration-[400ms] ease-[cubic-bezier(0.25,1,0.5,1)] placeholder:text-org-text-muted focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 resize-none",
1598
+ {
1599
+ variants: {
1600
+ variant: {
1601
+ default: "focus:border-primary-light/50 focus:shadow-[0_0_0_3px_rgba(79,57,246,0.10),0_0_20px_rgba(79,57,246,0.08)]",
1602
+ flat: "rounded-sm focus:border-primary-light/50 focus:shadow-[0_0_0_3px_rgba(79,57,246,0.10)]",
1603
+ rounded: "rounded-sm focus:border-primary-light/50 focus:shadow-[0_0_0_3px_rgba(79,57,246,0.10)]",
1604
+ error: "border-error/30 bg-error/5 text-red-100 placeholder:text-red-500/30 focus:border-error focus:shadow-[0_0_0_3px_rgba(224,17,95,0.10)]",
1605
+ cream: "bg-white/60 border-[rgba(36,25,121,0.06)] text-neutral-900 placeholder:text-neutral-400 focus:border-primary/40 focus:bg-white/80 focus:shadow-[0_0_0_3px_rgba(79,57,246,0.08)] backdrop-blur-sm"
1606
+ }
1607
+ },
1608
+ defaultVariants: {
1609
+ variant: "default"
1610
+ }
1611
+ }
1612
+ );
1613
+ var Textarea = React7.forwardRef(
1614
+ ({ className, variant, label, error, labelPosition = "left", ...props }, ref) => {
1615
+ const id = React7.useId();
1616
+ const effectiveVariant = error ? "error" : variant;
1617
+ return /* @__PURE__ */ jsxs("div", { className: "relative group", children: [
1618
+ label && /* @__PURE__ */ jsx(
1619
+ "label",
1620
+ {
1621
+ htmlFor: id,
1622
+ className: cn(
1623
+ "absolute -top-3 z-10 px-2 text-label uppercase tracking-widest",
1624
+ effectiveVariant === "cream" ? "bg-cream-base" : "bg-surface",
1625
+ labelPosition === "left" ? "left-0 ml-2" : "right-0 mr-2",
1626
+ error ? "text-error" : "text-primary-light"
1627
+ ),
1628
+ children: label
1629
+ }
1630
+ ),
1631
+ /* @__PURE__ */ jsx(
1632
+ "textarea",
1633
+ {
1634
+ id,
1635
+ className: cn(textareaVariants({ variant: effectiveVariant, className })),
1636
+ ref,
1637
+ "aria-invalid": !!error,
1638
+ "aria-describedby": error ? `${id}-error` : void 0,
1639
+ ...props
1640
+ }
1641
+ ),
1642
+ error && /* @__PURE__ */ jsx("div", { id: `${id}-error`, className: "mt-2 flex items-center justify-end gap-2", children: /* @__PURE__ */ jsx("span", { className: "text-mono-xs text-error", children: error }) })
1643
+ ] });
1644
+ }
1645
+ );
1646
+ Textarea.displayName = "Textarea";
1647
+ function Dialog({ ...props }) {
1648
+ return /* @__PURE__ */ jsx(DialogPrimitive.Root, { "data-slot": "dialog", ...props });
1649
+ }
1650
+ function DialogTrigger({ ...props }) {
1651
+ return /* @__PURE__ */ jsx(DialogPrimitive.Trigger, { "data-slot": "dialog-trigger", ...props });
1652
+ }
1653
+ function DialogPortal({ ...props }) {
1654
+ return /* @__PURE__ */ jsx(DialogPrimitive.Portal, { "data-slot": "dialog-portal", ...props });
1655
+ }
1656
+ function DialogClose({ ...props }) {
1657
+ return /* @__PURE__ */ jsx(DialogPrimitive.Close, { "data-slot": "dialog-close", ...props });
1658
+ }
1659
+ function DialogOverlay({
1660
+ className,
1661
+ ...props
1662
+ }) {
1663
+ return /* @__PURE__ */ jsx(
1664
+ DialogPrimitive.Overlay,
1665
+ {
1666
+ "data-slot": "dialog-overlay",
1667
+ className: cn(
1668
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
1669
+ className
1670
+ ),
1671
+ ...props
1672
+ }
1673
+ );
1674
+ }
1675
+ function DialogContent({
1676
+ className,
1677
+ children,
1678
+ showCloseButton = true,
1679
+ ...props
1680
+ }) {
1681
+ return /* @__PURE__ */ jsxs(DialogPortal, { "data-slot": "dialog-portal", children: [
1682
+ /* @__PURE__ */ jsx(DialogOverlay, {}),
1683
+ /* @__PURE__ */ jsxs(
1684
+ DialogPrimitive.Content,
1685
+ {
1686
+ "data-slot": "dialog-content",
1687
+ className: cn(
1688
+ "bg-theme-surface data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-sm border border-theme-subtle p-6 shadow-glass backdrop-blur-[40px] saturate-[180%] duration-[400ms] sm:max-w-lg text-theme",
1689
+ className
1690
+ ),
1691
+ ...props,
1692
+ children: [
1693
+ children,
1694
+ showCloseButton && /* @__PURE__ */ jsxs(
1695
+ DialogPrimitive.Close,
1696
+ {
1697
+ "data-slot": "dialog-close",
1698
+ className: "ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
1699
+ children: [
1700
+ /* @__PURE__ */ jsx(XIcon, {}),
1701
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
1702
+ ]
1703
+ }
1704
+ )
1705
+ ]
1706
+ }
1707
+ )
1708
+ ] });
1709
+ }
1710
+ function DialogHeader({ className, ...props }) {
1711
+ return /* @__PURE__ */ jsx(
1712
+ "div",
1713
+ {
1714
+ "data-slot": "dialog-header",
1715
+ className: cn("flex flex-col gap-2 text-center sm:text-left", className),
1716
+ ...props
1717
+ }
1718
+ );
1719
+ }
1720
+ function DialogFooter({ className, ...props }) {
1721
+ return /* @__PURE__ */ jsx(
1722
+ "div",
1723
+ {
1724
+ "data-slot": "dialog-footer",
1725
+ className: cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className),
1726
+ ...props
1727
+ }
1728
+ );
1729
+ }
1730
+ function DialogTitle({
1731
+ className,
1732
+ ...props
1733
+ }) {
1734
+ return /* @__PURE__ */ jsx(
1735
+ DialogPrimitive.Title,
1736
+ {
1737
+ "data-slot": "dialog-title",
1738
+ className: cn("text-lg leading-none font-semibold", className),
1739
+ ...props
1740
+ }
1741
+ );
1742
+ }
1743
+ function DialogDescription({
1744
+ className,
1745
+ ...props
1746
+ }) {
1747
+ return /* @__PURE__ */ jsx(
1748
+ DialogPrimitive.Description,
1749
+ {
1750
+ "data-slot": "dialog-description",
1751
+ className: cn("text-theme-secondary text-sm", className),
1752
+ ...props
1753
+ }
1754
+ );
1755
+ }
1756
+ function Drawer({
1757
+ shouldScaleBackground = true,
1758
+ ...props
1759
+ }) {
1760
+ return /* @__PURE__ */ jsx(Drawer$1.Root, { shouldScaleBackground, ...props });
1761
+ }
1762
+ var DrawerTrigger = Drawer$1.Trigger;
1763
+ var DrawerPortal = Drawer$1.Portal;
1764
+ var DrawerClose = Drawer$1.Close;
1765
+ function DrawerOverlay({
1766
+ className,
1767
+ ...props
1768
+ }) {
1769
+ return /* @__PURE__ */ jsx(
1770
+ Drawer$1.Overlay,
1771
+ {
1772
+ "data-slot": "drawer-overlay",
1773
+ className: cn("fixed inset-0 z-50 bg-black/80", className),
1774
+ ...props
1775
+ }
1776
+ );
1777
+ }
1778
+ function DrawerContent({
1779
+ className,
1780
+ children,
1781
+ ...props
1782
+ }) {
1783
+ return /* @__PURE__ */ jsxs(DrawerPortal, { children: [
1784
+ /* @__PURE__ */ jsx(DrawerOverlay, {}),
1785
+ /* @__PURE__ */ jsx(
1786
+ Drawer$1.Content,
1787
+ {
1788
+ asChild: true,
1789
+ "data-slot": "drawer-content",
1790
+ ...props,
1791
+ children: /* @__PURE__ */ jsxs(
1792
+ motion.div,
1793
+ {
1794
+ initial: { y: "100%", opacity: 0 },
1795
+ animate: { y: 0, opacity: 1 },
1796
+ exit: { y: "100%", opacity: 0 },
1797
+ transition: {
1798
+ type: "spring",
1799
+ stiffness: 400,
1800
+ damping: 40
1801
+ },
1802
+ className: cn(
1803
+ "fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border border-theme-subtle bg-theme-surface text-theme",
1804
+ className
1805
+ ),
1806
+ children: [
1807
+ /* @__PURE__ */ jsx("div", { className: "mx-auto mt-4 h-2 w-[100px] rounded-full bg-theme-subtle-20" }),
1808
+ children
1809
+ ]
1810
+ }
1811
+ )
1812
+ }
1813
+ )
1814
+ ] });
1815
+ }
1816
+ function DrawerHeader({ className, ...props }) {
1817
+ return /* @__PURE__ */ jsx(
1818
+ "div",
1819
+ {
1820
+ "data-slot": "drawer-header",
1821
+ className: cn("grid gap-1.5 p-4 text-center sm:text-left", className),
1822
+ ...props
1823
+ }
1824
+ );
1825
+ }
1826
+ function DrawerFooter({ className, ...props }) {
1827
+ return /* @__PURE__ */ jsx(
1828
+ "div",
1829
+ {
1830
+ "data-slot": "drawer-footer",
1831
+ className: cn("mt-auto flex flex-col gap-2 p-4", className),
1832
+ ...props
1833
+ }
1834
+ );
1835
+ }
1836
+ function DrawerTitle({
1837
+ className,
1838
+ ...props
1839
+ }) {
1840
+ return /* @__PURE__ */ jsx(
1841
+ Drawer$1.Title,
1842
+ {
1843
+ "data-slot": "drawer-title",
1844
+ className: cn("text-lg font-semibold leading-none tracking-tight", className),
1845
+ ...props
1846
+ }
1847
+ );
1848
+ }
1849
+ function DrawerDescription({
1850
+ className,
1851
+ ...props
1852
+ }) {
1853
+ return /* @__PURE__ */ jsx(
1854
+ Drawer$1.Description,
1855
+ {
1856
+ "data-slot": "drawer-description",
1857
+ className: cn("text-sm text-theme-secondary", className),
1858
+ ...props
1859
+ }
1860
+ );
1861
+ }
1862
+ function useMediaQuery(query) {
1863
+ const [matches, setMatches] = React7.useState(false);
1864
+ React7.useEffect(() => {
1865
+ const mql = window.matchMedia(query);
1866
+ setMatches(mql.matches);
1867
+ const handler = (e) => setMatches(e.matches);
1868
+ mql.addEventListener("change", handler);
1869
+ return () => mql.removeEventListener("change", handler);
1870
+ }, [query]);
1871
+ return matches;
1872
+ }
1873
+ function ResponsiveDialog({
1874
+ open,
1875
+ onOpenChange,
1876
+ title,
1877
+ description,
1878
+ children,
1879
+ footer,
1880
+ desktopQuery = "(min-width: 768px)",
1881
+ className,
1882
+ contentClassName
1883
+ }) {
1884
+ const isDesktop = useMediaQuery(desktopQuery);
1885
+ if (isDesktop) {
1886
+ return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(
1887
+ DialogContent,
1888
+ {
1889
+ className: cn(
1890
+ "max-w-2xl max-h-[85vh] overflow-y-auto",
1891
+ "border border-theme-subtle bg-theme-glass-heavy backdrop-blur-2xl",
1892
+ "shadow-glass-xl rounded-sm",
1893
+ contentClassName
1894
+ ),
1895
+ children: [
1896
+ (title || description) && /* @__PURE__ */ jsxs(DialogHeader, { children: [
1897
+ title && /* @__PURE__ */ jsx(DialogTitle, { className: "text-lg", children: title }),
1898
+ description && /* @__PURE__ */ jsx(DialogDescription, { className: "text-muted-foreground text-sm", children: description })
1899
+ ] }),
1900
+ /* @__PURE__ */ jsx("div", { className, children }),
1901
+ footer && /* @__PURE__ */ jsx(DialogFooter, { children: footer })
1902
+ ]
1903
+ }
1904
+ ) });
1905
+ }
1906
+ return /* @__PURE__ */ jsx(Drawer, { open, onOpenChange, children: /* @__PURE__ */ jsxs(
1907
+ DrawerContent,
1908
+ {
1909
+ className: cn(
1910
+ "max-h-[90vh]",
1911
+ "border-t border-theme-subtle bg-theme-glass-heavy backdrop-blur-2xl",
1912
+ contentClassName
1913
+ ),
1914
+ children: [
1915
+ (title || description) && /* @__PURE__ */ jsxs(DrawerHeader, { className: "text-left", children: [
1916
+ title && /* @__PURE__ */ jsx(DrawerTitle, { className: "text-lg", children: title }),
1917
+ description && /* @__PURE__ */ jsx(DrawerDescription, { className: "text-muted-foreground text-sm", children: description })
1918
+ ] }),
1919
+ /* @__PURE__ */ jsx("div", { className: cn("overflow-y-auto px-4 pb-4", className), children }),
1920
+ footer && /* @__PURE__ */ jsx(DrawerFooter, { children: footer })
1921
+ ]
1922
+ }
1923
+ ) });
1924
+ }
1925
+ ResponsiveDialog.displayName = "ResponsiveDialog";
1926
+ var Tabs = TabsPrimitive.Root;
1927
+ function TabsList({
1928
+ className,
1929
+ ...props
1930
+ }) {
1931
+ return /* @__PURE__ */ jsx(
1932
+ TabsPrimitive.List,
1933
+ {
1934
+ "data-slot": "tabs-list",
1935
+ className: cn(
1936
+ "inline-flex h-10 items-center justify-center rounded-sm bg-theme-glass-heavy backdrop-blur-md border border-glass-border p-1 text-theme-muted",
1937
+ className
1938
+ ),
1939
+ ...props
1940
+ }
1941
+ );
1942
+ }
1943
+ function TabsTrigger({
1944
+ className,
1945
+ ...props
1946
+ }) {
1947
+ return /* @__PURE__ */ jsx(
1948
+ TabsPrimitive.Trigger,
1949
+ {
1950
+ "data-slot": "tabs-trigger",
1951
+ className: cn(
1952
+ "inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all duration-[400ms] ease-[cubic-bezier(0.25,1,0.5,1)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-glass-highlight data-[state=active]:text-theme data-[state=active]:shadow-inner-light",
1953
+ className
1954
+ ),
1955
+ ...props
1956
+ }
1957
+ );
1958
+ }
1959
+ function TabsContent({
1960
+ className,
1961
+ ...props
1962
+ }) {
1963
+ return /* @__PURE__ */ jsx(
1964
+ TabsPrimitive.Content,
1965
+ {
1966
+ "data-slot": "tabs-content",
1967
+ className: cn(
1968
+ "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
1969
+ className
1970
+ ),
1971
+ ...props
1972
+ }
1973
+ );
1974
+ }
1975
+ function getInitials3(name) {
1976
+ return name.split(" ").map((w) => w[0]).slice(0, 2).join("").toUpperCase();
1977
+ }
1978
+ function CreateRoomDialog({
1979
+ open,
1980
+ onOpenChange,
1981
+ onCreateChannel,
1982
+ onCreateDM,
1983
+ workspaceMembers,
1984
+ loadingMembers
1985
+ }) {
1986
+ const [tab, setTab] = React7.useState("channel");
1987
+ const [creating, setCreating] = React7.useState(false);
1988
+ const [channelName, setChannelName] = React7.useState("");
1989
+ const [channelDesc, setChannelDesc] = React7.useState("");
1990
+ const [visibility, setVisibility] = React7.useState("WORKSPACE");
1991
+ const [selectedMembers, setSelectedMembers] = React7.useState([]);
1992
+ const [showAdvanced, setShowAdvanced] = React7.useState(false);
1993
+ const [dmSearch, setDmSearch] = React7.useState("");
1994
+ const [nameError, setNameError] = React7.useState("");
1995
+ const validateName = (value) => {
1996
+ if (!value.trim()) {
1997
+ setNameError("Nome do canal \xE9 obrigat\xF3rio");
1998
+ return false;
1999
+ }
2000
+ if (value.length < 2) {
2001
+ setNameError("Nome deve ter pelo menos 2 caracteres");
2002
+ return false;
2003
+ }
2004
+ if (!/^[a-zA-Z0-9À-ÿ\s\-_]+$/.test(value)) {
2005
+ setNameError("Apenas letras, n\xFAmeros, espa\xE7os e h\xEDfens");
2006
+ return false;
2007
+ }
2008
+ setNameError("");
2009
+ return true;
2010
+ };
2011
+ const filteredMembers = React7.useMemo(() => {
2012
+ if (!dmSearch) return workspaceMembers;
2013
+ const q = dmSearch.toLowerCase();
2014
+ return workspaceMembers.filter(
2015
+ (m) => m.displayName.toLowerCase().includes(q) || m.email?.toLowerCase().includes(q)
2016
+ );
2017
+ }, [workspaceMembers, dmSearch]);
2018
+ const handleCreateChannel = async () => {
2019
+ if (!validateName(channelName)) return;
2020
+ setCreating(true);
2021
+ try {
2022
+ const result = await onCreateChannel({
2023
+ name: channelName.trim(),
2024
+ description: channelDesc.trim() || void 0,
2025
+ visibility,
2026
+ memberIds: selectedMembers
2027
+ });
2028
+ if (result) {
2029
+ resetForm();
2030
+ onOpenChange(false);
2031
+ }
2032
+ } finally {
2033
+ setCreating(false);
2034
+ }
2035
+ };
2036
+ const handleCreateDM = async (userId) => {
2037
+ setCreating(true);
2038
+ try {
2039
+ const result = await onCreateDM(userId);
2040
+ if (result) {
2041
+ resetForm();
2042
+ onOpenChange(false);
2043
+ }
2044
+ } finally {
2045
+ setCreating(false);
2046
+ }
2047
+ };
2048
+ const toggleMember = (userId) => {
2049
+ setSelectedMembers(
2050
+ (prev) => prev.includes(userId) ? prev.filter((id) => id !== userId) : [...prev, userId]
2051
+ );
2052
+ };
2053
+ const resetForm = () => {
2054
+ setChannelName("");
2055
+ setChannelDesc("");
2056
+ setVisibility("WORKSPACE");
2057
+ setSelectedMembers([]);
2058
+ setShowAdvanced(false);
2059
+ setDmSearch("");
2060
+ setNameError("");
2061
+ setTab("channel");
2062
+ };
2063
+ return /* @__PURE__ */ jsx(
2064
+ ResponsiveDialog,
2065
+ {
2066
+ open,
2067
+ onOpenChange,
2068
+ title: "Nova conversa",
2069
+ description: "Crie um canal para a equipa ou inicie uma conversa direta.",
2070
+ contentClassName: "sm:max-w-md",
2071
+ children: /* @__PURE__ */ jsxs(Tabs, { value: tab, onValueChange: (v) => setTab(v), children: [
2072
+ /* @__PURE__ */ jsxs(TabsList, { className: "grid w-full grid-cols-2 bg-theme-subtle", children: [
2073
+ /* @__PURE__ */ jsxs(
2074
+ TabsTrigger,
2075
+ {
2076
+ value: "channel",
2077
+ className: "text-xs data-[state=active]:bg-primary/20 data-[state=active]:text-primary-light",
2078
+ children: [
2079
+ /* @__PURE__ */ jsx(OrgTeam, { className: "w-3.5 h-3.5 mr-1.5" }),
2080
+ "Canal"
2081
+ ]
2082
+ }
2083
+ ),
2084
+ /* @__PURE__ */ jsxs(
2085
+ TabsTrigger,
2086
+ {
2087
+ value: "dm",
2088
+ className: "text-xs data-[state=active]:bg-primary/20 data-[state=active]:text-primary-light",
2089
+ children: [
2090
+ /* @__PURE__ */ jsx(OrgComment, { className: "w-3.5 h-3.5 mr-1.5" }),
2091
+ "Mensagem Direta"
2092
+ ]
2093
+ }
2094
+ )
2095
+ ] }),
2096
+ /* @__PURE__ */ jsxs(TabsContent, { value: "channel", className: "space-y-4 mt-4", children: [
2097
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2098
+ /* @__PURE__ */ jsx(Label, { className: "text-theme-secondary text-xs", children: "Nome do canal" }),
2099
+ /* @__PURE__ */ jsx(
2100
+ Input,
2101
+ {
2102
+ variant: "flat",
2103
+ placeholder: "ex: equipa-design",
2104
+ value: channelName,
2105
+ onChange: (e) => {
2106
+ setChannelName(e.target.value);
2107
+ if (nameError) validateName(e.target.value);
2108
+ },
2109
+ onBlur: () => channelName && validateName(channelName),
2110
+ className: cn(
2111
+ "h-9 text-sm bg-theme-subtle border-theme-subtle",
2112
+ nameError && "border-rose-500/50 focus:border-rose-500"
2113
+ ),
2114
+ autoFocus: true
2115
+ }
2116
+ ),
2117
+ nameError && /* @__PURE__ */ jsx("p", { className: "text-[11px] text-rose-400 animate-in fade-in-0 slide-in-from-top-1 duration-[400ms]", children: nameError })
2118
+ ] }),
2119
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
2120
+ /* @__PURE__ */ jsxs(
2121
+ "button",
2122
+ {
2123
+ type: "button",
2124
+ onClick: () => setVisibility("WORKSPACE"),
2125
+ className: cn(
2126
+ "flex-1 flex items-center gap-2 px-3 py-2 rounded-sm text-xs transition-all duration-[400ms] ease-[cubic-bezier(0.25,1,0.5,1)] border",
2127
+ visibility === "WORKSPACE" ? "bg-primary/15 border-primary/30 text-primary-light" : "bg-theme-subtle border-theme-subtle text-theme-muted hover:bg-theme-subtle"
2128
+ ),
2129
+ children: [
2130
+ /* @__PURE__ */ jsx(OrgGlobe, { className: "w-3.5 h-3.5" }),
2131
+ "P\xFAblico"
2132
+ ]
2133
+ }
2134
+ ),
2135
+ /* @__PURE__ */ jsxs(
2136
+ "button",
2137
+ {
2138
+ type: "button",
2139
+ onClick: () => setVisibility("PRIVATE"),
2140
+ className: cn(
2141
+ "flex-1 flex items-center gap-2 px-3 py-2 rounded-sm text-xs transition-all duration-[400ms] ease-[cubic-bezier(0.25,1,0.5,1)] border",
2142
+ visibility === "PRIVATE" ? "bg-primary/15 border-primary/30 text-primary-light" : "bg-theme-subtle border-theme-subtle text-theme-muted hover:bg-theme-subtle"
2143
+ ),
2144
+ children: [
2145
+ /* @__PURE__ */ jsx(OrgLock, { className: "w-3.5 h-3.5" }),
2146
+ "Privado"
2147
+ ]
2148
+ }
2149
+ )
2150
+ ] }),
2151
+ !showAdvanced ? /* @__PURE__ */ jsx(
2152
+ "button",
2153
+ {
2154
+ type: "button",
2155
+ onClick: () => setShowAdvanced(true),
2156
+ className: "text-xs text-primary-light/70 hover:text-primary-light transition-colors",
2157
+ children: "+ Adicionar descri\xE7\xE3o e membros"
2158
+ }
2159
+ ) : /* @__PURE__ */ jsxs("div", { className: "space-y-4 animate-in fade-in-0 slide-in-from-top-2 duration-[400ms]", children: [
2160
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2161
+ /* @__PURE__ */ jsx(Label, { className: "text-theme-secondary text-xs", children: "Descri\xE7\xE3o (opcional)" }),
2162
+ /* @__PURE__ */ jsx(
2163
+ Textarea,
2164
+ {
2165
+ placeholder: "Sobre o que \xE9 este canal...",
2166
+ value: channelDesc,
2167
+ onChange: (e) => setChannelDesc(e.target.value),
2168
+ className: "min-h-[60px] text-sm bg-theme-subtle border-theme-subtle text-theme"
2169
+ }
2170
+ )
2171
+ ] }),
2172
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2173
+ /* @__PURE__ */ jsxs(Label, { className: "text-theme-secondary text-xs", children: [
2174
+ "Adicionar membros (",
2175
+ selectedMembers.length,
2176
+ " selecionados)"
2177
+ ] }),
2178
+ /* @__PURE__ */ jsx(ScrollArea, { className: "max-h-[150px] rounded-sm border border-theme-subtle bg-theme-subtle", children: /* @__PURE__ */ jsx("div", { className: "p-2 space-y-0.5", children: loadingMembers ? Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 p-2", children: [
2179
+ /* @__PURE__ */ jsx(Skeleton, { variant: "circular", className: "h-7 w-7" }),
2180
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-24" })
2181
+ ] }, i)) : workspaceMembers.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-xs text-theme-muted p-2 text-center", children: "Sem membros dispon\xEDveis" }) : workspaceMembers.map((member) => /* @__PURE__ */ jsxs(
2182
+ "button",
2183
+ {
2184
+ type: "button",
2185
+ onClick: () => toggleMember(member.id),
2186
+ className: cn(
2187
+ "flex items-center gap-2 w-full p-2 rounded-sm text-left text-xs transition-colors",
2188
+ selectedMembers.includes(member.id) ? "bg-primary/15 text-primary-light" : "text-theme-secondary hover:bg-theme-subtle"
2189
+ ),
2190
+ children: [
2191
+ /* @__PURE__ */ jsx(Avatar, { shape: "circle", size: "sm", className: "h-7 w-7", children: /* @__PURE__ */ jsx(AvatarFallback, { className: "bg-primary/20 text-primary-light text-[10px]", children: getInitials3(member.displayName) }) }),
2192
+ /* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: member.displayName }),
2193
+ selectedMembers.includes(member.id) && /* @__PURE__ */ jsx(Badge, { variant: "primary", className: "text-[9px] px-1 py-0 h-4", children: "\u2713" })
2194
+ ]
2195
+ },
2196
+ member.id
2197
+ )) }) })
2198
+ ] })
2199
+ ] }),
2200
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2 mt-6", children: [
2201
+ /* @__PURE__ */ jsx(
2202
+ Button,
2203
+ {
2204
+ variant: "ghost",
2205
+ size: "sm",
2206
+ onClick: () => onOpenChange(false),
2207
+ className: "text-xs text-theme-muted",
2208
+ children: "Cancelar"
2209
+ }
2210
+ ),
2211
+ /* @__PURE__ */ jsx(
2212
+ Button,
2213
+ {
2214
+ variant: "default",
2215
+ size: "sm",
2216
+ onClick: handleCreateChannel,
2217
+ disabled: !channelName.trim() || creating,
2218
+ className: "text-xs",
2219
+ children: creating ? "Criando..." : "Criar Canal"
2220
+ }
2221
+ )
2222
+ ] })
2223
+ ] }),
2224
+ /* @__PURE__ */ jsxs(TabsContent, { value: "dm", className: "space-y-3 mt-4", children: [
2225
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
2226
+ /* @__PURE__ */ jsx(OrgSearch, { className: "absolute left-3 top-1/2 -translate-y-1/2 w-3.5 h-3.5 text-theme-muted" }),
2227
+ /* @__PURE__ */ jsx(
2228
+ Input,
2229
+ {
2230
+ variant: "flat",
2231
+ placeholder: "Pesquisar membro...",
2232
+ value: dmSearch,
2233
+ onChange: (e) => setDmSearch(e.target.value),
2234
+ className: "h-9 text-sm bg-theme-subtle border-theme-subtle pl-9",
2235
+ autoFocus: true
2236
+ }
2237
+ )
2238
+ ] }),
2239
+ /* @__PURE__ */ jsx(ScrollArea, { className: "max-h-[280px]", children: /* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: loadingMembers ? Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 p-2.5", children: [
2240
+ /* @__PURE__ */ jsx(Skeleton, { variant: "circular", className: "h-8 w-8" }),
2241
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-1.5", children: [
2242
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-28" }),
2243
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-2 w-20" })
2244
+ ] })
2245
+ ] }, i)) : filteredMembers.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center py-8 text-theme-muted", children: [
2246
+ /* @__PURE__ */ jsx(OrgSearch, { className: "w-8 h-8 mb-2 opacity-50" }),
2247
+ /* @__PURE__ */ jsx("p", { className: "text-xs", children: dmSearch ? "Nenhum membro encontrado" : "Sem membros no workspace" })
2248
+ ] }) : filteredMembers.map((member) => /* @__PURE__ */ jsxs(
2249
+ "button",
2250
+ {
2251
+ onClick: () => handleCreateDM(member.id),
2252
+ disabled: creating,
2253
+ className: "flex items-center gap-3 w-full p-2.5 rounded-sm text-left transition-all duration-[400ms] ease-[cubic-bezier(0.25,1,0.5,1)] hover:bg-theme-subtle active:scale-[0.98] disabled:opacity-50",
2254
+ children: [
2255
+ /* @__PURE__ */ jsx(Avatar, { shape: "circle", size: "sm", className: "h-8 w-8", children: /* @__PURE__ */ jsx(AvatarFallback, { className: "bg-primary/20 text-primary-light text-xs", children: getInitials3(member.displayName) }) }),
2256
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
2257
+ /* @__PURE__ */ jsx("p", { className: "text-[13px] font-medium text-theme truncate", children: member.displayName }),
2258
+ member.email && /* @__PURE__ */ jsx("p", { className: "text-[11px] text-theme-muted truncate", children: member.email })
2259
+ ] }),
2260
+ member.status && /* @__PURE__ */ jsx(
2261
+ "span",
2262
+ {
2263
+ className: cn(
2264
+ "w-2 h-2 rounded-full flex-shrink-0",
2265
+ member.status === "ONLINE" && "bg-emerald-400 animate-pulse",
2266
+ member.status === "AWAY" && "bg-amber-400",
2267
+ member.status === "BUSY" && "bg-rose-400",
2268
+ member.status === "OFFLINE" && "bg-theme-subtle-20"
2269
+ )
2270
+ }
2271
+ )
2272
+ ]
2273
+ },
2274
+ member.id
2275
+ )) }) })
2276
+ ] })
2277
+ ] })
2278
+ }
2279
+ );
2280
+ }
2281
+ function Separator({
2282
+ className,
2283
+ orientation = "horizontal",
2284
+ decorative = true,
2285
+ ...props
2286
+ }) {
2287
+ return /* @__PURE__ */ jsx(
2288
+ SeparatorPrimitive.Root,
2289
+ {
2290
+ "data-slot": "separator",
2291
+ decorative,
2292
+ orientation,
2293
+ className: cn(
2294
+ "bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
2295
+ className
2296
+ ),
2297
+ ...props
2298
+ }
2299
+ );
2300
+ }
2301
+ var Select = SelectPrimitive.Root;
2302
+ var SelectGroup = SelectPrimitive.Group;
2303
+ var SelectValue = SelectPrimitive.Value;
2304
+ var SelectTrigger = React7.forwardRef(({ className, children, label, ...props }, ref) => /* @__PURE__ */ jsxs("div", { className: "relative group", children: [
2305
+ label && /* @__PURE__ */ jsx("span", { className: "absolute -top-3 right-0 z-10 mr-2 bg-theme-surface px-2 text-label uppercase tracking-widest text-theme-muted", children: label }),
2306
+ /* @__PURE__ */ jsxs(
2307
+ SelectPrimitive.Trigger,
2308
+ {
2309
+ ref,
2310
+ className: cn(
2311
+ "flex w-full items-center justify-between bg-theme-subtle backdrop-blur-md border border-theme-subtle px-4 py-3 text-sm font-light text-theme-secondary rounded-sm transition-all duration-[400ms] ease-[cubic-bezier(0.25,1,0.5,1)] focus:outline-none focus:shadow-[0_0_0_3px_rgba(79,57,246,0.10),0_0_20px_rgba(79,57,246,0.08)] focus:border-primary-light/50 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
2312
+ className
2313
+ ),
2314
+ ...props,
2315
+ children: [
2316
+ children,
2317
+ /* @__PURE__ */ jsx(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4 text-primary-light opacity-60" }) })
2318
+ ]
2319
+ }
2320
+ )
2321
+ ] }));
2322
+ SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
2323
+ var SelectScrollUpButton = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2324
+ SelectPrimitive.ScrollUpButton,
2325
+ {
2326
+ ref,
2327
+ className: cn("flex cursor-default items-center justify-center py-1", className),
2328
+ ...props,
2329
+ children: /* @__PURE__ */ jsx(ChevronUp, { className: "h-4 w-4 text-theme-muted" })
2330
+ }
2331
+ ));
2332
+ SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
2333
+ var SelectScrollDownButton = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2334
+ SelectPrimitive.ScrollDownButton,
2335
+ {
2336
+ ref,
2337
+ className: cn("flex cursor-default items-center justify-center py-1", className),
2338
+ ...props,
2339
+ children: /* @__PURE__ */ jsx(ChevronDown, { className: "h-4 w-4 text-theme-muted" })
2340
+ }
2341
+ ));
2342
+ SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
2343
+ var SelectContent = React7.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
2344
+ SelectPrimitive.Content,
2345
+ {
2346
+ ref,
2347
+ className: cn(
2348
+ "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-sm border border-glass-border bg-theme-glass-heavy backdrop-blur-[40px] saturate-[180%] text-theme shadow-glass data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
2349
+ position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
2350
+ className
2351
+ ),
2352
+ position,
2353
+ ...props,
2354
+ children: [
2355
+ /* @__PURE__ */ jsx(SelectScrollUpButton, {}),
2356
+ /* @__PURE__ */ jsx(
2357
+ SelectPrimitive.Viewport,
2358
+ {
2359
+ className: cn(
2360
+ "p-1",
2361
+ position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
2362
+ ),
2363
+ children
2364
+ }
2365
+ ),
2366
+ /* @__PURE__ */ jsx(SelectScrollDownButton, {})
2367
+ ]
2368
+ }
2369
+ ) }));
2370
+ SelectContent.displayName = SelectPrimitive.Content.displayName;
2371
+ var SelectItem = React7.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(
2372
+ SelectPrimitive.Item,
2373
+ {
2374
+ ref,
2375
+ className: cn(
2376
+ "relative flex w-full cursor-default select-none items-center rounded-sm py-2 pl-8 pr-2 text-sm font-light text-theme-secondary outline-none transition-colors duration-[400ms] ease-[cubic-bezier(0.25,1,0.5,1)] focus:bg-theme-subtle-10 focus:text-theme data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
2377
+ className
2378
+ ),
2379
+ ...props,
2380
+ children: [
2381
+ /* @__PURE__ */ jsx("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx(Check, { className: "h-4 w-4 text-primary-light" }) }) }),
2382
+ /* @__PURE__ */ jsx(SelectPrimitive.ItemText, { children })
2383
+ ]
2384
+ }
2385
+ ));
2386
+ SelectItem.displayName = SelectPrimitive.Item.displayName;
2387
+ var SelectSeparator = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2388
+ SelectPrimitive.Separator,
2389
+ {
2390
+ ref,
2391
+ className: cn("-mx-1 my-1 h-px bg-theme-subtle-10", className),
2392
+ ...props
2393
+ }
2394
+ ));
2395
+ SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
2396
+ var SelectLabel = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
2397
+ SelectPrimitive.Label,
2398
+ {
2399
+ ref,
2400
+ className: cn("py-1.5 pl-8 pr-2 text-label uppercase tracking-widest text-theme-muted", className),
2401
+ ...props
2402
+ }
2403
+ ));
2404
+ SelectLabel.displayName = SelectPrimitive.Label.displayName;
2405
+ function getInitials4(name) {
2406
+ return name.split(" ").map((w) => w[0]).slice(0, 2).join("").toUpperCase();
2407
+ }
2408
+ var roleBadgeColors = {
2409
+ OWNER: "bg-amber-500/15 text-amber-300 border-amber-500/30",
2410
+ ADMIN: "bg-blue-500/15 text-blue-300 border-blue-500/30",
2411
+ MEMBER: "bg-white/5 text-white/40 border-white/10"
2412
+ };
2413
+ var roleLabels = {
2414
+ OWNER: "Dono",
2415
+ ADMIN: "Admin",
2416
+ MEMBER: "Membro"
2417
+ };
2418
+ function RoomManagementPanel({
2419
+ room,
2420
+ members,
2421
+ permissions,
2422
+ currentUserId,
2423
+ loading,
2424
+ onClose,
2425
+ onUpdateRoom,
2426
+ onArchiveRoom,
2427
+ onLeaveRoom,
2428
+ onRemoveMember,
2429
+ onUpdateMemberRole,
2430
+ className
2431
+ }) {
2432
+ const [view, setView] = React7.useState("info");
2433
+ const [editName, setEditName] = React7.useState(room.name || "");
2434
+ const [editDesc, setEditDesc] = React7.useState(room.description || "");
2435
+ const [editVisibility, setEditVisibility] = React7.useState(room.visibility);
2436
+ const [saving, setSaving] = React7.useState(false);
2437
+ const [confirmArchive, setConfirmArchive] = React7.useState(false);
2438
+ React7.useEffect(() => {
2439
+ setEditName(room.name || "");
2440
+ setEditDesc(room.description || "");
2441
+ setEditVisibility(room.visibility);
2442
+ }, [room]);
2443
+ const handleSave = async () => {
2444
+ setSaving(true);
2445
+ try {
2446
+ await onUpdateRoom(room.id, {
2447
+ name: editName.trim(),
2448
+ description: editDesc.trim() || void 0,
2449
+ visibility: editVisibility
2450
+ });
2451
+ setView("info");
2452
+ } finally {
2453
+ setSaving(false);
2454
+ }
2455
+ };
2456
+ const renderHeader = (title, showBack) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-4 py-3 border-b border-theme-subtle", children: [
2457
+ showBack && /* @__PURE__ */ jsx(
2458
+ "button",
2459
+ {
2460
+ onClick: () => setView("info"),
2461
+ className: "p-1 rounded-sm hover:bg-theme-subtle text-theme-muted hover:text-theme transition-colors",
2462
+ children: /* @__PURE__ */ jsx(OrgChevronLeft, { className: "w-4 h-4" })
2463
+ }
2464
+ ),
2465
+ /* @__PURE__ */ jsx("h3", { className: "flex-1 text-sm font-semibold text-theme", children: title }),
2466
+ /* @__PURE__ */ jsx(
2467
+ "button",
2468
+ {
2469
+ onClick: onClose,
2470
+ className: "p-1 rounded-sm hover:bg-theme-subtle text-theme-muted hover:text-theme transition-colors",
2471
+ children: /* @__PURE__ */ jsx(OrgClose, { className: "w-4 h-4" })
2472
+ }
2473
+ )
2474
+ ] });
2475
+ const renderInfo = () => /* @__PURE__ */ jsxs(Fragment, { children: [
2476
+ renderHeader(room.name || "Detalhes"),
2477
+ /* @__PURE__ */ jsxs("div", { className: "p-4 space-y-4", children: [
2478
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
2479
+ /* @__PURE__ */ jsx(
2480
+ "div",
2481
+ {
2482
+ className: cn(
2483
+ "flex items-center justify-center h-12 w-12 rounded-sm text-lg",
2484
+ "bg-primary/15 text-primary-light"
2485
+ ),
2486
+ children: room.type === "DIRECT" ? "\u{1F4AC}" : "#"
2487
+ }
2488
+ ),
2489
+ /* @__PURE__ */ jsxs("div", { children: [
2490
+ /* @__PURE__ */ jsx("h4", { className: "text-[15px] font-semibold text-theme", children: room.name || "Sem nome" }),
2491
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mt-0.5", children: [
2492
+ /* @__PURE__ */ jsx(
2493
+ Badge,
2494
+ {
2495
+ variant: "default",
2496
+ className: "text-[10px] px-1.5 py-0 h-4 border-theme-subtle-10 text-theme-muted",
2497
+ children: room.type === "DIRECT" ? "DM" : room.visibility === "PRIVATE" ? "\u{1F512} Privado" : "\u{1F310} P\xFAblico"
2498
+ }
2499
+ ),
2500
+ /* @__PURE__ */ jsxs("span", { className: "text-[11px] text-theme-muted", children: [
2501
+ room.memberCount,
2502
+ " membros"
2503
+ ] })
2504
+ ] })
2505
+ ] })
2506
+ ] }),
2507
+ room.description && /* @__PURE__ */ jsx("p", { className: "text-xs text-theme-muted leading-relaxed", children: room.description }),
2508
+ /* @__PURE__ */ jsx(Separator, { className: "bg-theme-subtle" }),
2509
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
2510
+ /* @__PURE__ */ jsxs(
2511
+ "button",
2512
+ {
2513
+ onClick: () => setView("members"),
2514
+ className: "flex items-center gap-3 w-full px-3 py-2.5 rounded-sm text-sm text-theme-secondary hover:bg-theme-subtle hover:text-theme transition-colors",
2515
+ children: [
2516
+ /* @__PURE__ */ jsx(OrgTeam, { className: "w-4 h-4 text-theme-muted" }),
2517
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-left", children: "Membros" }),
2518
+ /* @__PURE__ */ jsx(Badge, { variant: "default", className: "text-[10px] px-1.5 py-0 h-4 border-theme-subtle-10 text-theme-muted", children: members.length })
2519
+ ]
2520
+ }
2521
+ ),
2522
+ permissions.canEditRoomSettings && room.type !== "DIRECT" && /* @__PURE__ */ jsxs(
2523
+ "button",
2524
+ {
2525
+ onClick: () => setView("edit"),
2526
+ className: "flex items-center gap-3 w-full px-3 py-2.5 rounded-sm text-sm text-theme-secondary hover:bg-theme-subtle hover:text-theme transition-colors",
2527
+ children: [
2528
+ /* @__PURE__ */ jsx(OrgEdit, { className: "w-4 h-4 text-theme-muted" }),
2529
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-left", children: "Editar canal" })
2530
+ ]
2531
+ }
2532
+ ),
2533
+ /* @__PURE__ */ jsx(Separator, { className: "bg-theme-subtle my-2" }),
2534
+ /* @__PURE__ */ jsxs(
2535
+ "button",
2536
+ {
2537
+ onClick: () => onLeaveRoom(room.id),
2538
+ className: "flex items-center gap-3 w-full px-3 py-2.5 rounded-sm text-sm text-theme-muted hover:bg-rose-500/10 hover:text-rose-400 transition-colors",
2539
+ children: [
2540
+ /* @__PURE__ */ jsx(OrgDoor, { className: "w-4 h-4" }),
2541
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-left", children: "Sair do canal" })
2542
+ ]
2543
+ }
2544
+ ),
2545
+ permissions.canArchiveRoom && /* @__PURE__ */ jsx(Fragment, { children: !confirmArchive ? /* @__PURE__ */ jsxs(
2546
+ "button",
2547
+ {
2548
+ onClick: () => setConfirmArchive(true),
2549
+ className: "flex items-center gap-3 w-full px-3 py-2.5 rounded-sm text-sm text-theme-muted hover:bg-rose-500/10 hover:text-rose-400 transition-colors",
2550
+ children: [
2551
+ /* @__PURE__ */ jsx(OrgTrash, { className: "w-4 h-4" }),
2552
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-left", children: "Arquivar canal" })
2553
+ ]
2554
+ }
2555
+ ) : /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-3 py-2 rounded-sm bg-rose-500/10 border border-rose-500/20 animate-in fade-in-0 duration-[400ms]", children: [
2556
+ /* @__PURE__ */ jsx("p", { className: "flex-1 text-xs text-rose-300", children: "Tem certeza?" }),
2557
+ /* @__PURE__ */ jsx(
2558
+ Button,
2559
+ {
2560
+ variant: "ghost",
2561
+ size: "sm",
2562
+ onClick: () => setConfirmArchive(false),
2563
+ className: "h-6 px-2 text-[10px] text-theme-muted",
2564
+ children: "N\xE3o"
2565
+ }
2566
+ ),
2567
+ /* @__PURE__ */ jsx(
2568
+ Button,
2569
+ {
2570
+ variant: "destructive",
2571
+ size: "sm",
2572
+ onClick: () => onArchiveRoom(room.id),
2573
+ className: "h-6 px-2 text-[10px]",
2574
+ children: "Sim, arquivar"
2575
+ }
2576
+ )
2577
+ ] }) })
2578
+ ] })
2579
+ ] })
2580
+ ] });
2581
+ const renderMembers = () => /* @__PURE__ */ jsxs(Fragment, { children: [
2582
+ renderHeader("Membros", true),
2583
+ /* @__PURE__ */ jsx(ScrollArea, { className: "flex-1", children: /* @__PURE__ */ jsx("div", { className: "p-3 space-y-0.5", children: loading ? Array.from({ length: 4 }).map((_, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 p-2", children: [
2584
+ /* @__PURE__ */ jsx(Skeleton, { variant: "circular", className: "h-8 w-8" }),
2585
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-1", children: [
2586
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-24" }),
2587
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-2 w-16" })
2588
+ ] })
2589
+ ] }, i)) : members.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-xs text-theme-muted text-center py-8", children: "Sem membros" }) : members.map((member) => /* @__PURE__ */ jsxs(
2590
+ "div",
2591
+ {
2592
+ className: "flex items-center gap-3 p-2 rounded-sm hover:bg-theme-subtle group transition-colors",
2593
+ children: [
2594
+ /* @__PURE__ */ jsx(Avatar, { shape: "circle", size: "sm", className: "h-8 w-8", children: /* @__PURE__ */ jsx(AvatarFallback, { className: "bg-primary/20 text-primary-light text-xs", children: getInitials4(member.displayName || member.userId.substring(0, 8)) }) }),
2595
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
2596
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2597
+ /* @__PURE__ */ jsx("span", { className: "text-[13px] font-medium text-theme truncate", children: member.displayName || member.userId.substring(0, 8) }),
2598
+ member.userId === currentUserId && /* @__PURE__ */ jsx("span", { className: "text-[10px] text-theme-muted", children: "(voc\xEA)" })
2599
+ ] }),
2600
+ /* @__PURE__ */ jsx(
2601
+ Badge,
2602
+ {
2603
+ variant: "default",
2604
+ className: cn(
2605
+ "text-[9px] px-1 py-0 h-3.5 border mt-0.5",
2606
+ roleBadgeColors[member.role]
2607
+ ),
2608
+ children: roleLabels[member.role]
2609
+ }
2610
+ )
2611
+ ] }),
2612
+ permissions.canManageMembers && member.userId !== currentUserId && member.role !== "OWNER" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity", children: [
2613
+ /* @__PURE__ */ jsxs(
2614
+ Select,
2615
+ {
2616
+ value: member.role,
2617
+ onValueChange: (val) => onUpdateMemberRole(room.id, member.userId, val),
2618
+ children: [
2619
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "h-6 w-20 text-[10px] bg-theme-subtle border-theme-subtle-10", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
2620
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
2621
+ /* @__PURE__ */ jsx(SelectItem, { value: "ADMIN", children: "Admin" }),
2622
+ /* @__PURE__ */ jsx(SelectItem, { value: "MEMBER", children: "Membro" })
2623
+ ] })
2624
+ ]
2625
+ }
2626
+ ),
2627
+ /* @__PURE__ */ jsx(
2628
+ Button,
2629
+ {
2630
+ variant: "ghost",
2631
+ size: "sm",
2632
+ onClick: () => onRemoveMember(room.id, member.userId),
2633
+ className: "h-6 w-6 p-0 text-theme-muted hover:text-rose-400 hover:bg-rose-500/10",
2634
+ children: /* @__PURE__ */ jsx(OrgClose, { className: "w-3 h-3" })
2635
+ }
2636
+ )
2637
+ ] })
2638
+ ]
2639
+ },
2640
+ member.id
2641
+ )) }) })
2642
+ ] });
2643
+ const renderEdit = () => /* @__PURE__ */ jsxs(Fragment, { children: [
2644
+ renderHeader("Editar canal", true),
2645
+ /* @__PURE__ */ jsxs("div", { className: "p-4 space-y-4", children: [
2646
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2647
+ /* @__PURE__ */ jsx(Label, { className: "text-theme-secondary text-xs", children: "Nome" }),
2648
+ /* @__PURE__ */ jsx(
2649
+ Input,
2650
+ {
2651
+ variant: "flat",
2652
+ value: editName,
2653
+ onChange: (e) => setEditName(e.target.value),
2654
+ className: "h-9 text-sm bg-theme-subtle border-theme-subtle"
2655
+ }
2656
+ )
2657
+ ] }),
2658
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2659
+ /* @__PURE__ */ jsx(Label, { className: "text-theme-secondary text-xs", children: "Descri\xE7\xE3o" }),
2660
+ /* @__PURE__ */ jsx(
2661
+ Textarea,
2662
+ {
2663
+ value: editDesc,
2664
+ onChange: (e) => setEditDesc(e.target.value),
2665
+ className: "min-h-[60px] text-sm bg-theme-subtle border-theme-subtle text-theme",
2666
+ placeholder: "Descri\xE7\xE3o do canal..."
2667
+ }
2668
+ )
2669
+ ] }),
2670
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2671
+ /* @__PURE__ */ jsx(Label, { className: "text-theme-secondary text-xs", children: "Visibilidade" }),
2672
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
2673
+ /* @__PURE__ */ jsxs(
2674
+ "button",
2675
+ {
2676
+ type: "button",
2677
+ onClick: () => setEditVisibility("WORKSPACE"),
2678
+ className: cn(
2679
+ "flex-1 flex items-center gap-2 px-3 py-2 rounded-sm text-xs transition-all duration-[400ms] border",
2680
+ editVisibility === "WORKSPACE" ? "bg-primary/15 border-primary/30 text-primary-light" : "bg-theme-subtle border-theme-subtle text-theme-muted hover:bg-theme-subtle"
2681
+ ),
2682
+ children: [
2683
+ /* @__PURE__ */ jsx(OrgGlobe, { className: "w-3.5 h-3.5" }),
2684
+ "P\xFAblico"
2685
+ ]
2686
+ }
2687
+ ),
2688
+ /* @__PURE__ */ jsxs(
2689
+ "button",
2690
+ {
2691
+ type: "button",
2692
+ onClick: () => setEditVisibility("PRIVATE"),
2693
+ className: cn(
2694
+ "flex-1 flex items-center gap-2 px-3 py-2 rounded-sm text-xs transition-all duration-[400ms] border",
2695
+ editVisibility === "PRIVATE" ? "bg-primary/15 border-primary/30 text-primary-light" : "bg-theme-subtle border-theme-subtle text-theme-muted hover:bg-theme-subtle"
2696
+ ),
2697
+ children: [
2698
+ /* @__PURE__ */ jsx(OrgLock, { className: "w-3.5 h-3.5" }),
2699
+ "Privado"
2700
+ ]
2701
+ }
2702
+ )
2703
+ ] })
2704
+ ] }),
2705
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 pt-2", children: [
2706
+ /* @__PURE__ */ jsx(
2707
+ Button,
2708
+ {
2709
+ variant: "ghost",
2710
+ size: "sm",
2711
+ onClick: () => setView("info"),
2712
+ className: "text-xs text-theme-muted",
2713
+ children: "Cancelar"
2714
+ }
2715
+ ),
2716
+ /* @__PURE__ */ jsx(
2717
+ Button,
2718
+ {
2719
+ variant: "default",
2720
+ size: "sm",
2721
+ onClick: handleSave,
2722
+ disabled: !editName.trim() || saving,
2723
+ className: "text-xs",
2724
+ children: saving ? "Salvando..." : "Salvar"
2725
+ }
2726
+ )
2727
+ ] })
2728
+ ] })
2729
+ ] });
2730
+ return /* @__PURE__ */ jsxs(
2731
+ "div",
2732
+ {
2733
+ className: cn(
2734
+ "flex flex-col h-full border-l border-theme-subtle bg-theme-surface w-[280px] shrink-0",
2735
+ "animate-in slide-in-from-right-5 duration-[400ms]",
2736
+ className
2737
+ ),
2738
+ children: [
2739
+ view === "info" && renderInfo(),
2740
+ view === "members" && renderMembers(),
2741
+ view === "edit" && renderEdit()
2742
+ ]
2743
+ }
2744
+ );
2745
+ }
2746
+
2747
+ // src/components/chat/types.ts
2748
+ function getRoomPermissions(role, isWorkspaceAdmin) {
2749
+ const isOwnerOrAdmin = role === "OWNER" || role === "ADMIN" || isWorkspaceAdmin;
2750
+ return {
2751
+ canCreateChannel: true,
2752
+ canCreateDM: true,
2753
+ canDeleteRoom: role === "OWNER" || !!isWorkspaceAdmin,
2754
+ canArchiveRoom: isOwnerOrAdmin ?? false,
2755
+ canManageMembers: isOwnerOrAdmin ?? false,
2756
+ canEditRoomSettings: isOwnerOrAdmin ?? false
2757
+ };
2758
+ }
2759
+
2760
+ // src/components/chat/use-chat.ts
2761
+ function useChat(options = {}) {
2762
+ const {
2763
+ workspaceRole,
2764
+ initialRooms,
2765
+ initialMessages
2766
+ } = options;
2767
+ const api = useOrganifyApi();
2768
+ const { gatewayUrl, authToken } = api;
2769
+ const user = useOrganifyUser();
2770
+ const { workspace } = useOrganifyWorkspace();
2771
+ const userId = user?.id ?? "";
2772
+ const workspaceId = workspace?.id ?? "";
2773
+ const [rooms, setRooms] = useState(initialRooms ?? []);
2774
+ const [messages, setMessages] = useState(initialMessages ?? []);
2775
+ const [activeRoomId, setActiveRoomId] = useState(null);
2776
+ const [loadingRooms, setLoadingRooms] = useState(false);
2777
+ const [loadingMessages, setLoadingMessages] = useState(false);
2778
+ const [hasMoreMessages, setHasMoreMessages] = useState(false);
2779
+ const [messageCursor, setMessageCursor] = useState(null);
2780
+ const [loadingMoreMessages, setLoadingMoreMessages] = useState(false);
2781
+ const [roomMembers, setRoomMembers] = useState([]);
2782
+ const [myRoomRole, setMyRoomRole] = useState(null);
2783
+ const [typingUsers, setTypingUsers] = useState([]);
2784
+ const [error, setError] = useState(null);
2785
+ const isWorkspaceAdmin = workspaceRole === "OWNER" || workspaceRole === "ADMIN";
2786
+ const isDemoMode = !!(initialRooms && initialRooms.length > 0);
2787
+ const permissions = getRoomPermissions(myRoomRole, isWorkspaceAdmin);
2788
+ const centralGql = useOrganifyGql();
2789
+ const gql = useCallback(
2790
+ async (query, variables) => {
2791
+ return centralGql("chat", query, variables);
2792
+ },
2793
+ [centralGql]
2794
+ );
2795
+ const [userCache, setUserCache] = useState(/* @__PURE__ */ new Map());
2796
+ const enrichedMessages = React7__default.useMemo(() => {
2797
+ return messages.map((msg) => {
2798
+ const cached = userCache.get(msg.authorId);
2799
+ if (cached && !msg.authorName) {
2800
+ return { ...msg, authorName: cached.displayName, authorAvatar: cached.avatarUrl };
2801
+ }
2802
+ return msg;
2803
+ });
2804
+ }, [messages, userCache]);
2805
+ useEffect(() => {
2806
+ setUserCache((prev) => {
2807
+ const next = new Map(prev);
2808
+ if (userId && user?.name) {
2809
+ next.set(userId, { displayName: user.name, avatarUrl: user.avatarUrl ?? void 0 });
2810
+ }
2811
+ if (options.workspaceMembers) {
2812
+ for (const member of options.workspaceMembers) {
2813
+ if (member.id && !next.has(member.id)) {
2814
+ next.set(member.id, {
2815
+ displayName: member.displayName || member.email || `User`,
2816
+ avatarUrl: member.avatarUrl ?? void 0
2817
+ });
2818
+ }
2819
+ }
2820
+ }
2821
+ return next;
2822
+ });
2823
+ }, [userId, user, options.workspaceMembers]);
2824
+ const fetchRooms = useCallback(async () => {
2825
+ if (initialRooms && initialRooms.length > 0) return;
2826
+ if (!workspaceId || workspaceId.startsWith("temp-")) return;
2827
+ if (!userId) return;
2828
+ setLoadingRooms(true);
2829
+ setError(null);
2830
+ try {
2831
+ const data = await gql(
2832
+ `query($workspaceId: String!) {
2833
+ rooms(workspaceId: $workspaceId) {
2834
+ items {
2835
+ id name slug type visibility description
2836
+ memberCount unreadCount avatarUrl createdBy
2837
+ archived lastMessageAt
2838
+ }
2839
+ total hasMore
2840
+ }
2841
+ }`,
2842
+ { workspaceId }
2843
+ );
2844
+ setRooms(data.rooms?.items ?? []);
2845
+ } catch (err) {
2846
+ console.error("[organify-chat] fetchRooms:", err);
2847
+ setError("N\xE3o foi poss\xEDvel carregar as conversas. Tente novamente.");
2848
+ } finally {
2849
+ setLoadingRooms(false);
2850
+ }
2851
+ }, [workspaceId, userId, gql, initialRooms]);
2852
+ const MESSAGE_FIELDS = `
2853
+ id roomId authorId parentId
2854
+ content edited editedAt createdAt
2855
+ mentions { type targetId display }
2856
+ reactions { emoji userId }
2857
+ `;
2858
+ const fetchMessages = useCallback(
2859
+ async (roomId) => {
2860
+ if (initialMessages && initialMessages.length > 0) {
2861
+ const roomMessages = initialMessages.filter((m) => m.roomId === roomId);
2862
+ setMessages(roomMessages);
2863
+ setHasMoreMessages(false);
2864
+ setMessageCursor(null);
2865
+ return;
2866
+ }
2867
+ if (!userId) return;
2868
+ setLoadingMessages(true);
2869
+ setError(null);
2870
+ try {
2871
+ const data = await gql(
2872
+ `query($roomId: ID!, $filter: MessageFilterInput) {
2873
+ messages(roomId: $roomId, filter: $filter) {
2874
+ items { ${MESSAGE_FIELDS} }
2875
+ total hasMore nextCursor
2876
+ }
2877
+ }`,
2878
+ { roomId, filter: { limit: 50 } }
2879
+ );
2880
+ setMessages(data.messages?.items ?? []);
2881
+ setHasMoreMessages(data.messages?.hasMore ?? false);
2882
+ setMessageCursor(data.messages?.nextCursor ?? null);
2883
+ } catch (err) {
2884
+ console.error("[organify-chat] fetchMessages:", err);
2885
+ setError("Erro ao carregar mensagens.");
2886
+ } finally {
2887
+ setLoadingMessages(false);
2888
+ }
2889
+ },
2890
+ [gql, initialMessages, userId]
2891
+ );
2892
+ const loadMoreMessages = useCallback(
2893
+ async () => {
2894
+ if (!activeRoomId || !hasMoreMessages || !messageCursor || loadingMoreMessages || !userId) return;
2895
+ setLoadingMoreMessages(true);
2896
+ try {
2897
+ const data = await gql(
2898
+ `query($roomId: ID!, $filter: MessageFilterInput) {
2899
+ messages(roomId: $roomId, filter: $filter) {
2900
+ items { ${MESSAGE_FIELDS} }
2901
+ total hasMore nextCursor
2902
+ }
2903
+ }`,
2904
+ { roomId: activeRoomId, filter: { limit: 50, cursor: messageCursor } }
2905
+ );
2906
+ const olderMessages = data.messages?.items ?? [];
2907
+ setMessages((prev) => [...olderMessages, ...prev]);
2908
+ setHasMoreMessages(data.messages?.hasMore ?? false);
2909
+ setMessageCursor(data.messages?.nextCursor ?? null);
2910
+ } catch (err) {
2911
+ console.error("[organify-chat] loadMore:", err);
2912
+ } finally {
2913
+ setLoadingMoreMessages(false);
2914
+ }
2915
+ },
2916
+ [gql, activeRoomId, hasMoreMessages, messageCursor, loadingMoreMessages, userId]
2917
+ );
2918
+ const fetchRoomMembers = useCallback(
2919
+ async (roomId) => {
2920
+ if (isDemoMode) return;
2921
+ try {
2922
+ const data = await gql(
2923
+ `query($roomId: ID!) {
2924
+ room(id: $roomId) {
2925
+ members {
2926
+ id userId role muted pinned joinedAt
2927
+ }
2928
+ }
2929
+ }`,
2930
+ { roomId }
2931
+ );
2932
+ const members = data?.room?.members ?? [];
2933
+ setRoomMembers(members);
2934
+ const myMembership = members.find((m) => m.userId === userId);
2935
+ setMyRoomRole(myMembership?.role ?? null);
2936
+ } catch (err) {
2937
+ console.error("[organify-chat] fetchRoomMembers:", err);
2938
+ }
2939
+ },
2940
+ [gql, userId, isDemoMode]
2941
+ );
2942
+ const selectRoom = useCallback(
2943
+ (roomId) => {
2944
+ if (activeRoomId === roomId) return;
2945
+ if (!workspaceId || workspaceId.startsWith("temp-")) {
2946
+ setActiveRoomId(roomId);
2947
+ setMessages([]);
2948
+ setRoomMembers([]);
2949
+ setMyRoomRole(null);
2950
+ setTypingUsers([]);
2951
+ setHasMoreMessages(false);
2952
+ setMessageCursor(null);
2953
+ return;
2954
+ }
2955
+ setActiveRoomId(roomId);
2956
+ setMessages([]);
2957
+ setRoomMembers([]);
2958
+ setMyRoomRole(null);
2959
+ setTypingUsers([]);
2960
+ setHasMoreMessages(false);
2961
+ setMessageCursor(null);
2962
+ fetchMessages(roomId);
2963
+ fetchRoomMembers(roomId);
2964
+ },
2965
+ [activeRoomId, workspaceId, fetchMessages, fetchRoomMembers]
2966
+ );
2967
+ const sendMessage = useCallback(
2968
+ async (content, replyToId) => {
2969
+ if (!activeRoomId || !content.trim()) return;
2970
+ const tempId = `temp_${Date.now()}_${Math.random().toString(36).slice(2)}`;
2971
+ const optimisticMsg = {
2972
+ id: tempId,
2973
+ roomId: activeRoomId,
2974
+ authorId: userId,
2975
+ content: content.trim(),
2976
+ edited: false,
2977
+ editedAt: null,
2978
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2979
+ mentions: [],
2980
+ reactions: [],
2981
+ replyToId: replyToId ?? null,
2982
+ _status: "pending"
2983
+ };
2984
+ setMessages((prev) => [...prev, optimisticMsg]);
2985
+ if (isDemoMode) {
2986
+ setMessages(
2987
+ (prev) => prev.map((m) => m.id === tempId ? { ...m, id: `demo_${Date.now()}`, _status: "sent" } : m)
2988
+ );
2989
+ return;
2990
+ }
2991
+ try {
2992
+ const input = { roomId: activeRoomId, content: content.trim() };
2993
+ if (replyToId) input.parentId = replyToId;
2994
+ const data = await gql(
2995
+ `mutation($input: SendMessageInput!) {
2996
+ sendMessage(input: $input) {
2997
+ id roomId authorId parentId
2998
+ content edited editedAt createdAt
2999
+ mentions { type targetId display }
3000
+ reactions { emoji userId }
3001
+ }
3002
+ }`,
3003
+ { input }
3004
+ );
3005
+ if (data?.sendMessage) {
3006
+ setMessages(
3007
+ (prev) => prev.map((m) => m.id === tempId ? { ...data.sendMessage, _status: "sent" } : m)
3008
+ );
3009
+ } else {
3010
+ setMessages(
3011
+ (prev) => prev.map((m) => m.id === tempId ? { ...m, _status: "error" } : m)
3012
+ );
3013
+ }
3014
+ } catch (err) {
3015
+ console.error("[organify-chat] sendMessage:", err);
3016
+ setMessages(
3017
+ (prev) => prev.map((m) => m.id === tempId ? { ...m, _status: "error" } : m)
3018
+ );
3019
+ }
3020
+ },
3021
+ [activeRoomId, gql, userId, isDemoMode]
3022
+ );
3023
+ const createRoom = useCallback(
3024
+ async (input) => {
3025
+ setError(null);
3026
+ if (isDemoMode) {
3027
+ const newRoom = {
3028
+ id: `demo_room_${Date.now()}`,
3029
+ name: input.name,
3030
+ slug: input.name.toLowerCase().replace(/\s+/g, "-"),
3031
+ type: input.type,
3032
+ visibility: input.visibility,
3033
+ description: input.description ?? null,
3034
+ memberCount: 1,
3035
+ unreadCount: 0,
3036
+ avatarUrl: null,
3037
+ createdBy: userId,
3038
+ archived: false,
3039
+ lastMessageAt: null
3040
+ };
3041
+ setRooms((prev) => [newRoom, ...prev]);
3042
+ return newRoom;
3043
+ }
3044
+ try {
3045
+ const data = await gql(
3046
+ `mutation($input: CreateRoomInput!) {
3047
+ createRoom(input: $input) {
3048
+ id name slug type visibility description
3049
+ memberCount unreadCount avatarUrl createdBy
3050
+ archived lastMessageAt
3051
+ }
3052
+ }`,
3053
+ {
3054
+ input: {
3055
+ ...input,
3056
+ workspaceId
3057
+ }
3058
+ }
3059
+ );
3060
+ const newRoom = data?.createRoom;
3061
+ if (!newRoom) throw new Error("Failed to create room");
3062
+ setRooms((prev) => [newRoom, ...prev]);
3063
+ return newRoom;
3064
+ } catch (err) {
3065
+ console.error("[organify-chat] createRoom:", err);
3066
+ setError(err.message || "N\xE3o foi poss\xEDvel criar a sala.");
3067
+ return null;
3068
+ }
3069
+ },
3070
+ [gql, workspaceId, isDemoMode, userId]
3071
+ );
3072
+ const createDirectMessage = useCallback(
3073
+ async (targetUserId) => {
3074
+ setError(null);
3075
+ if (isDemoMode) {
3076
+ const dm = {
3077
+ id: `demo_dm_${Date.now()}`,
3078
+ name: targetUserId,
3079
+ slug: null,
3080
+ type: "DIRECT",
3081
+ visibility: "PRIVATE",
3082
+ description: null,
3083
+ memberCount: 2,
3084
+ unreadCount: 0,
3085
+ avatarUrl: null,
3086
+ createdBy: userId,
3087
+ archived: false,
3088
+ lastMessageAt: null
3089
+ };
3090
+ setRooms((prev) => [dm, ...prev]);
3091
+ return dm;
3092
+ }
3093
+ try {
3094
+ const data = await gql(
3095
+ `mutation($input: CreateRoomInput!) {
3096
+ createRoom(input: $input) {
3097
+ id name slug type visibility description
3098
+ memberCount unreadCount avatarUrl createdBy
3099
+ archived lastMessageAt
3100
+ members { userId role }
3101
+ }
3102
+ }`,
3103
+ {
3104
+ input: {
3105
+ workspaceId,
3106
+ name: "DM",
3107
+ type: "DIRECT",
3108
+ visibility: "PRIVATE",
3109
+ memberIds: [targetUserId]
3110
+ }
3111
+ }
3112
+ );
3113
+ const dm = data?.createRoom;
3114
+ if (!dm) throw new Error("Failed to create DM");
3115
+ setRooms((prev) => {
3116
+ if (prev.find((r) => r.id === dm.id)) return prev;
3117
+ return [dm, ...prev];
3118
+ });
3119
+ return dm;
3120
+ } catch (err) {
3121
+ console.error("[organify-chat] createDM:", err);
3122
+ setError(err.message || "N\xE3o foi poss\xEDvel iniciar a conversa.");
3123
+ return null;
3124
+ }
3125
+ },
3126
+ [gql, workspaceId, isDemoMode, userId]
3127
+ );
3128
+ const updateRoom = useCallback(
3129
+ async (roomId, updates) => {
3130
+ if (!permissions.canEditRoomSettings) return;
3131
+ if (isDemoMode) {
3132
+ setRooms((prev) => prev.map((r) => r.id === roomId ? { ...r, ...updates } : r));
3133
+ return;
3134
+ }
3135
+ try {
3136
+ const data = await gql(
3137
+ `mutation($id: ID!, $input: UpdateRoomInput!) {
3138
+ updateRoom(id: $id, input: $input) {
3139
+ id name slug type visibility description
3140
+ memberCount unreadCount avatarUrl createdBy
3141
+ archived lastMessageAt
3142
+ }
3143
+ }`,
3144
+ { id: roomId, input: updates }
3145
+ );
3146
+ if (data?.updateRoom) {
3147
+ setRooms((prev) => prev.map((r) => r.id === roomId ? data.updateRoom : r));
3148
+ }
3149
+ } catch (err) {
3150
+ setError(err.message || "Erro ao atualizar sala.");
3151
+ }
3152
+ },
3153
+ [gql, permissions.canEditRoomSettings, isDemoMode]
3154
+ );
3155
+ const archiveRoom = useCallback(
3156
+ async (roomId) => {
3157
+ if (!permissions.canArchiveRoom) return;
3158
+ if (isDemoMode) {
3159
+ setRooms((prev) => prev.filter((r) => r.id !== roomId));
3160
+ if (activeRoomId === roomId) {
3161
+ setActiveRoomId(null);
3162
+ setMessages([]);
3163
+ }
3164
+ return;
3165
+ }
3166
+ try {
3167
+ await gql(
3168
+ `mutation($id: ID!, $input: UpdateRoomInput!) {
3169
+ updateRoom(id: $id, input: $input) { id archived }
3170
+ }`,
3171
+ { id: roomId, input: { archived: true } }
3172
+ );
3173
+ setRooms((prev) => prev.filter((r) => r.id !== roomId));
3174
+ if (activeRoomId === roomId) {
3175
+ setActiveRoomId(null);
3176
+ setMessages([]);
3177
+ }
3178
+ } catch (err) {
3179
+ setError(err.message || "Erro ao arquivar sala.");
3180
+ }
3181
+ },
3182
+ [gql, permissions.canArchiveRoom, activeRoomId, isDemoMode]
3183
+ );
3184
+ const leaveRoom = useCallback(
3185
+ async (roomId) => {
3186
+ if (isDemoMode) {
3187
+ setRooms((prev) => prev.filter((r) => r.id !== roomId));
3188
+ if (activeRoomId === roomId) {
3189
+ setActiveRoomId(null);
3190
+ setMessages([]);
3191
+ }
3192
+ return;
3193
+ }
3194
+ try {
3195
+ await gql(
3196
+ `mutation($roomId: ID!) { leaveRoom(roomId: $roomId) }`,
3197
+ { roomId }
3198
+ );
3199
+ setRooms((prev) => prev.filter((r) => r.id !== roomId));
3200
+ if (activeRoomId === roomId) {
3201
+ setActiveRoomId(null);
3202
+ setMessages([]);
3203
+ }
3204
+ } catch (err) {
3205
+ setError(err.message || "Erro ao sair da sala.");
3206
+ }
3207
+ },
3208
+ [gql, activeRoomId, isDemoMode]
3209
+ );
3210
+ const addMember = useCallback(
3211
+ async (roomId, targetUserId, _role = "MEMBER") => {
3212
+ if (!permissions.canManageMembers) return;
3213
+ if (isDemoMode) return;
3214
+ try {
3215
+ await gql(
3216
+ `mutation($roomId: ID!, $userId: String!) {
3217
+ inviteToRoom(roomId: $roomId, userId: $userId) { id userId role }
3218
+ }`,
3219
+ { roomId, userId: targetUserId }
3220
+ );
3221
+ fetchRoomMembers(roomId);
3222
+ } catch (err) {
3223
+ setError(err.message || "Erro ao adicionar membro.");
3224
+ }
3225
+ },
3226
+ [gql, permissions.canManageMembers, fetchRoomMembers, isDemoMode]
3227
+ );
3228
+ const removeMember = useCallback(
3229
+ async (roomId, targetUserId) => {
3230
+ if (!permissions.canManageMembers) return;
3231
+ if (isDemoMode) return;
3232
+ try {
3233
+ await gql(
3234
+ `mutation($roomId: ID!, $targetUserId: String!) {
3235
+ removeMember(roomId: $roomId, targetUserId: $targetUserId)
3236
+ }`,
3237
+ { roomId, targetUserId }
3238
+ );
3239
+ setRoomMembers((prev) => prev.filter((m) => m.userId !== targetUserId));
3240
+ } catch (err) {
3241
+ setError(err.message || "Erro ao remover membro.");
3242
+ }
3243
+ },
3244
+ [gql, permissions.canManageMembers, isDemoMode]
3245
+ );
3246
+ const updateMemberRole = useCallback(
3247
+ async (roomId, targetUserId, role) => {
3248
+ if (!permissions.canManageMembers) return;
3249
+ if (isDemoMode) return;
3250
+ try {
3251
+ await gql(
3252
+ `mutation($roomId: ID!, $targetUserId: String!, $role: MemberRole!) {
3253
+ updateMemberRole(roomId: $roomId, targetUserId: $targetUserId, role: $role) { id userId role }
3254
+ }`,
3255
+ { roomId, targetUserId, role }
3256
+ );
3257
+ setRoomMembers(
3258
+ (prev) => prev.map((m) => m.userId === targetUserId ? { ...m, role } : m)
3259
+ );
3260
+ } catch (err) {
3261
+ setError(err.message || "Erro ao atualizar cargo.");
3262
+ }
3263
+ },
3264
+ [gql, permissions.canManageMembers, isDemoMode]
3265
+ );
3266
+ const editMessage = useCallback(
3267
+ async (messageId, content) => {
3268
+ if (!content.trim()) return;
3269
+ if (isDemoMode) {
3270
+ setMessages(
3271
+ (prev) => prev.map(
3272
+ (m) => m.id === messageId ? { ...m, content: content.trim(), edited: true, editedAt: (/* @__PURE__ */ new Date()).toISOString() } : m
3273
+ )
3274
+ );
3275
+ return;
3276
+ }
3277
+ try {
3278
+ const data = await gql(
3279
+ `mutation($id: ID!, $input: EditMessageInput!) {
3280
+ editMessage(id: $id, input: $input) {
3281
+ id roomId authorId parentId
3282
+ content edited editedAt createdAt
3283
+ mentions { type targetId display }
3284
+ reactions { emoji userId }
3285
+ }
3286
+ }`,
3287
+ { id: messageId, input: { content: content.trim() } }
3288
+ );
3289
+ if (data?.editMessage) {
3290
+ setMessages(
3291
+ (prev) => prev.map((m) => m.id === messageId ? { ...data.editMessage, _status: "sent" } : m)
3292
+ );
3293
+ }
3294
+ } catch (err) {
3295
+ console.error("[organify-chat] editMessage:", err);
3296
+ setError(err.message || "Erro ao editar mensagem.");
3297
+ }
3298
+ },
3299
+ [gql, isDemoMode]
3300
+ );
3301
+ const deleteMessage = useCallback(
3302
+ async (messageId) => {
3303
+ if (isDemoMode) {
3304
+ setMessages((prev) => prev.filter((m) => m.id !== messageId));
3305
+ return;
3306
+ }
3307
+ const msg = messages.find((m) => m.id === messageId);
3308
+ if (!msg) return;
3309
+ try {
3310
+ await gql(
3311
+ `mutation($id: ID!, $roomId: ID!) {
3312
+ deleteMessage(id: $id, roomId: $roomId)
3313
+ }`,
3314
+ { id: messageId, roomId: msg.roomId }
3315
+ );
3316
+ setMessages((prev) => prev.filter((m) => m.id !== messageId));
3317
+ } catch (err) {
3318
+ console.error("[organify-chat] deleteMessage:", err);
3319
+ setError(err.message || "Erro ao eliminar mensagem.");
3320
+ }
3321
+ },
3322
+ [gql, isDemoMode, messages]
3323
+ );
3324
+ const addReaction = useCallback(
3325
+ async (messageId, emoji) => {
3326
+ if (isDemoMode) {
3327
+ setMessages(
3328
+ (prev) => prev.map((m) => {
3329
+ if (m.id !== messageId) return m;
3330
+ const hasReaction = m.reactions.some((r) => r.emoji === emoji && r.userId === userId);
3331
+ if (hasReaction) return m;
3332
+ return { ...m, reactions: [...m.reactions, { emoji, userId }] };
3333
+ })
3334
+ );
3335
+ return;
3336
+ }
3337
+ try {
3338
+ await gql(
3339
+ `mutation($messageId: ID!, $emoji: String!) {
3340
+ addReaction(messageId: $messageId, emoji: $emoji) { emoji userId createdAt }
3341
+ }`,
3342
+ { messageId, emoji }
3343
+ );
3344
+ setMessages(
3345
+ (prev) => prev.map((m) => {
3346
+ if (m.id !== messageId) return m;
3347
+ return { ...m, reactions: [...m.reactions, { emoji, userId }] };
3348
+ })
3349
+ );
3350
+ } catch (err) {
3351
+ console.error("[organify-chat] addReaction:", err);
3352
+ }
3353
+ },
3354
+ [gql, userId, isDemoMode]
3355
+ );
3356
+ const removeReaction = useCallback(
3357
+ async (messageId, emoji) => {
3358
+ if (isDemoMode) {
3359
+ setMessages(
3360
+ (prev) => prev.map((m) => {
3361
+ if (m.id !== messageId) return m;
3362
+ return { ...m, reactions: m.reactions.filter((r) => !(r.emoji === emoji && r.userId === userId)) };
3363
+ })
3364
+ );
3365
+ return;
3366
+ }
3367
+ try {
3368
+ await gql(
3369
+ `mutation($messageId: ID!, $emoji: String!) {
3370
+ removeReaction(messageId: $messageId, emoji: $emoji)
3371
+ }`,
3372
+ { messageId, emoji }
3373
+ );
3374
+ setMessages(
3375
+ (prev) => prev.map((m) => {
3376
+ if (m.id !== messageId) return m;
3377
+ return { ...m, reactions: m.reactions.filter((r) => !(r.emoji === emoji && r.userId === userId)) };
3378
+ })
3379
+ );
3380
+ } catch (err) {
3381
+ console.error("[organify-chat] removeReaction:", err);
3382
+ }
3383
+ },
3384
+ [gql, userId, isDemoMode]
3385
+ );
3386
+ const reactToMessage = useCallback(
3387
+ async (messageId, emoji) => {
3388
+ const msg = messages.find((m) => m.id === messageId);
3389
+ if (!msg) return;
3390
+ const hasReaction = msg.reactions.some((r) => r.emoji === emoji && r.userId === userId);
3391
+ if (hasReaction) {
3392
+ await removeReaction(messageId, emoji);
3393
+ } else {
3394
+ await addReaction(messageId, emoji);
3395
+ }
3396
+ },
3397
+ [messages, userId, addReaction, removeReaction]
3398
+ );
3399
+ useEffect(() => {
3400
+ if (!userId || !activeRoomId) return;
3401
+ if (isDemoMode) return;
3402
+ const chatServiceUrl = api?.services?.chat || gatewayUrl;
3403
+ const wsUrl = chatServiceUrl.replace(/^http/, "ws") + "/graphql/chat";
3404
+ let ws = null;
3405
+ let pingInterval;
3406
+ let reconnectTimer;
3407
+ let reconnectAttempts = 0;
3408
+ const maxReconnectAttempts = 8;
3409
+ let disposed = false;
3410
+ function connect() {
3411
+ if (disposed || reconnectAttempts >= maxReconnectAttempts) return;
3412
+ try {
3413
+ ws = new WebSocket(wsUrl, "graphql-transport-ws");
3414
+ ws.onopen = () => {
3415
+ reconnectAttempts = 0;
3416
+ ws?.send(JSON.stringify({
3417
+ type: "connection_init",
3418
+ payload: { userId, workspaceId }
3419
+ }));
3420
+ };
3421
+ ws.onmessage = (event) => {
3422
+ try {
3423
+ const msg = JSON.parse(event.data);
3424
+ switch (msg.type) {
3425
+ case "connection_ack":
3426
+ ws?.send(JSON.stringify({
3427
+ id: "sub_msg_created",
3428
+ type: "subscribe",
3429
+ payload: {
3430
+ query: `subscription($roomId: ID!) {
3431
+ messageCreated(roomId: $roomId) {
3432
+ ${MESSAGE_FIELDS}
3433
+ }
3434
+ }`,
3435
+ variables: { roomId: activeRoomId }
3436
+ }
3437
+ }));
3438
+ ws?.send(JSON.stringify({
3439
+ id: "sub_msg_updated",
3440
+ type: "subscribe",
3441
+ payload: {
3442
+ query: `subscription($roomId: ID!) {
3443
+ messageUpdated(roomId: $roomId) {
3444
+ ${MESSAGE_FIELDS}
3445
+ }
3446
+ }`,
3447
+ variables: { roomId: activeRoomId }
3448
+ }
3449
+ }));
3450
+ ws?.send(JSON.stringify({
3451
+ id: "sub_msg_deleted",
3452
+ type: "subscribe",
3453
+ payload: {
3454
+ query: `subscription($roomId: ID!) {
3455
+ messageDeleted(roomId: $roomId)
3456
+ }`,
3457
+ variables: { roomId: activeRoomId }
3458
+ }
3459
+ }));
3460
+ ws?.send(JSON.stringify({
3461
+ id: "sub_typing",
3462
+ type: "subscribe",
3463
+ payload: {
3464
+ query: `subscription($roomId: ID!) {
3465
+ typingIndicator(roomId: $roomId) {
3466
+ roomId userId isTyping
3467
+ }
3468
+ }`,
3469
+ variables: { roomId: activeRoomId }
3470
+ }
3471
+ }));
3472
+ pingInterval = setInterval(() => {
3473
+ if (ws?.readyState === WebSocket.OPEN) {
3474
+ ws.send(JSON.stringify({ type: "ping" }));
3475
+ }
3476
+ }, 25e3);
3477
+ break;
3478
+ case "next":
3479
+ if (msg.id === "sub_msg_created" && msg.payload?.data?.messageCreated) {
3480
+ const newMsg = msg.payload.data.messageCreated;
3481
+ if (newMsg.authorId === userId) {
3482
+ setMessages(
3483
+ (prev) => prev.map(
3484
+ (m) => m._status === "pending" && m.content === newMsg.content && m.authorId === newMsg.authorId ? { ...newMsg, _status: "sent" } : m
3485
+ )
3486
+ );
3487
+ } else {
3488
+ setMessages((prev) => {
3489
+ if (prev.find((m) => m.id === newMsg.id)) return prev;
3490
+ return [...prev, newMsg];
3491
+ });
3492
+ }
3493
+ }
3494
+ if (msg.id === "sub_msg_updated" && msg.payload?.data?.messageUpdated) {
3495
+ const updated = msg.payload.data.messageUpdated;
3496
+ setMessages(
3497
+ (prev) => prev.map((m) => m.id === updated.id ? { ...updated, _status: "sent" } : m)
3498
+ );
3499
+ }
3500
+ if (msg.id === "sub_msg_deleted" && msg.payload?.data?.messageDeleted) {
3501
+ const deletedId = msg.payload.data.messageDeleted;
3502
+ setMessages((prev) => prev.filter((m) => m.id !== deletedId));
3503
+ }
3504
+ if (msg.id === "sub_typing" && msg.payload?.data?.typingIndicator) {
3505
+ const { userId: typerId, isTyping } = msg.payload.data.typingIndicator;
3506
+ if (typerId !== userId) {
3507
+ if (isTyping) {
3508
+ setTypingUsers(
3509
+ (prev) => prev.includes(typerId) ? prev : [...prev, typerId]
3510
+ );
3511
+ setTimeout(() => {
3512
+ setTypingUsers((prev) => prev.filter((id) => id !== typerId));
3513
+ }, 4e3);
3514
+ } else {
3515
+ setTypingUsers((prev) => prev.filter((id) => id !== typerId));
3516
+ }
3517
+ }
3518
+ }
3519
+ break;
3520
+ case "pong":
3521
+ break;
3522
+ case "error":
3523
+ console.warn("[organify-chat] Subscription error:", msg.payload);
3524
+ break;
3525
+ case "complete":
3526
+ break;
3527
+ }
3528
+ } catch {
3529
+ }
3530
+ };
3531
+ ws.onerror = () => {
3532
+ };
3533
+ ws.onclose = () => {
3534
+ clearInterval(pingInterval);
3535
+ if (!disposed && reconnectAttempts < maxReconnectAttempts) {
3536
+ const delay = Math.min(1e3 * Math.pow(2, reconnectAttempts) + Math.random() * 500, 3e4);
3537
+ reconnectAttempts++;
3538
+ reconnectTimer = setTimeout(connect, delay);
3539
+ }
3540
+ };
3541
+ } catch {
3542
+ if (!disposed && reconnectAttempts < maxReconnectAttempts) {
3543
+ reconnectAttempts++;
3544
+ reconnectTimer = setTimeout(connect, 3e3);
3545
+ }
3546
+ }
3547
+ }
3548
+ connect();
3549
+ return () => {
3550
+ disposed = true;
3551
+ clearInterval(pingInterval);
3552
+ clearTimeout(reconnectTimer);
3553
+ if (ws?.readyState === WebSocket.OPEN) {
3554
+ ws.send(JSON.stringify({ id: "sub_msg_created", type: "complete" }));
3555
+ ws.send(JSON.stringify({ id: "sub_msg_updated", type: "complete" }));
3556
+ ws.send(JSON.stringify({ id: "sub_msg_deleted", type: "complete" }));
3557
+ ws.send(JSON.stringify({ id: "sub_typing", type: "complete" }));
3558
+ ws.close(1e3, "unmount");
3559
+ } else {
3560
+ ws?.close();
3561
+ }
3562
+ };
3563
+ }, [api?.services?.chat, gatewayUrl, userId, workspaceId, activeRoomId, isDemoMode]);
3564
+ const sendTyping = useCallback(() => {
3565
+ }, []);
3566
+ useEffect(() => {
3567
+ if (workspaceId && !workspaceId.startsWith("temp-")) {
3568
+ fetchRooms();
3569
+ }
3570
+ }, [fetchRooms]);
3571
+ useEffect(() => {
3572
+ if (error) {
3573
+ const t = setTimeout(() => setError(null), 5e3);
3574
+ return () => clearTimeout(t);
3575
+ }
3576
+ }, [error]);
3577
+ return {
3578
+ // State
3579
+ rooms,
3580
+ messages: enrichedMessages,
3581
+ activeRoomId,
3582
+ loadingRooms,
3583
+ loadingMessages,
3584
+ hasMoreMessages,
3585
+ loadingMoreMessages,
3586
+ roomMembers,
3587
+ myRoomRole,
3588
+ permissions,
3589
+ typingUsers,
3590
+ error,
3591
+ // Room selection
3592
+ selectRoom,
3593
+ // Messaging
3594
+ sendMessage,
3595
+ editMessage,
3596
+ deleteMessage,
3597
+ reactToMessage,
3598
+ sendTyping,
3599
+ loadMoreMessages,
3600
+ // Room CRUD
3601
+ createRoom,
3602
+ createDirectMessage,
3603
+ updateRoom,
3604
+ archiveRoom,
3605
+ leaveRoom,
3606
+ // Member management
3607
+ addMember,
3608
+ removeMember,
3609
+ updateMemberRole,
3610
+ // Refresh
3611
+ fetchRooms,
3612
+ fetchRoomMembers,
3613
+ userCache
3614
+ };
3615
+ }
3616
+ var alertVariants = cva(
3617
+ "group relative overflow-visible border-l-4 border border-glass-border bg-glass-highlight/90 backdrop-blur-xl py-5 pl-14 pr-6 shadow-glass rounded-sm",
3618
+ {
3619
+ variants: {
3620
+ variant: {
3621
+ success: "border-l-emerald-500 bg-emerald-500/[0.06]",
3622
+ error: "border-l-rose-500 bg-rose-500/[0.06]",
3623
+ warning: "border-l-amber-400 bg-amber-400/[0.06]",
3624
+ info: "border-l-blue-500 bg-blue-500/[0.06]"
3625
+ }
3626
+ },
3627
+ defaultVariants: {
3628
+ variant: "info"
3629
+ }
3630
+ }
3631
+ );
3632
+ var alertIconVariants = cva(
3633
+ "absolute -left-4 top-1/2 z-10 flex h-10 w-10 -translate-y-1/2 items-center justify-center border border-glass-border-strong shadow-lg transition-transform duration-[400ms] ease-[cubic-bezier(0.25,1,0.5,1)] group-hover:rotate-0 rounded-sm",
3634
+ {
3635
+ variants: {
3636
+ variant: {
3637
+ success: "bg-emerald-500 text-black rotate-[-6deg]",
3638
+ error: "bg-rose-500 text-white rotate-[6deg]",
3639
+ warning: "bg-amber-400 text-black rotate-[-3deg]",
3640
+ info: "bg-blue-500 text-white rotate-[3deg]"
3641
+ }
3642
+ },
3643
+ defaultVariants: {
3644
+ variant: "info"
3645
+ }
3646
+ }
3647
+ );
3648
+ function Alert({
3649
+ className,
3650
+ variant,
3651
+ title,
3652
+ description,
3653
+ icon,
3654
+ onClose,
3655
+ action,
3656
+ ...props
3657
+ }) {
3658
+ return /* @__PURE__ */ jsxs("div", { className: cn(alertVariants({ variant }), className), role: "alert", ...props, children: [
3659
+ /* @__PURE__ */ jsx("div", { className: cn(alertIconVariants({ variant })), children: icon || /* @__PURE__ */ jsxs(Fragment, { children: [
3660
+ variant === "success" && /* @__PURE__ */ jsx(OrgCheckCircle, { className: "w-5 h-5" }),
3661
+ variant === "error" && /* @__PURE__ */ jsx(OrgError, { className: "w-5 h-5" }),
3662
+ variant === "warning" && /* @__PURE__ */ jsx(OrgWarning, { className: "w-5 h-5" }),
3663
+ variant === "info" && /* @__PURE__ */ jsx(OrgInfo, { className: "w-5 h-5" })
3664
+ ] }) }),
3665
+ /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-0 rounded-sm shadow-inner-light" }),
3666
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-4", children: [
3667
+ /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
3668
+ /* @__PURE__ */ jsx("h4", { className: "text-base font-semibold text-org-text", children: title }),
3669
+ description && /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm font-light text-org-text-secondary", children: description })
3670
+ ] }),
3671
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
3672
+ action && /* @__PURE__ */ jsx(
3673
+ "button",
3674
+ {
3675
+ onClick: action.onClick,
3676
+ className: cn(
3677
+ "whitespace-nowrap px-3 py-1.5 text-xs font-semibold tracking-wide transition-all border rounded-sm",
3678
+ variant === "error" && "border-rose-500/30 bg-rose-500/20 text-rose-300 hover:bg-rose-500/30",
3679
+ variant === "success" && "border-emerald-500/30 bg-emerald-500/20 text-emerald-300 hover:bg-emerald-500/30",
3680
+ variant === "warning" && "border-amber-400/30 bg-amber-400/20 text-amber-300 hover:bg-amber-400/30",
3681
+ variant === "info" && "border-blue-500/30 bg-blue-500/20 text-blue-300 hover:bg-blue-500/30"
3682
+ ),
3683
+ children: action.label
3684
+ }
3685
+ ),
3686
+ onClose && /* @__PURE__ */ jsx(
3687
+ "button",
3688
+ {
3689
+ onClick: onClose,
3690
+ className: "p-1 text-org-text-muted transition-colors hover:text-org-text",
3691
+ "aria-label": "Close alert",
3692
+ children: /* @__PURE__ */ jsx(OrgClose, { className: "h-4 w-4" })
3693
+ }
3694
+ )
3695
+ ] })
3696
+ ] })
3697
+ ] });
3698
+ }
3699
+
3700
+ // src/components/chat/chat-mock-data.ts
3701
+ var MOCK_USERS = [
3702
+ {
3703
+ id: "user-1",
3704
+ displayName: "Ana Silva",
3705
+ email: "ana.silva@organify.dev",
3706
+ avatarUrl: null,
3707
+ status: "ONLINE"
3708
+ },
3709
+ {
3710
+ id: "user-2",
3711
+ displayName: "Bruno Costa",
3712
+ email: "bruno.costa@organify.dev",
3713
+ avatarUrl: null,
3714
+ status: "ONLINE"
3715
+ },
3716
+ {
3717
+ id: "user-3",
3718
+ displayName: "Carla Santos",
3719
+ email: "carla.santos@organify.dev",
3720
+ avatarUrl: null,
3721
+ status: "AWAY"
3722
+ },
3723
+ {
3724
+ id: "user-4",
3725
+ displayName: "Diego Ferreira",
3726
+ email: "diego.ferreira@organify.dev",
3727
+ avatarUrl: null,
3728
+ status: "ONLINE"
3729
+ },
3730
+ {
3731
+ id: "user-5",
3732
+ displayName: "Elena Rodrigues",
3733
+ email: "elena.rodrigues@organify.dev",
3734
+ avatarUrl: null,
3735
+ status: "BUSY"
3736
+ },
3737
+ {
3738
+ id: "user-6",
3739
+ displayName: "Fernando Lima",
3740
+ email: "fernando.lima@organify.dev",
3741
+ avatarUrl: null,
3742
+ status: "ONLINE"
3743
+ },
3744
+ {
3745
+ id: "user-7",
3746
+ displayName: "Gabriela Alves",
3747
+ email: "gabriela.alves@organify.dev",
3748
+ avatarUrl: null,
3749
+ status: "OFFLINE"
3750
+ },
3751
+ {
3752
+ id: "user-8",
3753
+ displayName: "Hugo Martins",
3754
+ email: "hugo.martins@organify.dev",
3755
+ avatarUrl: null,
3756
+ status: "ONLINE"
3757
+ }
3758
+ ];
3759
+ var MOCK_PROJECTS = [
3760
+ { id: "proj-1", name: "Organify Platform", key: "ORG" },
3761
+ { id: "proj-2", name: "Mobile App", key: "MOB" },
3762
+ { id: "proj-3", name: "Design System", key: "DS" },
3763
+ { id: "proj-4", name: "Marketing Website", key: "WEB" },
3764
+ { id: "proj-5", name: "API Gateway", key: "API" }
3765
+ ];
3766
+ function getMockMentionOptions(query) {
3767
+ const q = query.toLowerCase();
3768
+ const options = [];
3769
+ MOCK_USERS.filter(
3770
+ (u) => u.displayName.toLowerCase().includes(q) || u.email?.toLowerCase().includes(q)
3771
+ ).slice(0, 5).forEach((u) => {
3772
+ options.push({
3773
+ id: u.id,
3774
+ type: "user",
3775
+ display: u.displayName,
3776
+ avatarUrl: u.avatarUrl,
3777
+ subtitle: u.email
3778
+ });
3779
+ });
3780
+ MOCK_PROJECTS.filter(
3781
+ (p) => p.name.toLowerCase().includes(q) || p.key.toLowerCase().includes(q)
3782
+ ).slice(0, 3).forEach((p) => {
3783
+ options.push({
3784
+ id: p.id,
3785
+ type: "project",
3786
+ display: p.name,
3787
+ subtitle: p.key
3788
+ });
3789
+ });
3790
+ return options;
3791
+ }
3792
+ var REPLY_TEMPLATES = [
3793
+ "Excelente ideia! \u{1F44D}",
3794
+ "Concordo totalmente.",
3795
+ "Vou verificar isso agora.",
3796
+ "Obrigado pela atualiza\xE7\xE3o! \u{1F389}",
3797
+ "Isso faz sentido.",
3798
+ "Pode deixar comigo!",
3799
+ "Bom ponto! N\xE3o tinha pensado nisso.",
3800
+ "J\xE1 estou trabalhando nisso.",
3801
+ "Perfeito, vamos em frente!",
3802
+ "\xD3timo trabalho! \u{1F680}",
3803
+ "Interessante... vou investigar.",
3804
+ "Combinado!",
3805
+ "Aceito o desafio! \u{1F4AA}",
3806
+ "Bom demais!",
3807
+ "Isso vai ajudar muito."
3808
+ ];
3809
+ var RANDOM_COMMENTS = [
3810
+ "Algu\xE9m viu o novo design? Est\xE1 incr\xEDvel!",
3811
+ "Precisamos revisar a API de notifica\xE7\xF5es.",
3812
+ "O deploy de hoje foi um sucesso! \u{1F38A}",
3813
+ "Quem pode me ajudar com TypeScript?",
3814
+ "Reuni\xE3o marcada para amanh\xE3 \xE0s 10h.",
3815
+ "A feature de chat ficou muito boa!",
3816
+ "Encontrei um bug no formul\xE1rio de login.",
3817
+ "Code review pendente no PR #234",
3818
+ "Algu\xE9m tem tempo para pair programming?",
3819
+ "Nova sprint come\xE7a na segunda-feira!",
3820
+ "Preciso de feedback no mockup.",
3821
+ "Performance melhorou 40% com as \xFAltimas mudan\xE7as!",
3822
+ "Documenta\xE7\xE3o atualizada no Notion.",
3823
+ "Quem quer caf\xE9? \u2615",
3824
+ "Cliente adorou a demo!"
3825
+ ];
3826
+ function getRandomUser() {
3827
+ return MOCK_USERS[Math.floor(Math.random() * MOCK_USERS.length)];
3828
+ }
3829
+ function getRandomTemplate() {
3830
+ return REPLY_TEMPLATES[Math.floor(Math.random() * REPLY_TEMPLATES.length)];
3831
+ }
3832
+ function getRandomComment() {
3833
+ return RANDOM_COMMENTS[Math.floor(Math.random() * RANDOM_COMMENTS.length)];
3834
+ }
3835
+ function generateAutoReplies(userMessage, roomId, count = 5) {
3836
+ const replies = [];
3837
+ const now = Date.now();
3838
+ for (let i = 0; i < count; i++) {
3839
+ const user = getRandomUser();
3840
+ const isReply = Math.random() > 0.6;
3841
+ const isComment = Math.random() > 0.7;
3842
+ replies.push({
3843
+ id: `mock-${Date.now()}-${i}`,
3844
+ roomId,
3845
+ authorId: user.id,
3846
+ authorName: user.displayName,
3847
+ content: isComment ? getRandomComment() : getRandomTemplate(),
3848
+ createdAt: new Date(now + (i + 1) * 2e3).toISOString(),
3849
+ // 2s interval
3850
+ replyToId: isReply ? userMessage.id : null,
3851
+ edited: false,
3852
+ editedAt: null,
3853
+ mentions: [],
3854
+ reactions: []
3855
+ });
3856
+ }
3857
+ return replies;
3858
+ }
3859
+ var TypingIndicatorMock = class {
3860
+ typingUsers = /* @__PURE__ */ new Set();
3861
+ timeouts = /* @__PURE__ */ new Map();
3862
+ listeners = [];
3863
+ constructor() {
3864
+ }
3865
+ /** Simula alguém começando a digitar */
3866
+ startTyping(userId) {
3867
+ const user = userId ? MOCK_USERS.find((u) => u.id === userId) : getRandomUser();
3868
+ if (!user) return;
3869
+ const existingTimeout = this.timeouts.get(user.id);
3870
+ if (existingTimeout) {
3871
+ clearTimeout(existingTimeout);
3872
+ }
3873
+ this.typingUsers.add(user.displayName);
3874
+ this.notify();
3875
+ const duration = 3e3 + Math.random() * 2e3;
3876
+ const timeout = setTimeout(() => {
3877
+ this.stopTyping(user.id);
3878
+ }, duration);
3879
+ this.timeouts.set(user.id, timeout);
3880
+ }
3881
+ /** Para de digitar */
3882
+ stopTyping(userId) {
3883
+ const user = MOCK_USERS.find((u) => u.id === userId);
3884
+ if (!user) return;
3885
+ this.typingUsers.delete(user.displayName);
3886
+ const timeout = this.timeouts.get(userId);
3887
+ if (timeout) {
3888
+ clearTimeout(timeout);
3889
+ this.timeouts.delete(userId);
3890
+ }
3891
+ this.notify();
3892
+ }
3893
+ /** Subscribe to typing changes */
3894
+ subscribe(callback) {
3895
+ this.listeners.push(callback);
3896
+ return () => {
3897
+ this.listeners = this.listeners.filter((l) => l !== callback);
3898
+ };
3899
+ }
3900
+ notify() {
3901
+ const users = Array.from(this.typingUsers);
3902
+ this.listeners.forEach((cb) => cb(users));
3903
+ }
3904
+ /** Simula typing indicator aleatório */
3905
+ simulateRandomTyping() {
3906
+ const delay = 2e3 + Math.random() * 6e3;
3907
+ setTimeout(() => {
3908
+ if (Math.random() > 0.5) {
3909
+ this.startTyping();
3910
+ }
3911
+ this.simulateRandomTyping();
3912
+ }, delay);
3913
+ }
3914
+ clear() {
3915
+ this.typingUsers.clear();
3916
+ this.timeouts.forEach((timeout) => clearTimeout(timeout));
3917
+ this.timeouts.clear();
3918
+ this.notify();
3919
+ }
3920
+ };
3921
+ var typingIndicator = new TypingIndicatorMock();
3922
+ if (typeof window !== "undefined") {
3923
+ typingIndicator.simulateRandomTyping();
3924
+ }
3925
+ function useMediaQuery2(query) {
3926
+ const [matches, setMatches] = React7.useState(false);
3927
+ React7.useEffect(() => {
3928
+ const mql = window.matchMedia(query);
3929
+ setMatches(mql.matches);
3930
+ const handler = (e) => setMatches(e.matches);
3931
+ mql.addEventListener("change", handler);
3932
+ return () => mql.removeEventListener("change", handler);
3933
+ }, [query]);
3934
+ return matches;
3935
+ }
3936
+ function OrganifyChat({
3937
+ workspaceRole,
3938
+ workspaceMembers = [],
3939
+ initialRooms,
3940
+ initialMessages,
3941
+ className
3942
+ }) {
3943
+ const user = useOrganifyUser();
3944
+ const userId = user?.id ?? "";
3945
+ const chat = useChat({
3946
+ workspaceRole,
3947
+ initialRooms,
3948
+ initialMessages,
3949
+ workspaceMembers
3950
+ });
3951
+ const isMobile = !useMediaQuery2("(min-width: 768px)");
3952
+ const [createDialogOpen, setCreateDialogOpen] = React7.useState(false);
3953
+ const [managementOpen, setManagementOpen] = React7.useState(false);
3954
+ const [mobileView, setMobileView] = React7.useState("sidebar");
3955
+ const activeRoom = React7.useMemo(
3956
+ () => chat.rooms.find((r) => r.id === chat.activeRoomId),
3957
+ [chat.rooms, chat.activeRoomId]
3958
+ );
3959
+ const handleRoomSelect = (roomId) => {
3960
+ chat.selectRoom(roomId);
3961
+ if (isMobile) {
3962
+ setMobileView("room");
3963
+ }
3964
+ };
3965
+ const handleBackToSidebar = () => {
3966
+ setMobileView("sidebar");
3967
+ };
3968
+ const handleOpenManagement = () => {
3969
+ if (isMobile) {
3970
+ setMobileView("management");
3971
+ } else {
3972
+ setManagementOpen(true);
3973
+ }
3974
+ };
3975
+ const handleCloseManagement = () => {
3976
+ if (isMobile) {
3977
+ setMobileView("room");
3978
+ } else {
3979
+ setManagementOpen(false);
3980
+ }
3981
+ };
3982
+ return /* @__PURE__ */ jsxs(
3983
+ "div",
3984
+ {
3985
+ className: cn(
3986
+ "relative flex h-full min-h-[500px]",
3987
+ "bg-theme-surface border border-theme-subtle rounded-sm overflow-hidden",
3988
+ className
3989
+ ),
3990
+ children: [
3991
+ chat.error && /* @__PURE__ */ jsx("div", { className: "absolute top-0 left-0 right-0 z-50 px-4 pt-2 animate-in slide-in-from-top-2 duration-[400ms]", children: /* @__PURE__ */ jsx(
3992
+ Alert,
3993
+ {
3994
+ variant: "error",
3995
+ title: "Erro",
3996
+ description: chat.error,
3997
+ className: "py-3 text-xs"
3998
+ }
3999
+ ) }),
4000
+ !isMobile && /* @__PURE__ */ jsxs(Fragment, { children: [
4001
+ /* @__PURE__ */ jsx("div", { className: "w-[260px] shrink-0", children: /* @__PURE__ */ jsx(
4002
+ ChatSidebar,
4003
+ {
4004
+ rooms: chat.rooms,
4005
+ activeRoomId: chat.activeRoomId,
4006
+ loading: chat.loadingRooms,
4007
+ onSelectRoom: chat.selectRoom,
4008
+ onCreateRoom: () => setCreateDialogOpen(true)
4009
+ }
4010
+ ) }),
4011
+ /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(
4012
+ ChatMessages,
4013
+ {
4014
+ room: activeRoom,
4015
+ messages: chat.messages,
4016
+ loading: chat.loadingMessages,
4017
+ typingUsers: chat.typingUsers,
4018
+ currentUserId: userId,
4019
+ permissions: chat.permissions,
4020
+ onSendMessage: chat.sendMessage,
4021
+ onEditMessage: chat.editMessage,
4022
+ onDeleteMessage: chat.deleteMessage,
4023
+ onReactToMessage: chat.reactToMessage,
4024
+ onTyping: chat.sendTyping,
4025
+ onStopTyping: chat.sendTyping,
4026
+ onOpenManagement: () => setManagementOpen(true),
4027
+ isMobile: false,
4028
+ mentionUsers: workspaceMembers,
4029
+ mentionProjects: MOCK_PROJECTS,
4030
+ hasMore: chat.hasMoreMessages,
4031
+ onLoadMore: chat.loadMoreMessages,
4032
+ loadingMore: chat.loadingMoreMessages
4033
+ }
4034
+ ) }),
4035
+ managementOpen && activeRoom && /* @__PURE__ */ jsx("div", { className: "w-[300px] shrink-0 border-l border-theme-subtle bg-theme-glass", children: /* @__PURE__ */ jsx(
4036
+ RoomManagementPanel,
4037
+ {
4038
+ room: activeRoom,
4039
+ members: chat.roomMembers,
4040
+ currentUserId: userId,
4041
+ permissions: chat.permissions,
4042
+ onClose: () => setManagementOpen(false),
4043
+ onUpdateRoom: chat.updateRoom,
4044
+ onArchiveRoom: chat.archiveRoom,
4045
+ onLeaveRoom: chat.leaveRoom,
4046
+ onRemoveMember: chat.removeMember,
4047
+ onUpdateMemberRole: chat.updateMemberRole
4048
+ }
4049
+ ) })
4050
+ ] }),
4051
+ isMobile && /* @__PURE__ */ jsxs(Fragment, { children: [
4052
+ mobileView === "sidebar" && /* @__PURE__ */ jsx("div", { className: "w-full animate-in fade-in-0 slide-in-from-left-5 duration-[400ms]", children: /* @__PURE__ */ jsx(
4053
+ ChatSidebar,
4054
+ {
4055
+ rooms: chat.rooms,
4056
+ activeRoomId: chat.activeRoomId,
4057
+ loading: chat.loadingRooms,
4058
+ onSelectRoom: handleRoomSelect,
4059
+ onCreateRoom: () => setCreateDialogOpen(true)
4060
+ }
4061
+ ) }),
4062
+ mobileView === "room" && activeRoom && /* @__PURE__ */ jsx("div", { className: "w-full animate-in fade-in-0 slide-in-from-right-5 duration-[400ms]", children: /* @__PURE__ */ jsx(
4063
+ ChatMessages,
4064
+ {
4065
+ room: activeRoom,
4066
+ messages: chat.messages,
4067
+ loading: chat.loadingMessages,
4068
+ typingUsers: chat.typingUsers,
4069
+ currentUserId: userId,
4070
+ permissions: chat.permissions,
4071
+ onSendMessage: chat.sendMessage,
4072
+ onEditMessage: chat.editMessage,
4073
+ onDeleteMessage: chat.deleteMessage,
4074
+ onReactToMessage: chat.reactToMessage,
4075
+ onTyping: chat.sendTyping,
4076
+ onStopTyping: chat.sendTyping,
4077
+ onOpenManagement: handleOpenManagement,
4078
+ onBack: handleBackToSidebar,
4079
+ isMobile: true,
4080
+ mentionUsers: workspaceMembers,
4081
+ mentionProjects: MOCK_PROJECTS,
4082
+ hasMore: chat.hasMoreMessages,
4083
+ onLoadMore: chat.loadMoreMessages,
4084
+ loadingMore: chat.loadingMoreMessages
4085
+ }
4086
+ ) }),
4087
+ mobileView === "management" && activeRoom && /* @__PURE__ */ jsxs("div", { className: "absolute inset-0 z-50 flex", children: [
4088
+ /* @__PURE__ */ jsx(
4089
+ "div",
4090
+ {
4091
+ className: "flex-1 bg-black/50 backdrop-blur-sm",
4092
+ onClick: handleCloseManagement
4093
+ }
4094
+ ),
4095
+ /* @__PURE__ */ jsx("div", { className: "w-[85%] max-w-sm h-full bg-theme-glass-heavy backdrop-blur-2xl border-l border-theme-subtle animate-in slide-in-from-right-5 duration-[400ms]", children: /* @__PURE__ */ jsx(
4096
+ RoomManagementPanel,
4097
+ {
4098
+ room: activeRoom,
4099
+ members: chat.roomMembers,
4100
+ currentUserId: userId,
4101
+ permissions: chat.permissions,
4102
+ onClose: handleCloseManagement,
4103
+ onUpdateRoom: chat.updateRoom,
4104
+ onArchiveRoom: chat.archiveRoom,
4105
+ onLeaveRoom: chat.leaveRoom,
4106
+ onRemoveMember: chat.removeMember,
4107
+ onUpdateMemberRole: chat.updateMemberRole
4108
+ }
4109
+ ) })
4110
+ ] })
4111
+ ] }),
4112
+ /* @__PURE__ */ jsx(
4113
+ CreateRoomDialog,
4114
+ {
4115
+ open: createDialogOpen,
4116
+ onOpenChange: setCreateDialogOpen,
4117
+ onCreateChannel: async (data) => {
4118
+ const room = await chat.createRoom({
4119
+ name: data.name,
4120
+ type: "CHANNEL",
4121
+ visibility: data.visibility,
4122
+ description: data.description,
4123
+ memberIds: data.memberIds
4124
+ });
4125
+ if (room) chat.selectRoom(room.id);
4126
+ return room;
4127
+ },
4128
+ onCreateDM: async (targetUserId) => {
4129
+ const room = await chat.createDirectMessage(targetUserId);
4130
+ if (room) chat.selectRoom(room.id);
4131
+ return room;
4132
+ },
4133
+ workspaceMembers
4134
+ }
4135
+ )
4136
+ ]
4137
+ }
4138
+ );
4139
+ }
4140
+
4141
+ export { Alert, Button, ChatMessages, ChatSidebar, CreateRoomDialog, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, Input, Label, MOCK_PROJECTS, MOCK_USERS, MentionPopover, MessageBubble, MessageInput, OrgLoader, OrgLoaderInline, OrganifyChat, ResponsiveDialog, RoomManagementPanel, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, TypingIndicatorMock, alertVariants, buttonVariants, generateAutoReplies, getMockMentionOptions, getRoomPermissions, inputVariants, orgLoaderVariants, typingIndicator, useChat };
4142
+ //# sourceMappingURL=chunk-2Y3W6JSG.js.map
4143
+ //# sourceMappingURL=chunk-2Y3W6JSG.js.map