@geekapps/auth-elements-nextjs 0.1.0 → 0.2.0

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.
package/dist/index.js CHANGED
@@ -1,15 +1,6 @@
1
1
  "use client";
2
2
 
3
3
  // src/index.tsx
4
- import {
5
- useAccounts,
6
- useAuth,
7
- useOrg,
8
- usePermissions,
9
- useRoles,
10
- useSessions,
11
- useUsers
12
- } from "@geekapps/auth-nextjs/client";
13
4
  import {
14
5
  useEffect,
15
6
  useState
@@ -146,106 +137,236 @@ function Modal({
146
137
  footer && /* @__PURE__ */ jsx("div", { className: "border-t border-slate-200 p-5", children: footer })
147
138
  ] }) });
148
139
  }
149
- function SignInButton({
150
- children = "Entrar",
151
- redirectTo
152
- }) {
153
- const { signIn } = useAuth();
154
- return /* @__PURE__ */ jsx(
155
- Button,
156
- {
157
- onClick: () => void signIn({ redirectTo }),
158
- tone: "primary",
159
- type: "button",
160
- children
161
- }
162
- );
163
- }
164
- function SignOutButton({ children = "Sair" }) {
165
- const { signOut } = useAuth();
166
- return /* @__PURE__ */ jsx(Button, { onClick: () => void signOut(), tone: "ghost", type: "button", children });
167
- }
168
- function AccountSwitcher() {
169
- const {
170
- accounts,
171
- addAccount,
172
- isLoadingAccounts,
173
- refreshAccounts,
174
- switchAccount
175
- } = useAccounts();
176
- const activeAccount = accounts.find((account) => account.isActive) ?? accounts[0] ?? null;
177
- const [open, setOpen] = useState(false);
178
- return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
179
- /* @__PURE__ */ jsx(
180
- "button",
140
+ function createAuthElements(hooks) {
141
+ const { useAuth } = hooks;
142
+ function SignInButton({
143
+ children = "Entrar",
144
+ redirectTo
145
+ }) {
146
+ const { signIn } = useAuth();
147
+ return /* @__PURE__ */ jsx(
148
+ Button,
181
149
  {
182
- className: "flex h-10 w-10 items-center justify-center rounded-xl transition hover:opacity-80",
183
- onClick: () => setOpen((value) => !value),
184
- title: activeAccount?.user.name ?? activeAccount?.user.email ?? "Conta",
150
+ onClick: () => void signIn({ redirectTo }),
151
+ tone: "primary",
185
152
  type: "button",
186
- children: /* @__PURE__ */ jsx(
187
- Avatar,
188
- {
189
- name: activeAccount?.user.name ?? activeAccount?.user.email,
190
- size: "sm",
191
- src: activeAccount?.user.imageUrl
192
- }
193
- )
153
+ children
194
154
  }
195
- ),
196
- open && /* @__PURE__ */ jsxs(Fragment, { children: [
197
- /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-20", onClick: () => setOpen(false) }),
198
- /* @__PURE__ */ jsxs("div", { className: "absolute bottom-0 left-14 z-30 w-72 overflow-hidden rounded-xl border border-slate-200 bg-white shadow-lg", children: [
199
- /* @__PURE__ */ jsx("div", { className: "border-b border-slate-100 px-3 py-2.5", children: /* @__PURE__ */ jsx("p", { className: "text-[11px] font-medium uppercase tracking-wider text-slate-400", children: "Contas" }) }),
200
- /* @__PURE__ */ jsxs("div", { className: "p-1.5", children: [
201
- isLoadingAccounts && /* @__PURE__ */ jsx("p", { className: "px-2 py-3 text-xs text-slate-400", children: "Carregando..." }),
202
- accounts.map((account) => /* @__PURE__ */ jsxs(
203
- "button",
155
+ );
156
+ }
157
+ function SignOutButton({ children = "Sair" }) {
158
+ const { signOut } = useAuth();
159
+ return /* @__PURE__ */ jsx(Button, { onClick: () => void signOut(), tone: "ghost", type: "button", children });
160
+ }
161
+ function AccountSwitcher() {
162
+ const {
163
+ accounts,
164
+ addAccount,
165
+ isLoadingAccounts,
166
+ refreshAccounts,
167
+ switchAccount
168
+ } = useAuth();
169
+ const activeAccount = accounts.find((account) => account.isActive) ?? accounts[0] ?? null;
170
+ const [open, setOpen] = useState(false);
171
+ return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
172
+ /* @__PURE__ */ jsx(
173
+ "button",
174
+ {
175
+ className: "flex h-10 w-10 items-center justify-center rounded-xl transition hover:opacity-80",
176
+ onClick: () => setOpen((value) => !value),
177
+ title: activeAccount?.user.name ?? activeAccount?.user.email ?? "Conta",
178
+ type: "button",
179
+ children: /* @__PURE__ */ jsx(
180
+ Avatar,
204
181
  {
205
- className: cx(
206
- "flex w-full items-center gap-2.5 rounded-lg px-2 py-2 text-left transition hover:bg-slate-50",
207
- account.isActive && "bg-slate-50"
208
- ),
209
- onClick: () => {
210
- void switchAccount(account.sessionId ?? account.id);
211
- setOpen(false);
182
+ name: activeAccount?.user.name ?? activeAccount?.user.email,
183
+ size: "sm",
184
+ src: activeAccount?.user.imageUrl
185
+ }
186
+ )
187
+ }
188
+ ),
189
+ open && /* @__PURE__ */ jsxs(Fragment, { children: [
190
+ /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-20", onClick: () => setOpen(false) }),
191
+ /* @__PURE__ */ jsxs("div", { className: "absolute bottom-0 left-14 z-30 w-72 overflow-hidden rounded-xl border border-slate-200 bg-white shadow-lg", children: [
192
+ /* @__PURE__ */ jsx("div", { className: "border-b border-slate-100 px-3 py-2.5", children: /* @__PURE__ */ jsx("p", { className: "text-[11px] font-medium uppercase tracking-wider text-slate-400", children: "Contas" }) }),
193
+ /* @__PURE__ */ jsxs("div", { className: "p-1.5", children: [
194
+ isLoadingAccounts && /* @__PURE__ */ jsx("p", { className: "px-2 py-3 text-xs text-slate-400", children: "Carregando..." }),
195
+ accounts.map((account) => /* @__PURE__ */ jsxs(
196
+ "button",
197
+ {
198
+ className: cx(
199
+ "flex w-full items-center gap-2.5 rounded-lg px-2 py-2 text-left transition hover:bg-slate-50",
200
+ account.isActive && "bg-slate-50"
201
+ ),
202
+ onClick: () => {
203
+ void switchAccount(account.sessionId ?? account.id);
204
+ setOpen(false);
205
+ },
206
+ type: "button",
207
+ children: [
208
+ /* @__PURE__ */ jsx(
209
+ Avatar,
210
+ {
211
+ name: account.user.name ?? account.user.email,
212
+ size: "sm",
213
+ src: account.user.imageUrl
214
+ }
215
+ ),
216
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
217
+ /* @__PURE__ */ jsx("span", { className: "block truncate text-sm font-medium text-slate-900", children: account.user.name ?? account.user.email }),
218
+ /* @__PURE__ */ jsx("span", { className: "block truncate text-xs text-slate-500", children: account.user.email })
219
+ ] }),
220
+ account.isActive && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs font-medium text-emerald-600", children: "\u2713" })
221
+ ]
212
222
  },
213
- type: "button",
214
- children: [
223
+ account.sessionId ?? account.id
224
+ ))
225
+ ] }),
226
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-1.5 border-t border-slate-100 p-1.5", children: [
227
+ /* @__PURE__ */ jsx(
228
+ Button,
229
+ {
230
+ className: "flex-1",
231
+ onClick: () => void addAccount(),
232
+ size: "sm",
233
+ type: "button",
234
+ children: "+ Conta"
235
+ }
236
+ ),
237
+ /* @__PURE__ */ jsx(
238
+ Button,
239
+ {
240
+ className: "flex-1",
241
+ onClick: () => void refreshAccounts(),
242
+ size: "sm",
243
+ tone: "ghost",
244
+ type: "button",
245
+ children: "Atualizar"
246
+ }
247
+ )
248
+ ] })
249
+ ] })
250
+ ] })
251
+ ] });
252
+ }
253
+ function OrgSwitcher() {
254
+ const {
255
+ createOrganization,
256
+ currentOrg,
257
+ isLoadingOrganizations,
258
+ organizations,
259
+ refreshOrganizations,
260
+ setCurrentOrg
261
+ } = useAuth();
262
+ const [open, setOpen] = useState(false);
263
+ const [creating, setCreating] = useState(false);
264
+ async function onCreate(event) {
265
+ event.preventDefault();
266
+ const form = new FormData(event.currentTarget);
267
+ const name = String(form.get("name") ?? "");
268
+ const slug = String(form.get("slug") ?? "");
269
+ const result = await createOrganization({ name, slug });
270
+ if (result.success) {
271
+ setCreating(false);
272
+ setOpen(false);
273
+ await refreshOrganizations();
274
+ }
275
+ }
276
+ return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
277
+ /* @__PURE__ */ jsxs(
278
+ "button",
279
+ {
280
+ className: "flex w-full items-center gap-3 rounded-xl border border-slate-200 bg-white p-2 text-left hover:bg-slate-50",
281
+ onClick: () => setOpen((value) => !value),
282
+ type: "button",
283
+ children: [
284
+ /* @__PURE__ */ jsx(Avatar, { name: currentOrg?.name, src: currentOrg?.imageUrl }),
285
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
286
+ /* @__PURE__ */ jsx("span", { className: "block truncate text-sm font-medium text-slate-950", children: currentOrg?.name ?? "Selecionar organiza\xE7\xE3o" }),
287
+ /* @__PURE__ */ jsx("span", { className: "block truncate text-xs text-slate-500", children: isLoadingOrganizations ? "Carregando..." : `${organizations.length} organiza\xE7\xF5es` })
288
+ ] }),
289
+ /* @__PURE__ */ jsx("span", { className: "text-slate-400", children: "\u2304" })
290
+ ]
291
+ }
292
+ ),
293
+ open && /* @__PURE__ */ jsxs("div", { className: "absolute right-0 z-30 mt-2 w-80 overflow-hidden rounded-xl border border-slate-200 bg-white shadow-lg", children: [
294
+ /* @__PURE__ */ jsx("div", { className: "max-h-72 overflow-y-auto p-2", children: organizations.map((organization) => /* @__PURE__ */ jsxs(
295
+ "button",
296
+ {
297
+ className: "flex w-full items-center gap-3 rounded-lg p-2 text-left hover:bg-slate-50",
298
+ onClick: () => {
299
+ void setCurrentOrg(organization.id);
300
+ setOpen(false);
301
+ },
302
+ type: "button",
303
+ children: [
304
+ /* @__PURE__ */ jsx(
305
+ Avatar,
306
+ {
307
+ name: organization.name,
308
+ size: "sm",
309
+ src: organization.imageUrl
310
+ }
311
+ ),
312
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
313
+ /* @__PURE__ */ jsx("span", { className: "block truncate text-sm font-medium text-slate-900", children: organization.name }),
314
+ /* @__PURE__ */ jsx("span", { className: "block truncate text-xs text-slate-500", children: organization.slug })
315
+ ] }),
316
+ organization.id === currentOrg?.id && /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-emerald-600", children: "Atual" })
317
+ ]
318
+ },
319
+ organization.id
320
+ )) }),
321
+ creating ? /* @__PURE__ */ jsxs(
322
+ "form",
323
+ {
324
+ className: "grid gap-2 border-t border-slate-200 p-3",
325
+ onSubmit: onCreate,
326
+ children: [
327
+ /* @__PURE__ */ jsx(Input, { name: "name", placeholder: "Nome da org", required: true }),
328
+ /* @__PURE__ */ jsx(Input, { name: "slug", placeholder: "slug-da-org", required: true }),
329
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
215
330
  /* @__PURE__ */ jsx(
216
- Avatar,
331
+ Button,
217
332
  {
218
- name: account.user.name ?? account.user.email,
333
+ className: "flex-1",
219
334
  size: "sm",
220
- src: account.user.imageUrl
335
+ tone: "primary",
336
+ type: "submit",
337
+ children: "Criar"
221
338
  }
222
339
  ),
223
- /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
224
- /* @__PURE__ */ jsx("span", { className: "block truncate text-sm font-medium text-slate-900", children: account.user.name ?? account.user.email }),
225
- /* @__PURE__ */ jsx("span", { className: "block truncate text-xs text-slate-500", children: account.user.email })
226
- ] }),
227
- account.isActive && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs font-medium text-emerald-600", children: "\u2713" })
228
- ]
229
- },
230
- account.sessionId ?? account.id
231
- ))
232
- ] }),
233
- /* @__PURE__ */ jsxs("div", { className: "flex gap-1.5 border-t border-slate-100 p-1.5", children: [
340
+ /* @__PURE__ */ jsx(
341
+ Button,
342
+ {
343
+ className: "flex-1",
344
+ onClick: () => setCreating(false),
345
+ size: "sm",
346
+ tone: "ghost",
347
+ type: "button",
348
+ children: "Cancelar"
349
+ }
350
+ )
351
+ ] })
352
+ ]
353
+ }
354
+ ) : /* @__PURE__ */ jsxs("div", { className: "flex gap-2 border-t border-slate-200 p-2", children: [
234
355
  /* @__PURE__ */ jsx(
235
356
  Button,
236
357
  {
237
358
  className: "flex-1",
238
- onClick: () => void addAccount(),
359
+ onClick: () => setCreating(true),
239
360
  size: "sm",
240
361
  type: "button",
241
- children: "+ Conta"
362
+ children: "Nova org"
242
363
  }
243
364
  ),
244
365
  /* @__PURE__ */ jsx(
245
366
  Button,
246
367
  {
247
368
  className: "flex-1",
248
- onClick: () => void refreshAccounts(),
369
+ onClick: () => void refreshOrganizations(),
249
370
  size: "sm",
250
371
  tone: "ghost",
251
372
  type: "button",
@@ -254,749 +375,632 @@ function AccountSwitcher() {
254
375
  )
255
376
  ] })
256
377
  ] })
