@oondemand/oon-core-front 0.7.6 → 0.7.9

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.
@@ -8,7 +8,7 @@ import {
8
8
  CoreUsersAccess,
9
9
  MissingRenderer,
10
10
  resolveComponent
11
- } from "./chunk-A6FWKKZA.js";
11
+ } from "./chunk-JXU6W3ZU.js";
12
12
  import {
13
13
  OON_RESERVED_ROUTES,
14
14
  defineOonNavigation,
@@ -29,7 +29,7 @@ import {
29
29
  useCoreMetadata,
30
30
  useOonApi,
31
31
  useOonAuth
32
- } from "./chunk-TTQQMP5K.js";
32
+ } from "./chunk-3JBDEAKP.js";
33
33
  import {
34
34
  OonThemeProvider
35
35
  } from "./chunk-VC6NTMZS.js";
@@ -105,55 +105,89 @@ import { useEffect as useEffect2, useState as useState2 } from "react";
105
105
  import { Box as Box2, Text as Text2 } from "@chakra-ui/react";
106
106
 
107
107
  // src/security/AcceptInvitePage.tsx
108
- import { useEffect, useState } from "react";
108
+ import { useEffect, useState, useRef } from "react";
109
109
  import { Box, Button, Flex, Heading, Input, Text, VStack } from "@chakra-ui/react";
