@fayz-ai/admin 0.62.0 → 0.63.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.
Files changed (169) hide show
  1. package/dist/{CommandPalette-B5PMQFDG.js → CommandPalette-XDJJ5E3O.js} +3 -3
  2. package/dist/{CommandPalette-B5PMQFDG.js.map → CommandPalette-XDJJ5E3O.js.map} +1 -1
  3. package/dist/ConnectedBrandingSettings-43ZM3HCI.js +680 -0
  4. package/dist/ConnectedBrandingSettings-43ZM3HCI.js.map +1 -0
  5. package/dist/ConnectedCompanySettings-I4MALI2Q.js +197 -0
  6. package/dist/ConnectedCompanySettings-I4MALI2Q.js.map +1 -0
  7. package/dist/ConnectedModulesSettings-A2VJ5BMJ.js +563 -0
  8. package/dist/ConnectedModulesSettings-A2VJ5BMJ.js.map +1 -0
  9. package/dist/ConnectedSecuritySettings-25AHA4HJ.js +189 -0
  10. package/dist/ConnectedSecuritySettings-25AHA4HJ.js.map +1 -0
  11. package/dist/ConnectedUserProfile-E7USJRUE.js +424 -0
  12. package/dist/ConnectedUserProfile-E7USJRUE.js.map +1 -0
  13. package/dist/FieldRulesEditor-YGIPKI5T.js +129 -0
  14. package/dist/FieldRulesEditor-YGIPKI5T.js.map +1 -0
  15. package/dist/GettingStartedWidget-HMIJ3Y24.js +12 -0
  16. package/dist/GettingStartedWidget-HMIJ3Y24.js.map +1 -0
  17. package/dist/PermissionProfilesTab-3ZPRCHMZ.js +548 -0
  18. package/dist/PermissionProfilesTab-3ZPRCHMZ.js.map +1 -0
  19. package/dist/PersonTimeline-HQZT527S.js +3 -0
  20. package/dist/{PersonTimeline-X7JTPUWJ.js.map → PersonTimeline-HQZT527S.js.map} +1 -1
  21. package/dist/ProjectsSettings-7O2F27MD.js +5 -0
  22. package/dist/ProjectsSettings-7O2F27MD.js.map +1 -0
  23. package/dist/ScheduleEditor-54ELWR45.js +8 -0
  24. package/dist/{ScheduleEditor-L2UJXKMY.js.map → ScheduleEditor-54ELWR45.js.map} +1 -1
  25. package/dist/SeuSiteWidget-QLSUVC63.js +6 -0
  26. package/dist/SeuSiteWidget-QLSUVC63.js.map +1 -0
  27. package/dist/SubscriptionPage-5GE5HFJK.js +17 -0
  28. package/dist/{SubscriptionPage-IDVEFLZ5.js.map → SubscriptionPage-5GE5HFJK.js.map} +1 -1
  29. package/dist/TeamTab-6RAULFLW.js +502 -0
  30. package/dist/TeamTab-6RAULFLW.js.map +1 -0
  31. package/dist/TrialWidget-Z6CLUCU3.js +7 -0
  32. package/dist/TrialWidget-Z6CLUCU3.js.map +1 -0
  33. package/dist/app/AdminShell.d.ts.map +1 -1
  34. package/dist/app/admin-app.d.ts.map +1 -1
  35. package/dist/app/config.d.ts +14 -0
  36. package/dist/app/config.d.ts.map +1 -1
  37. package/dist/app/routing.d.ts +6 -0
  38. package/dist/app/routing.d.ts.map +1 -1
  39. package/dist/app/scaffold.d.ts.map +1 -1
  40. package/dist/billing/index.js +9 -4
  41. package/dist/chunk-2H46WDG5.js +53 -0
  42. package/dist/chunk-2H46WDG5.js.map +1 -0
  43. package/dist/chunk-3HLX7YB2.js +94 -0
  44. package/dist/chunk-3HLX7YB2.js.map +1 -0
  45. package/dist/chunk-3OUD4XBK.js +3 -0
  46. package/dist/chunk-3OUD4XBK.js.map +1 -0
  47. package/dist/{chunk-IXSY4GPK.js → chunk-5D5QLMOQ.js} +5 -3
  48. package/dist/chunk-5D5QLMOQ.js.map +1 -0
  49. package/dist/chunk-5WR62X2R.js +1081 -0
  50. package/dist/chunk-5WR62X2R.js.map +1 -0
  51. package/dist/{chunk-KPYRTOCK.js → chunk-6CQFGMEO.js} +4 -140
  52. package/dist/chunk-6CQFGMEO.js.map +1 -0
  53. package/dist/chunk-6MMSYC2I.js +116 -0
  54. package/dist/chunk-6MMSYC2I.js.map +1 -0
  55. package/dist/chunk-6QFOE3UD.js +1466 -0
  56. package/dist/chunk-6QFOE3UD.js.map +1 -0
  57. package/dist/chunk-6UUFVQ2E.js +283 -0
  58. package/dist/chunk-6UUFVQ2E.js.map +1 -0
  59. package/dist/chunk-7WNLL3F6.js +7889 -0
  60. package/dist/chunk-7WNLL3F6.js.map +1 -0
  61. package/dist/chunk-A74IHAQE.js +439 -0
  62. package/dist/chunk-A74IHAQE.js.map +1 -0
  63. package/dist/{chunk-JOBRLBIQ.js → chunk-AFA6IO23.js} +4 -3
  64. package/dist/chunk-AFA6IO23.js.map +1 -0
  65. package/dist/{chunk-P5UIGQFY.js → chunk-ALCSIN3Z.js} +5 -5
  66. package/dist/chunk-ALCSIN3Z.js.map +1 -0
  67. package/dist/chunk-AWM4AMBS.js +39 -0
  68. package/dist/chunk-AWM4AMBS.js.map +1 -0
  69. package/dist/{chunk-OQARLKZN.js → chunk-BG5Z6KLN.js} +6 -18
  70. package/dist/chunk-BG5Z6KLN.js.map +1 -0
  71. package/dist/chunk-DPNFZONC.js +19 -0
  72. package/dist/chunk-DPNFZONC.js.map +1 -0
  73. package/dist/chunk-DRCV643L.js +193 -0
  74. package/dist/chunk-DRCV643L.js.map +1 -0
  75. package/dist/chunk-E6DF3VR6.js +206 -0
  76. package/dist/chunk-E6DF3VR6.js.map +1 -0
  77. package/dist/chunk-ENHCVGXZ.js +120 -0
  78. package/dist/chunk-ENHCVGXZ.js.map +1 -0
  79. package/dist/chunk-FK6RHGI7.js +56 -0
  80. package/dist/chunk-FK6RHGI7.js.map +1 -0
  81. package/dist/chunk-G5HNA5QK.js +233 -0
  82. package/dist/chunk-G5HNA5QK.js.map +1 -0
  83. package/dist/chunk-HCFO4Z6A.js +53 -0
  84. package/dist/chunk-HCFO4Z6A.js.map +1 -0
  85. package/dist/chunk-JFIU6NQP.js +51 -0
  86. package/dist/chunk-JFIU6NQP.js.map +1 -0
  87. package/dist/chunk-JRZJBMOY.js +3 -0
  88. package/dist/chunk-JRZJBMOY.js.map +1 -0
  89. package/dist/{chunk-3YP7KW47.js → chunk-JVVOL4BB.js} +41 -512
  90. package/dist/chunk-JVVOL4BB.js.map +1 -0
  91. package/dist/chunk-KAQ3UIAA.js +415 -0
  92. package/dist/chunk-KAQ3UIAA.js.map +1 -0
  93. package/dist/{chunk-P6XUDT2P.js → chunk-KJELMULA.js} +4 -51
  94. package/dist/chunk-KJELMULA.js.map +1 -0
  95. package/dist/chunk-KLO7DKXX.js +1651 -0
  96. package/dist/chunk-KLO7DKXX.js.map +1 -0
  97. package/dist/chunk-M2CMDWUI.js +75 -0
  98. package/dist/chunk-M2CMDWUI.js.map +1 -0
  99. package/dist/chunk-PQ47MLTH.js +255 -0
  100. package/dist/chunk-PQ47MLTH.js.map +1 -0
  101. package/dist/{chunk-VX3WJLKK.js → chunk-QD7BMUDF.js} +17 -8
  102. package/dist/chunk-QD7BMUDF.js.map +1 -0
  103. package/dist/{chunk-E4MESMNR.js → chunk-QTSKCPSW.js} +7 -10
  104. package/dist/chunk-QTSKCPSW.js.map +1 -0
  105. package/dist/chunk-S56FQKPL.js +186 -0
  106. package/dist/chunk-S56FQKPL.js.map +1 -0
  107. package/dist/chunk-SGAFPNMA.js +75 -0
  108. package/dist/chunk-SGAFPNMA.js.map +1 -0
  109. package/dist/{chunk-OD7P4L3D.js → chunk-SOKCLVM4.js} +3 -3
  110. package/dist/{chunk-OD7P4L3D.js.map → chunk-SOKCLVM4.js.map} +1 -1
  111. package/dist/chunk-TL42NKTH.js +3 -0
  112. package/dist/chunk-TL42NKTH.js.map +1 -0
  113. package/dist/chunk-U6ZCO2PS.js +2964 -0
  114. package/dist/chunk-U6ZCO2PS.js.map +1 -0
  115. package/dist/chunk-VSXNROYH.js +16 -0
  116. package/dist/chunk-VSXNROYH.js.map +1 -0
  117. package/dist/chunk-WPFZCYZL.js +619 -0
  118. package/dist/chunk-WPFZCYZL.js.map +1 -0
  119. package/dist/chunk-XFTNIBDW.js +23 -0
  120. package/dist/chunk-XFTNIBDW.js.map +1 -0
  121. package/dist/chunk-Y66JDL6I.js +1020 -0
  122. package/dist/chunk-Y66JDL6I.js.map +1 -0
  123. package/dist/chunk-YEHIBPIX.js +137 -0
  124. package/dist/chunk-YEHIBPIX.js.map +1 -0
  125. package/dist/chunk-YKPPCV2Z.js +53 -0
  126. package/dist/chunk-YKPPCV2Z.js.map +1 -0
  127. package/dist/components/chat/markdown.d.ts.map +1 -1
  128. package/dist/components/plugins/PluginSettingsPanel.d.ts.map +1 -1
  129. package/dist/components/settings/SettingsPage.d.ts.map +1 -1
  130. package/dist/connect-XKQJOWR7.js +18 -0
  131. package/dist/connect-XKQJOWR7.js.map +1 -0
  132. package/dist/crud/CrudDetailPage.d.ts.map +1 -1
  133. package/dist/crud/CrudListView.d.ts.map +1 -1
  134. package/dist/crud/CrudPage.d.ts.map +1 -1
  135. package/dist/crud/RelatedListTab.d.ts.map +1 -1
  136. package/dist/crud/archetypes/EntityLink.d.ts +1 -1
  137. package/dist/crud/archetypes/EntityLink.d.ts.map +1 -1
  138. package/dist/crud/record-chrome.d.ts.map +1 -1
  139. package/dist/entity-routes-PGU7EHAD.js +4 -0
  140. package/dist/{entity-routes-LXOBW5IB.js.map → entity-routes-PGU7EHAD.js.map} +1 -1
  141. package/dist/hooks/useModuleNavigation.d.ts.map +1 -1
  142. package/dist/impersonation/ImpersonateDialog.d.ts.map +1 -1
  143. package/dist/impersonation/session.d.ts.map +1 -1
  144. package/dist/index.d.ts +1 -1
  145. package/dist/index.d.ts.map +1 -1
  146. package/dist/index.js +11902 -33551
  147. package/dist/index.js.map +1 -1
  148. package/dist/lib/entity-routes.d.ts.map +1 -1
  149. package/dist/org/index.js +4 -2
  150. package/dist/plugins/PluginRegistryManager.d.ts.map +1 -1
  151. package/dist/settings/MessageTemplateRow.d.ts.map +1 -1
  152. package/dist/timeline/PersonTimeline.d.ts.map +1 -1
  153. package/dist/timeline/TimelineList.d.ts.map +1 -1
  154. package/dist/units/UnitRailPage.d.ts.map +1 -1
  155. package/dist/units/useUnitFilter.d.ts.map +1 -1
  156. package/package.json +5 -5
  157. package/dist/PersonTimeline-X7JTPUWJ.js +0 -3
  158. package/dist/ScheduleEditor-L2UJXKMY.js +0 -6
  159. package/dist/SubscriptionPage-IDVEFLZ5.js +0 -8
  160. package/dist/chunk-3YP7KW47.js.map +0 -1
  161. package/dist/chunk-E4MESMNR.js.map +0 -1
  162. package/dist/chunk-IXSY4GPK.js.map +0 -1
  163. package/dist/chunk-JOBRLBIQ.js.map +0 -1
  164. package/dist/chunk-KPYRTOCK.js.map +0 -1
  165. package/dist/chunk-OQARLKZN.js.map +0 -1
  166. package/dist/chunk-P5UIGQFY.js.map +0 -1
  167. package/dist/chunk-P6XUDT2P.js.map +0 -1
  168. package/dist/chunk-VX3WJLKK.js.map +0 -1
  169. package/dist/entity-routes-LXOBW5IB.js +0 -4