257
- ] })
258
- ] });
259
- }
260
- function OrgSwitcher() {
261
- const {
262
- createOrganization,
263
- currentOrg,
264
- isLoadingOrganizations,
265
- organizations,
266
- refreshOrganizations,
267
- setCurrentOrg
268
- } = useOrg();
269
- const [open, setOpen] = useState(false);
270
- const [creating, setCreating] = useState(false);
271
- async function onCreate(event) {
272
- event.preventDefault();
273
- const form = new FormData(event.currentTarget);
274
- const name = String(form.get("name") ?? "");
275
- const slug = String(form.get("slug") ?? "");
276
- const result = await createOrganization({ name, slug });
277
- if (result.success) {
278
- setCreating(false);
279
- setOpen(false);
280
- await refreshOrganizations();
281
- }
378
+ ] });
282
379
  }
283
- return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
284
- /* @__PURE__ */ jsxs(
285
- "button",
286
- {
287
- className: "flex w-full items-center gap-3 rounded-xl border border-slate-200 bg-white p-2 text-left hover:bg-slate-50",
288
- onClick: () => setOpen((value) => !value),
289
- type: "button",
290
- children: [
291
- /* @__PURE__ */ jsx(Avatar, { name: currentOrg?.name, src: currentOrg?.imageUrl }),
292
- /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
293
- /* @__PURE__ */ jsx("span", { className: "block truncate text-sm font-medium text-slate-950", children: currentOrg?.name ?? "Selecionar organiza\xE7\xE3o" }),
294
- /* @__PURE__ */ jsx("span", { className: "block truncate text-xs text-slate-500", children: isLoadingOrganizations ? "Carregando..." : `${organizations.length} organiza\xE7\xF5es` })
295
- ] }),
296
- /* @__PURE__ */ jsx("span", { className: "text-slate-400", children: "\u2304" })
297
- ]
380
+ function UserButton() {
381
+ const { user } = useAuth();
382
+ const [open, setOpen] = useState(false);
383
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
384
+ /* @__PURE__ */ jsx("button", { onClick: () => setOpen(true), type: "button", children: /* @__PURE__ */ jsx(Avatar, { name: user?.name ?? user?.email, src: user?.imageUrl }) }),
385
+ /* @__PURE__ */ jsx(ProfileModal, { open, onOpenChange: setOpen })
386
+ ] });
387
+ }
388
+ function OrganizationButton() {
389
+ const { currentOrg } = useAuth();
390
+ const [open, setOpen] = useState(false);
391
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
392
+ /* @__PURE__ */ jsx(
393
+ "button",
394
+ {
395
+ className: "flex h-10 w-10 items-center justify-center rounded-xl bg-white border border-slate-200 text-xs font-semibold text-slate-700 transition hover:bg-slate-50 hover:border-slate-300",
396
+ onClick: () => setOpen(true),
397
+ title: currentOrg?.name ?? "Organiza\xE7\xE3o",
398
+ type: "button",
399
+ children: currentOrg?.imageUrl ? /* @__PURE__ */ jsx(
400
+ "img",
401
+ {
402
+ alt: currentOrg.name,
403
+ className: "h-full w-full rounded-xl object-cover",
404
+ src: currentOrg.imageUrl
405
+ }
406
+ ) : (currentOrg?.name ?? "O")[0]?.toUpperCase()
407
+ }
408
+ ),
409
+ /* @__PURE__ */ jsx(ManageOrganizationModal, { open, onOpenChange: setOpen })
410
+ ] });
411
+ }
412
+ function ProfileModal({
413
+ open,
414
+ onOpenChange
415
+ }) {
416
+ const {
417
+ signOut,
418
+ signOutAll,
419
+ user,
420
+ organizations,
421
+ currentOrg,
422
+ setCurrentOrg,
423
+ updateUser,
424
+ listUserSessions,
425
+ revokeUserSession
426
+ } = useAuth();
427
+ const [tab, setTab] = useState("profile");
428
+ const [sessions, setSessions] = useState([]);
429
+ const [saving, setSaving] = useState(false);
430
+ const [saveError, setSaveError] = useState(null);
431
+ const [saveSuccess, setSaveSuccess] = useState(false);
432
+ useEffect(() => {
433
+ if (!open) {
434
+ setTab("profile");
435
+ setSaveError(null);
436
+ setSaveSuccess(false);
437
+ }
438
+ }, [open]);
439
+ useEffect(() => {
440
+ if (open && user && tab === "sessions") {
441
+ void listUserSessions({ userId: user.id }).then(setSessions).catch(() => setSessions([]));
442
+ }
443
+ }, [listUserSessions, open, tab, user]);
444
+ async function onProfileSubmit(event) {
445
+ event.preventDefault();
446
+ if (!user) return;
447
+ const form = new FormData(event.currentTarget);
448
+ setSaving(true);
449
+ setSaveError(null);
450
+ setSaveSuccess(false);
451
+ try {
452
+ await updateUser(user.id, {
453
+ name: String(form.get("name") ?? "") || null,
454
+ phone: String(form.get("phone") ?? "") || null,
455
+ imageUrl: String(form.get("imageUrl") ?? "") || null
456
+ });
457
+ setSaveSuccess(true);
458
+ setTimeout(() => setSaveSuccess(false), 2500);
459
+ } catch (err) {
460
+ setSaveError(err instanceof Error ? err.message : "Erro ao salvar.");
461
+ } finally {
462
+ setSaving(false);
298
463
  }
299
- ),
300
- open && /* @__PURE__ */ jsxs("div", { className: "absolute right-0 z-30 mt-2 w-80 overflow-hidden rounded-xl border border-slate-200 bg-white shadow-lg", children: [
301
- /* @__PURE__ */ jsx("div", { className: "max-h-72 overflow-y-auto p-2", children: organizations.map((organization) => /* @__PURE__ */ jsxs(
464
+ }
465
+ if (!open) return null;
466
+ return /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4", children: /* @__PURE__ */ jsxs("div", { className: "flex max-h-[90vh] w-full max-w-lg flex-col overflow-hidden rounded-2xl bg-white shadow-2xl", children: [
467
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center justify-between border-b border-slate-100 px-6 py-4", children: [
468
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
469
+ /* @__PURE__ */ jsx(
470
+ Avatar,
471
+ {
472
+ name: user?.name ?? user?.email,
473
+ size: "sm",
474
+ src: user?.imageUrl
475
+ }
476
+ ),
477
+ /* @__PURE__ */ jsxs("div", { children: [
478
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-slate-900", children: user?.name ?? user?.email ?? "Minha conta" }),
479
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-slate-500", children: user?.email })
480
+ ] })
481
+ ] }),
482
+ /* @__PURE__ */ jsx(
483
+ "button",
484
+ {
485
+ "aria-label": "Fechar",
486
+ className: "rounded-lg p-1.5 text-slate-400 transition hover:bg-slate-100 hover:text-slate-700",
487
+ onClick: () => onOpenChange(false),
488
+ type: "button",
489
+ children: "\u2715"
490
+ }
491
+ )
492
+ ] }),
493
+ /* @__PURE__ */ jsx("div", { className: "shrink-0 flex gap-1 border-b border-slate-100 px-6 pt-3", children: [
494
+ { id: "profile", label: "Perfil" },
495
+ { id: "sessions", label: "Sess\xF5es" },
496
+ { id: "orgs", label: "Organiza\xE7\xF5es" }
497
+ ].map((t) => /* @__PURE__ */ jsx(
302
498
  "button",
303
499
  {
304
- className: "flex w-full items-center gap-3 rounded-lg p-2 text-left hover:bg-slate-50",
305
- onClick: () => {
306
- void setCurrentOrg(organization.id);
307
- setOpen(false);
308
- },
500
+ className: cx(
501
+ "mb-[-1px] border-b-2 px-3 pb-2.5 text-xs font-medium transition",
502
+ tab === t.id ? "border-slate-900 text-slate-900" : "border-transparent text-slate-500 hover:text-slate-700"
503
+ ),
504
+ onClick: () => setTab(t.id),
309
505
  type: "button",
310
- children: [
506
+ children: t.label
507
+ },
508
+ t.id
509
+ )) }),
510
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto px-6 py-5", children: [
511
+ tab === "profile" && user && /* @__PURE__ */ jsxs("form", { className: "grid gap-4", onSubmit: onProfileSubmit, children: [
512
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 rounded-xl bg-slate-50 p-4", children: [
311
513
  /* @__PURE__ */ jsx(
312
514
  Avatar,
313
515
  {
314
- name: organization.name,
315
- size: "sm",
316
- src: organization.imageUrl
516
+ name: user.name ?? user.email,
517
+ size: "lg",
518
+ src: user.imageUrl
317
519
  }
318
520
  ),
319
- /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
320
- /* @__PURE__ */ jsx("span", { className: "block truncate text-sm font-medium text-slate-900", children: organization.name }),
321
- /* @__PURE__ */ jsx("span", { className: "block truncate text-xs text-slate-500", children: organization.slug })
322
- ] }),
323
- organization.id === currentOrg?.id && /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-emerald-600", children: "Atual" })
324
- ]
325
- },
326
- organization.id
327
- )) }),
328
- creating ? /* @__PURE__ */ jsxs(
329
- "form",
330
- {
331
- className: "grid gap-2 border-t border-slate-200 p-3",
332
- onSubmit: onCreate,
333
- children: [
334
- /* @__PURE__ */ jsx(Input, { name: "name", placeholder: "Nome da org", required: true }),
335
- /* @__PURE__ */ jsx(Input, { name: "slug", placeholder: "slug-da-org", required: true }),
521
+ /* @__PURE__ */ jsxs("div", { children: [
522
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-slate-900", children: user.name ?? "Sem nome" }),
523
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-slate-500", children: user.email })
524
+ ] })
525
+ ] }),
526
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-3 sm:grid-cols-2", children: [
527
+ /* @__PURE__ */ jsx(Field, { label: "Nome", children: /* @__PURE__ */ jsx(
528
+ Input,
529
+ {
530
+ defaultValue: user.name ?? "",
531
+ name: "name",
532
+ placeholder: "Seu nome"
533
+ }
534
+ ) }),
535
+ /* @__PURE__ */ jsx(Field, { label: "Telefone", children: /* @__PURE__ */ jsx(
536
+ Input,
537
+ {
538
+ defaultValue: user.phone ?? "",
539
+ name: "phone",
540
+ placeholder: "+55 11 99999-9999"
541
+ }
542
+ ) })
543
+ ] }),
544
+ /* @__PURE__ */ jsx(Field, { label: "URL da imagem", children: /* @__PURE__ */ jsx(
545
+ Input,
546
+ {
547
+ defaultValue: user.imageUrl ?? "",
548
+ name: "imageUrl",
549
+ placeholder: "https://..."
550
+ }
551
+ ) }),
552
+ saveError && /* @__PURE__ */ jsx("p", { className: "rounded-lg bg-red-50 px-3 py-2 text-xs text-red-600", children: saveError }),
553
+ saveSuccess && /* @__PURE__ */ jsx("p", { className: "rounded-lg bg-emerald-50 px-3 py-2 text-xs text-emerald-600", children: "Perfil salvo com sucesso." }),
554
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-t border-slate-100 pt-2", children: [
336
555
  /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