110
- import { Link, useLocation } from "react-router-dom";
110
+ import { useLocation } from "react-router-dom";
111
111
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
112
112
  function AcceptInvitePage() {
113
113
  const { http } = useOonApi();
114
114
  const location = useLocation();
115
- const token = new URLSearchParams(location.search).get("token") || "";
115
+ const auth = useOonAuth();
116
+ const token = new URLSearchParams(location.hash.slice(1)).get("token") || new URLSearchParams(location.search).get("token") || "";
116
117
  const [invitation, setInvitation] = useState(null);
118
+ const [sessionEmail, setSessionEmail] = useState("");
119
+ const operationKey = useRef(crypto.randomUUID());
120
+ const [registration, setRegistration] = useState({ nome: "", userDocument: "", phone: "", termsAccepted: false });
117
121
  const [password, setPassword] = useState("");
118
122
  const [confirm, setConfirm] = useState("");
119
123
  const [message, setMessage] = useState(null);
124
+ const [inspectionAttempt, setInspectionAttempt] = useState(0);
125
+ const [submitting, setSubmitting] = useState(false);
120
126
  const [done, setDone] = useState(false);
121
127
  const [loading, setLoading] = useState(true);
122
128
  useEffect(() => {
123
129
  let active = true;
130
+ operationKey.current = crypto.randomUUID();
131
+ setLoading(true);
132
+ setInvitation(null);
133
+ setDone(false);
134
+ setMessage(null);
135
+ setPassword("");
136
+ setConfirm("");
124
137
  if (!token) {
125
138
  setMessage("Link de convite inv\xE1lido.");
126
139
  setLoading(false);
127
140
  return;
128
141
  }
129
- http.get(`/core/invitations/${encodeURIComponent(token)}`).then((response) => {
130
- if (active) setInvitation(response.data.invitation);
131
- }).catch(() => {
132
- if (active) setMessage("Este convite \xE9 inv\xE1lido, expirou ou j\xE1 foi utilizado.");
142
+ http.post("/core/invitations/inspect", { token }, { headers: { "x-oon-tenant-id": false } }).then((response) => {
143
+ if (active) {
144
+ setInvitation(response.data.invitation);
145
+ setSessionEmail(String(response.data.invitation.sessionUser?.email || "").trim().toLowerCase());
146
+ }
147
+ }).catch((error) => {
148
+ if (active) setMessage(error?.status === 410 ? "Este convite \xE9 inv\xE1lido, expirou, foi revogado ou j\xE1 foi utilizado. Convites anteriores ao corte tamb\xE9m podem ter sido invalidados. Solicite um novo convite ao administrador." : "N\xE3o foi poss\xEDvel validar o convite. Tente novamente.");
133
149
  }).finally(() => {
134
150
  if (active) setLoading(false);
135
151
  });
136
152
  return () => {
137
153
  active = false;
138
154
  };
139
- }, [http, token]);
155
+ }, [http, token, inspectionAttempt]);
156
+ function clearSession() {
157
+ auth.clearSession();
158
+ setSessionEmail("");
159
+ }
160
+ const sameSession = Boolean(sessionEmail && sessionEmail === invitation?.email.toLowerCase());
161
+ const otherSession = Boolean(sessionEmail && !sameSession);
162
+ const register = invitation?.accountExists === false;
140
163
  async function submit(event) {
141
164
  event.preventDefault();
165
+ if (submitting || otherSession || auth.status === "loading") return;
142
166
  setMessage(null);
143
- if (password.length < 8) {
167
+ if (!sameSession && register && password.length < 8) {
144
168
  setMessage("A senha deve possuir pelo menos 8 caracteres.");
145
169
  return;
146
170
  }
147
- if (password !== confirm) {
171
+ if (!sameSession && register && password !== confirm) {
148
172
  setMessage("As senhas informadas n\xE3o conferem.");
149
173
  return;
150
174
  }
175
+ setSubmitting(true);
151
176
  try {
152
- await http.post(`/core/invitations/${encodeURIComponent(token)}/accept`, { password });
177
+ await http.post("/core/invitations/accept", {
178
+ token,
179
+ ...invitation?.version !== void 0 ? { version: invitation.version } : {},
180
+ ...register && invitation?.registrationRequired ? { registration: { ...registration, termsVersion: "2026-08-18", privacyVersion: "2026-08-18" } } : {},
181
+ intent: sameSession ? "session" : register ? "register" : "authenticate",
182
+ ...sameSession ? {} : { password }
183
+ }, { headers: { "idempotency-key": operationKey.current, ...sameSession ? {} : { Authorization: false }, "x-oon-tenant-id": false } });
153
184
  setDone(true);
154
- setMessage("Convite aceito e senha definida. Voc\xEA j\xE1 pode entrar na Central.");
185
+ setMessage("Convite aceito. Seu acesso est\xE1 dispon\xEDvel.");
155
186
  } catch (error) {
187
+ if (sameSession && error?.status === 401) clearSession();
156
188
  setMessage(error?.message || "N\xE3o foi poss\xEDvel concluir o convite.");
189
+ } finally {
190
+ setSubmitting(false);
157
191
  }
158
192
  }
159
193
  return /* @__PURE__ */ jsx(Flex, { minH: "100vh", align: "center", justify: "center", bg: "#F5F8FA", px: 4, children: /* @__PURE__ */ jsx(Box, { width: "100%", maxW: "480px", bg: "white", borderWidth: "1px", borderRadius: "18px", p: { base: 6, md: 9 }, children: /* @__PURE__ */ jsxs(VStack, { align: "stretch", gap: 5, children: [
@@ -171,20 +205,50 @@ function AcceptInvitePage() {
171
205
  invitation.roleName || invitation.roleCode
172
206
  ] })
173
207
  ] }),
174
- /* @__PURE__ */ jsx("form", { onSubmit: (event) => void submit(event), children: /* @__PURE__ */ jsxs(VStack, { align: "stretch", gap: 4, children: [
175
- /* @__PURE__ */ jsxs(Box, { children: [
176
- /* @__PURE__ */ jsx(Text, { mb: 1, fontSize: "sm", fontWeight: "600", children: "Nova senha" }),
177
- /* @__PURE__ */ jsx(Input, { type: "password", autoComplete: "new-password", value: password, onChange: (event) => setPassword(event.target.value), required: true })
208
+ otherSession ? /* @__PURE__ */ jsxs(Box, { children: [
209
+ /* @__PURE__ */ jsxs(Text, { children: [
210
+ "Voc\xEA est\xE1 conectado como ",
211
+ sessionEmail,
212
+ ". Este convite \xE9 para ",
213
+ invitation.email,
214
+ "."
178
215
  ] }),
179
- /* @__PURE__ */ jsxs(Box, { children: [
180
- /* @__PURE__ */ jsx(Text, { mb: 1, fontSize: "sm", fontWeight: "600", children: "Confirmar senha" }),
181
- /* @__PURE__ */ jsx(Input, { type: "password", autoComplete: "new-password", value: confirm, onChange: (event) => setConfirm(event.target.value), required: true })
216
+ /* @__PURE__ */ jsx(Button, { onClick: clearSession, children: "Trocar de conta" })
217
+ ] }) : /* @__PURE__ */ jsx("form", { onSubmit: (event) => void submit(event), children: /* @__PURE__ */ jsxs(VStack, { align: "stretch", gap: 4, children: [
218
+ register && invitation.registrationRequired ? /* @__PURE__ */ jsxs(Box, { children: [
219
+ /* @__PURE__ */ jsx(Text, { children: "Complete seu cadastro para aceitar este convite. N\xE3o ser\xE1 criada outra organiza\xE7\xE3o." }),
220
+ /* @__PURE__ */ jsx(Input, { "aria-label": "Nome completo", placeholder: "Nome completo", required: true, value: registration.nome, onChange: (e) => setRegistration({ ...registration, nome: e.target.value }) }),
221
+ /* @__PURE__ */ jsx(Input, { "aria-label": "CPF", placeholder: "CPF", required: true, value: registration.userDocument, onChange: (e) => setRegistration({ ...registration, userDocument: e.target.value }) }),
222
+ /* @__PURE__ */ jsx(Input, { "aria-label": "Telefone", placeholder: "Telefone com DDD", required: true, value: registration.phone, onChange: (e) => setRegistration({ ...registration, phone: e.target.value }) }),
223
+ /* @__PURE__ */ jsxs("label", { children: [
224
+ /* @__PURE__ */ jsx("input", { type: "checkbox", required: true, checked: registration.termsAccepted, onChange: (e) => setRegistration({ ...registration, termsAccepted: e.target.checked }) }),
225
+ " Aceito os termos e a pol\xEDtica de privacidade da plataforma (2026-08-18)."
226
+ ] })
227
+ ] }) : null,
228
+ !sameSession ? /* @__PURE__ */ jsxs(Box, { children: [
229
+ /* @__PURE__ */ jsx(Text, { mb: 1, fontSize: "sm", fontWeight: "600", children: register ? "Nova senha" : "Senha atual" }),
230
+ /* @__PURE__ */ jsx(Input, { "aria-label": register ? "Nova senha" : "Senha atual", type: "password", autoComplete: register ? "new-password" : "current-password", value: password, onChange: (event) => setPassword(event.target.value), required: true })
231
+ ] }) : /* @__PURE__ */ jsxs(Text, { children: [
232
+ "Voc\xEA est\xE1 conectado como ",
233
+ sessionEmail,
234
+ ". Confirme o aceite para liberar este acesso."
182
235
  ] }),
183
- /* @__PURE__ */ jsx(Button, { type: "submit", children: "Concluir primeiro acesso" })
236
+ !sameSession && register ? /* @__PURE__ */ jsxs(Box, { children: [
237
+ /* @__PURE__ */ jsx(Text, { mb: 1, fontSize: "sm", fontWeight: "600", children: "Confirmar senha" }),
238
+ /* @__PURE__ */ jsx(Input, { "aria-label": "Confirmar senha", type: "password", autoComplete: "new-password", value: confirm, onChange: (event) => setConfirm(event.target.value), required: true })
239
+ ] }) : null,
240
+ !register && !sameSession ? /* @__PURE__ */ jsx(Text, { fontSize: "sm", children: "Use a senha atual da sua conta Oon. Se esqueceu a senha, recupere-a pelo login da plataforma e depois reabra este convite." }) : null,
241
+ invitation.blockedReason ? /* @__PURE__ */ jsxs(Text, { role: "alert", children: [
242
+ "O aceite est\xE1 indispon\xEDvel (",
243
+ invitation.blockedReason,
244
+ "). Solicite regulariza\xE7\xE3o ao administrador."
245
+ ] }) : null,
246
+ /* @__PURE__ */ jsx(Button, { type: "submit", disabled: submitting || auth.status === "loading" || Boolean(invitation.allowedActions && !invitation.allowedActions.includes("accept")), children: submitting ? "Aceitando\u2026" : "Aceitar convite" })
184
247
  ] }) })
185
248
  ] }) : null,
186
249
  message ? /* @__PURE__ */ jsx(Box, { role: "status", bg: done ? "green.50" : "red.50", borderRadius: "md", p: 3, children: /* @__PURE__ */ jsx(Text, { fontSize: "sm", children: message }) }) : null,
187
- done ? /* @__PURE__ */ jsx(Button, { asChild: true, children: /* @__PURE__ */ jsx(Link, { to: "/login", children: "Ir para o login" }) }) : null
250
+ !loading && !invitation && token ? /* @__PURE__ */ jsx(Button, { onClick: () => setInspectionAttempt((value2) => value2 + 1), children: "Tentar novamente" }) : null,
251
+ done ? /* @__PURE__ */ jsx(Button, { asChild: true, children: /* @__PURE__ */ jsx("a", { href: sameSession ? "/" : "/login", children: sameSession ? "Abrir aplicativo" : "Ir para o login" }) }) : null
188
252
  ] }) }) });
189
253
  }
190
254
 
@@ -212,9 +276,9 @@ function AcceptInviteCentralPage() {
212
276
  }
213
277
 
214
278
  // src/security/OnboardingPage.tsx
215
- import { useEffect as useEffect3, useRef, useState as useState3 } from "react";
279
+ import { useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
216
280
  import { Box as Box3, Button as Button2, Flex as Flex2, Heading as Heading2, Input as Input2, Text as Text3, VStack as VStack2 } from "@chakra-ui/react";
217
- import { Link as Link2, useLocation as useLocation2 } from "react-router-dom";
281
+ import { Link, useLocation as useLocation2 } from "react-router-dom";
218
282
  import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
219
283
  var TERMS_VERSION = "2026-08-18";
220
284
  var PRIVACY_VERSION = "2026-08-18";
@@ -234,7 +298,7 @@ function OnboardingPage({ baseUrl, mode }) {
234
298
  const [accepted, setAccepted] = useState3(false);
235
299
  const [message, setMessage] = useState3("");
236
300
  const [busy, setBusy] = useState3(false);
237
- const confirmationToken = useRef(null);
301
+ const confirmationToken = useRef2(null);
238
302
  useEffect3(() => {
239
303
  if (mode !== "confirm") return;
240
304
  const token = new URLSearchParams(location.search).get("token");
@@ -282,7 +346,7 @@ function OnboardingPage({ baseUrl, mode }) {
282
346
  /* @__PURE__ */ jsx3(Button2, { type: "submit", bg: "#07262E", color: "white", disabled: busy || !accepted, children: busy ? "Enviando..." : "Criar acesso" })
283
347
  ] }) }) : null,
284
348
  message ? /* @__PURE__ */ jsx3(Box3, { role: "status", bg: "blue.50", color: "blue.800", borderRadius: "10px", p: 4, children: message }) : null,
285
- /* @__PURE__ */ jsx3(Text3, { fontSize: "sm", children: /* @__PURE__ */ jsx3(Link2, { to: "/login", children: "Voltar para o login" }) })
349
+ /* @__PURE__ */ jsx3(Text3, { fontSize: "sm", children: /* @__PURE__ */ jsx3(Link, { to: "/login", children: "Voltar para o login" }) })
286
350
  ] }) }) });