@@ -0,0 +1,563 @@
1
+ import { useModuleCatalog, buildCategories, appLabelFor, applyRailPreset, labelFor } from './chunk-DRCV643L.js';
2
+ import { useAppConfig, clearAppConfigSnapshot, MODULE_FAMILIES, moduleFamilyOf, UPCOMING_MODULE_INFO } from './chunk-G5HNA5QK.js';
3
+ import { useSettingsUnitScope, UnitScopePicker } from './chunk-2H46WDG5.js';
4
+ import { useOfferedPlugins, useAppPreset } from './chunk-AWM4AMBS.js';
5
+ import { useAccessOptional } from './chunk-S56FQKPL.js';
6
+ import { toast } from './chunk-3OUD4XBK.js';
7
+ import { packageFor, COMING_SOON_MODULES, moduleFitsTrades, TRADE_BY_APP, PRICE_BOOK, includedIn } from './chunk-6CQFGMEO.js';
8
+ import './chunk-SGAFPNMA.js';
9
+ import './chunk-TL42NKTH.js';
10
+ import { useUnitStore, useAppConfigStore } from './chunk-5D5QLMOQ.js';
11
+ import './chunk-UQ2NTFQC.js';
12
+ import { getSupabaseClientOptional } from './chunk-KJELMULA.js';
13
+ import { cn } from './chunk-JRZJBMOY.js';
14
+ import { useOrganizationStore } from './chunk-YKPPCV2Z.js';
15
+ import { navigateTo } from './chunk-QD7BMUDF.js';
16
+ import * as React3 from 'react';
17
+ import { invalidateAppConfig, usePluginRuntime, unitDisabledModules, tl } from '@fayz-ai/core';
18
+ import { Plus, Puzzle, Building2, Crown, Lock, Settings, Home, ChevronRight, Search, ChevronDown } from 'lucide-react';
19
+ import { PageHeaderActions, Button, getLucideIcon, Card, CardHeader, CardTitle, Badge, Switch, CardContent, Separator, Modal, ModalContent, ModalHeader, ModalTitle, ModalDescription, Input } from '@fayz-ai/ui';
20
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
21
+
22
+ function modulePriceLabel(plugin, facet, pkg) {
23
+ const key = facet ? `${plugin}.${facet}` : plugin;
24
+ const entry = PRICE_BOOK[key];
25
+ if (!entry) return void 0;
26
+ if (includedIn(pkg, key)) return tl(`Included in ${pkg.name}`, `Inclu\xEDdo no ${pkg.name}`);
27
+ const price = `R$ ${entry.price.toLocaleString("pt-BR")}`;
28
+ return entry.per === "unit" ? tl(`${price} per unit`, `${price} por unidade`) : tl(`${price} a month, whole group`, `${price}/m\xEAs, grupo todo`);
29
+ }
30
+ function moduleSettingsHref(tabs, plugin, facet) {
31
+ const own = tabs.filter((t) => t.pluginId === plugin);
32
+ const tab = facet ? own.find((t) => t.requiresFacet === facet) ?? own.find((t) => t.id === `${plugin}-${facet}`) : own.find((t) => t.id === plugin) ?? own.find((t) => !t.requiresFacet && !t.parent) ?? own[0];
33
+ return tab ? `/settings/${tab.id}` : void 0;
34
+ }
35
+
36
+ // src/components/settings/module-scope.ts
37
+ function accountTrades(apps) {
38
+ const out = /* @__PURE__ */ new Set();
39
+ for (const app of apps) {
40
+ if (app.house) continue;
41
+ const trade = TRADE_BY_APP[app.id] ?? app.vertical_id;
42
+ if (trade) out.add(trade);
43
+ }
44
+ return [...out];
45
+ }
46
+ function splitAccountModules(rows, opts) {
47
+ const has = [];
48
+ const usedByOthers = [];
49
+ for (const row of rows) {
50
+ if (!row.plugin.isActive) continue;
51
+ if (row.plugin.activationReason === "dependency") {
52
+ usedByOthers.push({ row, by: row.neededBy });
53
+ continue;
54
+ }
55
+ const inTrade = opts.trades.length === 0 || moduleFitsTrades(row.plugin.id, opts.trades) || opts.chosen.has(row.plugin.id);
56
+ if (inTrade) has.push(row);
57
+ }
58
+ return { has, usedByOthers };
59
+ }
60
+ function UpcomingModuleRow({ moduleKey }) {
61
+ const entry = PRICE_BOOK[moduleKey];
62
+ const info = UPCOMING_MODULE_INFO[moduleKey];
63
+ if (!entry) return null;
64
+ const price = modulePriceLabel(moduleKey.includes(".") ? moduleKey.split(".")[0] : moduleKey, moduleKey.includes(".") ? moduleKey.split(".")[1] : void 0);
65
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 rounded-card border border-dashed bg-muted/20 p-4 sm:flex-row sm:items-start sm:justify-between", children: [
66
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
67
+ /* @__PURE__ */ jsxs("p", { className: "flex flex-wrap items-center gap-2 font-medium", children: [
68
+ tl(...entry.label),
69
+ /* @__PURE__ */ jsx(Badge, { variant: "secondary", children: tl("Coming soon", "Em breve") })
70
+ ] }),
71
+ info && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-sm text-muted-foreground", children: tl(...info.line) }),
72
+ info?.v1 && /* @__PURE__ */ jsxs("p", { className: "mt-0.5 text-xs text-muted-foreground", children: [
73
+ tl("From V1", "Vem do V1"),
74
+ ": ",
75
+ info.v1
76
+ ] })
77
+ ] }),
78
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 text-sm tabular-nums text-muted-foreground", children: price ?? tl("Price coming soon", "Pre\xE7o em breve") })
79
+ ] });
80
+ }
81
+ function pluginScreens(plugin) {
82
+ return plugin.navigation?.length ? plugin.navigation.map((n) => n.label) : (plugin.routes ?? []).map((r) => r.path).filter((p) => !p.endsWith("/*"));
83
+ }
84
+ function buildRows(plugins, hidden, permits) {
85
+ const visible = plugins.filter((p) => !hidden.has(p.id) && p.scope !== "core");
86
+ const hosted = new Set(visible.filter((p) => p.hostPluginId).map((p) => p.id));
87
+ return visible.filter((plugin) => !hosted.has(plugin.id)).map((plugin) => ({
88
+ plugin,
89
+ // O que o plugin oferece de menu. Um módulo sem entrada própria (o app
90
+ // desenhou o rail) cai nas rotas, que é o que some de verdade.
91
+ screens: pluginScreens(plugin),
92
+ neededBy: visible.filter((other) => other.isActive && other.id !== plugin.id && (other.dependencies ?? []).includes(plugin.id)).map((other) => other.name),
93
+ permitted: permits ? permits(plugin.id) : true,
94
+ addons: visible.filter((candidate) => candidate.hostPluginId === plugin.id).map((addon) => ({
95
+ plugin: addon,
96
+ screens: pluginScreens(addon),
97
+ permitted: permits ? permits(addon.id) : true
98
+ })).sort((a, b) => a.plugin.name.localeCompare(b.plugin.name))
99
+ })).sort((a, b) => a.plugin.name.localeCompare(b.plugin.name));
100
+ }
101
+ function ModuleCard({
102
+ row,
103
+ onToggle,
104
+ busy,
105
+ appLabel,
106
+ unit,
107
+ price,
108
+ facetPrice,
109
+ settingsHref,
110
+ onOpenSettings
111
+ }) {
112
+ const { plugin, screens, neededBy, permitted, addons } = row;
113
+ const Icon = getLucideIcon(plugin.icon) ?? Puzzle;
114
+ const blocked = !permitted && !plugin.isActive;
115
+ const locked = plugin.isActive && neededBy.length > 0;
116
+ const facets = (plugin.facets ?? []).filter((f) => !f.includedWithPlugin);
117
+ const facetState = plugin.config?.facets ?? {};
118
+ const offHere = !!unit?.disabled.has(plugin.id);
119
+ const moduleOn = unit ? !offHere : plugin.isActive;
120
+ const href = settingsHref?.();
121
+ const cog = (target, label) => target && onOpenSettings ? /* @__PURE__ */ jsx(
122
+ Button,
123
+ {
124
+ variant: "bare",
125
+ size: "bare",
126
+ type: "button",
127
+ onClick: () => onOpenSettings(target),
128
+ "aria-label": `Configurar ${label}`,
129
+ title: `Configurar ${label}`,
130
+ className: "font-normal whitespace-normal flex h-11 w-11 shrink-0 items-center justify-center rounded-button text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
131
+ children: /* @__PURE__ */ jsx(Settings, { className: "h-4 w-4" })
132
+ }
133
+ ) : null;
134
+ return /* @__PURE__ */ jsxs(Card, { className: cn(blocked && "opacity-60", unit && offHere && "border-dashed"), children: [
135
+ /* @__PURE__ */ jsxs(CardHeader, { className: "flex-row items-start justify-between gap-4 space-y-0", children: [
136
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
137
+ /* @__PURE__ */ jsx(Icon, { className: "mt-0.5 h-5 w-5 shrink-0 text-muted-foreground" }),
138
+ /* @__PURE__ */ jsxs("div", { children: [
139
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
140
+ /* @__PURE__ */ jsx(CardTitle, { className: "text-base", children: plugin.name }),
141
+ appLabel ? /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "shrink-0 font-normal", children: appLabel }) : null
142
+ ] }),
143
+ plugin.description ? /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: plugin.description }) : null,
144
+ price || unit ? /* @__PURE__ */ jsxs("p", { className: "mt-1.5 flex flex-wrap items-center gap-x-3 gap-y-1 text-sm", children: [
145
+ price ? /* @__PURE__ */ jsx("span", { className: "font-medium tabular-nums", children: price }) : null,
146
+ unit ? /* @__PURE__ */ jsxs("span", { className: cn("inline-flex items-center gap-1", offHere ? "text-foreground" : "text-muted-foreground"), children: [
147
+ /* @__PURE__ */ jsx(Building2, { className: "h-3.5 w-3.5", "aria-hidden": true }),
148
+ offHere ? `Desligado em ${unit.unitName}` : "Herdado da rede"
149
+ ] }) : null
150
+ ] }) : null
151
+ ] })
152
+ ] }),
153
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [
154
+ cog(href, plugin.name),
155
+ blocked ? /* @__PURE__ */ jsxs(Badge, { variant: "outline", className: "shrink-0 gap-1", children: [
156
+ /* @__PURE__ */ jsx(Crown, { className: "h-3 w-3" }),
157
+ " No plano maior"
158
+ ] }) : /* @__PURE__ */ jsx(
159
+ Switch,
160
+ {
161
+ checked: moduleOn,
162
+ disabled: busy || !unit && locked,
163
+ "aria-label": `${moduleOn ? "Desligar" : "Ligar"} ${plugin.name}${unit ? ` em ${unit.unitName}` : ""}`,
164
+ onCheckedChange: (next) => void (unit ? unit.onToggle : onToggle)(plugin.id, next ? "active" : "disabled")
165
+ }
166
+ )
167
+ ] })
168
+ ] }),
169
+ /* @__PURE__ */ jsxs(CardContent, { className: "space-y-3 pt-0", children: [
170
+ screens.length > 0 ? /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground", children: [
171
+ plugin.isActive ? "Some do menu se desligar: " : "Aparece no menu: ",
172
+ /* @__PURE__ */ jsx("span", { className: "text-foreground", children: screens.slice(0, 5).join(" \xB7 ") }),
173
+ screens.length > 5 ? ` e mais ${screens.length - 5}` : ""
174
+ ] }) : null,
175
+ locked && !unit ? /* @__PURE__ */ jsxs("p", { className: "flex items-center gap-1.5 text-sm text-muted-foreground", children: [
176
+ /* @__PURE__ */ jsx(Lock, { className: "h-3.5 w-3.5 shrink-0" }),
177
+ neededBy.join(", "),
178
+ " ",
179
+ neededBy.length > 1 ? "dependem" : "depende",
180
+ " deste m\xF3dulo. Desligue",
181
+ " ",
182
+ neededBy.length > 1 ? "esses" : "esse",
183
+ " primeiro."
184
+ ] }) : null,
185
+ plugin.isActive && moduleOn && facets.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
186
+ /* @__PURE__ */ jsx(Separator, {}),
187
+ /* @__PURE__ */ jsx("div", { className: "space-y-2", children: facets.map((facet) => {
188
+ const accountOn = facetState[facet.id] === true;
189
+ if (unit && !accountOn) return null;
190
+ const facetOn = unit ? !unit.disabled.has(`${plugin.id}.${facet.id}`) : accountOn;
191
+ const fPrice = facetPrice?.(facet.id);
192
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
193
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
194
+ /* @__PURE__ */ jsxs("p", { className: "text-sm", children: [
195
+ facet.label,
196
+ fPrice ? /* @__PURE__ */ jsxs("span", { className: "ml-2 text-xs tabular-nums text-muted-foreground", children: [
197
+ "+ ",
198
+ fPrice
199
+ ] }) : null
200
+ ] }),
201
+ facet.description ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: facet.description }) : null
202
+ ] }),
203
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [
204
+ facetOn ? cog(settingsHref?.(facet.id), facet.label) : null,
205
+ /* @__PURE__ */ jsx(
206
+ Switch,
207
+ {
208
+ checked: facetOn,
209
+ disabled: busy,
210
+ "aria-label": `${facetOn ? "Desligar" : "Ligar"} ${facet.label}${unit ? ` em ${unit.unitName}` : ""}`,
211
+ onCheckedChange: (next) => void (unit ? unit.onToggle : onToggle)(plugin.id, next ? "active" : "disabled", facet.id)
212
+ }
213
+ )
214
+ ] })
215
+ ] }, facet.id);
216
+ }) })
217
+ ] }) : null,
218
+ plugin.isActive && !unit && addons.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
219
+ /* @__PURE__ */ jsx(Separator, {}),
220
+ /* @__PURE__ */ jsx("div", { className: "space-y-3", children: addons.map((addon) => {
221
+ const addonBlocked = !addon.permitted && !addon.plugin.isActive;
222
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex items-center justify-between gap-4", addonBlocked && "opacity-60"), children: [
223
+ /* @__PURE__ */ jsxs("div", { children: [
224
+ /* @__PURE__ */ jsx("p", { className: "text-sm", children: addon.plugin.name }),
225
+ addon.plugin.description ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: addon.plugin.description }) : addon.screens.length > 0 ? /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
226
+ "Adiciona ao menu: ",
227
+ addon.screens.join(" \xB7 ")
228
+ ] }) : null
229
+ ] }),
230
+ addonBlocked ? /* @__PURE__ */ jsxs(Badge, { variant: "outline", className: "shrink-0 gap-1", children: [
231
+ /* @__PURE__ */ jsx(Crown, { className: "h-3 w-3" }),
232
+ " No plano maior"
233
+ ] }) : /* @__PURE__ */ jsx(
234
+ Switch,
235
+ {
236
+ checked: addon.plugin.isActive,
237
+ disabled: busy,
238
+ "aria-label": `${addon.plugin.isActive ? "Desligar" : "Ligar"} ${addon.plugin.name}`,
239
+ onCheckedChange: (next) => void onToggle(addon.plugin.id, next ? "active" : "disabled")
240
+ }
241
+ )
242
+ ] }, addon.plugin.id);
243
+ }) })
244
+ ] }) : null
245
+ ] })
246
+ ] });
247
+ }
248
+ function AddModulesPanel({
249
+ open,
250
+ onOpenChange,
251
+ categories,
252
+ onToggle,
253
+ busy
254
+ }) {
255
+ return /* @__PURE__ */ jsx(Modal, { open, onOpenChange, children: /* @__PURE__ */ jsxs(ModalContent, { size: "2xl", children: [
256
+ /* @__PURE__ */ jsxs(ModalHeader, { children: [
257
+ /* @__PURE__ */ jsx(ModalTitle, { children: "Adicionar m\xF3dulo" }),
258
+ /* @__PURE__ */ jsx(ModalDescription, { children: "O que o produto oferece, por ramo de neg\xF3cio. Ligar um m\xF3dulo p\xF5e as telas dele no menu." })
259
+ ] }),
260
+ /* @__PURE__ */ jsx(ModuleCatalogSections, { categories, onToggle, busy })
261
+ ] }) });
262
+ }
263
+ function ModuleCatalogSections({
264
+ categories,
265
+ onToggle,
266
+ busy
267
+ }) {
268
+ const [query, setQuery] = React3.useState("");
269
+ const total = categories.reduce((n, c) => n + c.rows.length, 0);
270
+ const searchable = total > 6;
271
+ const filtered = React3.useMemo(() => filterCategories(categories, query), [categories, query]);
272
+ if (categories.length === 0) {
273
+ return /* @__PURE__ */ jsxs("div", { className: "py-8 text-center", children: [
274
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground", children: "Nada a adicionar" }),
275
+ /* @__PURE__ */ jsx("p", { className: "mx-auto mt-1 max-w-sm text-sm text-muted-foreground", children: "Esta conta j\xE1 tem ligado tudo o que o produto oferece para ela." })
276
+ ] });
277
+ }
278
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
279
+ searchable ? /* @__PURE__ */ jsxs("div", { className: "relative", children: [
280
+ /* @__PURE__ */ jsx(Search, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }),
281
+ /* @__PURE__ */ jsx(
282
+ Input,
283
+ {
284
+ value: query,
285
+ onChange: (e) => setQuery(e.target.value),
286
+ placeholder: "Buscar m\xF3dulo",
287
+ className: "rounded-lg border-border bg-background pl-9"
288
+ }
289
+ )
290
+ ] }) : null,
291
+ /* @__PURE__ */ jsx("div", { className: "-mx-1 max-h-[55vh] space-y-3 overflow-y-auto px-1", children: filtered.length === 0 ? /* @__PURE__ */ jsxs("p", { className: "py-8 text-center text-sm text-muted-foreground", children: [
292
+ 'Nenhum m\xF3dulo com "',
293
+ query,
294
+ '".'
295
+ ] }) : filtered.map((category) => /* @__PURE__ */ jsx(
296
+ CategorySection,
297
+ {
298
+ category,
299
+ forceOpen: query.trim().length > 0,
300
+ onToggle,
301
+ busy
302
+ },
303
+ category.id
304
+ )) })
305
+ ] });
306
+ }
307
+ function CategorySection({
308
+ category,
309
+ forceOpen,
310
+ onToggle,
311
+ busy
312
+ }) {
313
+ const [open, setOpen] = React3.useState(category.mine);
314
+ const expanded = open || forceOpen;
315
+ const Chevron = expanded ? ChevronDown : ChevronRight;
316
+ return /* @__PURE__ */ jsxs("section", { children: [
317
+ /* @__PURE__ */ jsxs(
318
+ Button,
319
+ {
320
+ variant: "bare",
321
+ size: "bare",
322
+ type: "button",
323
+ onClick: () => setOpen(!expanded),
324
+ "aria-expanded": expanded,
325
+ className: "flex w-full items-center gap-2 rounded-button py-1.5 text-left transition-colors hover:bg-muted/40 justify-start whitespace-normal text-[length:inherit] font-normal",
326
+ children: [
327
+ /* @__PURE__ */ jsx(Chevron, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
328
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-foreground", children: category.label }),
329
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
330
+ "(",
331
+ category.rows.length,
332
+ ")"
333
+ ] })
334
+ ]
335
+ }
336
+ ),
337
+ expanded ? /* @__PURE__ */ jsx("div", { className: "space-y-3 pt-2", children: category.rows.map((row) => /* @__PURE__ */ jsx(ModuleCard, { row, onToggle, busy }, row.plugin.id)) }) : null
338
+ ] });
339
+ }
340
+ function filterCategories(categories, query) {
341
+ const needle = query.trim().toLowerCase();
342
+ if (!needle) return categories;
343
+ const matches = (row) => `${row.plugin.name} ${row.plugin.description ?? ""}`.toLowerCase().includes(needle);
344
+ return categories.map((category) => ({ ...category, rows: category.rows.filter(matches) })).filter((category) => category.rows.length > 0);
345
+ }
346
+ function ModulesPreview() {
347
+ const runtime = usePluginRuntime();
348
+ const preset = useAppPreset();
349
+ const rows = React3.useMemo(() => {
350
+ const flat = runtime.navigation.filter((entry) => entry.section !== "settings").map((entry) => toRailRow(entry, preset.labels));
351
+ return applyRailPreset(flat, preset.rail, preset.hide, preset.whole);
352
+ }, [runtime.navigation, preset.rail, preset.hide, preset.whole, preset.labels]);
353
+ return /* @__PURE__ */ jsxs("div", { className: "sticky top-4 overflow-hidden rounded-2xl border border-sidebar-border bg-sidebar p-3", children: [
354
+ /* @__PURE__ */ jsx("p", { className: "mb-2 px-2 text-xs font-medium text-sidebar-muted", children: "Pr\xE9via do menu" }),
355
+ rows.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-2 py-6 text-center text-xs text-sidebar-muted", children: "Nenhum m\xF3dulo ligado ainda." }) : /* @__PURE__ */ jsx("nav", { className: "space-y-0.5", children: rows.map((row) => /* @__PURE__ */ jsx(PreviewRow, { row }, row.id)) })
356
+ ] });
357
+ }
358
+ function toRailRow(entry, labels) {
359
+ return {
360
+ id: entry.id ?? entry.route,
361
+ label: labelFor(labels, entry.route, entry.label),
362
+ route: entry.route,
363
+ icon: entry.icon ?? "Circle",
364
+ section: entry.section,
365
+ pluginId: entry.pluginId
366
+ };
367
+ }
368
+ function PreviewRow({ row, depth = 0 }) {
369
+ const Icon = depth === 0 ? getLucideIcon(row.icon) ?? Home : null;
370
+ const hasChildren = !!row.children?.length;
371
+ return /* @__PURE__ */ jsxs("div", { children: [
372
+ /* @__PURE__ */ jsxs(
373
+ "div",
374
+ {
375
+ className: cn(
376
+ "flex items-center gap-2 rounded-lg px-2 py-1.5 text-sm text-sidebar-foreground/80",
377
+ depth === 0 && "hover:bg-sidebar-accent/60 hover:text-sidebar-accent-foreground"
378
+ ),
379
+ style: depth > 0 ? { paddingLeft: 12 + depth * 16 } : void 0,
380
+ children: [
381
+ Icon ? /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 shrink-0" }) : null,
382
+ /* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: row.label }),
383
+ hasChildren ? /* @__PURE__ */ jsx(ChevronRight, { className: "h-3.5 w-3.5 shrink-0 text-sidebar-muted" }) : null
384
+ ]
385
+ }
386
+ ),
387
+ row.children?.map((child) => /* @__PURE__ */ jsx(PreviewRow, { row: child, depth: depth + 1 }, child.id))
388
+ ] });
389
+ }
390
+ function ModulesSettings({ hidden = [], onToggle, permits, busy, catalog = [], onUnitToggle }) {
391
+ const runtime = usePluginRuntime();
392
+ const scope = useSettingsUnitScope();
393
+ const unitId = onUnitToggle ? scope.unitId : null;
394
+ const unitName = useUnitStore((s) => s.units.find((u) => u.id === unitId)?.name);
395
+ const config = useAppConfigStore((s) => s.config);
396
+ const unit = React3.useMemo(() => unitId && onUnitToggle ? {
397
+ unitName: unitName ?? "esta unidade",
398
+ disabled: unitDisabledModules(config, unitId),
399
+ onToggle: (plugin, status, facet) => onUnitToggle(unitId, plugin, status, facet)
400
+ } : void 0, [unitId, unitName, config, onUnitToggle]);
401
+ const settingsHref = (plugin) => (facet) => moduleSettingsHref(runtime.settingsTabs, plugin, facet);
402
+ const offered = useOfferedPlugins();
403
+ const [adding, setAdding] = React3.useState(false);
404
+ const rows = React3.useMemo(() => {
405
+ const known = catalog.length ? new Set(catalog.flatMap((app) => app.modules)) : new Set(offered);
406
+ const inCatalogue = known.size ? runtime.plugins.filter((p) => known.has(p.id) || p.isActive) : runtime.plugins;
407
+ return buildRows(inCatalogue, new Set(hidden), permits);
408
+ }, [runtime.plugins, hidden, permits, offered, catalog]);
409
+ const trades = React3.useMemo(() => accountTrades(config.apps ?? []), [config.apps]);
410
+ const pkg = React3.useMemo(
411
+ () => packageFor({ trades, modules: rows.filter((r) => r.plugin.isActive).map((r) => r.plugin.id) }),
412
+ [trades, rows]
413
+ );
414
+ const chosen = React3.useMemo(() => new Set(config.plugins.filter((p) => !p.facet && p.status === "active" && ["manual", "plan", "trial", "agent"].includes(p.source)).map((p) => p.plugin)), [config.plugins]);
415
+ const { has: on, usedByOthers } = React3.useMemo(
416
+ () => splitAccountModules(rows, { trades, chosen }),
417
+ [rows, trades, chosen]
418
+ );
419
+ const upcoming = React3.useMemo(
420
+ () => unit ? [] : COMING_SOON_MODULES.filter((k) => trades.length === 0 || moduleFitsTrades(k, trades)),
421
+ [unit, trades]
422
+ );
423
+ const families = MODULE_FAMILIES.map((f) => ({
424
+ family: f,
425
+ rows: on.filter((r) => moduleFamilyOf(r.plugin.id) === f.id),
426
+ upcoming: upcoming.filter((k) => moduleFamilyOf(k) === f.id)
427
+ })).filter((g) => g.rows.length > 0 || g.upcoming.length > 0);
428
+ const off = React3.useMemo(() => rows.filter((r) => !r.plugin.isActive), [rows]);
429
+ const categories = React3.useMemo(() => buildCategories(catalog, off), [catalog, off]);
430
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-8", children: [
431
+ onUnitToggle && /* @__PURE__ */ jsx(UnitScopePicker, {}),
432
+ !unit && /* @__PURE__ */ jsx(PageHeaderActions, { children: /* @__PURE__ */ jsxs(Button, { size: "sm", className: "shrink-0 gap-1.5", onClick: () => setAdding(true), children: [
433
+ /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }),
434
+ " Adicionar"
435
+ ] }) }),
436
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-8 lg:grid-cols-[minmax(0,1fr)_260px]", children: [
437
+ /* @__PURE__ */ jsxs("section", { className: "space-y-3", children: [
438
+ /* @__PURE__ */ jsxs("div", { children: [
439
+ /* @__PURE__ */ jsxs("h3", { className: "text-sm font-medium", children: [
440
+ unit ? `Em ${unit.unitName}` : "Ligados",
441
+ " (",
442
+ unit ? on.filter((r) => !unit.disabled.has(r.plugin.id)).length : on.length,
443
+ unit ? ` de ${on.length}` : "",
444
+ ")"
445
+ ] }),
446
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: unit ? `Cada unidade herda o que a rede tem. Desligar aqui vale s\xF3 para ${unit.unitName}: a tela mostra o aviso em vez de abrir, e as outras unidades continuam.` : "O que esta conta usa hoje. Desligar tira as telas do menu; os dados continuam onde est\xE3o." })
447
+ ] }),
448
+ on.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "rounded-xl border border-dashed border-border p-8 text-center", children: [
449
+ /* @__PURE__ */ jsx("p", { className: "font-medium text-foreground", children: "Nenhum m\xF3dulo ligado" }),
450
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: 'Abra o cat\xE1logo em "Adicionar" para escolher o que esta conta vai usar.' })
451
+ ] }) : families.map(({ family, rows: familyRows, upcoming: soon }) => /* @__PURE__ */ jsxs("div", { className: "space-y-3 pt-2", children: [
452
+ /* @__PURE__ */ jsxs("div", { className: "px-1", children: [
453
+ /* @__PURE__ */ jsx("h4", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: tl(...family.label) }),
454
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: tl(...family.line) })
455
+ ] }),
456
+ familyRows.map((row) => /* @__PURE__ */ jsx(
457
+ ModuleCard,
458
+ {
459
+ row,
460
+ onToggle,
461
+ busy,
462
+ appLabel: appLabelFor(catalog, row.plugin.id),
463
+ unit,
464
+ price: modulePriceLabel(row.plugin.id, void 0, pkg),
465
+ facetPrice: (facet) => modulePriceLabel(row.plugin.id, facet, pkg),
466
+ settingsHref: settingsHref(row.plugin.id),
467
+ onOpenSettings: navigateTo
468
+ },
469
+ row.plugin.id
470
+ )),
471
+ soon.map((k) => /* @__PURE__ */ jsx(UpcomingModuleRow, { moduleKey: k }, k))
472
+ ] }, family.id)),
473
+ usedByOthers.length > 0 && /* @__PURE__ */ jsxs("p", { className: "px-1 text-xs text-muted-foreground", children: [
474
+ "Tamb\xE9m rodam, sem custo, porque outro m\xF3dulo precisa:",
475
+ " ",
476
+ usedByOthers.map(({ row, by }) => `${row.plugin.name}${by.length ? ` (usado por ${by.join(", ")})` : ""}`).join(" \xB7 "),
477
+ "."
478
+ ] })
479
+ ] }),
480
+ /* @__PURE__ */ jsx(ModulesPreview, {})
481
+ ] }),
482
+ /* @__PURE__ */ jsx(
483
+ AddModulesPanel,
484
+ {
485
+ open: adding,
486
+ onOpenChange: setAdding,
487
+ categories,
488
+ onToggle,
489
+ busy
490
+ }
491
+ )
492
+ ] });
493
+ }
494
+ var SHELL_PLUGINS = ["admin", "dashboard", "notifications", "tasks"];
495
+ function ConnectedModulesSettings({ hidden = SHELL_PLUGINS }) {
496
+ const { refresh } = useAppConfig();
497
+ const access = useAccessOptional();
498
+ const catalog = useModuleCatalog();
499
+ const tenantId = useOrganizationStore((s) => s.currentOrg?.id ?? null);
500
+ const [busy, setBusy] = React3.useState(false);
501
+ const onToggle = React3.useCallback(
502
+ async (plugin, status, facet) => {
503
+ const supabase = getSupabaseClientOptional();
504
+ if (!supabase) return;
505
+ setBusy(true);
506
+ try {
507
+ const { error } = await supabase.rpc("tenant_plugin_set", {
508
+ p_plugin: plugin,
509
+ p_status: status,
510
+ p_facet: facet ?? ""
511
+ });
512
+ if (error) throw error;
513
+ if (tenantId) {
514
+ invalidateAppConfig(tenantId);
515
+ clearAppConfigSnapshot(tenantId);
516
+ }
517
+ await refresh();
518
+ toast.success(status === "active" ? "M\xF3dulo ligado" : "M\xF3dulo desligado");
519
+ } catch (err) {
520
+ toast.error("N\xE3o foi poss\xEDvel mudar o m\xF3dulo", { description: err?.hint ?? err?.message });
521
+ } finally {
522
+ setBusy(false);
523
+ }
524
+ },
525
+ [refresh, tenantId]
526
+ );
527
+ const onUnitToggle = React3.useCallback(
528
+ async (unitId, plugin, status, facet) => {
529
+ const supabase = getSupabaseClientOptional();
530
+ if (!supabase) return;
531
+ setBusy(true);
532
+ try {
533
+ const { error } = await supabase.rpc("unit_plugin_set", {
534
+ p_unit: unitId,
535
+ p_plugin: plugin,
536
+ p_facet: facet ?? "",
537
+ p_status: status
538
+ });
539
+ if (error) throw error;
540
+ if (tenantId) {
541
+ invalidateAppConfig(tenantId);
542
+ clearAppConfigSnapshot(tenantId);
543
+ }
544
+ await refresh();
545
+ toast.success(status === "active" ? "Volta a valer o da rede nesta unidade" : "Desligado nesta unidade");
546
+ } catch (err) {
547
+ toast.error("N\xE3o foi poss\xEDvel mudar a unidade", { description: err?.hint ?? err?.message });
548
+ } finally {
549
+ setBusy(false);
550
+ }
551
+ },
552
+ [refresh, tenantId]
553
+ );
554
+ const permits = React3.useCallback(
555
+ (plugin) => access ? access.can(plugin, "read").allowed || access.entitled(plugin) : true,
556
+ [access]
557
+ );
558
+ return /* @__PURE__ */ jsx(ModulesSettings, { hidden, onToggle, onUnitToggle, permits, busy, catalog });
559
+ }
560
+
561
+ export { ConnectedModulesSettings };
562
+ //# sourceMappingURL=ConnectedModulesSettings-A2VJ5BMJ.js.map
563
+ //# sourceMappingURL=ConnectedModulesSettings-A2VJ5BMJ.js.map