337
556
  /* @__PURE__ */ jsx(
338
557
  Button,
339
558
  {
340
- className: "flex-1",
559
+ onClick: () => void signOut(),
341
560
  size: "sm",
342
- tone: "primary",
343
- type: "submit",
344
- children: "Criar"
561
+ tone: "ghost",
562
+ type: "button",
563
+ children: "Sair"
345
564
  }
346
565
  ),
347
566
  /* @__PURE__ */ jsx(
348
567
  Button,
349
568
  {
350
- className: "flex-1",
351
- onClick: () => setCreating(false),
569
+ onClick: () => void signOutAll(),
352
570
  size: "sm",
353
- tone: "ghost",
571
+ tone: "danger",
354
572
  type: "button",
355
- children: "Cancelar"
573
+ children: "Sair de todas"
356
574
  }
357
575
  )
358
- ] })
359
- ]
360
- }
361
- ) : /* @__PURE__ */ jsxs("div", { className: "flex gap-2 border-t border-slate-200 p-2", children: [
362
- /* @__PURE__ */ jsx(
363
- Button,
364
- {
365
- className: "flex-1",
366
- onClick: () => setCreating(true),
367
- size: "sm",
368
- type: "button",
369
- children: "Nova org"
370
- }
371
- ),
372
- /* @__PURE__ */ jsx(
373
- Button,
374
- {
375
- className: "flex-1",
376
- onClick: () => void refreshOrganizations(),
377
- size: "sm",
378
- tone: "ghost",
379
- type: "button",
380
- children: "Atualizar"
381
- }
382
- )
576
+ ] }),
577
+ /* @__PURE__ */ jsx(
578
+ Button,
579
+ {
580
+ disabled: saving,
581
+ size: "sm",
582
+ tone: "primary",
583
+ type: "submit",
584
+ children: saving ? "Salvando\u2026" : "Salvar"
585
+ }
586
+ )
587
+ ] })
588
+ ] }),
589
+ tab === "sessions" && /* @__PURE__ */ jsxs("div", { className: "grid gap-2", children: [
590
+ sessions.length === 0 && /* @__PURE__ */ jsx("p", { className: "py-6 text-center text-sm text-slate-400", children: "Nenhuma sess\xE3o ativa." }),
591
+ sessions.map((session) => {
592
+ const expired = isExpired(session.expiresAt);
593
+ return /* @__PURE__ */ jsxs(
594
+ "div",
595
+ {
596
+ className: "flex items-center justify-between gap-4 rounded-xl border border-slate-200 p-4",
597
+ children: [
598
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
599
+ /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-medium text-slate-900", children: session.deviceName ?? "Dispositivo" }),
600
+ /* @__PURE__ */ jsxs("p", { className: "mt-0.5 truncate text-xs text-slate-500", children: [
601
+ session.ip ?? "IP desconhecido",
602
+ " \xB7",
603
+ " ",
604
+ /* @__PURE__ */ jsx("span", { className: expired ? "text-amber-600" : "", children: expired ? "Expirada" : `Expira ${formatDate(session.expiresAt)}` })
605
+ ] })
606
+ ] }),
607
+ /* @__PURE__ */ jsx(
608
+ Button,
609
+ {
610
+ onClick: async () => {
611
+ await revokeUserSession(session.id);
612
+ setSessions(
613
+ (s) => s.filter((x) => x.id !== session.id)
614
+ );
615
+ },
616
+ size: "sm",
617
+ tone: "danger",
618
+ type: "button",
619
+ children: "Revogar"
620
+ }
621
+ )
622
+ ]
623
+ },
624
+ session.id
625
+ );
626
+ })
627
+ ] }),
628
+ tab === "orgs" && /* @__PURE__ */ jsxs("div", { className: "grid gap-2", children: [
629
+ organizations.length === 0 && /* @__PURE__ */ jsx("p", { className: "py-6 text-center text-sm text-slate-400", children: "Nenhuma organiza\xE7\xE3o." }),
630
+ organizations.map((org) => /* @__PURE__ */ jsxs(
631
+ "button",
632
+ {
633
+ className: cx(
634
+ "flex w-full items-center gap-3 rounded-xl border p-3 text-left transition",
635
+ org.id === currentOrg?.id ? "border-slate-900 bg-slate-50" : "border-slate-200 hover:border-slate-300 hover:bg-slate-50"
636
+ ),
637
+ onClick: () => void setCurrentOrg(org.id),
638
+ type: "button",
639
+ children: [
640
+ /* @__PURE__ */ jsx(Avatar, { name: org.name, size: "sm", src: org.imageUrl }),
641
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
642
+ /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-medium text-slate-900", children: org.name }),
643
+ /* @__PURE__ */ jsxs("p", { className: "truncate text-xs text-slate-500", children: [
644
+ "/",
645
+ org.slug
646
+ ] })
647
+ ] }),
648
+ org.id === currentOrg?.id && /* @__PURE__ */ jsx("span", { className: "shrink-0 rounded-full bg-slate-900 px-2 py-0.5 text-[10px] font-medium text-white", children: "Ativa" })
649
+ ]
650
+ },
651
+ org.id
652
+ ))
653
+ ] })
383
654
  ] })
