@geekapps/auth-elements-nextjs 0.2.5 → 0.4.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/README.md +58 -12
- package/dist/index.d.ts +87 -16
- package/dist/index.js +335 -100
- package/dist/index.js.map +1 -1
- package/package.json +11 -4
package/README.md
CHANGED
|
@@ -1,17 +1,63 @@
|
|
|
1
1
|
# @geekapps/auth-elements-nextjs
|
|
2
2
|
|
|
3
|
-
Componentes
|
|
3
|
+
Componentes visuais simples para usar com `@geekapps/auth-nextjs`. Módulo separado: **não importa** o auth-nextjs em runtime, recebe o hook por `createAuthElements({ useAuth })`. Tem build, estilos (Tailwind) e versionamento próprios.
|
|
4
4
|
|
|
5
|
-
Não usa shadcn/ui, Radix, GSAP ou bibliotecas de UI.
|
|
5
|
+
Não usa shadcn/ui, Radix, GSAP ou bibliotecas de UI. Apenas React + classes Tailwind.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Instalação
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
9
|
+
```bash
|
|
10
|
+
bun add @geekapps/auth-nextjs @geekapps/auth-elements-nextjs
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Uso (Next.js)
|
|
14
|
+
|
|
15
|
+
Crie um módulo client, por exemplo `components/auth-elements.ts`:
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
"use client";
|
|
19
|
+
|
|
20
|
+
import { useAuth } from "@geekapps/auth-nextjs/client";
|
|
21
|
+
import { createAuthElements } from "@geekapps/auth-elements-nextjs";
|
|
22
|
+
|
|
23
|
+
export const {
|
|
24
|
+
SignInButton,
|
|
25
|
+
SignOutButton,
|
|
26
|
+
UserButton,
|
|
27
|
+
OrganizationButton,
|
|
28
|
+
OrgSwitcher,
|
|
29
|
+
AccountSwitcher,
|
|
30
|
+
ProfileModal,
|
|
31
|
+
ManageOrganizationModal,
|
|
32
|
+
CreateOrganizationForm,
|
|
33
|
+
WaitlistForm,
|
|
34
|
+
} = createAuthElements({ useAuth });
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
No layout, importe os estilos uma vez:
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import "@geekapps/auth-elements-nextjs/styles.css";
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Os componentes devem ficar dentro do `GeekappsAuthProvider` do auth-nextjs.
|
|
44
|
+
|
|
45
|
+
## Elementos
|
|
46
|
+
|
|
47
|
+
- `Avatar`, `Modal` (exports diretos)
|
|
48
|
+
- `SignInButton`, `SignOutButton`
|
|
49
|
+
- `AccountSwitcher`, `OrgSwitcher`
|
|
50
|
+
- `UserButton`, `OrganizationButton`
|
|
51
|
+
- `ProfileModal`, `ManageOrganizationModal`
|
|
52
|
+
- `CreateOrganizationForm`
|
|
53
|
+
- `WaitlistForm` — nome + e-mail, usa `useAuth().joinWaitlist`; props `clientId` (obrigatória), `defaultEmail`, `onJoined`, `submitLabel`. Após entrar mostra a posição na fila.
|
|
54
|
+
|
|
55
|
+
Erros do auth-nextjs são traduzidos pelo `code` (`waitlist_required`, `waitlist_disabled`, `password_reset_required`, `account_locked` com `retryAfter`); sem código conhecido, usa o `error` original. O helper `authErrorMessage(result, fallback)` é exportado.
|
|
56
|
+
|
|
57
|
+
## Compatibilidade
|
|
58
|
+
|
|
59
|
+
Testado contra `@geekapps/auth-nextjs` 0.26.x. Funciona com versões anteriores (>=0.20): membros novos do contrato são opcionais (`lookupTaxId?`, `joinWaitlist?`); sem `joinWaitlist` o `WaitlistForm` mostra um aviso para atualizar.
|
|
60
|
+
|
|
61
|
+
## Guarda de contrato
|
|
62
|
+
|
|
63
|
+
`bun run check:contract` compila `tests/contract.ts`, que verifica (só tipos) que `typeof useAuth` de `@geekapps/auth-nextjs/client` é atribuível ao contrato do elements. O auth-nextjs é resolvido pelo workspace (`../auth-nextjs/dist`; rode o build dele antes). Falha de compilação = o contrato divergiu.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
|
|
4
4
|
type ElementSize = "sm" | "md" | "lg";
|
|
@@ -23,6 +23,10 @@ type Organization = {
|
|
|
23
23
|
domain: string | null;
|
|
24
24
|
imageUrl: string | null;
|
|
25
25
|
faviconUrl: string | null;
|
|
26
|
+
type?: OrganizationType;
|
|
27
|
+
taxId?: string | null;
|
|
28
|
+
taxIdType?: TaxIdType | null;
|
|
29
|
+
legalName?: string | null;
|
|
26
30
|
members?: Array<{
|
|
27
31
|
id: string;
|
|
28
32
|
user: {
|
|
@@ -41,6 +45,40 @@ type Organization = {
|
|
|
41
45
|
}>;
|
|
42
46
|
}>;
|
|
43
47
|
};
|
|
48
|
+
type OrganizationType = "standard" | "legal";
|
|
49
|
+
type TaxIdType = "br_cnpj" | "generic";
|
|
50
|
+
type OrganizationLegalAddress = Partial<Record<"street" | "number" | "complement" | "district" | "city" | "state" | "postalCode" | "country", string | null>>;
|
|
51
|
+
type OrganizationCreateInput = {
|
|
52
|
+
name: string;
|
|
53
|
+
slug: string;
|
|
54
|
+
type?: OrganizationType;
|
|
55
|
+
taxId?: string | null;
|
|
56
|
+
taxIdType?: TaxIdType | null;
|
|
57
|
+
taxIdCountry?: string | null;
|
|
58
|
+
legalName?: string | null;
|
|
59
|
+
tradeName?: string | null;
|
|
60
|
+
legalEmail?: string | null;
|
|
61
|
+
legalPhone?: string | null;
|
|
62
|
+
legalAddress?: OrganizationLegalAddress | null;
|
|
63
|
+
};
|
|
64
|
+
type TaxIdLookupResult = {
|
|
65
|
+
taxId: string;
|
|
66
|
+
taxIdType: TaxIdType;
|
|
67
|
+
taxIdCountry: string | null;
|
|
68
|
+
alreadyRegistered: boolean;
|
|
69
|
+
lookupAvailable: boolean;
|
|
70
|
+
found: boolean;
|
|
71
|
+
registrationStatus: string | null;
|
|
72
|
+
suggestedName: string | null;
|
|
73
|
+
data: {
|
|
74
|
+
legalName: string | null;
|
|
75
|
+
tradeName: string | null;
|
|
76
|
+
legalEmail: string | null;
|
|
77
|
+
legalPhone: string | null;
|
|
78
|
+
legalAddress: OrganizationLegalAddress | null;
|
|
79
|
+
};
|
|
80
|
+
missingFields: string[];
|
|
81
|
+
};
|
|
44
82
|
type Permission = {
|
|
45
83
|
id: string;
|
|
46
84
|
key: string;
|
|
@@ -65,13 +103,34 @@ type User = {
|
|
|
65
103
|
imageUrl: string | null;
|
|
66
104
|
phone?: string | null;
|
|
67
105
|
};
|
|
106
|
+
/** Espelha `AuthResult` do auth-nextjs >=0.26 (campos extras são opcionais). */
|
|
68
107
|
type AuthResult<T> = {
|
|
69
108
|
success: true;
|
|
70
109
|
data: T;
|
|
71
110
|
} | {
|
|
72
111
|
success: false;
|
|
73
112
|
error?: string;
|
|
113
|
+
status?: number;
|
|
114
|
+
code?: string;
|
|
115
|
+
retryAfter?: number;
|
|
116
|
+
missingFields?: string[];
|
|
74
117
|
};
|
|
118
|
+
type JoinWaitlistParams = {
|
|
119
|
+
clientId: string;
|
|
120
|
+
email: string;
|
|
121
|
+
name?: string;
|
|
122
|
+
};
|
|
123
|
+
type JoinWaitlistResponse = {
|
|
124
|
+
ok: true;
|
|
125
|
+
status: "waiting" | "approved" | "joined";
|
|
126
|
+
position: number | null;
|
|
127
|
+
};
|
|
128
|
+
/** Mensagem em português para um resultado de erro; `fallback` se o código for desconhecido. */
|
|
129
|
+
declare function authErrorMessage(result: {
|
|
130
|
+
error?: string;
|
|
131
|
+
code?: string;
|
|
132
|
+
retryAfter?: number;
|
|
133
|
+
}, fallback: string): string;
|
|
75
134
|
type UseAuthHook = () => {
|
|
76
135
|
user: User | null;
|
|
77
136
|
signIn: (opts?: {
|
|
@@ -94,10 +153,11 @@ type UseAuthHook = () => {
|
|
|
94
153
|
isLoadingOrganizations: boolean;
|
|
95
154
|
refreshOrganizations: () => Promise<void>;
|
|
96
155
|
setCurrentOrg: (id: string) => Promise<void>;
|
|
97
|
-
createOrganization: (input:
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
156
|
+
createOrganization: (input: OrganizationCreateInput) => Promise<AuthResult<Organization>>;
|
|
157
|
+
/** Opcional: SDKs antigos não têm — sem ele, o formulário só não busca os dados do CNPJ. */
|
|
158
|
+
lookupTaxId?: (value: string, type?: TaxIdType) => Promise<AuthResult<TaxIdLookupResult>>;
|
|
159
|
+
/** Opcional (auth-nextjs >=0.26): sem ele o WaitlistForm mostra um aviso. */
|
|
160
|
+
joinWaitlist?: (params: JoinWaitlistParams) => Promise<AuthResult<JoinWaitlistResponse>>;
|
|
101
161
|
updateOrganization: (id: string, input: Partial<{
|
|
102
162
|
name: string;
|
|
103
163
|
slug: string;
|
|
@@ -134,7 +194,7 @@ declare function Avatar({ src, name, size, className, }: {
|
|
|
134
194
|
name?: string | null;
|
|
135
195
|
size?: ElementSize;
|
|
136
196
|
className?: string;
|
|
137
|
-
}):
|
|
197
|
+
}): react.JSX.Element;
|
|
138
198
|
declare function Modal({ open, onOpenChange, title, description, children, footer, }: {
|
|
139
199
|
open: boolean;
|
|
140
200
|
onOpenChange: (open: boolean) => void;
|
|
@@ -142,7 +202,7 @@ declare function Modal({ open, onOpenChange, title, description, children, foote
|
|
|
142
202
|
description?: string;
|
|
143
203
|
children: ReactNode;
|
|
144
204
|
footer?: ReactNode;
|
|
145
|
-
}):
|
|
205
|
+
}): react.JSX.Element | null;
|
|
146
206
|
/**
|
|
147
207
|
* Creates auth UI components bound to the provided `useAuth` hook instance.
|
|
148
208
|
* This lets consumers supply their own auth-nextjs instance without requiring
|
|
@@ -156,25 +216,36 @@ declare function Modal({ open, onOpenChange, title, description, children, foote
|
|
|
156
216
|
declare function createAuthElements(hooks: {
|
|
157
217
|
useAuth: UseAuthHook;
|
|
158
218
|
}): {
|
|
219
|
+
WaitlistForm: ({ clientId, defaultEmail, onJoined, submitLabel, }: {
|
|
220
|
+
clientId: string;
|
|
221
|
+
defaultEmail?: string;
|
|
222
|
+
onJoined?: (response: JoinWaitlistResponse) => void;
|
|
223
|
+
submitLabel?: string;
|
|
224
|
+
}) => react.JSX.Element;
|
|
159
225
|
SignInButton: ({ children, redirectTo, }: {
|
|
160
226
|
children?: ReactNode;
|
|
161
227
|
redirectTo?: string;
|
|
162
|
-
}) =>
|
|
228
|
+
}) => react.JSX.Element;
|
|
163
229
|
SignOutButton: ({ children }: {
|
|
164
230
|
children?: ReactNode;
|
|
165
|
-
}) =>
|
|
166
|
-
AccountSwitcher: () =>
|
|
167
|
-
OrgSwitcher: () =>
|
|
168
|
-
UserButton: () =>
|
|
169
|
-
OrganizationButton: () =>
|
|
231
|
+
}) => react.JSX.Element;
|
|
232
|
+
AccountSwitcher: () => react.JSX.Element;
|
|
233
|
+
OrgSwitcher: () => react.JSX.Element;
|
|
234
|
+
UserButton: () => react.JSX.Element;
|
|
235
|
+
OrganizationButton: () => react.JSX.Element;
|
|
170
236
|
ProfileModal: ({ open, onOpenChange, }: {
|
|
171
237
|
open: boolean;
|
|
172
238
|
onOpenChange: (open: boolean) => void;
|
|
173
|
-
}) =>
|
|
239
|
+
}) => react.JSX.Element | null;
|
|
174
240
|
ManageOrganizationModal: ({ open, onOpenChange, }: {
|
|
175
241
|
open: boolean;
|
|
176
242
|
onOpenChange: (open: boolean) => void;
|
|
177
|
-
}) =>
|
|
243
|
+
}) => react.JSX.Element | null;
|
|
244
|
+
CreateOrganizationForm: ({ onCreated, onCancel, compact, }: {
|
|
245
|
+
onCreated?: (organization: Organization) => void;
|
|
246
|
+
onCancel?: () => void;
|
|
247
|
+
compact?: boolean;
|
|
248
|
+
}) => react.JSX.Element;
|
|
178
249
|
};
|
|
179
250
|
|
|
180
|
-
export { Avatar, type ConnectedAccount, type ElementSize, type ElementTone, Modal, type Organization, type Permission, type Role, type UserSession, createAuthElements };
|
|
251
|
+
export { type AuthResult, Avatar, type ConnectedAccount, type ElementSize, type ElementTone, type JoinWaitlistParams, type JoinWaitlistResponse, Modal, type Organization, type OrganizationCreateInput, type OrganizationType, type Permission, type Role, type TaxIdLookupResult, type TaxIdType, type UserSession, authErrorMessage, createAuthElements };
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,56 @@ import {
|
|
|
6
6
|
useState
|
|
7
7
|
} from "react";
|
|
8
8
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
var ADDRESS_KEYS = [
|
|
10
|
+
"street",
|
|
11
|
+
"number",
|
|
12
|
+
"complement",
|
|
13
|
+
"district",
|
|
14
|
+
"city",
|
|
15
|
+
"state",
|
|
16
|
+
"postalCode",
|
|
17
|
+
"country"
|
|
18
|
+
];
|
|
19
|
+
var REQUIRED_LEGAL = /* @__PURE__ */ new Set([
|
|
20
|
+
"taxIdCountry",
|
|
21
|
+
"legalName",
|
|
22
|
+
"legalAddress.street",
|
|
23
|
+
"legalAddress.city",
|
|
24
|
+
"legalAddress.postalCode",
|
|
25
|
+
"legalAddress.country"
|
|
26
|
+
]);
|
|
27
|
+
var EMPTY_ORG_FORM = {
|
|
28
|
+
type: "standard",
|
|
29
|
+
taxIdType: "br_cnpj",
|
|
30
|
+
taxId: "",
|
|
31
|
+
name: "",
|
|
32
|
+
slug: ""
|
|
33
|
+
};
|
|
34
|
+
function slugify(value) {
|
|
35
|
+
return value.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60);
|
|
36
|
+
}
|
|
37
|
+
function authErrorMessage(result, fallback) {
|
|
38
|
+
switch (result.code) {
|
|
39
|
+
case "waitlist_required":
|
|
40
|
+
return "Esta aplica\xE7\xE3o est\xE1 com lista de espera. Entre na lista para receber acesso.";
|
|
41
|
+
case "waitlist_disabled":
|
|
42
|
+
return "A lista de espera n\xE3o est\xE1 ativa para esta aplica\xE7\xE3o.";
|
|
43
|
+
case "password_reset_required":
|
|
44
|
+
return "Sua senha precisa ser redefinida antes de continuar. Use a op\xE7\xE3o de recuperar senha.";
|
|
45
|
+
case "account_locked": {
|
|
46
|
+
const s = result.retryAfter;
|
|
47
|
+
if (typeof s === "number" && s > 0) {
|
|
48
|
+
const wait = s >= 60 ? `${Math.ceil(s / 60)} min` : `${s} s`;
|
|
49
|
+
return `Conta temporariamente bloqueada por tentativas excessivas. Tente novamente em ${wait}.`;
|
|
50
|
+
}
|
|
51
|
+
return "Conta temporariamente bloqueada. Tente novamente mais tarde.";
|
|
52
|
+
}
|
|
53
|
+
case "invalid_credentials":
|
|
54
|
+
return result.error ?? "E-mail ou senha incorretos.";
|
|
55
|
+
default:
|
|
56
|
+
return result.error ?? fallback;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
9
59
|
function cx(...classes) {
|
|
10
60
|
return classes.filter(Boolean).join(" ");
|
|
11
61
|
}
|
|
@@ -250,9 +300,199 @@ function createAuthElements(hooks) {
|
|
|
250
300
|
] })
|
|
251
301
|
] });
|
|
252
302
|
}
|
|
303
|
+
function CreateOrganizationForm({
|
|
304
|
+
onCreated,
|
|
305
|
+
onCancel,
|
|
306
|
+
compact = false
|
|
307
|
+
}) {
|
|
308
|
+
const { createOrganization, lookupTaxId, setCurrentOrg } = useAuth();
|
|
309
|
+
const [values, setValues] = useState({ ...EMPTY_ORG_FORM });
|
|
310
|
+
const [missing, setMissing] = useState([]);
|
|
311
|
+
const [lookupInfo, setLookupInfo] = useState(null);
|
|
312
|
+
const [error, setError] = useState(null);
|
|
313
|
+
const [busy, setBusy] = useState(null);
|
|
314
|
+
const isLegal = values.type === "legal";
|
|
315
|
+
const isCnpj = values.taxIdType === "br_cnpj";
|
|
316
|
+
const set = (key, value) => setValues((current) => {
|
|
317
|
+
const next = { ...current, [key]: value };
|
|
318
|
+
if (key === "name" && !current.slugTouched) next.slug = slugify(value);
|
|
319
|
+
if (key === "slug") next.slugTouched = "1";
|
|
320
|
+
return next;
|
|
321
|
+
});
|
|
322
|
+
async function runLookup() {
|
|
323
|
+
if (!lookupTaxId || !values.taxId) return;
|
|
324
|
+
setBusy("lookup");
|
|
325
|
+
setError(null);
|
|
326
|
+
setLookupInfo(null);
|
|
327
|
+
const result = await lookupTaxId(values.taxId, values.taxIdType);
|
|
328
|
+
setBusy(null);
|
|
329
|
+
if (!result.success) {
|
|
330
|
+
setError(authErrorMessage(result, "Tax ID inv\xE1lido."));
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
const { data } = result.data;
|
|
334
|
+
setValues((current) => {
|
|
335
|
+
const next = { ...current, taxId: result.data.taxId };
|
|
336
|
+
const fill = (key, value) => {
|
|
337
|
+
if (value && !current[key]) next[key] = value;
|
|
338
|
+
};
|
|
339
|
+
fill("legalName", data.legalName);
|
|
340
|
+
fill("tradeName", data.tradeName);
|
|
341
|
+
fill("legalEmail", data.legalEmail);
|
|
342
|
+
fill("legalPhone", data.legalPhone);
|
|
343
|
+
for (const key of ADDRESS_KEYS) fill(`legalAddress.${key}`, data.legalAddress?.[key]);
|
|
344
|
+
if (result.data.taxIdCountry) next.taxIdCountry = result.data.taxIdCountry;
|
|
345
|
+
if (!current.name && result.data.suggestedName) {
|
|
346
|
+
next.name = result.data.suggestedName;
|
|
347
|
+
if (!current.slugTouched) next.slug = slugify(result.data.suggestedName);
|
|
348
|
+
}
|
|
349
|
+
return next;
|
|
350
|
+
});
|
|
351
|
+
setMissing(result.data.missingFields);
|
|
352
|
+
if (result.data.alreadyRegistered) {
|
|
353
|
+
setError("J\xE1 existe uma organiza\xE7\xE3o com este documento neste app.");
|
|
354
|
+
} else if (result.data.found) {
|
|
355
|
+
setLookupInfo(
|
|
356
|
+
`Dados encontrados${result.data.registrationStatus ? ` \xB7 situa\xE7\xE3o ${result.data.registrationStatus}` : ""}. Revise e complete o que faltar.`
|
|
357
|
+
);
|
|
358
|
+
} else {
|
|
359
|
+
setLookupInfo(
|
|
360
|
+
result.data.lookupAvailable ? "Documento v\xE1lido, mas sem dados p\xFAblicos. Preencha os campos obrigat\xF3rios." : "Consulta indispon\xEDvel no momento. Preencha os campos obrigat\xF3rios."
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
async function onSubmit(event) {
|
|
365
|
+
event.preventDefault();
|
|
366
|
+
setBusy("create");
|
|
367
|
+
setError(null);
|
|
368
|
+
const blank = (key) => values[key]?.trim() || null;
|
|
369
|
+
const input = {
|
|
370
|
+
name: values.name.trim(),
|
|
371
|
+
slug: values.slug.trim(),
|
|
372
|
+
type: isLegal ? "legal" : "standard"
|
|
373
|
+
};
|
|
374
|
+
if (isLegal) {
|
|
375
|
+
Object.assign(input, {
|
|
376
|
+
taxId: blank("taxId"),
|
|
377
|
+
taxIdType: values.taxIdType,
|
|
378
|
+
taxIdCountry: isCnpj ? "BR" : blank("taxIdCountry"),
|
|
379
|
+
legalName: blank("legalName"),
|
|
380
|
+
tradeName: blank("tradeName"),
|
|
381
|
+
legalEmail: blank("legalEmail"),
|
|
382
|
+
legalPhone: blank("legalPhone"),
|
|
383
|
+
legalAddress: Object.fromEntries(
|
|
384
|
+
ADDRESS_KEYS.map((key) => [key, blank(`legalAddress.${key}`)])
|
|
385
|
+
)
|
|
386
|
+
});
|
|
387
|
+
if (!isCnpj && !input.legalAddress?.country) {
|
|
388
|
+
input.legalAddress.country = blank("taxIdCountry");
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
const result = await createOrganization(input);
|
|
392
|
+
setBusy(null);
|
|
393
|
+
if (!result.success) {
|
|
394
|
+
if (result.missingFields?.length) setMissing(result.missingFields);
|
|
395
|
+
setError(authErrorMessage(result, "Erro ao criar organiza\xE7\xE3o."));
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
setValues({ ...EMPTY_ORG_FORM });
|
|
399
|
+
setMissing([]);
|
|
400
|
+
setLookupInfo(null);
|
|
401
|
+
if (result.data?.id) void setCurrentOrg(result.data.id);
|
|
402
|
+
onCreated?.(result.data);
|
|
403
|
+
}
|
|
404
|
+
const field = (key, label, props = {}) => {
|
|
405
|
+
const required = REQUIRED_LEGAL.has(key);
|
|
406
|
+
return /* @__PURE__ */ jsx(Field, { label: `${label}${required ? " *" : ""}`, children: /* @__PURE__ */ jsx(
|
|
407
|
+
Input,
|
|
408
|
+
{
|
|
409
|
+
...props,
|
|
410
|
+
className: missing.includes(key) && !values[key] ? "border-red-300" : void 0,
|
|
411
|
+
name: key,
|
|
412
|
+
onChange: (event) => set(key, event.target.value),
|
|
413
|
+
required,
|
|
414
|
+
value: values[key] ?? ""
|
|
415
|
+
}
|
|
416
|
+
) });
|
|
417
|
+
};
|
|
418
|
+
return /* @__PURE__ */ jsxs("form", { className: cx("grid", compact ? "gap-2" : "gap-4"), onSubmit, children: [
|
|
419
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-1 rounded-lg bg-slate-100 p-1", children: [
|
|
420
|
+
["standard", "Padr\xE3o"],
|
|
421
|
+
["legal", "Empresa (CNPJ / Tax ID)"]
|
|
422
|
+
].map(([type, label]) => /* @__PURE__ */ jsx(
|
|
423
|
+
"button",
|
|
424
|
+
{
|
|
425
|
+
className: cx(
|
|
426
|
+
"rounded-md px-2 py-1.5 text-xs font-medium transition",
|
|
427
|
+
values.type === type ? "bg-white text-slate-900 shadow-sm" : "text-slate-500"
|
|
428
|
+
),
|
|
429
|
+
onClick: () => set("type", type),
|
|
430
|
+
type: "button",
|
|
431
|
+
children: label
|
|
432
|
+
},
|
|
433
|
+
type
|
|
434
|
+
)) }),
|
|
435
|
+
isLegal && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
436
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[auto_1fr] gap-2", children: [
|
|
437
|
+
/* @__PURE__ */ jsxs(
|
|
438
|
+
"select",
|
|
439
|
+
{
|
|
440
|
+
className: "h-10 rounded-lg border border-slate-200 bg-white px-2 text-sm text-slate-900",
|
|
441
|
+
onChange: (event) => set("taxIdType", event.target.value),
|
|
442
|
+
value: values.taxIdType,
|
|
443
|
+
children: [
|
|
444
|
+
/* @__PURE__ */ jsx("option", { value: "br_cnpj", children: "CNPJ" }),
|
|
445
|
+
/* @__PURE__ */ jsx("option", { value: "generic", children: "Outro Tax ID" })
|
|
446
|
+
]
|
|
447
|
+
}
|
|
448
|
+
),
|
|
449
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
450
|
+
/* @__PURE__ */ jsx(
|
|
451
|
+
Input,
|
|
452
|
+
{
|
|
453
|
+
name: "taxId",
|
|
454
|
+
onBlur: () => isCnpj && void runLookup(),
|
|
455
|
+
onChange: (event) => set("taxId", event.target.value),
|
|
456
|
+
placeholder: isCnpj ? "00.000.000/0000-00" : "Tax ID",
|
|
457
|
+
required: true,
|
|
458
|
+
value: values.taxId
|
|
459
|
+
}
|
|
460
|
+
),
|
|
461
|
+
/* @__PURE__ */ jsx(Button, { disabled: busy !== null || !values.taxId, onClick: () => void runLookup(), size: "sm", type: "button", children: busy === "lookup" ? "Buscando\u2026" : isCnpj ? "Buscar" : "Validar" })
|
|
462
|
+
] })
|
|
463
|
+
] }),
|
|
464
|
+
!isCnpj && field("taxIdCountry", "Pa\xEDs do Tax ID (ISO, ex.: US)", { maxLength: 2 }),
|
|
465
|
+
lookupInfo && /* @__PURE__ */ jsx("p", { className: "rounded-lg bg-slate-50 px-3 py-2 text-xs text-slate-600", children: lookupInfo })
|
|
466
|
+
] }),
|
|
467
|
+
field("name", "Nome", { placeholder: "Minha organiza\xE7\xE3o", required: true }),
|
|
468
|
+
field("slug", "Slug", { placeholder: "minha-org", required: true }),
|
|
469
|
+
isLegal && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
470
|
+
field("legalName", "Raz\xE3o social"),
|
|
471
|
+
field("tradeName", "Nome fantasia"),
|
|
472
|
+
/* @__PURE__ */ jsxs("div", { className: "grid gap-2 sm:grid-cols-2", children: [
|
|
473
|
+
field("legalEmail", "E-mail", { type: "email" }),
|
|
474
|
+
field("legalPhone", "Telefone")
|
|
475
|
+
] }),
|
|
476
|
+
field("legalAddress.street", "Logradouro"),
|
|
477
|
+
/* @__PURE__ */ jsxs("div", { className: "grid gap-2 sm:grid-cols-2", children: [
|
|
478
|
+
field("legalAddress.number", "N\xFAmero"),
|
|
479
|
+
field("legalAddress.complement", "Complemento"),
|
|
480
|
+
field("legalAddress.district", "Bairro"),
|
|
481
|
+
field("legalAddress.city", "Cidade"),
|
|
482
|
+
field("legalAddress.state", "Estado"),
|
|
483
|
+
field("legalAddress.postalCode", "CEP / C\xF3digo postal")
|
|
484
|
+
] }),
|
|
485
|
+
!isCnpj && field("legalAddress.country", "Pa\xEDs do endere\xE7o (ISO)", { maxLength: 2 })
|
|
486
|
+
] }),
|
|
487
|
+
error && /* @__PURE__ */ jsx("p", { className: "rounded-lg bg-red-50 px-3 py-2 text-xs text-red-600", children: error }),
|
|
488
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
|
|
489
|
+
onCancel && /* @__PURE__ */ jsx(Button, { onClick: onCancel, size: "sm", tone: "ghost", type: "button", children: "Cancelar" }),
|
|
490
|
+
/* @__PURE__ */ jsx(Button, { disabled: busy !== null, size: "sm", tone: "primary", type: "submit", children: busy === "create" ? "Criando\u2026" : "Criar organiza\xE7\xE3o" })
|
|
491
|
+
] })
|
|
492
|
+
] });
|
|
493
|
+
}
|
|
253
494
|
function OrgSwitcher() {
|
|
254
495
|
const {
|
|
255
|
-
createOrganization,
|
|
256
496
|
currentOrg,
|
|
257
497
|
isLoadingOrganizations,
|
|
258
498
|
organizations,
|
|
@@ -261,18 +501,6 @@ function createAuthElements(hooks) {
|
|
|
261
501
|
} = useAuth();
|
|
262
502
|
const [open, setOpen] = useState(false);
|
|
263
503
|
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
504
|
return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
277
505
|
/* @__PURE__ */ jsxs(
|
|
278
506
|
"button",
|
|
@@ -318,40 +546,18 @@ function createAuthElements(hooks) {
|
|
|
318
546
|
},
|
|
319
547
|
organization.id
|
|
320
548
|
)) }),
|
|
321
|
-
creating ? /* @__PURE__ */
|
|
322
|
-
|
|
549
|
+
creating ? /* @__PURE__ */ jsx("div", { className: "max-h-[70vh] overflow-y-auto border-t border-slate-200 p-3", children: /* @__PURE__ */ jsx(
|
|
550
|
+
CreateOrganizationForm,
|
|
323
551
|
{
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
Button,
|
|
332
|
-
{
|
|
333
|
-
className: "flex-1",
|
|
334
|
-
size: "sm",
|
|
335
|
-
tone: "primary",
|
|
336
|
-
type: "submit",
|
|
337
|
-
children: "Criar"
|
|
338
|
-
}
|
|
339
|
-
),
|
|
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
|
-
]
|
|
552
|
+
compact: true,
|
|
553
|
+
onCancel: () => setCreating(false),
|
|
554
|
+
onCreated: () => {
|
|
555
|
+
setCreating(false);
|
|
556
|
+
setOpen(false);
|
|
557
|
+
void refreshOrganizations();
|
|
558
|
+
}
|
|
353
559
|
}
|
|
354
|
-
) : /* @__PURE__ */ jsxs("div", { className: "flex gap-2 border-t border-slate-200 p-2", children: [
|
|
560
|
+
) }) : /* @__PURE__ */ jsxs("div", { className: "flex gap-2 border-t border-slate-200 p-2", children: [
|
|
355
561
|
/* @__PURE__ */ jsx(
|
|
356
562
|
Button,
|
|
357
563
|
{
|
|
@@ -674,15 +880,11 @@ function createAuthElements(hooks) {
|
|
|
674
880
|
const [saving, setSaving] = useState(false);
|
|
675
881
|
const [saveSuccess, setSaveSuccess] = useState(false);
|
|
676
882
|
const [saveError, setSaveError] = useState(null);
|
|
677
|
-
const [creating, setCreating] = useState(false);
|
|
678
|
-
const [createError, setCreateError] = useState(null);
|
|
679
883
|
useEffect(() => {
|
|
680
884
|
if (!open) {
|
|
681
885
|
setTab("orgs");
|
|
682
886
|
setSaveError(null);
|
|
683
887
|
setSaveSuccess(false);
|
|
684
|
-
setCreating(false);
|
|
685
|
-
setCreateError(null);
|
|
686
888
|
}
|
|
687
889
|
}, [open]);
|
|
688
890
|
useEffect(() => {
|
|
@@ -716,31 +918,6 @@ function createAuthElements(hooks) {
|
|
|
716
918
|
setSaving(false);
|
|
717
919
|
}
|
|
718
920
|
}
|
|
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
921
|
if (!open) return null;
|
|
745
922
|
const orgTabs = [
|
|
746
923
|
{ id: "orgs", label: "Organiza\xE7\xF5es" },
|
|
@@ -907,33 +1084,18 @@ function createAuthElements(hooks) {
|
|
|
907
1084
|
member.id
|
|
908
1085
|
))
|
|
909
1086
|
] }),
|
|
910
|
-
tab === "new" && /* @__PURE__ */ jsxs("
|
|
1087
|
+
tab === "new" && /* @__PURE__ */ jsxs("div", { className: "grid gap-4", children: [
|
|
911
1088
|
/* @__PURE__ */ jsx("p", { className: "text-sm text-slate-500", children: "Crie uma nova organiza\xE7\xE3o e alterne para ela automaticamente." }),
|
|
912
|
-
/* @__PURE__ */ jsx(
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
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"
|
|
1089
|
+
/* @__PURE__ */ jsx(
|
|
1090
|
+
CreateOrganizationForm,
|
|
1091
|
+
{
|
|
1092
|
+
onCancel: () => setTab("info"),
|
|
1093
|
+
onCreated: () => {
|
|
1094
|
+
void refreshOrganizations();
|
|
1095
|
+
setTab("info");
|
|
934
1096
|
}
|
|
935
|
-
|
|
936
|
-
|
|
1097
|
+
}
|
|
1098
|
+
)
|
|
937
1099
|
] }),
|
|
938
1100
|
tab === "roles" && /* @__PURE__ */ jsxs("div", { className: "grid gap-5 sm:grid-cols-2", children: [
|
|
939
1101
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
@@ -987,7 +1149,78 @@ function createAuthElements(hooks) {
|
|
|
987
1149
|
] })
|
|
988
1150
|
] }) });
|
|
989
1151
|
}
|
|
1152
|
+
function WaitlistForm({
|
|
1153
|
+
clientId,
|
|
1154
|
+
defaultEmail = "",
|
|
1155
|
+
onJoined,
|
|
1156
|
+
submitLabel = "Entrar na lista de espera"
|
|
1157
|
+
}) {
|
|
1158
|
+
const { joinWaitlist } = useAuth();
|
|
1159
|
+
const [name, setName] = useState("");
|
|
1160
|
+
const [email, setEmail] = useState(defaultEmail);
|
|
1161
|
+
const [busy, setBusy] = useState(false);
|
|
1162
|
+
const [error, setError] = useState(null);
|
|
1163
|
+
const [done, setDone] = useState(null);
|
|
1164
|
+
async function submit(event) {
|
|
1165
|
+
event.preventDefault();
|
|
1166
|
+
if (!joinWaitlist) {
|
|
1167
|
+
setError("Lista de espera indispon\xEDvel: atualize @geekapps/auth-nextjs para 0.26 ou superior.");
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
setBusy(true);
|
|
1171
|
+
setError(null);
|
|
1172
|
+
const result = await joinWaitlist({
|
|
1173
|
+
clientId,
|
|
1174
|
+
email: email.trim(),
|
|
1175
|
+
name: name.trim() || void 0
|
|
1176
|
+
});
|
|
1177
|
+
setBusy(false);
|
|
1178
|
+
if (!result.success) {
|
|
1179
|
+
setError(authErrorMessage(result, "N\xE3o foi poss\xEDvel entrar na lista de espera."));
|
|
1180
|
+
return;
|
|
1181
|
+
}
|
|
1182
|
+
setDone(result.data);
|
|
1183
|
+
onJoined?.(result.data);
|
|
1184
|
+
}
|
|
1185
|
+
if (done) {
|
|
1186
|
+
return /* @__PURE__ */ jsxs("div", { className: "grid gap-1 rounded-xl border border-emerald-200 bg-emerald-50 p-4 text-center", children: [
|
|
1187
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-emerald-800", children: done.status === "approved" ? "Seu acesso foi liberado!" : done.status === "joined" ? "Voc\xEA j\xE1 tem acesso." : "Voc\xEA est\xE1 na lista de espera." }),
|
|
1188
|
+
done.status === "waiting" && done.position != null && /* @__PURE__ */ jsxs("p", { className: "text-sm text-emerald-700", children: [
|
|
1189
|
+
"Sua posi\xE7\xE3o na fila: ",
|
|
1190
|
+
/* @__PURE__ */ jsxs("span", { className: "font-semibold", children: [
|
|
1191
|
+
"#",
|
|
1192
|
+
done.position
|
|
1193
|
+
] })
|
|
1194
|
+
] })
|
|
1195
|
+
] });
|
|
1196
|
+
}
|
|
1197
|
+
return /* @__PURE__ */ jsxs("form", { className: "grid gap-3", onSubmit: (event) => void submit(event), children: [
|
|
1198
|
+
/* @__PURE__ */ jsx(Field, { label: "Nome", children: /* @__PURE__ */ jsx(
|
|
1199
|
+
Input,
|
|
1200
|
+
{
|
|
1201
|
+
autoComplete: "name",
|
|
1202
|
+
onChange: (event) => setName(event.target.value),
|
|
1203
|
+
placeholder: "Seu nome",
|
|
1204
|
+
value: name
|
|
1205
|
+
}
|
|
1206
|
+
) }),
|
|
1207
|
+
/* @__PURE__ */ jsx(Field, { label: "E-mail", children: /* @__PURE__ */ jsx(
|
|
1208
|
+
Input,
|
|
1209
|
+
{
|
|
1210
|
+
autoComplete: "email",
|
|
1211
|
+
onChange: (event) => setEmail(event.target.value),
|
|
1212
|
+
placeholder: "voce@exemplo.com",
|
|
1213
|
+
required: true,
|
|
1214
|
+
type: "email",
|
|
1215
|
+
value: email
|
|
1216
|
+
}
|
|
1217
|
+
) }),
|
|
1218
|
+
error && /* @__PURE__ */ jsx("p", { className: "text-xs text-red-600", children: error }),
|
|
1219
|
+
/* @__PURE__ */ jsx(Button, { disabled: busy || !email.trim(), tone: "primary", type: "submit", children: busy ? "Enviando..." : submitLabel })
|
|
1220
|
+
] });
|
|
1221
|
+
}
|
|
990
1222
|
return {
|
|
1223
|
+
WaitlistForm,
|
|
991
1224
|
SignInButton,
|
|
992
1225
|
SignOutButton,
|
|
993
1226
|
AccountSwitcher,
|
|
@@ -995,12 +1228,14 @@ function createAuthElements(hooks) {
|
|
|
995
1228
|
UserButton,
|
|
996
1229
|
OrganizationButton,
|
|
997
1230
|
ProfileModal,
|
|
998
|
-
ManageOrganizationModal
|
|
1231
|
+
ManageOrganizationModal,
|
|
1232
|
+
CreateOrganizationForm
|
|
999
1233
|
};
|
|
1000
1234
|
}
|
|
1001
1235
|
export {
|
|
1002
1236
|
Avatar,
|
|
1003
1237
|
Modal,
|
|
1238
|
+
authErrorMessage,
|
|
1004
1239
|
createAuthElements
|
|
1005
1240
|
};
|
|
1006
1241
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n type ButtonHTMLAttributes,\n type FormEvent,\n type ReactNode,\n useEffect,\n useState,\n} from \"react\";\n\n// ── Local type definitions ────────────────────────────────────────────────────\n\nexport type ElementSize = \"sm\" | \"md\" | \"lg\";\nexport type ElementTone = \"default\" | \"primary\" | \"danger\" | \"ghost\";\n\nexport type ConnectedAccount = {\n id: string;\n sessionId?: string;\n isActive: boolean;\n user: {\n id?: string;\n name: string | null;\n email: string | null;\n imageUrl: string | null;\n phone?: string | null;\n };\n};\n\nexport type Organization = {\n id: string;\n name: string;\n description: string | null;\n slug: string;\n domain: string | null;\n imageUrl: string | null;\n faviconUrl: string | null;\n members?: Array<{\n id: string;\n user: { name: string | null; email: string | null; imageUrl: string | null };\n roleAssignments?: Array<{\n id: string;\n roleDefinition?: { name: string } | null;\n customRole?: { name: string } | null;\n }>;\n }>;\n};\n\nexport type Permission = {\n id: string;\n key: string;\n category: string | null;\n};\n\nexport type Role = {\n id: string;\n key: string;\n name: string;\n permissions: unknown[];\n};\n\nexport type UserSession = {\n id: string;\n deviceName: string | null;\n ip: string | null;\n expiresAt: string | Date;\n};\n\ntype User = {\n id: string;\n name: string | null;\n email: string | null;\n imageUrl: string | null;\n phone?: string | null;\n};\n\ntype AuthResult<T> = { success: true; data: T } | { success: false; error?: string };\n\n// ── Hook contract (structural — no import from auth-nextjs) ───────────────────\n\ntype UseAuthHook = () => {\n user: User | null;\n signIn: (opts?: { redirectTo?: string }) => Promise<void> | void;\n signOut: () => Promise<void> | void;\n signOutAll: () => Promise<void> | void;\n accounts: ConnectedAccount[];\n addAccount: (opts?: { redirectTo?: string }) => Promise<void> | void;\n isLoadingAccounts: boolean;\n refreshAccounts: () => Promise<void>;\n switchAccount: (id: string, opts?: { redirectTo?: string }) => Promise<void>;\n organizations: Organization[];\n currentOrg: Organization | null;\n currentOrgId?: string | null;\n isLoadingOrganizations: boolean;\n refreshOrganizations: () => Promise<void>;\n setCurrentOrg: (id: string) => Promise<void>;\n createOrganization: (input: {\n name: string;\n slug: string;\n }) => Promise<AuthResult<Organization>>;\n updateOrganization: (\n id: string,\n input: Partial<{\n name: string;\n slug: string;\n description: string | null;\n domain: string | null;\n imageUrl: string | null;\n faviconUrl: string | null;\n }>,\n ) => Promise<AuthResult<Organization>>;\n updateUser: (\n id: string,\n input: { name?: string | null; phone?: string | null; imageUrl?: string | null },\n ) => Promise<AuthResult<User>>;\n listUserSessions: (params: { userId?: string; organizationId?: string }) => Promise<UserSession[]>;\n revokeUserSession: (sessionId: string) => Promise<AuthResult<null>>;\n listPermissions: (params: {\n applicationId?: string;\n roleId?: string | null;\n }) => Promise<Permission[]>;\n listRoles: (params?: {\n organizationId?: string;\n applicationId?: string;\n type?: \"system\" | \"custom\" | \"all\";\n }) => Promise<{ systemRoles: Role[]; customRoles: Role[] }>;\n};\n\n// ── Primitive UI helpers ──────────────────────────────────────────────────────\n\ntype ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {\n tone?: ElementTone;\n size?: ElementSize;\n};\n\nfunction cx(...classes: Array<string | false | null | undefined>) {\n return classes.filter(Boolean).join(\" \");\n}\n\nfunction initials(value?: string | null) {\n const normalized = value?.trim();\n if (!normalized) return \"?\";\n const parts = normalized.split(/\\s+/).slice(0, 2);\n return parts.map((part) => part[0]?.toUpperCase()).join(\"\") || \"?\";\n}\n\nfunction formatDate(value?: string | Date | null) {\n if (!value) return \"-\";\n return new Intl.DateTimeFormat(undefined, {\n dateStyle: \"medium\",\n timeStyle: \"short\",\n }).format(new Date(value));\n}\n\nfunction isExpired(value: string | Date) {\n return new Date(value).getTime() <= Date.now();\n}\n\nfunction Button({\n className,\n tone = \"default\",\n size = \"md\",\n ...props\n}: ButtonProps) {\n return (\n <button\n {...props}\n className={cx(\n \"inline-flex items-center justify-center gap-2 rounded-lg font-medium transition disabled:cursor-not-allowed disabled:opacity-50\",\n size === \"sm\" && \"h-8 px-3 text-xs\",\n size === \"md\" && \"h-10 px-4 text-sm\",\n size === \"lg\" && \"h-11 px-5 text-sm\",\n tone === \"default\" &&\n \"border border-slate-200 bg-white text-slate-800 hover:bg-slate-50\",\n tone === \"primary\" && \"bg-slate-950 text-white hover:bg-slate-800\",\n tone === \"danger\" && \"bg-red-600 text-white hover:bg-red-700\",\n tone === \"ghost\" &&\n \"bg-transparent text-slate-600 hover:bg-slate-100 hover:text-slate-950\",\n className,\n )}\n />\n );\n}\n\nfunction Input(props: React.InputHTMLAttributes<HTMLInputElement>) {\n return (\n <input\n {...props}\n className={cx(\n \"h-10 w-full rounded-lg border border-slate-200 bg-white px-3 text-sm text-slate-900 outline-none placeholder:text-slate-400 focus:border-slate-400\",\n props.className,\n )}\n />\n );\n}\n\nfunction Textarea(props: React.TextareaHTMLAttributes<HTMLTextAreaElement>) {\n return (\n <textarea\n {...props}\n className={cx(\n \"min-h-[86px] w-full resize-none rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm text-slate-900 outline-none placeholder:text-slate-400 focus:border-slate-400\",\n props.className,\n )}\n />\n );\n}\n\nfunction Field({ label, children }: { label: string; children: ReactNode }) {\n return (\n <label className=\"grid gap-1.5\">\n <span className=\"text-xs font-medium text-slate-600\">{label}</span>\n {children}\n </label>\n );\n}\n\n// ── Standalone components (no hooks) ─────────────────────────────────────────\n\nexport function Avatar({\n src,\n name,\n size = \"md\",\n className,\n}: {\n src?: string | null;\n name?: string | null;\n size?: ElementSize;\n className?: string;\n}) {\n return (\n <span\n className={cx(\n \"inline-flex shrink-0 items-center justify-center overflow-hidden rounded-full bg-slate-100 font-semibold text-slate-700\",\n size === \"sm\" && \"h-8 w-8 text-xs\",\n size === \"md\" && \"h-10 w-10 text-sm\",\n size === \"lg\" && \"h-12 w-12 text-base\",\n className,\n )}\n >\n {src ? (\n <img\n alt={name ?? \"Avatar\"}\n className=\"h-full w-full object-cover\"\n src={src}\n />\n ) : (\n initials(name)\n )}\n </span>\n );\n}\n\nexport function Modal({\n open,\n onOpenChange,\n title,\n description,\n children,\n footer,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n title: string;\n description?: string;\n children: ReactNode;\n footer?: ReactNode;\n}) {\n if (!open) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4\">\n <div className=\"max-h-[90vh] w-full max-w-3xl overflow-hidden rounded-2xl bg-white shadow-xl\">\n <div className=\"flex items-start justify-between gap-4 border-b border-slate-200 p-5\">\n <div>\n <h2 className=\"text-lg font-semibold text-slate-950\">{title}</h2>\n {description && (\n <p className=\"mt-1 text-sm text-slate-500\">{description}</p>\n )}\n </div>\n <Button\n aria-label=\"Close\"\n onClick={() => onOpenChange(false)}\n size=\"sm\"\n tone=\"ghost\"\n type=\"button\"\n >\n ✕\n </Button>\n </div>\n <div className=\"max-h-[68vh] overflow-y-auto p-5\">{children}</div>\n {footer && (\n <div className=\"border-t border-slate-200 p-5\">{footer}</div>\n )}\n </div>\n </div>\n );\n}\n\n// ── Factory ───────────────────────────────────────────────────────────────────\n\n/**\n * Creates auth UI components bound to the provided `useAuth` hook instance.\n * This lets consumers supply their own auth-nextjs instance without requiring\n * a separate installed copy inside auth-elements-nextjs.\n *\n * @example\n * import { createAuthElements } from '@geekapps/auth-elements-nextjs'\n * import { useAuth } from '@geekapps/auth-nextjs/client'\n * export const { SignInButton, ProfileModal } = createAuthElements({ useAuth })\n */\nexport function createAuthElements(hooks: { useAuth: UseAuthHook }) {\n const { useAuth } = hooks;\n\n function SignInButton({\n children = \"Entrar\",\n redirectTo,\n }: {\n children?: ReactNode;\n redirectTo?: string;\n }) {\n const { signIn } = useAuth();\n return (\n <Button\n onClick={() => void signIn({ redirectTo })}\n tone=\"primary\"\n type=\"button\"\n >\n {children}\n </Button>\n );\n }\n\n function SignOutButton({ children = \"Sair\" }: { children?: ReactNode }) {\n const { signOut } = useAuth();\n return (\n <Button onClick={() => void signOut()} tone=\"ghost\" type=\"button\">\n {children}\n </Button>\n );\n }\n\n function AccountSwitcher() {\n const {\n accounts,\n addAccount,\n isLoadingAccounts,\n refreshAccounts,\n switchAccount,\n } = useAuth();\n const activeAccount =\n accounts.find((account) => account.isActive) ?? accounts[0] ?? null;\n const [open, setOpen] = useState(false);\n\n return (\n <div className=\"relative\">\n <button\n className=\"flex h-10 w-10 items-center justify-center rounded-xl transition hover:opacity-80\"\n onClick={() => setOpen((value) => !value)}\n title={activeAccount?.user.name ?? activeAccount?.user.email ?? \"Conta\"}\n type=\"button\"\n >\n <Avatar\n name={activeAccount?.user.name ?? activeAccount?.user.email}\n size=\"sm\"\n src={activeAccount?.user.imageUrl}\n />\n </button>\n\n {open && (\n <>\n <div className=\"fixed inset-0 z-20\" onClick={() => setOpen(false)} />\n <div className=\"absolute bottom-0 left-14 z-30 w-72 overflow-hidden rounded-xl border border-slate-200 bg-white shadow-lg\">\n <div className=\"border-b border-slate-100 px-3 py-2.5\">\n <p className=\"text-[11px] font-medium uppercase tracking-wider text-slate-400\">\n Contas\n </p>\n </div>\n <div className=\"p-1.5\">\n {isLoadingAccounts && (\n <p className=\"px-2 py-3 text-xs text-slate-400\">\n Carregando...\n </p>\n )}\n {accounts.map((account) => (\n <button\n className={cx(\n \"flex w-full items-center gap-2.5 rounded-lg px-2 py-2 text-left transition hover:bg-slate-50\",\n account.isActive && \"bg-slate-50\",\n )}\n key={account.sessionId ?? account.id}\n onClick={() => {\n void switchAccount(account.sessionId ?? account.id);\n setOpen(false);\n }}\n type=\"button\"\n >\n <Avatar\n name={account.user.name ?? account.user.email}\n size=\"sm\"\n src={account.user.imageUrl}\n />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm font-medium text-slate-900\">\n {account.user.name ?? account.user.email}\n </span>\n <span className=\"block truncate text-xs text-slate-500\">\n {account.user.email}\n </span>\n </span>\n {account.isActive && (\n <span className=\"shrink-0 text-xs font-medium text-emerald-600\">\n ✓\n </span>\n )}\n </button>\n ))}\n </div>\n <div className=\"flex gap-1.5 border-t border-slate-100 p-1.5\">\n <Button\n className=\"flex-1\"\n onClick={() => void addAccount()}\n size=\"sm\"\n type=\"button\"\n >\n + Conta\n </Button>\n <Button\n className=\"flex-1\"\n onClick={() => void refreshAccounts()}\n size=\"sm\"\n tone=\"ghost\"\n type=\"button\"\n >\n Atualizar\n </Button>\n </div>\n </div>\n </>\n )}\n </div>\n );\n }\n\n function OrgSwitcher() {\n const {\n createOrganization,\n currentOrg,\n isLoadingOrganizations,\n organizations,\n refreshOrganizations,\n setCurrentOrg,\n } = useAuth();\n const [open, setOpen] = useState(false);\n const [creating, setCreating] = useState(false);\n\n async function onCreate(event: FormEvent<HTMLFormElement>) {\n event.preventDefault();\n const form = new FormData(event.currentTarget);\n const name = String(form.get(\"name\") ?? \"\");\n const slug = String(form.get(\"slug\") ?? \"\");\n const result = await createOrganization({ name, slug });\n if (result.success) {\n setCreating(false);\n setOpen(false);\n await refreshOrganizations();\n }\n }\n\n return (\n <div className=\"relative\">\n <button\n className=\"flex w-full items-center gap-3 rounded-xl border border-slate-200 bg-white p-2 text-left hover:bg-slate-50\"\n onClick={() => setOpen((value) => !value)}\n type=\"button\"\n >\n <Avatar name={currentOrg?.name} src={currentOrg?.imageUrl} />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm font-medium text-slate-950\">\n {currentOrg?.name ?? \"Selecionar organização\"}\n </span>\n <span className=\"block truncate text-xs text-slate-500\">\n {isLoadingOrganizations\n ? \"Carregando...\"\n : `${organizations.length} organizações`}\n </span>\n </span>\n <span className=\"text-slate-400\">⌄</span>\n </button>\n\n {open && (\n <div className=\"absolute right-0 z-30 mt-2 w-80 overflow-hidden rounded-xl border border-slate-200 bg-white shadow-lg\">\n <div className=\"max-h-72 overflow-y-auto p-2\">\n {organizations.map((organization) => (\n <button\n className=\"flex w-full items-center gap-3 rounded-lg p-2 text-left hover:bg-slate-50\"\n key={organization.id}\n onClick={() => {\n void setCurrentOrg(organization.id);\n setOpen(false);\n }}\n type=\"button\"\n >\n <Avatar\n name={organization.name}\n size=\"sm\"\n src={organization.imageUrl}\n />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm font-medium text-slate-900\">\n {organization.name}\n </span>\n <span className=\"block truncate text-xs text-slate-500\">\n {organization.slug}\n </span>\n </span>\n {organization.id === currentOrg?.id && (\n <span className=\"text-xs font-medium text-emerald-600\">\n Atual\n </span>\n )}\n </button>\n ))}\n </div>\n\n {creating ? (\n <form\n className=\"grid gap-2 border-t border-slate-200 p-3\"\n onSubmit={onCreate}\n >\n <Input name=\"name\" placeholder=\"Nome da org\" required />\n <Input name=\"slug\" placeholder=\"slug-da-org\" required />\n <div className=\"flex gap-2\">\n <Button\n className=\"flex-1\"\n size=\"sm\"\n tone=\"primary\"\n type=\"submit\"\n >\n Criar\n </Button>\n <Button\n className=\"flex-1\"\n onClick={() => setCreating(false)}\n size=\"sm\"\n tone=\"ghost\"\n type=\"button\"\n >\n Cancelar\n </Button>\n </div>\n </form>\n ) : (\n <div className=\"flex gap-2 border-t border-slate-200 p-2\">\n <Button\n className=\"flex-1\"\n onClick={() => setCreating(true)}\n size=\"sm\"\n type=\"button\"\n >\n Nova org\n </Button>\n <Button\n className=\"flex-1\"\n onClick={() => void refreshOrganizations()}\n size=\"sm\"\n tone=\"ghost\"\n type=\"button\"\n >\n Atualizar\n </Button>\n </div>\n )}\n </div>\n )}\n </div>\n );\n }\n\n function UserButton() {\n const { user } = useAuth();\n const [open, setOpen] = useState(false);\n return (\n <>\n <button onClick={() => setOpen(true)} type=\"button\">\n <Avatar name={user?.name ?? user?.email} src={user?.imageUrl} />\n </button>\n <ProfileModal open={open} onOpenChange={setOpen} />\n </>\n );\n }\n\n function OrganizationButton() {\n const { currentOrg } = useAuth();\n const [open, setOpen] = useState(false);\n return (\n <>\n <button\n 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\"\n onClick={() => setOpen(true)}\n title={currentOrg?.name ?? \"Organização\"}\n type=\"button\"\n >\n {currentOrg?.imageUrl ? (\n <img\n alt={currentOrg.name}\n className=\"h-full w-full rounded-xl object-cover\"\n src={currentOrg.imageUrl}\n />\n ) : (\n (currentOrg?.name ?? \"O\")[0]?.toUpperCase()\n )}\n </button>\n <ManageOrganizationModal open={open} onOpenChange={setOpen} />\n </>\n );\n }\n\n function ProfileModal({\n open,\n onOpenChange,\n }: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n }) {\n const {\n signOut,\n signOutAll,\n user,\n organizations,\n currentOrg,\n setCurrentOrg,\n updateUser,\n listUserSessions,\n revokeUserSession,\n } = useAuth();\n const [tab, setTab] = useState(\"profile\");\n const [sessions, setSessions] = useState<UserSession[]>([]);\n const [saving, setSaving] = useState(false);\n const [saveError, setSaveError] = useState<string | null>(null);\n const [saveSuccess, setSaveSuccess] = useState(false);\n\n useEffect(() => {\n if (!open) {\n setTab(\"profile\");\n setSaveError(null);\n setSaveSuccess(false);\n }\n }, [open]);\n\n useEffect(() => {\n if (open && user && tab === \"sessions\") {\n void listUserSessions({ userId: user.id })\n .then(setSessions)\n .catch(() => setSessions([]));\n }\n }, [listUserSessions, open, tab, user]);\n\n async function onProfileSubmit(event: FormEvent<HTMLFormElement>) {\n event.preventDefault();\n if (!user) return;\n const form = new FormData(event.currentTarget);\n setSaving(true);\n setSaveError(null);\n setSaveSuccess(false);\n try {\n await updateUser(user.id, {\n name: String(form.get(\"name\") ?? \"\") || null,\n phone: String(form.get(\"phone\") ?? \"\") || null,\n imageUrl: String(form.get(\"imageUrl\") ?? \"\") || null,\n });\n setSaveSuccess(true);\n setTimeout(() => setSaveSuccess(false), 2500);\n } catch (err) {\n setSaveError(err instanceof Error ? err.message : \"Erro ao salvar.\");\n } finally {\n setSaving(false);\n }\n }\n\n if (!open) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4\">\n <div className=\"flex max-h-[90vh] w-full max-w-lg flex-col overflow-hidden rounded-2xl bg-white shadow-2xl\">\n {/* Header */}\n <div className=\"flex shrink-0 items-center justify-between border-b border-slate-100 px-6 py-4\">\n <div className=\"flex items-center gap-3\">\n <Avatar\n name={user?.name ?? user?.email}\n size=\"sm\"\n src={user?.imageUrl}\n />\n <div>\n <p className=\"text-sm font-semibold text-slate-900\">\n {user?.name ?? user?.email ?? \"Minha conta\"}\n </p>\n <p className=\"text-xs text-slate-500\">{user?.email}</p>\n </div>\n </div>\n <button\n aria-label=\"Fechar\"\n className=\"rounded-lg p-1.5 text-slate-400 transition hover:bg-slate-100 hover:text-slate-700\"\n onClick={() => onOpenChange(false)}\n type=\"button\"\n >\n ✕\n </button>\n </div>\n\n {/* Tabs */}\n <div className=\"shrink-0 flex gap-1 border-b border-slate-100 px-6 pt-3\">\n {(\n [\n { id: \"profile\", label: \"Perfil\" },\n { id: \"sessions\", label: \"Sessões\" },\n { id: \"orgs\", label: \"Organizações\" },\n ] as const\n ).map((t) => (\n <button\n className={cx(\n \"mb-[-1px] border-b-2 px-3 pb-2.5 text-xs font-medium transition\",\n tab === t.id\n ? \"border-slate-900 text-slate-900\"\n : \"border-transparent text-slate-500 hover:text-slate-700\",\n )}\n key={t.id}\n onClick={() => setTab(t.id)}\n type=\"button\"\n >\n {t.label}\n </button>\n ))}\n </div>\n\n {/* Body */}\n <div className=\"flex-1 overflow-y-auto px-6 py-5\">\n {tab === \"profile\" && user && (\n <form className=\"grid gap-4\" onSubmit={onProfileSubmit}>\n <div className=\"flex items-center gap-4 rounded-xl bg-slate-50 p-4\">\n <Avatar\n name={user.name ?? user.email}\n size=\"lg\"\n src={user.imageUrl}\n />\n <div>\n <p className=\"text-sm font-semibold text-slate-900\">\n {user.name ?? \"Sem nome\"}\n </p>\n <p className=\"text-xs text-slate-500\">{user.email}</p>\n </div>\n </div>\n\n <div className=\"grid gap-3 sm:grid-cols-2\">\n <Field label=\"Nome\">\n <Input\n defaultValue={user.name ?? \"\"}\n name=\"name\"\n placeholder=\"Seu nome\"\n />\n </Field>\n <Field label=\"Telefone\">\n <Input\n defaultValue={user.phone ?? \"\"}\n name=\"phone\"\n placeholder=\"+55 11 99999-9999\"\n />\n </Field>\n </div>\n <Field label=\"URL da imagem\">\n <Input\n defaultValue={user.imageUrl ?? \"\"}\n name=\"imageUrl\"\n placeholder=\"https://...\"\n />\n </Field>\n\n {saveError && (\n <p className=\"rounded-lg bg-red-50 px-3 py-2 text-xs text-red-600\">\n {saveError}\n </p>\n )}\n {saveSuccess && (\n <p className=\"rounded-lg bg-emerald-50 px-3 py-2 text-xs text-emerald-600\">\n Perfil salvo com sucesso.\n </p>\n )}\n\n <div className=\"flex items-center justify-between border-t border-slate-100 pt-2\">\n <div className=\"flex gap-2\">\n <Button\n onClick={() => void signOut()}\n size=\"sm\"\n tone=\"ghost\"\n type=\"button\"\n >\n Sair\n </Button>\n <Button\n onClick={() => void signOutAll()}\n size=\"sm\"\n tone=\"danger\"\n type=\"button\"\n >\n Sair de todas\n </Button>\n </div>\n <Button\n disabled={saving}\n size=\"sm\"\n tone=\"primary\"\n type=\"submit\"\n >\n {saving ? \"Salvando…\" : \"Salvar\"}\n </Button>\n </div>\n </form>\n )}\n\n {tab === \"sessions\" && (\n <div className=\"grid gap-2\">\n {sessions.length === 0 && (\n <p className=\"py-6 text-center text-sm text-slate-400\">\n Nenhuma sessão ativa.\n </p>\n )}\n {sessions.map((session) => {\n const expired = isExpired(session.expiresAt);\n return (\n <div\n className=\"flex items-center justify-between gap-4 rounded-xl border border-slate-200 p-4\"\n key={session.id}\n >\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-slate-900\">\n {session.deviceName ?? \"Dispositivo\"}\n </p>\n <p className=\"mt-0.5 truncate text-xs text-slate-500\">\n {session.ip ?? \"IP desconhecido\"} ·{\" \"}\n <span className={expired ? \"text-amber-600\" : \"\"}>\n {expired\n ? \"Expirada\"\n : `Expira ${formatDate(session.expiresAt)}`}\n </span>\n </p>\n </div>\n <Button\n onClick={async () => {\n await revokeUserSession(session.id);\n setSessions((s) =>\n s.filter((x) => x.id !== session.id),\n );\n }}\n size=\"sm\"\n tone=\"danger\"\n type=\"button\"\n >\n Revogar\n </Button>\n </div>\n );\n })}\n </div>\n )}\n\n {tab === \"orgs\" && (\n <div className=\"grid gap-2\">\n {organizations.length === 0 && (\n <p className=\"py-6 text-center text-sm text-slate-400\">\n Nenhuma organização.\n </p>\n )}\n {organizations.map((org) => (\n <button\n className={cx(\n \"flex w-full items-center gap-3 rounded-xl border p-3 text-left transition\",\n org.id === currentOrg?.id\n ? \"border-slate-900 bg-slate-50\"\n : \"border-slate-200 hover:border-slate-300 hover:bg-slate-50\",\n )}\n key={org.id}\n onClick={() => void setCurrentOrg(org.id)}\n type=\"button\"\n >\n <Avatar name={org.name} size=\"sm\" src={org.imageUrl} />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-slate-900\">\n {org.name}\n </p>\n <p className=\"truncate text-xs text-slate-500\">\n /{org.slug}\n </p>\n </div>\n {org.id === currentOrg?.id && (\n <span className=\"shrink-0 rounded-full bg-slate-900 px-2 py-0.5 text-[10px] font-medium text-white\">\n Ativa\n </span>\n )}\n </button>\n ))}\n </div>\n )}\n </div>\n </div>\n </div>\n );\n }\n\n function ManageOrganizationModal({\n open,\n onOpenChange,\n }: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n }) {\n const {\n createOrganization,\n currentOrg,\n organizations,\n refreshOrganizations,\n setCurrentOrg,\n updateOrganization,\n listPermissions,\n listRoles,\n } = useAuth();\n const [tab, setTab] = useState(\"orgs\");\n const [roles, setRoles] = useState<{\n systemRoles: Role[];\n customRoles: Role[];\n }>({ systemRoles: [], customRoles: [] });\n const [permissions, setPermissions] = useState<Permission[]>([]);\n const [saving, setSaving] = useState(false);\n const [saveSuccess, setSaveSuccess] = useState(false);\n const [saveError, setSaveError] = useState<string | null>(null);\n const [creating, setCreating] = useState(false);\n const [createError, setCreateError] = useState<string | null>(null);\n\n useEffect(() => {\n if (!open) {\n setTab(\"orgs\");\n setSaveError(null);\n setSaveSuccess(false);\n setCreating(false);\n setCreateError(null);\n }\n }, [open]);\n\n useEffect(() => {\n if (!open || !currentOrg) return;\n if (tab === \"members\" || tab === \"roles\") {\n void listRoles({ organizationId: currentOrg.id })\n .then(setRoles)\n .catch(() => setRoles({ systemRoles: [], customRoles: [] }));\n void listPermissions({})\n .then(setPermissions)\n .catch(() => setPermissions([]));\n }\n }, [currentOrg, listPermissions, listRoles, open, tab]);\n\n async function onOrgSubmit(event: FormEvent<HTMLFormElement>) {\n event.preventDefault();\n if (!currentOrg) return;\n const form = new FormData(event.currentTarget);\n setSaving(true);\n setSaveError(null);\n setSaveSuccess(false);\n try {\n await updateOrganization(currentOrg.id, {\n name: String(form.get(\"name\") ?? \"\"),\n description: String(form.get(\"description\") ?? \"\") || null,\n slug: String(form.get(\"slug\") ?? \"\"),\n domain: String(form.get(\"domain\") ?? \"\") || null,\n imageUrl: String(form.get(\"imageUrl\") ?? \"\") || null,\n faviconUrl: String(form.get(\"faviconUrl\") ?? \"\") || null,\n });\n setSaveSuccess(true);\n setTimeout(() => setSaveSuccess(false), 2500);\n } catch (err) {\n setSaveError(err instanceof Error ? err.message : \"Erro ao salvar.\");\n } finally {\n setSaving(false);\n }\n }\n\n async function onCreateOrg(event: FormEvent<HTMLFormElement>) {\n event.preventDefault();\n const form = new FormData(event.currentTarget);\n setCreating(true);\n setCreateError(null);\n try {\n const result = await createOrganization({\n name: String(form.get(\"name\") ?? \"\"),\n slug: String(form.get(\"slug\") ?? \"\"),\n });\n if (result.success) {\n await refreshOrganizations();\n if (result.data?.id) {\n void setCurrentOrg(result.data.id);\n }\n setTab(\"info\");\n } else {\n setCreateError(result.error ?? \"Erro ao criar organização.\");\n }\n } catch (err) {\n setCreateError(err instanceof Error ? err.message : \"Erro ao criar.\");\n } finally {\n setCreating(false);\n }\n }\n\n if (!open) return null;\n\n const orgTabs = [\n { id: \"orgs\", label: \"Organizações\" },\n { id: \"info\", label: \"Geral\" },\n { id: \"members\", label: \"Membros\" },\n { id: \"roles\", label: \"Roles\" },\n { id: \"new\", label: \"+ Nova org\" },\n ] as const;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4\">\n <div className=\"flex max-h-[90vh] w-full max-w-2xl flex-col overflow-hidden rounded-2xl bg-white shadow-2xl\">\n {/* Header */}\n <div className=\"flex shrink-0 items-center justify-between border-b border-slate-100 px-6 py-4\">\n <div className=\"flex items-center gap-3\">\n {currentOrg?.imageUrl ? (\n <img\n alt={currentOrg.name}\n className=\"h-8 w-8 rounded-lg object-cover\"\n src={currentOrg.imageUrl}\n />\n ) : (\n <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\">\n {(currentOrg?.name ?? \"O\")[0]?.toUpperCase()}\n </span>\n )}\n <div>\n <p className=\"text-sm font-semibold text-slate-900\">\n {currentOrg?.name ?? \"Organização\"}\n </p>\n {currentOrg?.slug && (\n <p className=\"text-xs text-slate-500\">/{currentOrg.slug}</p>\n )}\n </div>\n </div>\n <button\n aria-label=\"Fechar\"\n className=\"rounded-lg p-1.5 text-slate-400 transition hover:bg-slate-100 hover:text-slate-700\"\n onClick={() => onOpenChange(false)}\n type=\"button\"\n >\n ✕\n </button>\n </div>\n\n {/* Tabs */}\n <div className=\"flex shrink-0 gap-1 border-b border-slate-100 px-6 pt-3\">\n {orgTabs.map((t) => (\n <button\n className={cx(\n \"mb-[-1px] border-b-2 px-3 pb-2.5 text-xs font-medium transition\",\n tab === t.id\n ? \"border-slate-900 text-slate-900\"\n : \"border-transparent text-slate-500 hover:text-slate-700\",\n )}\n key={t.id}\n onClick={() => setTab(t.id)}\n type=\"button\"\n >\n {t.label}\n </button>\n ))}\n </div>\n\n {/* Body */}\n <div className=\"flex-1 overflow-y-auto px-6 py-5\">\n {!currentOrg && (\n <p className=\"py-8 text-center text-sm text-slate-400\">\n Nenhuma organização selecionada.\n </p>\n )}\n\n {tab === \"orgs\" && (\n <div className=\"grid gap-2\">\n {organizations.length === 0 && (\n <p className=\"py-8 text-center text-sm text-slate-400\">\n Nenhuma organização disponível.\n </p>\n )}\n {organizations.map((org) => (\n <button\n className={cx(\n \"flex w-full items-center gap-3 rounded-xl border p-3 text-left transition\",\n org.id === currentOrg?.id\n ? \"border-slate-900 bg-slate-50\"\n : \"border-slate-200 hover:border-slate-300 hover:bg-slate-50\",\n )}\n key={org.id}\n onClick={() => {\n void setCurrentOrg(org.id);\n onOpenChange(false);\n }}\n type=\"button\"\n >\n <Avatar name={org.name} size=\"sm\" src={org.imageUrl} />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-slate-900\">\n {org.name}\n </p>\n <p className=\"truncate text-xs text-slate-500\">\n /{org.slug}\n </p>\n </div>\n {org.id === currentOrg?.id && (\n <span className=\"shrink-0 rounded-full bg-slate-900 px-2 py-0.5 text-[10px] font-medium text-white\">\n Ativa\n </span>\n )}\n </button>\n ))}\n </div>\n )}\n\n {tab === \"info\" && currentOrg && (\n <form className=\"grid gap-4\" onSubmit={onOrgSubmit}>\n <div className=\"grid gap-3 sm:grid-cols-2\">\n <Field label=\"Nome *\">\n <Input defaultValue={currentOrg.name} name=\"name\" required />\n </Field>\n <Field label=\"Slug *\">\n <Input defaultValue={currentOrg.slug} name=\"slug\" required />\n </Field>\n </div>\n <Field label=\"Descrição\">\n <Textarea\n defaultValue={currentOrg.description ?? \"\"}\n name=\"description\"\n placeholder=\"Descreva a organização…\"\n />\n </Field>\n <div className=\"grid gap-3 sm:grid-cols-2\">\n <Field label=\"Domínio\">\n <Input\n defaultValue={currentOrg.domain ?? \"\"}\n name=\"domain\"\n placeholder=\"acme.com\"\n />\n </Field>\n <Field label=\"URL da imagem\">\n <Input\n defaultValue={currentOrg.imageUrl ?? \"\"}\n name=\"imageUrl\"\n placeholder=\"https://...\"\n />\n </Field>\n </div>\n <Field label=\"URL do favicon\">\n <Input\n defaultValue={currentOrg.faviconUrl ?? \"\"}\n name=\"faviconUrl\"\n placeholder=\"https://...\"\n />\n </Field>\n\n {saveError && (\n <p className=\"rounded-lg bg-red-50 px-3 py-2 text-xs text-red-600\">\n {saveError}\n </p>\n )}\n {saveSuccess && (\n <p className=\"rounded-lg bg-emerald-50 px-3 py-2 text-xs text-emerald-600\">\n Organização atualizada.\n </p>\n )}\n\n <div className=\"flex justify-end pt-1\">\n <Button\n disabled={saving}\n size=\"sm\"\n tone=\"primary\"\n type=\"submit\"\n >\n {saving ? \"Salvando…\" : \"Salvar organização\"}\n </Button>\n </div>\n </form>\n )}\n\n {tab === \"members\" && currentOrg && (\n <div className=\"grid gap-2\">\n {(currentOrg.members ?? []).length === 0 && (\n <p className=\"py-8 text-center text-sm text-slate-400\">\n Nenhum membro nesta organização.\n </p>\n )}\n {(currentOrg.members ?? []).map((member) => (\n <div\n className=\"flex items-center gap-3 rounded-xl border border-slate-200 p-4\"\n key={member.id}\n >\n <Avatar\n name={member.user.name ?? member.user.email}\n size=\"sm\"\n src={member.user.imageUrl}\n />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-slate-900\">\n {member.user.name ?? member.user.email}\n </p>\n <p className=\"truncate text-xs text-slate-500\">\n {member.user.email}\n </p>\n </div>\n <div className=\"flex shrink-0 flex-wrap justify-end gap-1\">\n {(member.roleAssignments ?? []).map((a) => (\n <span\n className=\"rounded-full bg-slate-900 px-2 py-0.5 text-[11px] font-medium text-white\"\n key={a.id}\n >\n {a.roleDefinition?.name ?? a.customRole?.name ?? a.id}\n </span>\n ))}\n </div>\n </div>\n ))}\n </div>\n )}\n\n {tab === \"new\" && (\n <form className=\"grid gap-4\" onSubmit={onCreateOrg}>\n <p className=\"text-sm text-slate-500\">\n Crie uma nova organização e alterne para ela automaticamente.\n </p>\n <Field label=\"Nome *\">\n <Input name=\"name\" placeholder=\"Minha organização\" required />\n </Field>\n <Field label=\"Slug *\">\n <Input name=\"slug\" placeholder=\"minha-org\" required />\n </Field>\n {createError && (\n <p className=\"rounded-lg bg-red-50 px-3 py-2 text-xs text-red-600\">\n {createError}\n </p>\n )}\n <div className=\"flex justify-end gap-2\">\n <Button\n onClick={() => setTab(\"info\")}\n size=\"sm\"\n tone=\"ghost\"\n type=\"button\"\n >\n Cancelar\n </Button>\n <Button\n disabled={creating}\n size=\"sm\"\n tone=\"primary\"\n type=\"submit\"\n >\n {creating ? \"Criando…\" : \"Criar organização\"}\n </Button>\n </div>\n </form>\n )}\n\n {tab === \"roles\" && (\n <div className=\"grid gap-5 sm:grid-cols-2\">\n <div className=\"min-w-0\">\n <h3 className=\"mb-3 text-xs font-semibold uppercase tracking-wider text-slate-400\">\n Roles ({roles.systemRoles.length + roles.customRoles.length})\n </h3>\n <div className=\"max-h-[280px] space-y-2 overflow-y-auto pr-1\">\n {roles.systemRoles.length === 0 &&\n roles.customRoles.length === 0 && (\n <p className=\"text-sm text-slate-400\">Nenhuma role.</p>\n )}\n {[...roles.systemRoles, ...roles.customRoles].map((role) => (\n <div\n className=\"overflow-hidden rounded-xl border border-slate-200 p-3\"\n key={role.id}\n >\n <p className=\"truncate text-sm font-semibold text-slate-900\">\n {role.name}\n </p>\n <p className=\"truncate text-xs text-slate-400\">\n {role.key}\n </p>\n <p className=\"mt-1 text-xs text-slate-500\">\n {role.permissions.length} permission\n {role.permissions.length !== 1 ? \"s\" : \"\"}\n </p>\n </div>\n ))}\n </div>\n </div>\n <div className=\"min-w-0\">\n <h3 className=\"mb-3 text-xs font-semibold uppercase tracking-wider text-slate-400\">\n Permissions ({permissions.length})\n </h3>\n <div className=\"max-h-[280px] space-y-2 overflow-y-auto pr-1\">\n {permissions.length === 0 && (\n <p className=\"text-sm text-slate-400\">\n Nenhuma permission.\n </p>\n )}\n {permissions.map((permission) => (\n <div\n className=\"overflow-hidden rounded-xl border border-slate-200 p-3\"\n key={permission.id}\n >\n <p className=\"truncate text-sm font-semibold text-slate-900\">\n {permission.key}\n </p>\n <p className=\"truncate text-xs text-slate-400\">\n {permission.category ?? \"custom\"}\n </p>\n </div>\n ))}\n </div>\n </div>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n }\n\n return {\n SignInButton,\n SignOutButton,\n AccountSwitcher,\n OrgSwitcher,\n UserButton,\n OrganizationButton,\n ProfileModal,\n ManageOrganizationModal,\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n type ButtonHTMLAttributes,\n type FormEvent,\n type ReactNode,\n useEffect,\n useState,\n} from \"react\";\n\n// ── Local type definitions ────────────────────────────────────────────────────\n\nexport type ElementSize = \"sm\" | \"md\" | \"lg\";\nexport type ElementTone = \"default\" | \"primary\" | \"danger\" | \"ghost\";\n\nexport type ConnectedAccount = {\n id: string;\n sessionId?: string;\n isActive: boolean;\n user: {\n id?: string;\n name: string | null;\n email: string | null;\n imageUrl: string | null;\n phone?: string | null;\n };\n};\n\nexport type Organization = {\n id: string;\n name: string;\n description: string | null;\n slug: string;\n domain: string | null;\n imageUrl: string | null;\n faviconUrl: string | null;\n type?: OrganizationType;\n taxId?: string | null;\n taxIdType?: TaxIdType | null;\n legalName?: string | null;\n members?: Array<{\n id: string;\n user: { name: string | null; email: string | null; imageUrl: string | null };\n roleAssignments?: Array<{\n id: string;\n roleDefinition?: { name: string } | null;\n customRole?: { name: string } | null;\n }>;\n }>;\n};\n\nexport type OrganizationType = \"standard\" | \"legal\";\nexport type TaxIdType = \"br_cnpj\" | \"generic\";\n\ntype OrganizationLegalAddress = Partial<\n Record<\"street\" | \"number\" | \"complement\" | \"district\" | \"city\" | \"state\" | \"postalCode\" | \"country\", string | null>\n>;\n\nexport type OrganizationCreateInput = {\n name: string;\n slug: string;\n type?: OrganizationType;\n taxId?: string | null;\n taxIdType?: TaxIdType | null;\n taxIdCountry?: string | null;\n legalName?: string | null;\n tradeName?: string | null;\n legalEmail?: string | null;\n legalPhone?: string | null;\n legalAddress?: OrganizationLegalAddress | null;\n};\n\nexport type TaxIdLookupResult = {\n taxId: string;\n taxIdType: TaxIdType;\n taxIdCountry: string | null;\n alreadyRegistered: boolean;\n lookupAvailable: boolean;\n found: boolean;\n registrationStatus: string | null;\n suggestedName: string | null;\n data: {\n legalName: string | null;\n tradeName: string | null;\n legalEmail: string | null;\n legalPhone: string | null;\n legalAddress: OrganizationLegalAddress | null;\n };\n missingFields: string[];\n};\n\nconst ADDRESS_KEYS = [\n \"street\",\n \"number\",\n \"complement\",\n \"district\",\n \"city\",\n \"state\",\n \"postalCode\",\n \"country\",\n] as const;\n\nconst REQUIRED_LEGAL = new Set([\n \"taxIdCountry\",\n \"legalName\",\n \"legalAddress.street\",\n \"legalAddress.city\",\n \"legalAddress.postalCode\",\n \"legalAddress.country\",\n]);\n\nconst EMPTY_ORG_FORM: Record<string, string> = {\n type: \"standard\",\n taxIdType: \"br_cnpj\",\n taxId: \"\",\n name: \"\",\n slug: \"\",\n};\n\nfunction slugify(value: string) {\n return value\n .normalize(\"NFD\")\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 60);\n}\n\nexport type Permission = {\n id: string;\n key: string;\n category: string | null;\n};\n\nexport type Role = {\n id: string;\n key: string;\n name: string;\n permissions: unknown[];\n};\n\nexport type UserSession = {\n id: string;\n deviceName: string | null;\n ip: string | null;\n expiresAt: string | Date;\n};\n\ntype User = {\n id: string;\n name: string | null;\n email: string | null;\n imageUrl: string | null;\n phone?: string | null;\n};\n\n/** Espelha `AuthResult` do auth-nextjs >=0.26 (campos extras são opcionais). */\nexport type AuthResult<T> =\n | { success: true; data: T }\n | {\n success: false;\n error?: string;\n status?: number;\n code?: string;\n retryAfter?: number;\n missingFields?: string[];\n };\n\nexport type JoinWaitlistParams = { clientId: string; email: string; name?: string };\nexport type JoinWaitlistResponse = {\n ok: true;\n status: \"waiting\" | \"approved\" | \"joined\";\n position: number | null;\n};\n\n/** Mensagem em português para um resultado de erro; `fallback` se o código for desconhecido. */\nexport function authErrorMessage(\n result: { error?: string; code?: string; retryAfter?: number },\n fallback: string,\n): string {\n switch (result.code) {\n case \"waitlist_required\":\n return \"Esta aplicação está com lista de espera. Entre na lista para receber acesso.\";\n case \"waitlist_disabled\":\n return \"A lista de espera não está ativa para esta aplicação.\";\n case \"password_reset_required\":\n return \"Sua senha precisa ser redefinida antes de continuar. Use a opção de recuperar senha.\";\n case \"account_locked\": {\n const s = result.retryAfter;\n if (typeof s === \"number\" && s > 0) {\n const wait = s >= 60 ? `${Math.ceil(s / 60)} min` : `${s} s`;\n return `Conta temporariamente bloqueada por tentativas excessivas. Tente novamente em ${wait}.`;\n }\n return \"Conta temporariamente bloqueada. Tente novamente mais tarde.\";\n }\n case \"invalid_credentials\":\n return result.error ?? \"E-mail ou senha incorretos.\";\n default:\n return result.error ?? fallback;\n }\n}\n\n// ── Hook contract (structural — no import from auth-nextjs) ───────────────────\n\ntype UseAuthHook = () => {\n user: User | null;\n signIn: (opts?: { redirectTo?: string }) => Promise<void> | void;\n signOut: () => Promise<void> | void;\n signOutAll: () => Promise<void> | void;\n accounts: ConnectedAccount[];\n addAccount: (opts?: { redirectTo?: string }) => Promise<void> | void;\n isLoadingAccounts: boolean;\n refreshAccounts: () => Promise<void>;\n switchAccount: (id: string, opts?: { redirectTo?: string }) => Promise<void>;\n organizations: Organization[];\n currentOrg: Organization | null;\n currentOrgId?: string | null;\n isLoadingOrganizations: boolean;\n refreshOrganizations: () => Promise<void>;\n setCurrentOrg: (id: string) => Promise<void>;\n createOrganization: (input: OrganizationCreateInput) => Promise<AuthResult<Organization>>;\n /** Opcional: SDKs antigos não têm — sem ele, o formulário só não busca os dados do CNPJ. */\n lookupTaxId?: (value: string, type?: TaxIdType) => Promise<AuthResult<TaxIdLookupResult>>;\n /** Opcional (auth-nextjs >=0.26): sem ele o WaitlistForm mostra um aviso. */\n joinWaitlist?: (params: JoinWaitlistParams) => Promise<AuthResult<JoinWaitlistResponse>>;\n updateOrganization: (\n id: string,\n input: Partial<{\n name: string;\n slug: string;\n description: string | null;\n domain: string | null;\n imageUrl: string | null;\n faviconUrl: string | null;\n }>,\n ) => Promise<AuthResult<Organization>>;\n updateUser: (\n id: string,\n input: { name?: string | null; phone?: string | null; imageUrl?: string | null },\n ) => Promise<AuthResult<User>>;\n listUserSessions: (params: { userId?: string; organizationId?: string }) => Promise<UserSession[]>;\n revokeUserSession: (sessionId: string) => Promise<AuthResult<null>>;\n listPermissions: (params: {\n applicationId?: string;\n roleId?: string | null;\n }) => Promise<Permission[]>;\n listRoles: (params?: {\n organizationId?: string;\n applicationId?: string;\n type?: \"system\" | \"custom\" | \"all\";\n }) => Promise<{ systemRoles: Role[]; customRoles: Role[] }>;\n};\n\n// ── Primitive UI helpers ──────────────────────────────────────────────────────\n\ntype ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {\n tone?: ElementTone;\n size?: ElementSize;\n};\n\nfunction cx(...classes: Array<string | false | null | undefined>) {\n return classes.filter(Boolean).join(\" \");\n}\n\nfunction initials(value?: string | null) {\n const normalized = value?.trim();\n if (!normalized) return \"?\";\n const parts = normalized.split(/\\s+/).slice(0, 2);\n return parts.map((part) => part[0]?.toUpperCase()).join(\"\") || \"?\";\n}\n\nfunction formatDate(value?: string | Date | null) {\n if (!value) return \"-\";\n return new Intl.DateTimeFormat(undefined, {\n dateStyle: \"medium\",\n timeStyle: \"short\",\n }).format(new Date(value));\n}\n\nfunction isExpired(value: string | Date) {\n return new Date(value).getTime() <= Date.now();\n}\n\nfunction Button({\n className,\n tone = \"default\",\n size = \"md\",\n ...props\n}: ButtonProps) {\n return (\n <button\n {...props}\n className={cx(\n \"inline-flex items-center justify-center gap-2 rounded-lg font-medium transition disabled:cursor-not-allowed disabled:opacity-50\",\n size === \"sm\" && \"h-8 px-3 text-xs\",\n size === \"md\" && \"h-10 px-4 text-sm\",\n size === \"lg\" && \"h-11 px-5 text-sm\",\n tone === \"default\" &&\n \"border border-slate-200 bg-white text-slate-800 hover:bg-slate-50\",\n tone === \"primary\" && \"bg-slate-950 text-white hover:bg-slate-800\",\n tone === \"danger\" && \"bg-red-600 text-white hover:bg-red-700\",\n tone === \"ghost\" &&\n \"bg-transparent text-slate-600 hover:bg-slate-100 hover:text-slate-950\",\n className,\n )}\n />\n );\n}\n\nfunction Input(props: React.InputHTMLAttributes<HTMLInputElement>) {\n return (\n <input\n {...props}\n className={cx(\n \"h-10 w-full rounded-lg border border-slate-200 bg-white px-3 text-sm text-slate-900 outline-none placeholder:text-slate-400 focus:border-slate-400\",\n props.className,\n )}\n />\n );\n}\n\nfunction Textarea(props: React.TextareaHTMLAttributes<HTMLTextAreaElement>) {\n return (\n <textarea\n {...props}\n className={cx(\n \"min-h-[86px] w-full resize-none rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm text-slate-900 outline-none placeholder:text-slate-400 focus:border-slate-400\",\n props.className,\n )}\n />\n );\n}\n\nfunction Field({ label, children }: { label: string; children: ReactNode }) {\n return (\n <label className=\"grid gap-1.5\">\n <span className=\"text-xs font-medium text-slate-600\">{label}</span>\n {children}\n </label>\n );\n}\n\n// ── Standalone components (no hooks) ─────────────────────────────────────────\n\nexport function Avatar({\n src,\n name,\n size = \"md\",\n className,\n}: {\n src?: string | null;\n name?: string | null;\n size?: ElementSize;\n className?: string;\n}) {\n return (\n <span\n className={cx(\n \"inline-flex shrink-0 items-center justify-center overflow-hidden rounded-full bg-slate-100 font-semibold text-slate-700\",\n size === \"sm\" && \"h-8 w-8 text-xs\",\n size === \"md\" && \"h-10 w-10 text-sm\",\n size === \"lg\" && \"h-12 w-12 text-base\",\n className,\n )}\n >\n {src ? (\n <img\n alt={name ?? \"Avatar\"}\n className=\"h-full w-full object-cover\"\n src={src}\n />\n ) : (\n initials(name)\n )}\n </span>\n );\n}\n\nexport function Modal({\n open,\n onOpenChange,\n title,\n description,\n children,\n footer,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n title: string;\n description?: string;\n children: ReactNode;\n footer?: ReactNode;\n}) {\n if (!open) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4\">\n <div className=\"max-h-[90vh] w-full max-w-3xl overflow-hidden rounded-2xl bg-white shadow-xl\">\n <div className=\"flex items-start justify-between gap-4 border-b border-slate-200 p-5\">\n <div>\n <h2 className=\"text-lg font-semibold text-slate-950\">{title}</h2>\n {description && (\n <p className=\"mt-1 text-sm text-slate-500\">{description}</p>\n )}\n </div>\n <Button\n aria-label=\"Close\"\n onClick={() => onOpenChange(false)}\n size=\"sm\"\n tone=\"ghost\"\n type=\"button\"\n >\n ✕\n </Button>\n </div>\n <div className=\"max-h-[68vh] overflow-y-auto p-5\">{children}</div>\n {footer && (\n <div className=\"border-t border-slate-200 p-5\">{footer}</div>\n )}\n </div>\n </div>\n );\n}\n\n// ── Factory ───────────────────────────────────────────────────────────────────\n\n/**\n * Creates auth UI components bound to the provided `useAuth` hook instance.\n * This lets consumers supply their own auth-nextjs instance without requiring\n * a separate installed copy inside auth-elements-nextjs.\n *\n * @example\n * import { createAuthElements } from '@geekapps/auth-elements-nextjs'\n * import { useAuth } from '@geekapps/auth-nextjs/client'\n * export const { SignInButton, ProfileModal } = createAuthElements({ useAuth })\n */\nexport function createAuthElements(hooks: { useAuth: UseAuthHook }) {\n const { useAuth } = hooks;\n\n function SignInButton({\n children = \"Entrar\",\n redirectTo,\n }: {\n children?: ReactNode;\n redirectTo?: string;\n }) {\n const { signIn } = useAuth();\n return (\n <Button\n onClick={() => void signIn({ redirectTo })}\n tone=\"primary\"\n type=\"button\"\n >\n {children}\n </Button>\n );\n }\n\n function SignOutButton({ children = \"Sair\" }: { children?: ReactNode }) {\n const { signOut } = useAuth();\n return (\n <Button onClick={() => void signOut()} tone=\"ghost\" type=\"button\">\n {children}\n </Button>\n );\n }\n\n function AccountSwitcher() {\n const {\n accounts,\n addAccount,\n isLoadingAccounts,\n refreshAccounts,\n switchAccount,\n } = useAuth();\n const activeAccount =\n accounts.find((account) => account.isActive) ?? accounts[0] ?? null;\n const [open, setOpen] = useState(false);\n\n return (\n <div className=\"relative\">\n <button\n className=\"flex h-10 w-10 items-center justify-center rounded-xl transition hover:opacity-80\"\n onClick={() => setOpen((value) => !value)}\n title={activeAccount?.user.name ?? activeAccount?.user.email ?? \"Conta\"}\n type=\"button\"\n >\n <Avatar\n name={activeAccount?.user.name ?? activeAccount?.user.email}\n size=\"sm\"\n src={activeAccount?.user.imageUrl}\n />\n </button>\n\n {open && (\n <>\n <div className=\"fixed inset-0 z-20\" onClick={() => setOpen(false)} />\n <div className=\"absolute bottom-0 left-14 z-30 w-72 overflow-hidden rounded-xl border border-slate-200 bg-white shadow-lg\">\n <div className=\"border-b border-slate-100 px-3 py-2.5\">\n <p className=\"text-[11px] font-medium uppercase tracking-wider text-slate-400\">\n Contas\n </p>\n </div>\n <div className=\"p-1.5\">\n {isLoadingAccounts && (\n <p className=\"px-2 py-3 text-xs text-slate-400\">\n Carregando...\n </p>\n )}\n {accounts.map((account) => (\n <button\n className={cx(\n \"flex w-full items-center gap-2.5 rounded-lg px-2 py-2 text-left transition hover:bg-slate-50\",\n account.isActive && \"bg-slate-50\",\n )}\n key={account.sessionId ?? account.id}\n onClick={() => {\n void switchAccount(account.sessionId ?? account.id);\n setOpen(false);\n }}\n type=\"button\"\n >\n <Avatar\n name={account.user.name ?? account.user.email}\n size=\"sm\"\n src={account.user.imageUrl}\n />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm font-medium text-slate-900\">\n {account.user.name ?? account.user.email}\n </span>\n <span className=\"block truncate text-xs text-slate-500\">\n {account.user.email}\n </span>\n </span>\n {account.isActive && (\n <span className=\"shrink-0 text-xs font-medium text-emerald-600\">\n ✓\n </span>\n )}\n </button>\n ))}\n </div>\n <div className=\"flex gap-1.5 border-t border-slate-100 p-1.5\">\n <Button\n className=\"flex-1\"\n onClick={() => void addAccount()}\n size=\"sm\"\n type=\"button\"\n >\n + Conta\n </Button>\n <Button\n className=\"flex-1\"\n onClick={() => void refreshAccounts()}\n size=\"sm\"\n tone=\"ghost\"\n type=\"button\"\n >\n Atualizar\n </Button>\n </div>\n </div>\n </>\n )}\n </div>\n );\n }\n\n // Formulário de criação compartilhado: organização padrão (sem documento)\n // ou legal (associada a CNPJ / Tax ID, com os dados da empresa buscados\n // automaticamente e os obrigatórios que faltarem pedidos ao usuário).\n function CreateOrganizationForm({\n onCreated,\n onCancel,\n compact = false,\n }: {\n onCreated?: (organization: Organization) => void;\n onCancel?: () => void;\n compact?: boolean;\n }) {\n const { createOrganization, lookupTaxId, setCurrentOrg } = useAuth();\n const [values, setValues] = useState<Record<string, string>>({ ...EMPTY_ORG_FORM });\n const [missing, setMissing] = useState<string[]>([]);\n const [lookupInfo, setLookupInfo] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [busy, setBusy] = useState<\"lookup\" | \"create\" | null>(null);\n const isLegal = values.type === \"legal\";\n const isCnpj = values.taxIdType === \"br_cnpj\";\n\n const set = (key: string, value: string) =>\n setValues((current) => {\n const next = { ...current, [key]: value };\n if (key === \"name\" && !current.slugTouched) next.slug = slugify(value);\n if (key === \"slug\") next.slugTouched = \"1\";\n return next;\n });\n\n async function runLookup() {\n if (!lookupTaxId || !values.taxId) return;\n setBusy(\"lookup\");\n setError(null);\n setLookupInfo(null);\n const result = await lookupTaxId(values.taxId, values.taxIdType as TaxIdType);\n setBusy(null);\n if (!result.success) {\n setError(authErrorMessage(result, \"Tax ID inválido.\"));\n return;\n }\n const { data } = result.data;\n setValues((current) => {\n const next: Record<string, string> = { ...current, taxId: result.data.taxId };\n const fill = (key: string, value: string | null | undefined) => {\n if (value && !current[key]) next[key] = value;\n };\n fill(\"legalName\", data.legalName);\n fill(\"tradeName\", data.tradeName);\n fill(\"legalEmail\", data.legalEmail);\n fill(\"legalPhone\", data.legalPhone);\n for (const key of ADDRESS_KEYS) fill(`legalAddress.${key}`, data.legalAddress?.[key]);\n if (result.data.taxIdCountry) next.taxIdCountry = result.data.taxIdCountry;\n if (!current.name && result.data.suggestedName) {\n next.name = result.data.suggestedName;\n if (!current.slugTouched) next.slug = slugify(result.data.suggestedName);\n }\n return next;\n });\n setMissing(result.data.missingFields);\n if (result.data.alreadyRegistered) {\n setError(\"Já existe uma organização com este documento neste app.\");\n } else if (result.data.found) {\n setLookupInfo(\n `Dados encontrados${result.data.registrationStatus ? ` · situação ${result.data.registrationStatus}` : \"\"}. Revise e complete o que faltar.`,\n );\n } else {\n setLookupInfo(\n result.data.lookupAvailable\n ? \"Documento válido, mas sem dados públicos. Preencha os campos obrigatórios.\"\n : \"Consulta indisponível no momento. Preencha os campos obrigatórios.\",\n );\n }\n }\n\n async function onSubmit(event: FormEvent<HTMLFormElement>) {\n event.preventDefault();\n setBusy(\"create\");\n setError(null);\n const blank = (key: string) => values[key]?.trim() || null;\n const input: OrganizationCreateInput = {\n name: values.name.trim(),\n slug: values.slug.trim(),\n type: isLegal ? \"legal\" : \"standard\",\n };\n if (isLegal) {\n Object.assign(input, {\n taxId: blank(\"taxId\"),\n taxIdType: values.taxIdType,\n taxIdCountry: isCnpj ? \"BR\" : blank(\"taxIdCountry\"),\n legalName: blank(\"legalName\"),\n tradeName: blank(\"tradeName\"),\n legalEmail: blank(\"legalEmail\"),\n legalPhone: blank(\"legalPhone\"),\n legalAddress: Object.fromEntries(\n ADDRESS_KEYS.map((key) => [key, blank(`legalAddress.${key}`)]),\n ),\n });\n if (!isCnpj && !input.legalAddress?.country) {\n (input.legalAddress as Record<string, string | null>).country = blank(\"taxIdCountry\");\n }\n }\n const result = await createOrganization(input);\n setBusy(null);\n if (!result.success) {\n if (result.missingFields?.length) setMissing(result.missingFields);\n setError(authErrorMessage(result, \"Erro ao criar organização.\"));\n return;\n }\n setValues({ ...EMPTY_ORG_FORM });\n setMissing([]);\n setLookupInfo(null);\n if (result.data?.id) void setCurrentOrg(result.data.id);\n onCreated?.(result.data);\n }\n\n const field = (key: string, label: string, props: React.InputHTMLAttributes<HTMLInputElement> = {}) => {\n const required = REQUIRED_LEGAL.has(key);\n return (\n <Field label={`${label}${required ? \" *\" : \"\"}`}>\n <Input\n {...props}\n className={missing.includes(key) && !values[key] ? \"border-red-300\" : undefined}\n name={key}\n onChange={(event) => set(key, event.target.value)}\n required={required}\n value={values[key] ?? \"\"}\n />\n </Field>\n );\n };\n\n return (\n <form className={cx(\"grid\", compact ? \"gap-2\" : \"gap-4\")} onSubmit={onSubmit}>\n <div className=\"grid grid-cols-2 gap-1 rounded-lg bg-slate-100 p-1\">\n {(\n [\n [\"standard\", \"Padrão\"],\n [\"legal\", \"Empresa (CNPJ / Tax ID)\"],\n ] as const\n ).map(([type, label]) => (\n <button\n className={cx(\n \"rounded-md px-2 py-1.5 text-xs font-medium transition\",\n values.type === type ? \"bg-white text-slate-900 shadow-sm\" : \"text-slate-500\",\n )}\n key={type}\n onClick={() => set(\"type\", type)}\n type=\"button\"\n >\n {label}\n </button>\n ))}\n </div>\n\n {isLegal && (\n <>\n <div className=\"grid grid-cols-[auto_1fr] gap-2\">\n <select\n className=\"h-10 rounded-lg border border-slate-200 bg-white px-2 text-sm text-slate-900\"\n onChange={(event) => set(\"taxIdType\", event.target.value)}\n value={values.taxIdType}\n >\n <option value=\"br_cnpj\">CNPJ</option>\n <option value=\"generic\">Outro Tax ID</option>\n </select>\n <div className=\"flex gap-2\">\n <Input\n name=\"taxId\"\n onBlur={() => isCnpj && void runLookup()}\n onChange={(event) => set(\"taxId\", event.target.value)}\n placeholder={isCnpj ? \"00.000.000/0000-00\" : \"Tax ID\"}\n required\n value={values.taxId}\n />\n <Button disabled={busy !== null || !values.taxId} onClick={() => void runLookup()} size=\"sm\" type=\"button\">\n {busy === \"lookup\" ? \"Buscando…\" : isCnpj ? \"Buscar\" : \"Validar\"}\n </Button>\n </div>\n </div>\n {!isCnpj && field(\"taxIdCountry\", \"País do Tax ID (ISO, ex.: US)\", { maxLength: 2 })}\n {lookupInfo && (\n <p className=\"rounded-lg bg-slate-50 px-3 py-2 text-xs text-slate-600\">{lookupInfo}</p>\n )}\n </>\n )}\n\n {field(\"name\", \"Nome\", { placeholder: \"Minha organização\", required: true })}\n {field(\"slug\", \"Slug\", { placeholder: \"minha-org\", required: true })}\n\n {isLegal && (\n <>\n {field(\"legalName\", \"Razão social\")}\n {field(\"tradeName\", \"Nome fantasia\")}\n <div className=\"grid gap-2 sm:grid-cols-2\">\n {field(\"legalEmail\", \"E-mail\", { type: \"email\" })}\n {field(\"legalPhone\", \"Telefone\")}\n </div>\n {field(\"legalAddress.street\", \"Logradouro\")}\n <div className=\"grid gap-2 sm:grid-cols-2\">\n {field(\"legalAddress.number\", \"Número\")}\n {field(\"legalAddress.complement\", \"Complemento\")}\n {field(\"legalAddress.district\", \"Bairro\")}\n {field(\"legalAddress.city\", \"Cidade\")}\n {field(\"legalAddress.state\", \"Estado\")}\n {field(\"legalAddress.postalCode\", \"CEP / Código postal\")}\n </div>\n {!isCnpj && field(\"legalAddress.country\", \"País do endereço (ISO)\", { maxLength: 2 })}\n </>\n )}\n\n {error && <p className=\"rounded-lg bg-red-50 px-3 py-2 text-xs text-red-600\">{error}</p>}\n\n <div className=\"flex justify-end gap-2\">\n {onCancel && (\n <Button onClick={onCancel} size=\"sm\" tone=\"ghost\" type=\"button\">\n Cancelar\n </Button>\n )}\n <Button disabled={busy !== null} size=\"sm\" tone=\"primary\" type=\"submit\">\n {busy === \"create\" ? \"Criando…\" : \"Criar organização\"}\n </Button>\n </div>\n </form>\n );\n }\n\n function OrgSwitcher() {\n const {\n currentOrg,\n isLoadingOrganizations,\n organizations,\n refreshOrganizations,\n setCurrentOrg,\n } = useAuth();\n const [open, setOpen] = useState(false);\n const [creating, setCreating] = useState(false);\n\n return (\n <div className=\"relative\">\n <button\n className=\"flex w-full items-center gap-3 rounded-xl border border-slate-200 bg-white p-2 text-left hover:bg-slate-50\"\n onClick={() => setOpen((value) => !value)}\n type=\"button\"\n >\n <Avatar name={currentOrg?.name} src={currentOrg?.imageUrl} />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm font-medium text-slate-950\">\n {currentOrg?.name ?? \"Selecionar organização\"}\n </span>\n <span className=\"block truncate text-xs text-slate-500\">\n {isLoadingOrganizations\n ? \"Carregando...\"\n : `${organizations.length} organizações`}\n </span>\n </span>\n <span className=\"text-slate-400\">⌄</span>\n </button>\n\n {open && (\n <div className=\"absolute right-0 z-30 mt-2 w-80 overflow-hidden rounded-xl border border-slate-200 bg-white shadow-lg\">\n <div className=\"max-h-72 overflow-y-auto p-2\">\n {organizations.map((organization) => (\n <button\n className=\"flex w-full items-center gap-3 rounded-lg p-2 text-left hover:bg-slate-50\"\n key={organization.id}\n onClick={() => {\n void setCurrentOrg(organization.id);\n setOpen(false);\n }}\n type=\"button\"\n >\n <Avatar\n name={organization.name}\n size=\"sm\"\n src={organization.imageUrl}\n />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm font-medium text-slate-900\">\n {organization.name}\n </span>\n <span className=\"block truncate text-xs text-slate-500\">\n {organization.slug}\n </span>\n </span>\n {organization.id === currentOrg?.id && (\n <span className=\"text-xs font-medium text-emerald-600\">\n Atual\n </span>\n )}\n </button>\n ))}\n </div>\n\n {creating ? (\n <div className=\"max-h-[70vh] overflow-y-auto border-t border-slate-200 p-3\">\n <CreateOrganizationForm\n compact\n onCancel={() => setCreating(false)}\n onCreated={() => {\n setCreating(false);\n setOpen(false);\n void refreshOrganizations();\n }}\n />\n </div>\n ) : (\n <div className=\"flex gap-2 border-t border-slate-200 p-2\">\n <Button\n className=\"flex-1\"\n onClick={() => setCreating(true)}\n size=\"sm\"\n type=\"button\"\n >\n Nova org\n </Button>\n <Button\n className=\"flex-1\"\n onClick={() => void refreshOrganizations()}\n size=\"sm\"\n tone=\"ghost\"\n type=\"button\"\n >\n Atualizar\n </Button>\n </div>\n )}\n </div>\n )}\n </div>\n );\n }\n\n function UserButton() {\n const { user } = useAuth();\n const [open, setOpen] = useState(false);\n return (\n <>\n <button onClick={() => setOpen(true)} type=\"button\">\n <Avatar name={user?.name ?? user?.email} src={user?.imageUrl} />\n </button>\n <ProfileModal open={open} onOpenChange={setOpen} />\n </>\n );\n }\n\n function OrganizationButton() {\n const { currentOrg } = useAuth();\n const [open, setOpen] = useState(false);\n return (\n <>\n <button\n 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\"\n onClick={() => setOpen(true)}\n title={currentOrg?.name ?? \"Organização\"}\n type=\"button\"\n >\n {currentOrg?.imageUrl ? (\n <img\n alt={currentOrg.name}\n className=\"h-full w-full rounded-xl object-cover\"\n src={currentOrg.imageUrl}\n />\n ) : (\n (currentOrg?.name ?? \"O\")[0]?.toUpperCase()\n )}\n </button>\n <ManageOrganizationModal open={open} onOpenChange={setOpen} />\n </>\n );\n }\n\n function ProfileModal({\n open,\n onOpenChange,\n }: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n }) {\n const {\n signOut,\n signOutAll,\n user,\n organizations,\n currentOrg,\n setCurrentOrg,\n updateUser,\n listUserSessions,\n revokeUserSession,\n } = useAuth();\n const [tab, setTab] = useState(\"profile\");\n const [sessions, setSessions] = useState<UserSession[]>([]);\n const [saving, setSaving] = useState(false);\n const [saveError, setSaveError] = useState<string | null>(null);\n const [saveSuccess, setSaveSuccess] = useState(false);\n\n useEffect(() => {\n if (!open) {\n setTab(\"profile\");\n setSaveError(null);\n setSaveSuccess(false);\n }\n }, [open]);\n\n useEffect(() => {\n if (open && user && tab === \"sessions\") {\n void listUserSessions({ userId: user.id })\n .then(setSessions)\n .catch(() => setSessions([]));\n }\n }, [listUserSessions, open, tab, user]);\n\n async function onProfileSubmit(event: FormEvent<HTMLFormElement>) {\n event.preventDefault();\n if (!user) return;\n const form = new FormData(event.currentTarget);\n setSaving(true);\n setSaveError(null);\n setSaveSuccess(false);\n try {\n await updateUser(user.id, {\n name: String(form.get(\"name\") ?? \"\") || null,\n phone: String(form.get(\"phone\") ?? \"\") || null,\n imageUrl: String(form.get(\"imageUrl\") ?? \"\") || null,\n });\n setSaveSuccess(true);\n setTimeout(() => setSaveSuccess(false), 2500);\n } catch (err) {\n setSaveError(err instanceof Error ? err.message : \"Erro ao salvar.\");\n } finally {\n setSaving(false);\n }\n }\n\n if (!open) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4\">\n <div className=\"flex max-h-[90vh] w-full max-w-lg flex-col overflow-hidden rounded-2xl bg-white shadow-2xl\">\n {/* Header */}\n <div className=\"flex shrink-0 items-center justify-between border-b border-slate-100 px-6 py-4\">\n <div className=\"flex items-center gap-3\">\n <Avatar\n name={user?.name ?? user?.email}\n size=\"sm\"\n src={user?.imageUrl}\n />\n <div>\n <p className=\"text-sm font-semibold text-slate-900\">\n {user?.name ?? user?.email ?? \"Minha conta\"}\n </p>\n <p className=\"text-xs text-slate-500\">{user?.email}</p>\n </div>\n </div>\n <button\n aria-label=\"Fechar\"\n className=\"rounded-lg p-1.5 text-slate-400 transition hover:bg-slate-100 hover:text-slate-700\"\n onClick={() => onOpenChange(false)}\n type=\"button\"\n >\n ✕\n </button>\n </div>\n\n {/* Tabs */}\n <div className=\"shrink-0 flex gap-1 border-b border-slate-100 px-6 pt-3\">\n {(\n [\n { id: \"profile\", label: \"Perfil\" },\n { id: \"sessions\", label: \"Sessões\" },\n { id: \"orgs\", label: \"Organizações\" },\n ] as const\n ).map((t) => (\n <button\n className={cx(\n \"mb-[-1px] border-b-2 px-3 pb-2.5 text-xs font-medium transition\",\n tab === t.id\n ? \"border-slate-900 text-slate-900\"\n : \"border-transparent text-slate-500 hover:text-slate-700\",\n )}\n key={t.id}\n onClick={() => setTab(t.id)}\n type=\"button\"\n >\n {t.label}\n </button>\n ))}\n </div>\n\n {/* Body */}\n <div className=\"flex-1 overflow-y-auto px-6 py-5\">\n {tab === \"profile\" && user && (\n <form className=\"grid gap-4\" onSubmit={onProfileSubmit}>\n <div className=\"flex items-center gap-4 rounded-xl bg-slate-50 p-4\">\n <Avatar\n name={user.name ?? user.email}\n size=\"lg\"\n src={user.imageUrl}\n />\n <div>\n <p className=\"text-sm font-semibold text-slate-900\">\n {user.name ?? \"Sem nome\"}\n </p>\n <p className=\"text-xs text-slate-500\">{user.email}</p>\n </div>\n </div>\n\n <div className=\"grid gap-3 sm:grid-cols-2\">\n <Field label=\"Nome\">\n <Input\n defaultValue={user.name ?? \"\"}\n name=\"name\"\n placeholder=\"Seu nome\"\n />\n </Field>\n <Field label=\"Telefone\">\n <Input\n defaultValue={user.phone ?? \"\"}\n name=\"phone\"\n placeholder=\"+55 11 99999-9999\"\n />\n </Field>\n </div>\n <Field label=\"URL da imagem\">\n <Input\n defaultValue={user.imageUrl ?? \"\"}\n name=\"imageUrl\"\n placeholder=\"https://...\"\n />\n </Field>\n\n {saveError && (\n <p className=\"rounded-lg bg-red-50 px-3 py-2 text-xs text-red-600\">\n {saveError}\n </p>\n )}\n {saveSuccess && (\n <p className=\"rounded-lg bg-emerald-50 px-3 py-2 text-xs text-emerald-600\">\n Perfil salvo com sucesso.\n </p>\n )}\n\n <div className=\"flex items-center justify-between border-t border-slate-100 pt-2\">\n <div className=\"flex gap-2\">\n <Button\n onClick={() => void signOut()}\n size=\"sm\"\n tone=\"ghost\"\n type=\"button\"\n >\n Sair\n </Button>\n <Button\n onClick={() => void signOutAll()}\n size=\"sm\"\n tone=\"danger\"\n type=\"button\"\n >\n Sair de todas\n </Button>\n </div>\n <Button\n disabled={saving}\n size=\"sm\"\n tone=\"primary\"\n type=\"submit\"\n >\n {saving ? \"Salvando…\" : \"Salvar\"}\n </Button>\n </div>\n </form>\n )}\n\n {tab === \"sessions\" && (\n <div className=\"grid gap-2\">\n {sessions.length === 0 && (\n <p className=\"py-6 text-center text-sm text-slate-400\">\n Nenhuma sessão ativa.\n </p>\n )}\n {sessions.map((session) => {\n const expired = isExpired(session.expiresAt);\n return (\n <div\n className=\"flex items-center justify-between gap-4 rounded-xl border border-slate-200 p-4\"\n key={session.id}\n >\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-slate-900\">\n {session.deviceName ?? \"Dispositivo\"}\n </p>\n <p className=\"mt-0.5 truncate text-xs text-slate-500\">\n {session.ip ?? \"IP desconhecido\"} ·{\" \"}\n <span className={expired ? \"text-amber-600\" : \"\"}>\n {expired\n ? \"Expirada\"\n : `Expira ${formatDate(session.expiresAt)}`}\n </span>\n </p>\n </div>\n <Button\n onClick={async () => {\n await revokeUserSession(session.id);\n setSessions((s) =>\n s.filter((x) => x.id !== session.id),\n );\n }}\n size=\"sm\"\n tone=\"danger\"\n type=\"button\"\n >\n Revogar\n </Button>\n </div>\n );\n })}\n </div>\n )}\n\n {tab === \"orgs\" && (\n <div className=\"grid gap-2\">\n {organizations.length === 0 && (\n <p className=\"py-6 text-center text-sm text-slate-400\">\n Nenhuma organização.\n </p>\n )}\n {organizations.map((org) => (\n <button\n className={cx(\n \"flex w-full items-center gap-3 rounded-xl border p-3 text-left transition\",\n org.id === currentOrg?.id\n ? \"border-slate-900 bg-slate-50\"\n : \"border-slate-200 hover:border-slate-300 hover:bg-slate-50\",\n )}\n key={org.id}\n onClick={() => void setCurrentOrg(org.id)}\n type=\"button\"\n >\n <Avatar name={org.name} size=\"sm\" src={org.imageUrl} />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-slate-900\">\n {org.name}\n </p>\n <p className=\"truncate text-xs text-slate-500\">\n /{org.slug}\n </p>\n </div>\n {org.id === currentOrg?.id && (\n <span className=\"shrink-0 rounded-full bg-slate-900 px-2 py-0.5 text-[10px] font-medium text-white\">\n Ativa\n </span>\n )}\n </button>\n ))}\n </div>\n )}\n </div>\n </div>\n </div>\n );\n }\n\n function ManageOrganizationModal({\n open,\n onOpenChange,\n }: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n }) {\n const {\n createOrganization,\n currentOrg,\n organizations,\n refreshOrganizations,\n setCurrentOrg,\n updateOrganization,\n listPermissions,\n listRoles,\n } = useAuth();\n const [tab, setTab] = useState(\"orgs\");\n const [roles, setRoles] = useState<{\n systemRoles: Role[];\n customRoles: Role[];\n }>({ systemRoles: [], customRoles: [] });\n const [permissions, setPermissions] = useState<Permission[]>([]);\n const [saving, setSaving] = useState(false);\n const [saveSuccess, setSaveSuccess] = useState(false);\n const [saveError, setSaveError] = useState<string | null>(null);\n\n useEffect(() => {\n if (!open) {\n setTab(\"orgs\");\n setSaveError(null);\n setSaveSuccess(false);\n }\n }, [open]);\n\n useEffect(() => {\n if (!open || !currentOrg) return;\n if (tab === \"members\" || tab === \"roles\") {\n void listRoles({ organizationId: currentOrg.id })\n .then(setRoles)\n .catch(() => setRoles({ systemRoles: [], customRoles: [] }));\n void listPermissions({})\n .then(setPermissions)\n .catch(() => setPermissions([]));\n }\n }, [currentOrg, listPermissions, listRoles, open, tab]);\n\n async function onOrgSubmit(event: FormEvent<HTMLFormElement>) {\n event.preventDefault();\n if (!currentOrg) return;\n const form = new FormData(event.currentTarget);\n setSaving(true);\n setSaveError(null);\n setSaveSuccess(false);\n try {\n await updateOrganization(currentOrg.id, {\n name: String(form.get(\"name\") ?? \"\"),\n description: String(form.get(\"description\") ?? \"\") || null,\n slug: String(form.get(\"slug\") ?? \"\"),\n domain: String(form.get(\"domain\") ?? \"\") || null,\n imageUrl: String(form.get(\"imageUrl\") ?? \"\") || null,\n faviconUrl: String(form.get(\"faviconUrl\") ?? \"\") || null,\n });\n setSaveSuccess(true);\n setTimeout(() => setSaveSuccess(false), 2500);\n } catch (err) {\n setSaveError(err instanceof Error ? err.message : \"Erro ao salvar.\");\n } finally {\n setSaving(false);\n }\n }\n\n if (!open) return null;\n\n const orgTabs = [\n { id: \"orgs\", label: \"Organizações\" },\n { id: \"info\", label: \"Geral\" },\n { id: \"members\", label: \"Membros\" },\n { id: \"roles\", label: \"Roles\" },\n { id: \"new\", label: \"+ Nova org\" },\n ] as const;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4\">\n <div className=\"flex max-h-[90vh] w-full max-w-2xl flex-col overflow-hidden rounded-2xl bg-white shadow-2xl\">\n {/* Header */}\n <div className=\"flex shrink-0 items-center justify-between border-b border-slate-100 px-6 py-4\">\n <div className=\"flex items-center gap-3\">\n {currentOrg?.imageUrl ? (\n <img\n alt={currentOrg.name}\n className=\"h-8 w-8 rounded-lg object-cover\"\n src={currentOrg.imageUrl}\n />\n ) : (\n <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\">\n {(currentOrg?.name ?? \"O\")[0]?.toUpperCase()}\n </span>\n )}\n <div>\n <p className=\"text-sm font-semibold text-slate-900\">\n {currentOrg?.name ?? \"Organização\"}\n </p>\n {currentOrg?.slug && (\n <p className=\"text-xs text-slate-500\">/{currentOrg.slug}</p>\n )}\n </div>\n </div>\n <button\n aria-label=\"Fechar\"\n className=\"rounded-lg p-1.5 text-slate-400 transition hover:bg-slate-100 hover:text-slate-700\"\n onClick={() => onOpenChange(false)}\n type=\"button\"\n >\n ✕\n </button>\n </div>\n\n {/* Tabs */}\n <div className=\"flex shrink-0 gap-1 border-b border-slate-100 px-6 pt-3\">\n {orgTabs.map((t) => (\n <button\n className={cx(\n \"mb-[-1px] border-b-2 px-3 pb-2.5 text-xs font-medium transition\",\n tab === t.id\n ? \"border-slate-900 text-slate-900\"\n : \"border-transparent text-slate-500 hover:text-slate-700\",\n )}\n key={t.id}\n onClick={() => setTab(t.id)}\n type=\"button\"\n >\n {t.label}\n </button>\n ))}\n </div>\n\n {/* Body */}\n <div className=\"flex-1 overflow-y-auto px-6 py-5\">\n {!currentOrg && (\n <p className=\"py-8 text-center text-sm text-slate-400\">\n Nenhuma organização selecionada.\n </p>\n )}\n\n {tab === \"orgs\" && (\n <div className=\"grid gap-2\">\n {organizations.length === 0 && (\n <p className=\"py-8 text-center text-sm text-slate-400\">\n Nenhuma organização disponível.\n </p>\n )}\n {organizations.map((org) => (\n <button\n className={cx(\n \"flex w-full items-center gap-3 rounded-xl border p-3 text-left transition\",\n org.id === currentOrg?.id\n ? \"border-slate-900 bg-slate-50\"\n : \"border-slate-200 hover:border-slate-300 hover:bg-slate-50\",\n )}\n key={org.id}\n onClick={() => {\n void setCurrentOrg(org.id);\n onOpenChange(false);\n }}\n type=\"button\"\n >\n <Avatar name={org.name} size=\"sm\" src={org.imageUrl} />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-slate-900\">\n {org.name}\n </p>\n <p className=\"truncate text-xs text-slate-500\">\n /{org.slug}\n </p>\n </div>\n {org.id === currentOrg?.id && (\n <span className=\"shrink-0 rounded-full bg-slate-900 px-2 py-0.5 text-[10px] font-medium text-white\">\n Ativa\n </span>\n )}\n </button>\n ))}\n </div>\n )}\n\n {tab === \"info\" && currentOrg && (\n <form className=\"grid gap-4\" onSubmit={onOrgSubmit}>\n <div className=\"grid gap-3 sm:grid-cols-2\">\n <Field label=\"Nome *\">\n <Input defaultValue={currentOrg.name} name=\"name\" required />\n </Field>\n <Field label=\"Slug *\">\n <Input defaultValue={currentOrg.slug} name=\"slug\" required />\n </Field>\n </div>\n <Field label=\"Descrição\">\n <Textarea\n defaultValue={currentOrg.description ?? \"\"}\n name=\"description\"\n placeholder=\"Descreva a organização…\"\n />\n </Field>\n <div className=\"grid gap-3 sm:grid-cols-2\">\n <Field label=\"Domínio\">\n <Input\n defaultValue={currentOrg.domain ?? \"\"}\n name=\"domain\"\n placeholder=\"acme.com\"\n />\n </Field>\n <Field label=\"URL da imagem\">\n <Input\n defaultValue={currentOrg.imageUrl ?? \"\"}\n name=\"imageUrl\"\n placeholder=\"https://...\"\n />\n </Field>\n </div>\n <Field label=\"URL do favicon\">\n <Input\n defaultValue={currentOrg.faviconUrl ?? \"\"}\n name=\"faviconUrl\"\n placeholder=\"https://...\"\n />\n </Field>\n\n {saveError && (\n <p className=\"rounded-lg bg-red-50 px-3 py-2 text-xs text-red-600\">\n {saveError}\n </p>\n )}\n {saveSuccess && (\n <p className=\"rounded-lg bg-emerald-50 px-3 py-2 text-xs text-emerald-600\">\n Organização atualizada.\n </p>\n )}\n\n <div className=\"flex justify-end pt-1\">\n <Button\n disabled={saving}\n size=\"sm\"\n tone=\"primary\"\n type=\"submit\"\n >\n {saving ? \"Salvando…\" : \"Salvar organização\"}\n </Button>\n </div>\n </form>\n )}\n\n {tab === \"members\" && currentOrg && (\n <div className=\"grid gap-2\">\n {(currentOrg.members ?? []).length === 0 && (\n <p className=\"py-8 text-center text-sm text-slate-400\">\n Nenhum membro nesta organização.\n </p>\n )}\n {(currentOrg.members ?? []).map((member) => (\n <div\n className=\"flex items-center gap-3 rounded-xl border border-slate-200 p-4\"\n key={member.id}\n >\n <Avatar\n name={member.user.name ?? member.user.email}\n size=\"sm\"\n src={member.user.imageUrl}\n />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-slate-900\">\n {member.user.name ?? member.user.email}\n </p>\n <p className=\"truncate text-xs text-slate-500\">\n {member.user.email}\n </p>\n </div>\n <div className=\"flex shrink-0 flex-wrap justify-end gap-1\">\n {(member.roleAssignments ?? []).map((a) => (\n <span\n className=\"rounded-full bg-slate-900 px-2 py-0.5 text-[11px] font-medium text-white\"\n key={a.id}\n >\n {a.roleDefinition?.name ?? a.customRole?.name ?? a.id}\n </span>\n ))}\n </div>\n </div>\n ))}\n </div>\n )}\n\n {tab === \"new\" && (\n <div className=\"grid gap-4\">\n <p className=\"text-sm text-slate-500\">\n Crie uma nova organização e alterne para ela automaticamente.\n </p>\n <CreateOrganizationForm\n onCancel={() => setTab(\"info\")}\n onCreated={() => {\n void refreshOrganizations();\n setTab(\"info\");\n }}\n />\n </div>\n )}\n\n {tab === \"roles\" && (\n <div className=\"grid gap-5 sm:grid-cols-2\">\n <div className=\"min-w-0\">\n <h3 className=\"mb-3 text-xs font-semibold uppercase tracking-wider text-slate-400\">\n Roles ({roles.systemRoles.length + roles.customRoles.length})\n </h3>\n <div className=\"max-h-[280px] space-y-2 overflow-y-auto pr-1\">\n {roles.systemRoles.length === 0 &&\n roles.customRoles.length === 0 && (\n <p className=\"text-sm text-slate-400\">Nenhuma role.</p>\n )}\n {[...roles.systemRoles, ...roles.customRoles].map((role) => (\n <div\n className=\"overflow-hidden rounded-xl border border-slate-200 p-3\"\n key={role.id}\n >\n <p className=\"truncate text-sm font-semibold text-slate-900\">\n {role.name}\n </p>\n <p className=\"truncate text-xs text-slate-400\">\n {role.key}\n </p>\n <p className=\"mt-1 text-xs text-slate-500\">\n {role.permissions.length} permission\n {role.permissions.length !== 1 ? \"s\" : \"\"}\n </p>\n </div>\n ))}\n </div>\n </div>\n <div className=\"min-w-0\">\n <h3 className=\"mb-3 text-xs font-semibold uppercase tracking-wider text-slate-400\">\n Permissions ({permissions.length})\n </h3>\n <div className=\"max-h-[280px] space-y-2 overflow-y-auto pr-1\">\n {permissions.length === 0 && (\n <p className=\"text-sm text-slate-400\">\n Nenhuma permission.\n </p>\n )}\n {permissions.map((permission) => (\n <div\n className=\"overflow-hidden rounded-xl border border-slate-200 p-3\"\n key={permission.id}\n >\n <p className=\"truncate text-sm font-semibold text-slate-900\">\n {permission.key}\n </p>\n <p className=\"truncate text-xs text-slate-400\">\n {permission.category ?? \"custom\"}\n </p>\n </div>\n ))}\n </div>\n </div>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n }\n\n function WaitlistForm({\n clientId,\n defaultEmail = \"\",\n onJoined,\n submitLabel = \"Entrar na lista de espera\",\n }: {\n clientId: string;\n defaultEmail?: string;\n onJoined?: (response: JoinWaitlistResponse) => void;\n submitLabel?: string;\n }) {\n const { joinWaitlist } = useAuth();\n const [name, setName] = useState(\"\");\n const [email, setEmail] = useState(defaultEmail);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [done, setDone] = useState<JoinWaitlistResponse | null>(null);\n\n async function submit(event: FormEvent) {\n event.preventDefault();\n if (!joinWaitlist) {\n setError(\"Lista de espera indisponível: atualize @geekapps/auth-nextjs para 0.26 ou superior.\");\n return;\n }\n setBusy(true);\n setError(null);\n const result = await joinWaitlist({\n clientId,\n email: email.trim(),\n name: name.trim() || undefined,\n });\n setBusy(false);\n if (!result.success) {\n setError(authErrorMessage(result, \"Não foi possível entrar na lista de espera.\"));\n return;\n }\n setDone(result.data);\n onJoined?.(result.data);\n }\n\n if (done) {\n return (\n <div className=\"grid gap-1 rounded-xl border border-emerald-200 bg-emerald-50 p-4 text-center\">\n <p className=\"text-sm font-semibold text-emerald-800\">\n {done.status === \"approved\"\n ? \"Seu acesso foi liberado!\"\n : done.status === \"joined\"\n ? \"Você já tem acesso.\"\n : \"Você está na lista de espera.\"}\n </p>\n {done.status === \"waiting\" && done.position != null && (\n <p className=\"text-sm text-emerald-700\">\n Sua posição na fila: <span className=\"font-semibold\">#{done.position}</span>\n </p>\n )}\n </div>\n );\n }\n\n return (\n <form className=\"grid gap-3\" onSubmit={(event) => void submit(event)}>\n <Field label=\"Nome\">\n <Input\n autoComplete=\"name\"\n onChange={(event) => setName(event.target.value)}\n placeholder=\"Seu nome\"\n value={name}\n />\n </Field>\n <Field label=\"E-mail\">\n <Input\n autoComplete=\"email\"\n onChange={(event) => setEmail(event.target.value)}\n placeholder=\"voce@exemplo.com\"\n required\n type=\"email\"\n value={email}\n />\n </Field>\n {error && <p className=\"text-xs text-red-600\">{error}</p>}\n <Button disabled={busy || !email.trim()} tone=\"primary\" type=\"submit\">\n {busy ? \"Enviando...\" : submitLabel}\n </Button>\n </form>\n );\n }\n\n return {\n WaitlistForm,\n SignInButton,\n SignOutButton,\n AccountSwitcher,\n OrgSwitcher,\n UserButton,\n OrganizationButton,\n ProfileModal,\n ManageOrganizationModal,\n CreateOrganizationForm,\n };\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geekapps/auth-elements-nextjs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": [
|
|
6
6
|
"./src/styles.css"
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"README.md"
|
|
18
18
|
],
|
|
19
19
|
"scripts": {
|
|
20
|
-
"build": "tsup && tailwindcss -i ./src/styles.css -o ./dist/styles.css --minify"
|
|
20
|
+
"build": "tsup && tailwindcss -i ./src/styles.css -o ./dist/styles.css --minify",
|
|
21
|
+
"check:contract": "tsc --noEmit -p tsconfig.contract.json"
|
|
21
22
|
},
|
|
22
23
|
"dependencies": {
|
|
23
24
|
"tailwindcss": "^4.2.2"
|
|
@@ -26,7 +27,8 @@
|
|
|
26
27
|
"next": ">=15",
|
|
27
28
|
"react": ">=18",
|
|
28
29
|
"react-dom": ">=18",
|
|
29
|
-
"typescript": ">=5"
|
|
30
|
+
"typescript": ">=5",
|
|
31
|
+
"@geekapps/auth-nextjs": ">=0.20.0"
|
|
30
32
|
},
|
|
31
33
|
"devDependencies": {
|
|
32
34
|
"@types/node": "^25.0.0",
|
|
@@ -34,5 +36,10 @@
|
|
|
34
36
|
"tsup": "^8.5.1",
|
|
35
37
|
"typescript": "^5.0.0",
|
|
36
38
|
"@tailwindcss/cli": "^4.2.2"
|
|
39
|
+
},
|
|
40
|
+
"peerDependenciesMeta": {
|
|
41
|
+
"@geekapps/auth-nextjs": {
|
|
42
|
+
"optional": true
|
|
43
|
+
}
|
|
37
44
|
}
|
|
38
|
-
}
|
|
45
|
+
}
|