@oondemand/oon-core-front 0.4.10 → 0.4.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -237,11 +237,14 @@ interface OonModule {
237
237
  views?: OonViewDefinition[];
238
238
  }
239
239
  type CollectionMode = "full" | "minimal" | "dynamic";
240
+ type OonValueFormat = "text" | "number" | "currency" | "percent" | "date" | "datetime" | "badge";
240
241
  interface OonColumnDef {
241
242
  field: string;
242
243
  label?: string;
243
244
  /** kind sobrescreve o inferido da metadata. */
244
245
  kind?: FieldKind;
246
+ /** Formato de apresentação; datetime preserva data e hora no locale do usuário. */
247
+ format?: OonValueFormat;
245
248
  sortable?: boolean;
246
249
  width?: number;
247
250
  renderer?: string;
@@ -362,7 +365,7 @@ type OonRelationDef = {
362
365
  type OonRelatedGridColumnDef = OonColumnDef & {
363
366
  editable?: boolean;
364
367
  readonly?: boolean;
365
- format?: "text" | "number" | "currency" | "percent" | "date" | "badge";
368
+ format?: OonValueFormat;
366
369
  editor?: "string" | "number" | "currency" | "date" | "enum" | "select" | "ref" | "boolean" | "textarea";
367
370
  hidden?: boolean;
368
371
  roles?: string[];
@@ -375,7 +378,7 @@ type OonSummaryCardDef = {
375
378
  field?: string;
376
379
  relation?: string | OonRelationDef;
377
380
  metric?: string;
378
- format?: "text" | "number" | "currency" | "percent" | "date" | "badge";
381
+ format?: OonValueFormat;
379
382
  };
380
383
  type OonDetailTabDef = {
381
384
  id: string;
@@ -1135,8 +1138,10 @@ interface TenantStorage {
1135
1138
  clear(): void;
1136
1139
  }
1137
1140
  /**
1138
- * Guarda somente a seleção de tenant do usuário. O valor persistido não é
1139
- * autoridade: o backend/Control Plane precisa validar o header a cada request.
1141
+ * Mantém o tenant no escopo da aba. Isso permite abrir Tenant A e Tenant B em
1142
+ * janelas diferentes sem uma aba trocar o contexto da outra. O query param
1143
+ * `tenant` transporta somente o identificador selecionado; o backend continua
1144
+ * validando o membership em todas as requisições.
1140
1145
  */
1141
1146
  declare function createTenantStorage(appId: string): TenantStorage;
1142
1147
 
package/dist/index.js CHANGED
@@ -160,24 +160,37 @@ function normalize(value3) {
160
160
  const normalized3 = String(value3 ?? "").trim();
161
161
  return normalized3 || null;
162
162
  }
163
+ function tenantFromUrl(key) {
164
+ if (typeof window === "undefined") return null;
165
+ const url = new URL(window.location.href);
166
+ const tenantId = normalize(url.searchParams.get("tenant"));
167
+ if (!tenantId) return null;
168
+ window.sessionStorage.setItem(key, tenantId);
169
+ url.searchParams.delete("tenant");
170
+ window.history.replaceState(window.history.state, "", `${url.pathname}${url.search}${url.hash}`);
171
+ return tenantId;
172
+ }
163
173
  function createTenantStorage(appId) {
164
174
  const key = `oon:${appId}:tenant`;
165
175
  return {
166
176
  get() {
167
177
  if (typeof window === "undefined") return null;
168
- return normalize(window.localStorage.getItem(key));
178
+ const incoming = tenantFromUrl(key);
179
+ if (incoming) return incoming;
180
+ window.localStorage.removeItem(key);
181
+ return normalize(window.sessionStorage.getItem(key));
169
182
  },
170
183
  set(tenantId) {
171
184
  if (typeof window === "undefined") return;
172
185
  const value3 = normalize(tenantId);
173
186
  if (!value3) {
174
- window.localStorage.removeItem(key);
187
+ window.sessionStorage.removeItem(key);
175
188
  return;
176
189
  }
177
- window.localStorage.setItem(key, value3);
190
+ window.sessionStorage.setItem(key, value3);
178
191
  },
179
192
  clear() {
180
- if (typeof window !== "undefined") window.localStorage.removeItem(key);
193
+ if (typeof window !== "undefined") window.sessionStorage.removeItem(key);
181
194
  }
182
195
  };
183
196
  }
@@ -1053,7 +1066,7 @@ function formFieldsFromMeta(fields) {
1053
1066
  };
1054
1067
  });
1055
1068
  }
1056
- function formatCell(value3, kind) {
1069
+ function formatCell(value3, kind, format2) {
1057
1070
  if (value3 == null || value3 === "") return "\u2014";
1058
1071
  if (value3 && typeof value3 === "object" && !Array.isArray(value3) && kind !== "date") {
1059
1072
  return referenceOptionLabel(value3);
@@ -1063,7 +1076,8 @@ function formatCell(value3, kind) {
1063
1076
  return value3 ? "Sim" : "N\xE3o";
1064
1077
  case "date":
1065
1078
  try {
1066
- return new Date(value3).toLocaleDateString("pt-BR");
1079
+ const date = new Date(value3);
1080
+ return format2 === "datetime" ? date.toLocaleString("pt-BR", { dateStyle: "short", timeStyle: "short" }) : date.toLocaleDateString("pt-BR");
1067
1081
  } catch {
1068
1082
  return String(value3);
1069
1083
  }
@@ -1140,8 +1154,8 @@ function ChevronIcon({ direction }) {
1140
1154
  function PlusIcon() {
1141
1155
  return /* @__PURE__ */ jsx11("svg", { viewBox: "0 0 20 20", width: "17", height: "17", "aria-hidden": "true", children: /* @__PURE__ */ jsx11("path", { d: "M10 4v12M4 10h12", fill: "none", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" }) });
1142
1156
  }
1143
- function renderCell(value3, kind) {
1144
- const formatted = formatCell(value3, kind);
1157
+ function renderCell(value3, kind, format2) {
1158
+ const formatted = formatCell(value3, kind, format2);
1145
1159
  if (kind === "enum") {
1146
1160
  const normalized3 = String(value3 ?? "").toLowerCase();
1147
1161
  const palette = /erro|cancel|inativo|recus|critica/.test(normalized3) ? "red" : /pendente|aguardando|rascunho/.test(normalized3) ? "orange" : /processando|conferencia|integrando|validando/.test(normalized3) ? "blue" : /ativo|sucesso|conclu|aplicada|disponivel|aprov/.test(normalized3) ? "green" : "gray";
@@ -1157,7 +1171,7 @@ function renderColumnCell(row, column, cellRenderers) {
1157
1171
  const value3 = row[column.field];
1158
1172
  const Renderer = column.renderer ? cellRenderers?.[column.renderer] : void 0;
1159
1173
  if (Renderer) return /* @__PURE__ */ jsx11(Renderer, { value: value3, row, column });
1160
- return renderCell(value3, column.kind);
1174
+ return renderCell(value3, column.kind, column.format);
1161
1175
  }
1162
1176
  function DataGrid({
1163
1177
  resource,
@@ -2539,7 +2553,7 @@ import { Fragment as Fragment2, jsx as jsx15, jsxs as jsxs10 } from "react/jsx-r
2539
2553
  function format(value3, format2) {
2540
2554
  if (format2 === "currency") return new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL" }).format(Number(value3 ?? 0));
2541
2555
  if (format2 === "percent") return `${Number(value3 ?? 0).toLocaleString("pt-BR")}%`;
2542
- if (format2 === "date") return formatCell(value3, "date");
2556
+ if (format2 === "date" || format2 === "datetime") return formatCell(value3, "date", format2);
2543
2557
  return value3 == null || value3 === "" ? "\u2014" : String(value3);
2544
2558
  }
2545
2559
  function RelatedMetric({ card, relation, parent }) {
@@ -5277,7 +5291,7 @@ function Sidebar({ app, menu, registry }) {
5277
5291
  // package.json
5278
5292
  var package_default = {
5279
5293
  name: "@oondemand/oon-core-front",
5280
- version: "0.4.10",
5294
+ version: "0.4.12",
5281
5295
  repository: {
5282
5296
  type: "git",
5283
5297
  url: "git+https://github.com/oondemand/oon-platform.git",
@@ -5733,16 +5747,7 @@ function AppAccessGuard({ children }) {
5733
5747
 
5734
5748
  // src/security/LoginPage.tsx
5735
5749
  import { useState as useState18 } from "react";
5736
- import {
5737
- Box as Box25,
5738
- Button as Button18,
5739
- Flex as Flex18,
5740
- Heading as Heading14,
5741
- Input as Input10,
5742
- SimpleGrid as SimpleGrid6,
5743
- Text as Text26,
5744
- VStack as VStack5
5745
- } from "@chakra-ui/react";
5750
+ import { Box as Box25, Button as Button18, Flex as Flex18, Heading as Heading14, Input as Input10, SimpleGrid as SimpleGrid6, Text as Text26, VStack as VStack5 } from "@chakra-ui/react";
5746
5751
  import { Link as Link3, Navigate as Navigate2, useLocation as useLocation4 } from "react-router-dom";
5747
5752
  import { jsx as jsx37, jsxs as jsxs26 } from "react/jsx-runtime";
5748
5753
  function tenantOptions(error) {
@@ -5753,17 +5758,22 @@ function tenantOptions(error) {
5753
5758
  return tenants.filter((tenant) => Boolean(tenant) && typeof tenant === "object").map((tenant) => ({
5754
5759
  id: String(tenant.id || ""),
5755
5760
  nome: String(tenant.nome || tenant.slug || tenant.id || ""),
5756
- slug: tenant.slug ? String(tenant.slug) : void 0
5761
+ slug: tenant.slug ? String(tenant.slug) : void 0,
5762
+ tipo: tenant.tipo ? String(tenant.tipo) : void 0,
5763
+ status: tenant.status ? String(tenant.status) : void 0
5757
5764
  })).filter((tenant) => tenant.id && tenant.nome);
5758
5765
  }
5759
5766
  function safeRedirect(search) {
5760
5767
  const value3 = new URLSearchParams(search).get("redirect") || "/";
5761
5768
  if (!value3.startsWith("/") || value3.startsWith("//")) return "/";
5762
- if (value3.startsWith("/login") || value3.startsWith("/acesso-negado")) {
5763
- return "/";
5764
- }
5769
+ if (value3.startsWith("/login") || value3.startsWith("/acesso-negado")) return "/";
5765
5770
  return value3;
5766
5771
  }
5772
+ function tenantUrl(path, tenantId) {
5773
+ const target = new URL(path, window.location.origin);
5774
+ target.searchParams.set("tenant", tenantId);
5775
+ return target.toString();
5776
+ }
5767
5777
  function LoginPage({ app, onboardingEnabled = false }) {
5768
5778
  const { status, login } = useOonAuth();
5769
5779
  const location = useLocation4();
@@ -5772,168 +5782,92 @@ function LoginPage({ app, onboardingEnabled = false }) {
5772
5782
  const [submitting, setSubmitting] = useState18(false);
5773
5783
  const [message, setMessage] = useState18(null);
5774
5784
  const [tenants, setTenants] = useState18([]);
5775
- const [tenantId, setTenantId] = useState18("");
5785
+ const [selectorMode, setSelectorMode] = useState18(false);
5786
+ const [openingTenant, setOpeningTenant] = useState18(null);
5776
5787
  const redirect = safeRedirect(location.search);
5777
- if (status === "authenticated") {
5778
- return /* @__PURE__ */ jsx37(Navigate2, { to: redirect, replace: true });
5779
- }
5780
- if (status === "forbidden") {
5781
- return /* @__PURE__ */ jsx37(Navigate2, { to: "/acesso-negado", replace: true });
5782
- }
5788
+ if (status === "authenticated" && !selectorMode) return /* @__PURE__ */ jsx37(Navigate2, { to: redirect, replace: true });
5789
+ if (status === "forbidden") return /* @__PURE__ */ jsx37(Navigate2, { to: "/acesso-negado", replace: true });
5783
5790
  async function handleSubmit(event) {
5784
5791
  event.preventDefault();
5792
+ if (tenants.length > 1) return;
5785
5793
  setSubmitting(true);
5786
5794
  setMessage(null);
5787
5795
  try {
5788
- if (tenants.length > 1 && !tenantId) {
5789
- setMessage("Selecione a organiza\xE7\xE3o para continuar.");
5790
- return;
5791
- }
5792
- await login(email.trim(), password, tenantId || void 0);
5796
+ await login(email.trim(), password);
5793
5797
  } catch (error) {
5794
5798
  const authError = error;
5795
5799
  if (authError.code === "TENANT_SELECTION_REQUIRED") {
5796
5800
  const options = tenantOptions(authError);
5797
5801
  if (options.length > 1) {
5798
5802
  setTenants(options);
5799
- setTenantId("");
5800
- setMessage("Seu usu\xE1rio possui acesso a mais de uma organiza\xE7\xE3o. Selecione uma para continuar.");
5803
+ setMessage("Escolha uma organiza\xE7\xE3o. O tenant ser\xE1 aberto em uma nova aba.");
5801
5804
  return;
5802
5805
  }
5803
5806
  }
5804
5807
  if (authError.status === 403) return;
5805
- setMessage(
5806
- authError.status === 401 ? "E-mail ou senha inv\xE1lidos." : authError.message || "N\xE3o foi poss\xEDvel entrar. Tente novamente."
5807
- );
5808
+ setMessage(authError.status === 401 ? "E-mail ou senha inv\xE1lidos." : authError.message || "N\xE3o foi poss\xEDvel entrar. Tente novamente.");
5808
5809
  } finally {
5809
5810
  setSubmitting(false);
5810
5811
  }
5811
5812
  }
5812
- return /* @__PURE__ */ jsx37(Flex18, { minH: "100vh", align: "center", justify: "center", bg: "#F5F8FA", px: 4, children: /* @__PURE__ */ jsx37(
5813
- Box25,
5814
- {
5815
- width: "100%",
5816
- maxW: tenants.length > 1 ? "680px" : "440px",
5817
- bg: "white",
5818
- borderWidth: "1px",
5819
- borderColor: "#E4EBEF",
5820
- borderRadius: "18px",
5821
- boxShadow: "0 24px 70px rgba(7, 38, 46, 0.10)",
5822
- p: { base: 6, md: 9 },
5823
- children: /* @__PURE__ */ jsx37("form", { onSubmit: handleSubmit, children: /* @__PURE__ */ jsxs26(VStack5, { align: "stretch", gap: 6, children: [
5824
- /* @__PURE__ */ jsxs26(Box25, { children: [
5825
- /* @__PURE__ */ jsx37(
5826
- Text26,
5827
- {
5828
- color: "#39BFED",
5829
- fontSize: "xs",
5830
- fontWeight: "700",
5831
- letterSpacing: "0.12em",
5832
- textTransform: "uppercase",
5833
- children: "Central Oon"
5834
- }
5835
- ),
5836
- /* @__PURE__ */ jsx37(Heading14, { mt: 2, size: "lg", color: "#07262E", children: app.title ?? app.name }),
5837
- /* @__PURE__ */ jsx37(Text26, { mt: 2, color: "gray.600", fontSize: "sm", children: "Entre com seu usu\xE1rio autorizado para acessar este aplicativo." })
5838
- ] }),
5839
- /* @__PURE__ */ jsxs26(VStack5, { align: "stretch", gap: 4, children: [
5840
- /* @__PURE__ */ jsxs26(Box25, { children: [
5841
- /* @__PURE__ */ jsx37(Text26, { mb: 2, fontSize: "sm", fontWeight: "600", color: "#24323A", children: "E-mail" }),
5842
- /* @__PURE__ */ jsx37(
5843
- Input10,
5844
- {
5845
- type: "email",
5846
- value: email,
5847
- onChange: (event) => {
5848
- setEmail(event.target.value);
5849
- setTenants([]);
5850
- setTenantId("");
5851
- },
5852
- autoComplete: "email",
5853
- placeholder: "voce@empresa.com.br",
5854
- required: true
5855
- }
5856
- )
5857
- ] }),
5858
- /* @__PURE__ */ jsxs26(Box25, { children: [
5859
- /* @__PURE__ */ jsx37(Text26, { mb: 2, fontSize: "sm", fontWeight: "600", color: "#24323A", children: "Senha" }),
5860
- /* @__PURE__ */ jsx37(
5861
- Input10,
5862
- {
5863
- type: "password",
5864
- value: password,
5865
- onChange: (event) => setPassword(event.target.value),
5866
- autoComplete: "current-password",
5867
- placeholder: "Sua senha",
5868
- required: true
5869
- }
5870
- )
5871
- ] }),
5872
- tenants.length > 1 ? /* @__PURE__ */ jsxs26(Box25, { children: [
5873
- /* @__PURE__ */ jsx37(Text26, { mb: 3, fontSize: "sm", fontWeight: "600", color: "#24323A", children: "Escolha o tenant para acessar" }),
5874
- /* @__PURE__ */ jsx37(SimpleGrid6, { columns: { base: 1, md: 2 }, gap: 3, children: tenants.map((tenant) => {
5875
- const selected = tenantId === tenant.id;
5876
- return /* @__PURE__ */ jsx37(
5877
- Button18,
5878
- {
5879
- type: "button",
5880
- variant: "outline",
5881
- height: "auto",
5882
- minH: "88px",
5883
- justifyContent: "flex-start",
5884
- whiteSpace: "normal",
5885
- textAlign: "left",
5886
- borderWidth: "2px",
5887
- borderColor: selected ? "#39BFED" : "#D9E2E7",
5888
- bg: selected ? "#EFFAFF" : "white",
5889
- color: "#24323A",
5890
- "aria-pressed": selected,
5891
- onClick: () => {
5892
- setTenantId(tenant.id);
5893
- setMessage(null);
5894
- },
5895
- _hover: { borderColor: "#39BFED", bg: "#F6FCFE" },
5896
- children: /* @__PURE__ */ jsxs26(VStack5, { align: "start", gap: 1, py: 3, children: [
5897
- /* @__PURE__ */ jsx37(Text26, { fontWeight: "700", children: tenant.nome }),
5898
- tenant.slug ? /* @__PURE__ */ jsx37(Text26, { fontSize: "xs", color: "gray.500", children: tenant.slug }) : null
5899
- ] })
5900
- },
5901
- tenant.id
5902
- );
5903
- }) })
5904
- ] }) : null
5905
- ] }),
5906
- message ? /* @__PURE__ */ jsx37(
5907
- Box25,
5908
- {
5909
- role: "alert",
5910
- borderRadius: "10px",
5911
- bg: "red.50",
5912
- color: "red.700",
5913
- px: 4,
5914
- py: 3,
5915
- fontSize: "sm",
5916
- children: message
5917
- }
5918
- ) : null,
5919
- /* @__PURE__ */ jsx37(
5920
- Button18,
5921
- {
5922
- type: "submit",
5923
- bg: "#07262E",
5924
- color: "white",
5925
- _hover: { bg: "#0B3843" },
5926
- disabled: submitting || !email.trim() || !password || tenants.length > 1 && !tenantId,
5927
- children: submitting ? "Validando acesso..." : "Entrar"
5928
- }
5929
- ),
5930
- app.kind === "portal-cockpit" && onboardingEnabled ? /* @__PURE__ */ jsxs26(Text26, { textAlign: "center", fontSize: "sm", color: "gray.600", children: [
5931
- "Ainda n\xE3o possui acesso? ",
5932
- /* @__PURE__ */ jsx37(Link3, { to: "/cadastro", children: "Criar cadastro" })
5933
- ] }) : null
5934
- ] }) })
5813
+ async function openTenant(tenant) {
5814
+ if (openingTenant) return;
5815
+ const popup = window.open("about:blank", "_blank");
5816
+ if (!popup) {
5817
+ setMessage("Permita pop-ups para abrir o tenant em uma nova aba.");
5818
+ return;
5935
5819
  }
5936
- ) });
5820
+ popup.opener = null;
5821
+ setOpeningTenant(tenant.id);
5822
+ setSelectorMode(true);
5823
+ setMessage(null);
5824
+ try {
5825
+ if (status !== "authenticated") await login(email.trim(), password, tenant.id);
5826
+ popup.location.replace(tenantUrl(redirect, tenant.id));
5827
+ setPassword("");
5828
+ setMessage(`${tenant.nome} foi aberto em uma nova aba. Escolha outro tenant quando precisar.`);
5829
+ } catch (error) {
5830
+ popup.close();
5831
+ const authError = error;
5832
+ setMessage(authError.message || "N\xE3o foi poss\xEDvel abrir o tenant.");
5833
+ } finally {
5834
+ setOpeningTenant(null);
5835
+ }
5836
+ }
5837
+ return /* @__PURE__ */ jsx37(Flex18, { minH: "100vh", align: "center", justify: "center", bg: "#F5F8FA", px: 4, children: /* @__PURE__ */ jsx37(Box25, { width: "100%", maxW: tenants.length > 1 ? "760px" : "440px", bg: "white", borderWidth: "1px", borderColor: "#E4EBEF", borderRadius: "18px", boxShadow: "0 24px 70px rgba(7, 38, 46, 0.10)", p: { base: 6, md: 9 }, children: /* @__PURE__ */ jsx37("form", { onSubmit: handleSubmit, children: /* @__PURE__ */ jsxs26(VStack5, { align: "stretch", gap: 6, children: [
5838
+ /* @__PURE__ */ jsxs26(Box25, { children: [
5839
+ /* @__PURE__ */ jsx37(Text26, { color: "#39BFED", fontSize: "xs", fontWeight: "700", letterSpacing: "0.12em", textTransform: "uppercase", children: "Central Oon" }),
5840
+ /* @__PURE__ */ jsx37(Heading14, { mt: 2, size: "lg", color: "#07262E", children: app.title ?? app.name }),
5841
+ /* @__PURE__ */ jsx37(Text26, { mt: 2, color: "gray.600", fontSize: "sm", children: tenants.length > 1 ? "Abra uma ou mais organiza\xE7\xF5es para trabalhar em contextos separados." : "Entre com seu usu\xE1rio autorizado para acessar este aplicativo." })
5842
+ ] }),
5843
+ tenants.length <= 1 ? /* @__PURE__ */ jsxs26(VStack5, { align: "stretch", gap: 4, children: [
5844
+ /* @__PURE__ */ jsxs26(Box25, { children: [
5845
+ /* @__PURE__ */ jsx37(Text26, { mb: 2, fontSize: "sm", fontWeight: "600", color: "#24323A", children: "E-mail" }),
5846
+ /* @__PURE__ */ jsx37(Input10, { type: "email", value: email, onChange: (event) => {
5847
+ setEmail(event.target.value);
5848
+ setTenants([]);
5849
+ setSelectorMode(false);
5850
+ }, autoComplete: "email", placeholder: "voce@empresa.com.br", required: true })
5851
+ ] }),
5852
+ /* @__PURE__ */ jsxs26(Box25, { children: [
5853
+ /* @__PURE__ */ jsx37(Text26, { mb: 2, fontSize: "sm", fontWeight: "600", color: "#24323A", children: "Senha" }),
5854
+ /* @__PURE__ */ jsx37(Input10, { type: "password", value: password, onChange: (event) => setPassword(event.target.value), autoComplete: "current-password", placeholder: "Sua senha", required: true })
5855
+ ] })
5856
+ ] }) : /* @__PURE__ */ jsxs26(Box25, { children: [
5857
+ /* @__PURE__ */ jsx37(Text26, { mb: 3, fontSize: "sm", fontWeight: "600", color: "#24323A", children: "Escolha o tenant para acessar" }),
5858
+ /* @__PURE__ */ jsx37(SimpleGrid6, { columns: { base: 1, md: 2 }, gap: 3, children: tenants.map((tenant) => /* @__PURE__ */ jsx37(Button18, { type: "button", variant: "outline", height: "auto", minH: "104px", justifyContent: "flex-start", whiteSpace: "normal", textAlign: "left", borderWidth: "2px", borderColor: "#D9E2E7", bg: "white", color: "#24323A", disabled: Boolean(openingTenant), "aria-label": `Abrir ${tenant.nome} em nova aba`, onClick: () => void openTenant(tenant), _hover: { borderColor: "#39BFED", bg: "#F6FCFE" }, children: /* @__PURE__ */ jsxs26(VStack5, { align: "start", gap: 1, py: 3, children: [
5859
+ /* @__PURE__ */ jsx37(Text26, { fontWeight: "700", children: tenant.nome }),
5860
+ /* @__PURE__ */ jsx37(Text26, { fontSize: "xs", color: "gray.500", children: [tenant.slug, tenant.tipo, tenant.status].filter(Boolean).join(" \xB7 ") }),
5861
+ /* @__PURE__ */ jsx37(Text26, { fontSize: "xs", color: "#168EB9", children: openingTenant === tenant.id ? "Abrindo..." : "Abrir em nova aba" })
5862
+ ] }) }, tenant.id)) })
5863
+ ] }),
5864
+ message ? /* @__PURE__ */ jsx37(Box25, { role: "status", borderRadius: "10px", bg: "blue.50", color: "blue.800", px: 4, py: 3, fontSize: "sm", children: message }) : null,
5865
+ tenants.length <= 1 ? /* @__PURE__ */ jsx37(Button18, { type: "submit", bg: "#07262E", color: "white", _hover: { bg: "#0B3843" }, disabled: submitting || !email.trim() || !password, children: submitting ? "Validando acesso..." : "Entrar" }) : null,
5866
+ app.kind === "portal-cockpit" && onboardingEnabled && tenants.length <= 1 ? /* @__PURE__ */ jsxs26(Text26, { textAlign: "center", fontSize: "sm", color: "gray.600", children: [
5867
+ "Ainda n\xE3o possui acesso? ",
5868
+ /* @__PURE__ */ jsx37(Link3, { to: "/cadastro", children: "Criar conta" })
5869
+ ] }) : null
5870
+ ] }) }) }) });
5937
5871
  }
5938
5872
 
5939
5873
  // src/security/FirstAccessPage.tsx