384
- ] })
385
- ] });
386
- }
387
- function UserButton() {
388
- const { user } = useAuth();
389
- const [open, setOpen] = useState(false);
390
- return /* @__PURE__ */ jsxs(Fragment, { children: [
391
- /* @__PURE__ */ jsx("button", { onClick: () => setOpen(true), type: "button", children: /* @__PURE__ */ jsx(Avatar, { name: user?.name ?? user?.email, src: user?.imageUrl }) }),
392
- /* @__PURE__ */ jsx(ProfileModal, { open, onOpenChange: setOpen })
393
- ] });
394
- }
395
- function OrganizationButton() {
396
- const { currentOrg } = useOrg();
397
- const [open, setOpen] = useState(false);
398
- return /* @__PURE__ */ jsxs(Fragment, { children: [
399
- /* @__PURE__ */ jsx(
400
- "button",
401
- {
402
- className: "flex h-10 w-10 items-center justify-center rounded-xl bg-white border border-slate-200 text-xs font-semibold text-slate-700 transition hover:bg-slate-50 hover:border-slate-300",
403
- onClick: () => setOpen(true),
404
- title: currentOrg?.name ?? "Organiza\xE7\xE3o",
405
- type: "button",
406
- children: currentOrg?.imageUrl ? /* @__PURE__ */ jsx(
407
- "img",
408
- {
409
- alt: currentOrg.name,
410
- className: "h-full w-full rounded-xl object-cover",
411
- src: currentOrg.imageUrl
412
- }
413
- ) : (currentOrg?.name ?? "O")[0]?.toUpperCase()
655
+ ] }) });
656
+ }
657
+ function ManageOrganizationModal({
658
+ open,
659
+ onOpenChange
660
+ }) {
661
+ const {
662
+ createOrganization,
663
+ currentOrg,
664
+ organizations,
665
+ refreshOrganizations,
666
+ setCurrentOrg,
667
+ updateOrganization,
668
+ listPermissions,
669
+ listRoles
670
+ } = useAuth();
671
+ const [tab, setTab] = useState("orgs");
672
+ const [roles, setRoles] = useState({ systemRoles: [], customRoles: [] });
673
+ const [permissions, setPermissions] = useState([]);
674
+ const [saving, setSaving] = useState(false);
675
+ const [saveSuccess, setSaveSuccess] = useState(false);
676
+ const [saveError, setSaveError] = useState(null);
677
+ const [creating, setCreating] = useState(false);
678
+ const [createError, setCreateError] = useState(null);
679
+ useEffect(() => {
680
+ if (!open) {
681
+ setTab("orgs");
682
+ setSaveError(null);
683
+ setSaveSuccess(false);
684
+ setCreating(false);
685
+ setCreateError(null);
414
686
  }
415
- ),
416
- /* @__PURE__ */ jsx(ManageOrganizationModal, { open, onOpenChange: setOpen })
417
- ] });
418
- }
419
- function ProfileModal({
420
- open,
421
- onOpenChange
422
- }) {
423
- const { signOut, signOutAll, user } = useAuth();
424
- const { currentOrg, organizations, setCurrentOrg } = useOrg();
425
- const { updateUser } = useUsers();
426
- const { listUserSessions, revokeUserSession } = useSessions();
427
- const [tab, setTab] = useState("profile");
428
- const [sessions, setSessions] = useState([]);
429
- const [saving, setSaving] = useState(false);
430
- const [saveError, setSaveError] = useState(null);
431
- const [saveSuccess, setSaveSuccess] = useState(false);
432
- useEffect(() => {
433
- if (!open) {
434
- setTab("profile");
687
+ }, [open]);
688
+ useEffect(() => {
689
+ if (!open || !currentOrg) return;
690
+ if (tab === "members" || tab === "roles") {
691
+ void listRoles({ organizationId: currentOrg.id }).then(setRoles).catch(() => setRoles({ systemRoles: [], customRoles: [] }));
692
+ void listPermissions({}).then(setPermissions).catch(() => setPermissions([]));
693
+ }
694
+ }, [currentOrg, listPermissions, listRoles, open, tab]);
695
+ async function onOrgSubmit(event) {
696
+ event.preventDefault();
697
+ if (!currentOrg) return;
698
+ const form = new FormData(event.currentTarget);
699
+ setSaving(true);
435
700
  setSaveError(null);
436
701
  setSaveSuccess(false);
702
+ try {
703
+ await updateOrganization(currentOrg.id, {
704
+ name: String(form.get("name") ?? ""),
705
+ description: String(form.get("description") ?? "") || null,
706
+ slug: String(form.get("slug") ?? ""),
707
+ domain: String(form.get("domain") ?? "") || null,
708
+ imageUrl: String(form.get("imageUrl") ?? "") || null,
709
+ faviconUrl: String(form.get("faviconUrl") ?? "") || null
710
+ });
711
+ setSaveSuccess(true);
712
+ setTimeout(() => setSaveSuccess(false), 2500);
713
+ } catch (err) {
714
+ setSaveError(err instanceof Error ? err.message : "Erro ao salvar.");
715
+ } finally {
716
+ setSaving(false);
717
+ }
437
718
  }
438
- }, [open]);
439
- useEffect(() => {
440
- if (open && user && tab === "sessions") {
441
- void listUserSessions({ userId: user.id }).then(setSessions).catch(() => setSessions([]));
442
- }
443
- }, [listUserSessions, open, tab, user]);
444
- async function onProfileSubmit(event) {
445
- event.preventDefault();
446
- if (!user) return;
447
- const form = new FormData(event.currentTarget);
448
- setSaving(true);
449
- setSaveError(null);
450
- setSaveSuccess(false);
451
- try {
452
- await updateUser(user.id, {
453
- name: String(form.get("name") ?? "") || null,
454
- phone: String(form.get("phone") ?? "") || null,
455
- imageUrl: String(form.get("imageUrl") ?? "") || null
456
- });
457
- setSaveSuccess(true);
458
- setTimeout(() => setSaveSuccess(false), 2500);
459
- } catch (err) {
460
- setSaveError(err instanceof Error ? err.message : "Erro ao salvar.");
461
- } finally {
462
- setSaving(false);
719
+ async function onCreateOrg(event) {
720
+ event.preventDefault();
721
+ const form = new FormData(event.currentTarget);
722
+ setCreating(true);
723
+ setCreateError(null);
724
+ try {
725
+ const result = await createOrganization({
726
+ name: String(form.get("name") ?? ""),
727
+ slug: String(form.get("slug") ?? "")
728
+ });
729
+ if (result.success) {
730
+ await refreshOrganizations();
731
+ if (result.data?.id) {
732
+ void setCurrentOrg(result.data.id);
733
+ }
734
+ setTab("info");
735
+ } else {
736
+ setCreateError(result.error ?? "Erro ao criar organiza\xE7\xE3o.");
737
+ }
738
+ } catch (err) {
739
+ setCreateError(err instanceof Error ? err.message : "Erro ao criar.");
740
+ } finally {
741
+ setCreating(false);
742
+ }
463
743
  }
464
- }
465
- if (!open) return null;
466
- return /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4", children: /* @__PURE__ */ jsxs("div", { className: "flex max-h-[90vh] w-full max-w-lg flex-col overflow-hidden rounded-2xl bg-white shadow-2xl", children: [
467
- /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center justify-between border-b border-slate-100 px-6 py-4", children: [
468
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
744
+ if (!open) return null;
745
+ const orgTabs = [
746
+ { id: "orgs", label: "Organiza\xE7\xF5es" },
747
+ { id: "info", label: "Geral" },
748
+ { id: "members", label: "Membros" },
749
+ { id: "roles", label: "Roles" },
750
+ { id: "new", label: "+ Nova org" }
751
+ ];
752
+ return /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4", children: /* @__PURE__ */ jsxs("div", { className: "flex max-h-[90vh] w-full max-w-2xl flex-col overflow-hidden rounded-2xl bg-white shadow-2xl", children: [
753
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center justify-between border-b border-slate-100 px-6 py-4", children: [
754
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
755
+ currentOrg?.imageUrl ? /* @__PURE__ */ jsx(
756
+ "img",
757
+ {
758
+ alt: currentOrg.name,
759
+ className: "h-8 w-8 rounded-lg object-cover",
760
+ src: currentOrg.imageUrl
761
+ }
762
+ ) : /* @__PURE__ */ jsx("span", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-slate-100 text-xs font-semibold text-slate-600", children: (currentOrg?.name ?? "O")[0]?.toUpperCase() }),
763
+ /* @__PURE__ */ jsxs("div", { children: [
764
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-slate-900", children: currentOrg?.name ?? "Organiza\xE7\xE3o" }),
765
+ currentOrg?.slug && /* @__PURE__ */ jsxs("p", { className: "text-xs text-slate-500", children: [
766
+ "/",
767
+ currentOrg.slug
768
+ ] })
769
+ ] })
770
+ ] }),
469
771
  /* @__PURE__ */ jsx(
470
- Avatar,
772
+ "button",
471
773
  {
472
- name: user?.name ?? user?.email,
473
- size: "sm",
474
- src: user?.imageUrl
774
+ "aria-label": "Fechar",
775
+ className: "rounded-lg p-1.5 text-slate-400 transition hover:bg-slate-100 hover:text-slate-700",
776
+ onClick: () => onOpenChange(false),
777
+ type: "button",
778
+ children: "\u2715"
475
779
  }
476
- ),
477
- /* @__PURE__ */ jsxs("div", { children: [
478
- /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-slate-900", children: user?.name ?? user?.email ?? "Minha conta" }),
479
- /* @__PURE__ */ jsx("p", { className: "text-xs text-slate-500", children: user?.email })
480
- ] })
780
+ )
481
781
  ] }),