287
351
  }
288
352
 
@@ -710,7 +774,7 @@ function Sidebar({ app, menu, registry }) {
710
774
  // package.json
711
775
  var package_default = {
712
776
  name: "@oondemand/oon-core-front",
713
- version: "0.7.6",
777
+ version: "0.7.9",
714
778
  repository: {
715
779
  type: "git",
716
780
  url: "git+https://github.com/oondemand/oon-platform.git",
@@ -1182,7 +1246,7 @@ function AppAccessGuard({ children }) {
1182
1246
  // src/security/LoginPage.tsx
1183
1247
  import { useState as useState6 } from "react";
1184
1248
  import { Box as Box7, Button as Button5, Flex as Flex6, Heading as Heading4, Input as Input3, SimpleGrid, Text as Text7, VStack as VStack4 } from "@chakra-ui/react";
1185
- import { Link as Link3, Navigate as Navigate2, useLocation as useLocation4 } from "react-router-dom";
1249
+ import { Link as Link2, Navigate as Navigate2, useLocation as useLocation4 } from "react-router-dom";
1186
1250
  import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
1187
1251
  function tenantOptions(error) {
1188
1252
  const details = error.details;
@@ -1299,7 +1363,7 @@ function LoginPage({ app, onboardingEnabled = false }) {
1299
1363
  tenants.length <= 1 ? /* @__PURE__ */ jsx12(Button5, { type: "submit", bg: "#07262E", color: "white", _hover: { bg: "#0B3843" }, disabled: submitting || !email.trim() || !password, children: submitting ? "Validando acesso..." : "Entrar" }) : null,
1300
1364
  app.kind === "portal-cockpit" && onboardingEnabled && tenants.length <= 1 ? /* @__PURE__ */ jsxs8(Text7, { textAlign: "center", fontSize: "sm", color: "gray.600", children: [
1301
1365
  "Ainda n\xE3o possui acesso? ",
1302
- /* @__PURE__ */ jsx12(Link3, { to: "/cadastro", children: "Criar conta" })
1366
+ /* @__PURE__ */ jsx12(Link2, { to: "/cadastro", children: "Criar conta" })
1303
1367
  ] }) : null
1304
1368
  ] }) }) }) });
1305
1369
  }
@@ -1893,7 +1957,7 @@ function OonApp({ config }) {
1893
1957
  getTenantId: () => tenantStorage2.get(),
1894
1958
  onUnauthorized: () => {
1895
1959
  storage2.clear();
1896
- if (config.runtimeMode === "local") return;
1960
+ if (config.runtimeMode === "local" || window.location.pathname === "/accept-invite") return;
1897
1961
  if (externalLoginUrl) {
1898
1962
  window.location.href = externalLoginUrl;
1899
1963
  return;
@@ -2103,4 +2167,4 @@ export {
2103
2167
  appDefinitionToConfig,
2104
2168
  startOonApp
2105
2169
  };
2106
- //# sourceMappingURL=chunk-XEIPX33G.js.map
2170
+ //# sourceMappingURL=chunk-3EZ6GRFQ.js.map