482
- /* @__PURE__ */ jsx(
782
+ /* @__PURE__ */ jsx("div", { className: "flex shrink-0 gap-1 border-b border-slate-100 px-6 pt-3", children: orgTabs.map((t) => /* @__PURE__ */ jsx(
483
783
  "button",
484
784
  {
485
- "aria-label": "Fechar",
486
- className: "rounded-lg p-1.5 text-slate-400 transition hover:bg-slate-100 hover:text-slate-700",
487
- onClick: () => onOpenChange(false),
785
+ className: cx(
786
+ "mb-[-1px] border-b-2 px-3 pb-2.5 text-xs font-medium transition",
787
+ tab === t.id ? "border-slate-900 text-slate-900" : "border-transparent text-slate-500 hover:text-slate-700"
788
+ ),
789
+ onClick: () => setTab(t.id),
488
790
  type: "button",
489
- children: "\u2715"
490
- }
491
- )
492
- ] }),
493
- /* @__PURE__ */ jsx("div", { className: "shrink-0 flex gap-1 border-b border-slate-100 px-6 pt-3", children: [
494
- { id: "profile", label: "Perfil" },
495
- { id: "sessions", label: "Sess\xF5es" },
496
- { id: "orgs", label: "Organiza\xE7\xF5es" }
497
- ].map((t) => /* @__PURE__ */ jsx(
498
- "button",
499
- {
500
- className: cx(
501
- "mb-[-1px] border-b-2 px-3 pb-2.5 text-xs font-medium transition",
502
- tab === t.id ? "border-slate-900 text-slate-900" : "border-transparent text-slate-500 hover:text-slate-700"
503
- ),
504
- onClick: () => setTab(t.id),
505
- type: "button",
506
- children: t.label
507
- },
508
- t.id
509
- )) }),
510
- /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto px-6 py-5", children: [
511
- tab === "profile" && user && /* @__PURE__ */ jsxs("form", { className: "grid gap-4", onSubmit: onProfileSubmit, children: [
512
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 rounded-xl bg-slate-50 p-4", children: [
513
- /* @__PURE__ */ jsx(
514
- Avatar,
791
+ children: t.label
792
+ },
793
+ t.id
794
+ )) }),
795
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto px-6 py-5", children: [
796
+ !currentOrg && /* @__PURE__ */ jsx("p", { className: "py-8 text-center text-sm text-slate-400", children: "Nenhuma organiza\xE7\xE3o selecionada." }),
797
+ tab === "orgs" && /* @__PURE__ */ jsxs("div", { className: "grid gap-2", children: [
798
+ organizations.length === 0 && /* @__PURE__ */ jsx("p", { className: "py-8 text-center text-sm text-slate-400", children: "Nenhuma organiza\xE7\xE3o dispon\xEDvel." }),
799
+ organizations.map((org) => /* @__PURE__ */ jsxs(
800
+ "button",
515
801
  {
516
- name: user.name ?? user.email,
517
- size: "lg",
518
- src: user.imageUrl
519
- }
520
- ),
521
- /* @__PURE__ */ jsxs("div", { children: [
522
- /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-slate-900", children: user.name ?? "Sem nome" }),
523
- /* @__PURE__ */ jsx("p", { className: "text-xs text-slate-500", children: user.email })
524
- ] })
802
+ className: cx(
803
+ "flex w-full items-center gap-3 rounded-xl border p-3 text-left transition",
804
+ org.id === currentOrg?.id ? "border-slate-900 bg-slate-50" : "border-slate-200 hover:border-slate-300 hover:bg-slate-50"
805
+ ),
806
+ onClick: () => {
807
+ void setCurrentOrg(org.id);
808
+ onOpenChange(false);
809
+ },
810
+ type: "button",
811
+ children: [
812
+ /* @__PURE__ */ jsx(Avatar, { name: org.name, size: "sm", src: org.imageUrl }),
813
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
814
+ /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-medium text-slate-900", children: org.name }),
815
+ /* @__PURE__ */ jsxs("p", { className: "truncate text-xs text-slate-500", children: [
816
+ "/",
817
+ org.slug
818
+ ] })
819
+ ] }),
820
+ org.id === currentOrg?.id && /* @__PURE__ */ jsx("span", { className: "shrink-0 rounded-full bg-slate-900 px-2 py-0.5 text-[10px] font-medium text-white", children: "Ativa" })
821
+ ]
822
+ },
823
+ org.id
824
+ ))
525
825
  ] }),
526
- /* @__PURE__ */ jsxs("div", { className: "grid gap-3 sm:grid-cols-2", children: [
527
- /* @__PURE__ */ jsx(Field, { label: "Nome", children: /* @__PURE__ */ jsx(
528
- Input,
826
+ tab === "info" && currentOrg && /* @__PURE__ */ jsxs("form", { className: "grid gap-4", onSubmit: onOrgSubmit, children: [
827
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-3 sm:grid-cols-2", children: [
828
+ /* @__PURE__ */ jsx(Field, { label: "Nome *", children: /* @__PURE__ */ jsx(Input, { defaultValue: currentOrg.name, name: "name", required: true }) }),
829
+ /* @__PURE__ */ jsx(Field, { label: "Slug *", children: /* @__PURE__ */ jsx(Input, { defaultValue: currentOrg.slug, name: "slug", required: true }) })
830
+ ] }),
831
+ /* @__PURE__ */ jsx(Field, { label: "Descri\xE7\xE3o", children: /* @__PURE__ */ jsx(
832
+ Textarea,
529
833
  {
530
- defaultValue: user.name ?? "",
531
- name: "name",
532
- placeholder: "Seu nome"
834
+ defaultValue: currentOrg.description ?? "",
835
+ name: "description",
836
+ placeholder: "Descreva a organiza\xE7\xE3o\u2026"
533
837
  }
534
838
  ) }),
535
- /* @__PURE__ */ jsx(Field, { label: "Telefone", children: /* @__PURE__ */ jsx(
536
- Input,
537
- {
538
- defaultValue: user.phone ?? "",
539
- name: "phone",
540
- placeholder: "+55 11 99999-9999"
541
- }
542
- ) })
543
- ] }),
544
- /* @__PURE__ */ jsx(Field, { label: "URL da imagem", children: /* @__PURE__ */ jsx(
545
- Input,
546
- {
547
- defaultValue: user.imageUrl ?? "",
548
- name: "imageUrl",
549
- placeholder: "https://..."
550
- }
551
- ) }),
552
- saveError && /* @__PURE__ */ jsx("p", { className: "rounded-lg bg-red-50 px-3 py-2 text-xs text-red-600", children: saveError }),
553
- saveSuccess && /* @__PURE__ */ jsx("p", { className: "rounded-lg bg-emerald-50 px-3 py-2 text-xs text-emerald-600", children: "Perfil salvo com sucesso." }),
554
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-t border-slate-100 pt-2", children: [
555
- /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
556
- /* @__PURE__ */ jsx(
557
- Button,
839
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-3 sm:grid-cols-2", children: [
840
+ /* @__PURE__ */ jsx(Field, { label: "Dom\xEDnio", children: /* @__PURE__ */ jsx(
841
+ Input,
558
842
  {
559
- onClick: () => void signOut(),
560
- size: "sm",
561
- tone: "ghost",
562
- type: "button",
563
- children: "Sair"
843
+ defaultValue: currentOrg.domain ?? "",
844
+ name: "domain",
845
+ placeholder: "acme.com"
564
846
  }
565
- ),
566
- /* @__PURE__ */ jsx(
567
- Button,
847
+ ) }),
848
+ /* @__PURE__ */ jsx(Field, { label: "URL da imagem", children: /* @__PURE__ */ jsx(
849
+ Input,
568
850
  {
569
- onClick: () => void signOutAll(),
570
- size: "sm",
571
- tone: "danger",
572
- type: "button",
573
- children: "Sair de todas"
851
+ defaultValue: currentOrg.imageUrl ?? "",
852
+ name: "imageUrl",
853
+ placeholder: "https://..."
574
854
  }
575
- )
855
+ ) })
576
856
  ] }),
577
- /* @__PURE__ */ jsx(
857
+ /* @__PURE__ */ jsx(Field, { label: "URL do favicon", children: /* @__PURE__ */ jsx(
858
+ Input,
859
+ {
860
+ defaultValue: currentOrg.faviconUrl ?? "",
861
+ name: "faviconUrl",
862
+ placeholder: "https://..."
863
+ }
864
+ ) }),
865
+ saveError && /* @__PURE__ */ jsx("p", { className: "rounded-lg bg-red-50 px-3 py-2 text-xs text-red-600", children: saveError }),
866
+ saveSuccess && /* @__PURE__ */ jsx("p", { className: "rounded-lg bg-emerald-50 px-3 py-2 text-xs text-emerald-600", children: "Organiza\xE7\xE3o atualizada." }),
867
+ /* @__PURE__ */ jsx("div", { className: "flex justify-end pt-1", children: /* @__PURE__ */ jsx(
578
868
  Button,
579
869
  {
580
870
  disabled: saving,
581
871
  size: "sm",
582
872
  tone: "primary",
583
873
  type: "submit",
584
- children: saving ? "Salvando\u2026" : "Salvar"
874
+ children: saving ? "Salvando\u2026" : "Salvar organiza\xE7\xE3o"
585
875
  }
586
- )
587
- ] })
588
- ] }),
589
- tab === "sessions" && /* @__PURE__ */ jsxs("div", { className: "grid gap-2", children: [
590
- sessions.length === 0 && /* @__PURE__ */ jsx("p", { className: "py-6 text-center text-sm text-slate-400", children: "Nenhuma sess\xE3o ativa." }),
591
- sessions.map((session) => {
592
- const expired = isExpired(session.expiresAt);
593
- return /* @__PURE__ */ jsxs(
876
+ ) })
877
+ ] }),
878
+ tab === "members" && currentOrg && /* @__PURE__ */ jsxs("div", { className: "grid gap-2", children: [
879
+ (currentOrg.members ?? []).length === 0 && /* @__PURE__ */ jsx("p", { className: "py-8 text-center text-sm text-slate-400", children: "Nenhum membro nesta organiza\xE7\xE3o." }),
880
+ (currentOrg.members ?? []).map((member) => /* @__PURE__ */ jsxs(
594
881
  "div",
595
882
  {
596
- className: "flex items-center justify-between gap-4 rounded-xl border border-slate-200 p-4",
883
+ className: "flex items-center gap-3 rounded-xl border border-slate-200 p-4",
597
884
  children: [
598
- /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
599
- /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-medium text-slate-900", children: session.deviceName ?? "Dispositivo" }),
600
- /* @__PURE__ */ jsxs("p", { className: "mt-0.5 truncate text-xs text-slate-500", children: [
601
- session.ip ?? "IP desconhecido",
602
- " \xB7",
603
- " ",
604
- /* @__PURE__ */ jsx("span", { className: expired ? "text-amber-600" : "", children: expired ? "Expirada" : `Expira ${formatDate(session.expiresAt)}` })
605
- ] })
606
- ] }),
607
885
  /* @__PURE__ */ jsx(
608
- Button,
886
+ Avatar,
609
887
  {
610
- onClick: async () => {
611
- await revokeUserSession(session.id);
612
- setSessions(
613
- (s) => s.filter((x) => x.id !== session.id)
614
- );
615
- },
888
+ name: member.user.name ?? member.user.email,
616
889
  size: "sm",
617
- tone: "danger",
618
- type: "button",
619
- children: "Revogar"
890
+ src: member.user.imageUrl
620
891
  }
621
- )
892
+ ),
893
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
894
+ /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-medium text-slate-900", children: member.user.name ?? member.user.email }),
895
+ /* @__PURE__ */ jsx("p", { className: "truncate text-xs text-slate-500", children: member.user.email })
896
+ ] }),
897
+ /* @__PURE__ */ jsx("div", { className: "flex shrink-0 flex-wrap justify-end gap-1", children: (member.roleAssignments ?? []).map((a) => /* @__PURE__ */ jsx(
898
+ "span",
899
+ {
900
+ className: "rounded-full bg-slate-900 px-2 py-0.5 text-[11px] font-medium text-white",
901
+ children: a.roleDefinition?.name ?? a.customRole?.name ?? a.id
902
+ },
903
+ a.id
904
+ )) })
622
905
  ]
623
906
  },
624
- session.id
625
- );
626
- })
627
- ] }),
628
- tab === "orgs" && /* @__PURE__ */ jsxs("div", { className: "grid gap-2", children: [
629
- organizations.length === 0 && /* @__PURE__ */ jsx("p", { className: "py-6 text-center text-sm text-slate-400", children: "Nenhuma organiza\xE7\xE3o." }),
630
- organizations.map((org) => /* @__PURE__ */ jsxs(
631
- "button",
632
- {
633
- className: cx(
634
- "flex w-full items-center gap-3 rounded-xl border p-3 text-left transition",
635
- org.id === currentOrg?.id ? "border-slate-900 bg-slate-50" : "border-slate-200 hover:border-slate-300 hover:bg-slate-50"
907
+ member.id
908
+ ))
909
+ ] }),
910
+ tab === "new" && /* @__PURE__ */ jsxs("form", { className: "grid gap-4", onSubmit: onCreateOrg, children: [
911
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-500", children: "Crie uma nova organiza\xE7\xE3o e alterne para ela automaticamente." }),
912
+ /* @__PURE__ */ jsx(Field, { label: "Nome *", children: /* @__PURE__ */ jsx(Input, { name: "name", placeholder: "Minha organiza\xE7\xE3o", required: true }) }),
913
+ /* @__PURE__ */ jsx(Field, { label: "Slug *", children: /* @__PURE__ */ jsx(Input, { name: "slug", placeholder: "minha-org", required: true }) }),
914
+ createError && /* @__PURE__ */ jsx("p", { className: "rounded-lg bg-red-50 px-3 py-2 text-xs text-red-600", children: createError }),
915
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
916
+ /* @__PURE__ */ jsx(
917
+ Button,
918
+ {
919
+ onClick: () => setTab("info"),
920
+ size: "sm",
921
+ tone: "ghost",
922
+ type: "button",
923
+ children: "Cancelar"
924
+ }
636
925
  ),
637
- onClick: () => void setCurrentOrg(org.id),
638
- type: "button",
639
- children: [
640
- /* @__PURE__ */ jsx(Avatar, { name: org.name, size: "sm", src: org.imageUrl }),
641
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
642
- /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-medium text-slate-900", children: org.name }),
643
- /* @__PURE__ */ jsxs("p", { className: "truncate text-xs text-slate-500", children: [
644
- "/",
645
- org.slug
646
- ] })
647
- ] }),
648
- org.id === currentOrg?.id && /* @__PURE__ */ jsx("span", { className: "shrink-0 rounded-full bg-slate-900 px-2 py-0.5 text-[10px] font-medium text-white", children: "Ativa" })
649
- ]
650
- },
651
- org.id
652
- ))
653
- ] })
654
- ] })
655
- ] }) });
656
- }
657
- function ManageOrganizationModal({
658
- open,
659
- onOpenChange
660
- }) {
661
- const {
662
- createOrganization,
663
- currentOrg,
664
- organizations,
665
- refreshOrganizations,
666
- setCurrentOrg,
667
- updateOrganization
668
- } = useOrg();
669
- const { listPermissions } = usePermissions();
670
- const { listRoles } = useRoles();
671
- const [tab, setTab] = useState("orgs");
672
- const [roles, setRoles] = useState({ systemRoles: [], customRoles: [] });
673
- const [permissions, setPermissions] = useState([]);
674
- const [saving, setSaving] = useState(false);
675
- const [saveSuccess, setSaveSuccess] = useState(false);
676
- const [saveError, setSaveError] = useState(null);
677
- const [creating, setCreating] = useState(false);
678
- const [createError, setCreateError] = useState(null);
679
- useEffect(() => {
680
- if (!open) {
681
- setTab("orgs");
682
- setSaveError(null);
683
- setSaveSuccess(false);
684
- setCreating(false);
685
- setCreateError(null);
686
- }
687
- }, [open]);
688
- useEffect(() => {
689
- if (!open || !currentOrg) return;
690
- if (tab === "members" || tab === "roles") {
691
- void listRoles({ organizationId: currentOrg.id }).then(setRoles).catch(() => setRoles({ systemRoles: [], customRoles: [] }));
692
- void listPermissions({}).then(setPermissions).catch(() => setPermissions([]));
693
- }
694
- }, [currentOrg, listPermissions, listRoles, open, tab]);
695
- async function onOrgSubmit(event) {
696
- event.preventDefault();
697
- if (!currentOrg) return;
698
- const form = new FormData(event.currentTarget);
699
- setSaving(true);
700
- setSaveError(null);
701
- setSaveSuccess(false);
702
- try {
703
- await updateOrganization(currentOrg.id, {
704
- name: String(form.get("name") ?? ""),
705
- description: String(form.get("description") ?? "") || null,
706
- slug: String(form.get("slug") ?? ""),
707
- domain: String(form.get("domain") ?? "") || null,
708
- imageUrl: String(form.get("imageUrl") ?? "") || null,
709
- faviconUrl: String(form.get("faviconUrl") ?? "") || null
710
- });
711
- setSaveSuccess(true);
712
- setTimeout(() => setSaveSuccess(false), 2500);
713
- } catch (err) {
714
- setSaveError(err instanceof Error ? err.message : "Erro ao salvar.");
715
- } finally {
716
- setSaving(false);
717
- }
718
- }
719
- async function onCreateOrg(event) {
720
- event.preventDefault();
721
- const form = new FormData(event.currentTarget);
722
- setCreating(true);
723
- setCreateError(null);
724
- try {
725
- const result = await createOrganization({
726
- name: String(form.get("name") ?? ""),
727
- slug: String(form.get("slug") ?? "")
728
- });
729
- if (result.success) {
730
- await refreshOrganizations();
731
- if (result.data?.id) {
732
- void setCurrentOrg(result.data.id);
733
- }
734
- setTab("info");
735
- } else {
736
- setCreateError(result.error ?? "Erro ao criar organiza\xE7\xE3o.");
737
- }
738
- } catch (err) {
739
- setCreateError(err instanceof Error ? err.message : "Erro ao criar.");
740
- } finally {
741
- setCreating(false);
742
- }
743
- }
744
- if (!open) return null;
745
- const orgTabs = [
746
- { id: "orgs", label: "Organiza\xE7\xF5es" },
747
- { id: "info", label: "Geral" },
748
- { id: "members", label: "Membros" },
749
- { id: "roles", label: "Roles" },
750
- { id: "new", label: "+ Nova org" }
751
- ];
752
- return /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4", children: /* @__PURE__ */ jsxs("div", { className: "flex max-h-[90vh] w-full max-w-2xl flex-col overflow-hidden rounded-2xl bg-white shadow-2xl", children: [
753
- /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center justify-between border-b border-slate-100 px-6 py-4", children: [
754
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
755
- currentOrg?.imageUrl ? /* @__PURE__ */ jsx(
756
- "img",
757
- {
758
- alt: currentOrg.name,
759
- className: "h-8 w-8 rounded-lg object-cover",
760
- src: currentOrg.imageUrl
761
- }
762
- ) : /* @__PURE__ */ jsx("span", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-slate-100 text-xs font-semibold text-slate-600", children: (currentOrg?.name ?? "O")[0]?.toUpperCase() }),
763
- /* @__PURE__ */ jsxs("div", { children: [
764
- /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-slate-900", children: currentOrg?.name ?? "Organiza\xE7\xE3o" }),
765
- currentOrg?.slug && /* @__PURE__ */ jsxs("p", { className: "text-xs text-slate-500", children: [
766
- "/",
767
- currentOrg.slug
926
+ /* @__PURE__ */ jsx(
927
+ Button,
928
+ {
929
+ disabled: creating,
930
+ size: "sm",
931
+ tone: "primary",
932
+ type: "submit",
933
+ children: creating ? "Criando\u2026" : "Criar organiza\xE7\xE3o"
934
+ }
935
+ )
768
936
  ] })
769
- ] })
770
- ] }),
771
- /* @__PURE__ */ jsx(
772
- "button",
773
- {
774
- "aria-label": "Fechar",
775
- className: "rounded-lg p-1.5 text-slate-400 transition hover:bg-slate-100 hover:text-slate-700",
776
- onClick: () => onOpenChange(false),
777
- type: "button",
778
- children: "\u2715"
779
- }
780
- )
781
- ] }),
782
- /* @__PURE__ */ jsx("div", { className: "flex shrink-0 gap-1 border-b border-slate-100 px-6 pt-3", children: orgTabs.map((t) => /* @__PURE__ */ jsx(
783
- "button",
784
- {
785
- className: cx(
786
- "mb-[-1px] border-b-2 px-3 pb-2.5 text-xs font-medium transition",
787
- tab === t.id ? "border-slate-900 text-slate-900" : "border-transparent text-slate-500 hover:text-slate-700"
788
- ),
789
- onClick: () => setTab(t.id),
790
- type: "button",
791
- children: t.label
792
- },
793
- t.id
794
- )) }),
795
- /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto px-6 py-5", children: [
796
- !currentOrg && /* @__PURE__ */ jsx("p", { className: "py-8 text-center text-sm text-slate-400", children: "Nenhuma organiza\xE7\xE3o selecionada." }),
797
- tab === "orgs" && /* @__PURE__ */ jsxs("div", { className: "grid gap-2", children: [
798
- organizations.length === 0 && /* @__PURE__ */ jsx("p", { className: "py-8 text-center text-sm text-slate-400", children: "Nenhuma organiza\xE7\xE3o dispon\xEDvel." }),
799
- organizations.map((org) => /* @__PURE__ */ jsxs(
800
- "button",
801
- {
802
- className: cx(
803
- "flex w-full items-center gap-3 rounded-xl border p-3 text-left transition",
804
- org.id === currentOrg?.id ? "border-slate-900 bg-slate-50" : "border-slate-200 hover:border-slate-300 hover:bg-slate-50"
805
- ),
806
- onClick: () => {
807
- void setCurrentOrg(org.id);
808
- onOpenChange(false);
809
- },
810
- type: "button",
811
- children: [
812
- /* @__PURE__ */ jsx(Avatar, { name: org.name, size: "sm", src: org.imageUrl }),
813
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
814
- /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-medium text-slate-900", children: org.name }),
815
- /* @__PURE__ */ jsxs("p", { className: "truncate text-xs text-slate-500", children: [
816
- "/",
817
- org.slug
818
- ] })
819
- ] }),
820
- org.id === currentOrg?.id && /* @__PURE__ */ jsx("span", { className: "shrink-0 rounded-full bg-slate-900 px-2 py-0.5 text-[10px] font-medium text-white", children: "Ativa" })
821
- ]
822
- },
823
- org.id
824
- ))
825
- ] }),
826
- tab === "info" && currentOrg && /* @__PURE__ */ jsxs("form", { className: "grid gap-4", onSubmit: onOrgSubmit, children: [
827
- /* @__PURE__ */ jsxs("div", { className: "grid gap-3 sm:grid-cols-2", children: [
828
- /* @__PURE__ */ jsx(Field, { label: "Nome *", children: /* @__PURE__ */ jsx(Input, { defaultValue: currentOrg.name, name: "name", required: true }) }),
829
- /* @__PURE__ */ jsx(Field, { label: "Slug *", children: /* @__PURE__ */ jsx(Input, { defaultValue: currentOrg.slug, name: "slug", required: true }) })
830
- ] }),
831
- /* @__PURE__ */ jsx(Field, { label: "Descri\xE7\xE3o", children: /* @__PURE__ */ jsx(
832
- Textarea,
833
- {
834
- defaultValue: currentOrg.description ?? "",
835
- name: "description",
836
- placeholder: "Descreva a organiza\xE7\xE3o\u2026"
837
- }
838
- ) }),
839
- /* @__PURE__ */ jsxs("div", { className: "grid gap-3 sm:grid-cols-2", children: [
840
- /* @__PURE__ */ jsx(Field, { label: "Dom\xEDnio", children: /* @__PURE__ */ jsx(
841
- Input,
842
- {
843
- defaultValue: currentOrg.domain ?? "",
844
- name: "domain",
845
- placeholder: "acme.com"
846
- }
847
- ) }),
848
- /* @__PURE__ */ jsx(Field, { label: "URL da imagem", children: /* @__PURE__ */ jsx(
849
- Input,
850
- {
851
- defaultValue: currentOrg.imageUrl ?? "",
852
- name: "imageUrl",
853
- placeholder: "https://..."
854
- }
855
- ) })
856
937
  ] }),
857
- /* @__PURE__ */ jsx(Field, { label: "URL do favicon", children: /* @__PURE__ */ jsx(
858
- Input,
859
- {
860
- defaultValue: currentOrg.faviconUrl ?? "",
861
- name: "faviconUrl",
862
- placeholder: "https://..."
863
- }
864
- ) }),
865
- saveError && /* @__PURE__ */ jsx("p", { className: "rounded-lg bg-red-50 px-3 py-2 text-xs text-red-600", children: saveError }),
866
- saveSuccess && /* @__PURE__ */ jsx("p", { className: "rounded-lg bg-emerald-50 px-3 py-2 text-xs text-emerald-600", children: "Organiza\xE7\xE3o atualizada." }),
867
- /* @__PURE__ */ jsx("div", { className: "flex justify-end pt-1", children: /* @__PURE__ */ jsx(
868
- Button,
869
- {
870
- disabled: saving,
871
- size: "sm",
872
- tone: "primary",
873
- type: "submit",
874
- children: saving ? "Salvando\u2026" : "Salvar organiza\xE7\xE3o"
875
- }
876
- ) })
877
- ] }),
878
- tab === "members" && currentOrg && /* @__PURE__ */ jsxs("div", { className: "grid gap-2", children: [
879
- (currentOrg.members ?? []).length === 0 && /* @__PURE__ */ jsx("p", { className: "py-8 text-center text-sm text-slate-400", children: "Nenhum membro nesta organiza\xE7\xE3o." }),
880
- (currentOrg.members ?? []).map((member) => /* @__PURE__ */ jsxs(
881
- "div",
882
- {
883
- className: "flex items-center gap-3 rounded-xl border border-slate-200 p-4",
884
- children: [
885
- /* @__PURE__ */ jsx(
886
- Avatar,
887
- {
888
- name: member.user.name ?? member.user.email,
889
- size: "sm",
890
- src: member.user.imageUrl
891
- }
892
- ),
893
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
894
- /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-medium text-slate-900", children: member.user.name ?? member.user.email }),
895
- /* @__PURE__ */ jsx("p", { className: "truncate text-xs text-slate-500", children: member.user.email })
896
- ] }),
897
- /* @__PURE__ */ jsx("div", { className: "flex shrink-0 flex-wrap justify-end gap-1", children: (member.roleAssignments ?? []).map((a) => /* @__PURE__ */ jsx(
898
- "span",
938
+ tab === "roles" && /* @__PURE__ */ jsxs("div", { className: "grid gap-5 sm:grid-cols-2", children: [
939
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
940
+ /* @__PURE__ */ jsxs("h3", { className: "mb-3 text-xs font-semibold uppercase tracking-wider text-slate-400", children: [
941
+ "Roles (",
942
+ roles.systemRoles.length + roles.customRoles.length,
943
+ ")"
944
+ ] }),
945
+ /* @__PURE__ */ jsxs("div", { className: "max-h-[280px] space-y-2 overflow-y-auto pr-1", children: [
946
+ roles.systemRoles.length === 0 && roles.customRoles.length === 0 && /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-400", children: "Nenhuma role." }),
947
+ [...roles.systemRoles, ...roles.customRoles].map((role) => /* @__PURE__ */ jsxs(
948
+ "div",
899
949
  {
900
- className: "rounded-full bg-slate-900 px-2 py-0.5 text-[11px] font-medium text-white",
901
- children: a.roleDefinition?.name ?? a.customRole?.name ?? a.id
950
+ className: "overflow-hidden rounded-xl border border-slate-200 p-3",
951
+ children: [
952
+ /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-semibold text-slate-900", children: role.name }),
953
+ /* @__PURE__ */ jsx("p", { className: "truncate text-xs text-slate-400", children: role.key }),
954
+ /* @__PURE__ */ jsxs("p", { className: "mt-1 text-xs text-slate-500", children: [
955
+ role.permissions.length,
956
+ " permission",
957
+ role.permissions.length !== 1 ? "s" : ""
958
+ ] })
959
+ ]
902
960
  },
903
- a.id
904
- )) })
905
- ]
906
- },
907
- member.id
908
- ))
909
- ] }),
910
- tab === "new" && /* @__PURE__ */ jsxs("form", { className: "grid gap-4", onSubmit: onCreateOrg, children: [
911
- /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-500", children: "Crie uma nova organiza\xE7\xE3o e alterne para ela automaticamente." }),
912
- /* @__PURE__ */ jsx(Field, { label: "Nome *", children: /* @__PURE__ */ jsx(Input, { name: "name", placeholder: "Minha organiza\xE7\xE3o", required: true }) }),
913
- /* @__PURE__ */ jsx(Field, { label: "Slug *", children: /* @__PURE__ */ jsx(Input, { name: "slug", placeholder: "minha-org", required: true }) }),
914
- createError && /* @__PURE__ */ jsx("p", { className: "rounded-lg bg-red-50 px-3 py-2 text-xs text-red-600", children: createError }),
915
- /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
916
- /* @__PURE__ */ jsx(
917
- Button,
918
- {
919
- onClick: () => setTab("info"),
920
- size: "sm",
921
- tone: "ghost",
922
- type: "button",
923
- children: "Cancelar"
924
- }
925
- ),
926
- /* @__PURE__ */ jsx(
927
- Button,
928
- {
929
- disabled: creating,
930
- size: "sm",
931
- tone: "primary",
932
- type: "submit",
933
- children: creating ? "Criando\u2026" : "Criar organiza\xE7\xE3o"
934
- }
935
- )
936
- ] })
937
- ] }),
938
- tab === "roles" && /* @__PURE__ */ jsxs("div", { className: "grid gap-5 sm:grid-cols-2", children: [
939
- /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
940
- /* @__PURE__ */ jsxs("h3", { className: "mb-3 text-xs font-semibold uppercase tracking-wider text-slate-400", children: [
941
- "Roles (",
942
- roles.systemRoles.length + roles.customRoles.length,
943
- ")"
944
- ] }),
945
- /* @__PURE__ */ jsxs("div", { className: "max-h-[280px] space-y-2 overflow-y-auto pr-1", children: [
946
- roles.systemRoles.length === 0 && roles.customRoles.length === 0 && /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-400", children: "Nenhuma role." }),
947
- [...roles.systemRoles, ...roles.customRoles].map((role) => /* @__PURE__ */ jsxs(
948
- "div",
949
- {
950
- className: "overflow-hidden rounded-xl border border-slate-200 p-3",
951
- children: [
952
- /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-semibold text-slate-900", children: role.name }),
953
- /* @__PURE__ */ jsx("p", { className: "truncate text-xs text-slate-400", children: role.key }),
954
- /* @__PURE__ */ jsxs("p", { className: "mt-1 text-xs text-slate-500", children: [
955
- role.permissions.length,
956
- " permission",
957
- role.permissions.length !== 1 ? "s" : ""
958
- ] })
959
- ]
960
- },
961
- role.id
962
- ))
963
- ] })
964
- ] }),
965
- /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
966
- /* @__PURE__ */ jsxs("h3", { className: "mb-3 text-xs font-semibold uppercase tracking-wider text-slate-400", children: [
967
- "Permissions (",
968
- permissions.length,
969
- ")"
961
+ role.id
962
+ ))
963
+ ] })
970
964
  ] }),
971
- /* @__PURE__ */ jsxs("div", { className: "max-h-[280px] space-y-2 overflow-y-auto pr-1", children: [
972
- permissions.length === 0 && /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-400", children: "Nenhuma permission." }),
973
- permissions.map((permission) => /* @__PURE__ */ jsxs(
974
- "div",
975
- {
976
- className: "overflow-hidden rounded-xl border border-slate-200 p-3",
977
- children: [
978
- /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-semibold text-slate-900", children: permission.key }),
979
- /* @__PURE__ */ jsx("p", { className: "truncate text-xs text-slate-400", children: permission.category ?? "custom" })
980
- ]
981
- },
982
- permission.id
983
- ))
965
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
966
+ /* @__PURE__ */ jsxs("h3", { className: "mb-3 text-xs font-semibold uppercase tracking-wider text-slate-400", children: [
967
+ "Permissions (",
968
+ permissions.length,
969
+ ")"
970
+ ] }),
971
+ /* @__PURE__ */ jsxs("div", { className: "max-h-[280px] space-y-2 overflow-y-auto pr-1", children: [
972
+ permissions.length === 0 && /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-400", children: "Nenhuma permission." }),
973
+ permissions.map((permission) => /* @__PURE__ */ jsxs(
974
+ "div",
975
+ {
976
+ className: "overflow-hidden rounded-xl border border-slate-200 p-3",
977
+ children: [
978
+ /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-semibold text-slate-900", children: permission.key }),
979
+ /* @__PURE__ */ jsx("p", { className: "truncate text-xs text-slate-400", children: permission.category ?? "custom" })
980
+ ]
981
+ },
982
+ permission.id
983
+ ))
984
+ ] })
984
985
  ] })
985
986
  ] })
986
987
  ] })
987
- ] })
988
- ] }) });
988
+ ] }) });
989
+ }
990
+ return {
991
+ SignInButton,
992
+ SignOutButton,
993
+ AccountSwitcher,
994
+ OrgSwitcher,
995
+ UserButton,
996
+ OrganizationButton,
997
+ ProfileModal,
998
+ ManageOrganizationModal
999
+ };
989
1000
  }
990
1001
  export {
991
- AccountSwitcher,
992
1002
  Avatar,
993
- ManageOrganizationModal,
994
1003
  Modal,
995
- OrgSwitcher,
996
- OrganizationButton,
997
- ProfileModal,
998
- SignInButton,
999
- SignOutButton,
1000
- UserButton
1004
+ createAuthElements
1001
1005
  };
1002
1006
  //# sourceMappingURL=index.js.map