@fayz-ai/admin 0.36.0 → 0.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ScheduleEditor-VGDE57L2.js +7 -0
- package/dist/{ScheduleEditor-VJYYNGSV.js.map → ScheduleEditor-VGDE57L2.js.map} +1 -1
- package/dist/{chunk-HZGF5N3A.js → chunk-TRDVM4ZO.js} +3 -2
- package/dist/chunk-TRDVM4ZO.js.map +1 -0
- package/dist/crud/BankField.d.ts +1 -1
- package/dist/crud/BankField.d.ts.map +1 -1
- package/dist/crud/CrudPage.d.ts.map +1 -1
- package/dist/crud/RelatedSection.d.ts +2 -0
- package/dist/crud/RelatedSection.d.ts.map +1 -1
- package/dist/crud/archetype-lookup.d.ts +26 -0
- package/dist/crud/archetype-lookup.d.ts.map +1 -1
- package/dist/crud/archetypes/OrderFormView.d.ts +1 -0
- package/dist/crud/archetypes/OrderFormView.d.ts.map +1 -1
- package/dist/crud/archetypes/PayeeAccountsSection.d.ts +1 -1
- package/dist/crud/archetypes/PayeeAccountsSection.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +309 -44
- package/dist/index.js.map +1 -1
- package/dist/units/data.d.ts.map +1 -1
- package/dist/units/useUnitFilter.d.ts.map +1 -1
- package/package.json +5 -5
- package/dist/ScheduleEditor-VJYYNGSV.js +0 -7
- package/dist/chunk-HZGF5N3A.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -10,8 +10,8 @@ export { openEntity, resolveEntityAnchor, resolveEntityHref, resolveEntityRoute
|
|
|
10
10
|
import { useAdminPath, navigateTo, normalizeAdminPath, routeScore, matchRoute } from './chunk-VX3WJLKK.js';
|
|
11
11
|
export { navigateTo as adminNavigateTo, useAdminPath } from './chunk-VX3WJLKK.js';
|
|
12
12
|
export { ImportWizard } from './chunk-46UABOOC.js';
|
|
13
|
-
import { createArchetypeLookup, getPersonLookup } from './chunk-
|
|
14
|
-
export { ScheduleDateExceptions, ScheduleEditor, ScheduleGridPanel, createArchetypeLookup, deleteSchedule, getPersonBookable, getPersonLookup, getScheduleBlockConfig, getSchedules, mergeBlockSettings, parseBlockSettings, registerPersonLookup, replaceWeeklySchedules, saveSchedule, setPersonBookable, setScheduleBlockConfig, subscribeScheduleBlockConfig } from './chunk-
|
|
13
|
+
import { createArchetypeLookup, getPersonLookup } from './chunk-TRDVM4ZO.js';
|
|
14
|
+
export { ScheduleDateExceptions, ScheduleEditor, ScheduleGridPanel, createArchetypeLookup, deleteSchedule, getPersonBookable, getPersonLookup, getScheduleBlockConfig, getSchedules, mergeBlockSettings, parseBlockSettings, registerPersonLookup, replaceWeeklySchedules, saveSchedule, setPersonBookable, setScheduleBlockConfig, subscribeScheduleBlockConfig } from './chunk-TRDVM4ZO.js';
|
|
15
15
|
import { getFayzSupabaseClientOptional, getSupabaseClientOptional as getSupabaseClientOptional$1, useAppConfigStore, activePluginIds, hasPlugin, useWorkspaceSwitchingStore, searchWorkspaces, OrgMark, WorkspaceChooserGate, WorkspaceSwitchingHost, createFayzSupabaseClient, resolveAppId, createSupabaseOrgAdapter, createMockOrgAdapter, getFayzSupabaseClient } from './chunk-4YF6R7T3.js';
|
|
16
16
|
export { OrgMark, activePluginIds, createFayzSupabaseClient, createMockOrgAdapter, createSupabaseOrgAdapter, getFayzSupabaseClient, getFayzSupabaseClientOptional, hasPlugin, orgInitials, useAppConfigStore } from './chunk-4YF6R7T3.js';
|
|
17
17
|
import { readOrgSnapshot, useTenantOptional, useOrgAdapter, useTenant, OrgProvider, useOrgAdapterOptional } from './chunk-IDOTNT43.js';
|
|
@@ -32,7 +32,7 @@ import { useAuthStore, useAuth, buildAppHandoffUrl } from '@fayz-ai/auth';
|
|
|
32
32
|
export { useAuth } from '@fayz-ai/auth';
|
|
33
33
|
import { create, useStore as useStore$1 } from 'zustand';
|
|
34
34
|
import * as LucideIcons from 'lucide-react';
|
|
35
|
-
import { Pencil, Trash2, Upload, Search, ArrowDown, ArrowUp, ArrowUpDown, Check, Download, ChevronLeft, ChevronRight, AlertTriangle, Building2, Inbox, Package, Sparkles, Plug, DollarSign, Clock, X, WandSparkles, Loader2, ArrowDownToLine, ArrowUpFromLine, CheckCircle2, Crown, ArrowRight, History, SquarePen, Settings2, Mic, User, Plus, Minus, ListChecks, ChevronDown, ArrowLeft, Calendar, ClipboardList, CheckSquare, BookOpen, Lock, PinOff, Pin, Eye, Users, StickyNote, CheckSquare2, Square, RotateCcw,
|
|
35
|
+
import { Pencil, Copy, Trash2, Upload, Search, ArrowDown, ArrowUp, ArrowUpDown, Check, Download, ChevronLeft, ChevronRight, AlertTriangle, Building2, Inbox, Package, Sparkles, Plug, DollarSign, Clock, X, WandSparkles, Loader2, ArrowDownToLine, ArrowUpFromLine, CheckCircle2, Crown, ArrowRight, History, SquarePen, Settings2, Mic, User, Plus, Minus, ListChecks, ChevronDown, ArrowLeft, Calendar, ClipboardList, CheckSquare, BookOpen, Lock, PinOff, Pin, Eye, Users, StickyNote, CheckSquare2, Square, RotateCcw, Globe, LayoutTemplate, Store, ChevronsUpDown, ExternalLink, PenSquare, RefreshCw, XCircle, Camera, Edit, Star, Link2Off, Layers, ShoppingBag, MoreHorizontal, ChevronUp, List, LayoutGrid, CircleDollarSign, Receipt, Settings, Mail, MessageCircle, Cake, HelpCircle, Wrench, ShieldCheck, MessageSquare, Paperclip, Infinity, CheckCheck, PartyPopper, Compass, Play, MapPin, Landmark, LocateFixed, ArrowUpCircle, ArrowUpRight, Pause, CalendarDays, CircleCheckBig, UserX, Ban, CircleAlert, CircleEllipsis, FileText, CircleDashed, Power, ArrowRightLeft, File as File$1, FileImage, FileSpreadsheet, AlertCircle, CreditCard, SlidersHorizontal, Puzzle, Shield, Palette, Blocks, ShieldAlert, UserCog, LogOut, Bell, Database, Radio, Zap, Save, ImagePlus, UserPlus, Contact, UserMinus, Send, Sun, Moon, Monitor, Languages, Info, Link2, KeyRound, Bug, Home, Heart, Briefcase, BarChart3, Tag, Truck, Globe2 } from 'lucide-react';
|
|
36
36
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
37
37
|
import { createPortal } from 'react-dom';
|
|
38
38
|
import { profileHasSystemPermission, mergeLimitDeclarations } from '@fayz-ai/core/access';
|
|
@@ -4078,7 +4078,9 @@ async function fetchUnitBootstrap(tenantId2, deviceId) {
|
|
|
4078
4078
|
{ unitColumn: v?.unit_column ?? "unit_id", shareable: v?.shareable !== false }
|
|
4079
4079
|
])
|
|
4080
4080
|
),
|
|
4081
|
-
|
|
4081
|
+
// user_unit_ids_in walks the tree with UNION over (id, depth): a branch
|
|
4082
|
+
// reached directly AND through its HQ comes back twice.
|
|
4083
|
+
reachable: Array.isArray(raw.reachable) ? [...new Set(raw.reachable)] : void 0,
|
|
4082
4084
|
devicePin: { set: Boolean(raw.device_pin_set), unitId: raw.device_pin ?? null },
|
|
4083
4085
|
accountPin: { set: Boolean(raw.account_pin_set), unitId: raw.account_pin ?? null }
|
|
4084
4086
|
};
|
|
@@ -22799,6 +22801,10 @@ function PayeeAccountsSection({
|
|
|
22799
22801
|
const [form, setForm] = useState(EMPTY_FORM2);
|
|
22800
22802
|
const [saving, setSaving] = useState(false);
|
|
22801
22803
|
const [deleting, setDeleting] = useState(null);
|
|
22804
|
+
const can = usePermissionOptional();
|
|
22805
|
+
const canRead = can("financial", "read");
|
|
22806
|
+
const canEdit = can("financial", "edit");
|
|
22807
|
+
const canDelete = can("financial", "delete");
|
|
22802
22808
|
const db2 = () => getSupabaseClientOptional();
|
|
22803
22809
|
const load = useCallback(async () => {
|
|
22804
22810
|
const client3 = db2();
|
|
@@ -22872,6 +22878,7 @@ function PayeeAccountsSection({
|
|
|
22872
22878
|
await load();
|
|
22873
22879
|
toast.success(t("crud.archetype.payeeAccounts.deleted"));
|
|
22874
22880
|
};
|
|
22881
|
+
if (!canRead) return null;
|
|
22875
22882
|
if (loading) {
|
|
22876
22883
|
return /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsxs(CardContent, { className: "space-y-2 py-6", children: [
|
|
22877
22884
|
/* @__PURE__ */ jsx("div", { className: "h-4 w-56 animate-pulse rounded bg-muted/40" }),
|
|
@@ -22887,7 +22894,7 @@ function PayeeAccountsSection({
|
|
|
22887
22894
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
22888
22895
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
22889
22896
|
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold", children: t("crud.archetype.payeeAccounts.title") }),
|
|
22890
|
-
/* @__PURE__ */ jsxs(
|
|
22897
|
+
canEdit && /* @__PURE__ */ jsxs(
|
|
22891
22898
|
Button,
|
|
22892
22899
|
{
|
|
22893
22900
|
type: "button",
|
|
@@ -22928,7 +22935,7 @@ function PayeeAccountsSection({
|
|
|
22928
22935
|
(a.holder_name || a.holder_document) && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: [a.holder_name, a.holder_document].filter(Boolean).join(" \xB7 ") })
|
|
22929
22936
|
] }),
|
|
22930
22937
|
/* @__PURE__ */ jsxs("div", { className: "flex shrink-0 gap-1", children: [
|
|
22931
|
-
/* @__PURE__ */ jsx(
|
|
22938
|
+
canEdit && /* @__PURE__ */ jsx(
|
|
22932
22939
|
Button,
|
|
22933
22940
|
{
|
|
22934
22941
|
type: "button",
|
|
@@ -22943,7 +22950,7 @@ function PayeeAccountsSection({
|
|
|
22943
22950
|
children: /* @__PURE__ */ jsx(Pencil, { className: "h-3.5 w-3.5" })
|
|
22944
22951
|
}
|
|
22945
22952
|
),
|
|
22946
|
-
/* @__PURE__ */ jsx(
|
|
22953
|
+
canDelete && /* @__PURE__ */ jsx(
|
|
22947
22954
|
Button,
|
|
22948
22955
|
{
|
|
22949
22956
|
type: "button",
|
|
@@ -23472,21 +23479,77 @@ function RelatedSection({ parentId, related, compact }) {
|
|
|
23472
23479
|
}
|
|
23473
23480
|
}
|
|
23474
23481
|
const shown = child.fields.filter((f) => f.showInTable !== false);
|
|
23482
|
+
const groupKey = related.duplicable ? child.fields.find((f) => f.type === "relation")?.key : void 0;
|
|
23483
|
+
const [lastEdit, setLastEdit] = React127.useState(null);
|
|
23484
|
+
function siblingsToSync(row, key) {
|
|
23485
|
+
if (!groupKey || key === groupKey || row[groupKey] == null) return [];
|
|
23486
|
+
return rows.filter((r) => r.id !== row.id && r[groupKey] === row[groupKey] && r[key] !== row[key]);
|
|
23487
|
+
}
|
|
23488
|
+
async function applyToSiblings(row, key) {
|
|
23489
|
+
const alvos = siblingsToSync(row, key);
|
|
23490
|
+
if (!alvos.length) return;
|
|
23491
|
+
const value = row[key];
|
|
23492
|
+
const ids = new Set(alvos.map((r) => r.id));
|
|
23493
|
+
const antes = rows;
|
|
23494
|
+
setRows((prev) => prev.map((r) => ids.has(r.id) ? { ...r, [key]: value } : r));
|
|
23495
|
+
setLastEdit(null);
|
|
23496
|
+
if (orfa) return;
|
|
23497
|
+
try {
|
|
23498
|
+
await Promise.all(alvos.map((r) => provider2.update(r.id, { [key]: value })));
|
|
23499
|
+
} catch (e) {
|
|
23500
|
+
setRows(antes);
|
|
23501
|
+
toast.error(errorMessage(e));
|
|
23502
|
+
}
|
|
23503
|
+
}
|
|
23475
23504
|
async function patch(id, key, value, price) {
|
|
23476
23505
|
const antes = rows.find((r) => r.id === id);
|
|
23477
23506
|
if (!antes) return;
|
|
23507
|
+
if (key !== groupKey) setLastEdit({ id, key });
|
|
23478
23508
|
const mudanca = { [key]: value, ...heranca(key, price, { ...antes, [key]: value }) };
|
|
23479
23509
|
if (Object.entries(mudanca).every(([k, v]) => antes[k] === v)) return;
|
|
23480
23510
|
setRows((prev) => prev.map((r) => r.id === id ? { ...r, ...mudanca } : r));
|
|
23481
23511
|
if (orfa) return;
|
|
23482
|
-
|
|
23483
|
-
|
|
23484
|
-
|
|
23485
|
-
|
|
23486
|
-
|
|
23487
|
-
}
|
|
23512
|
+
queueWrite(id, mudanca, antes);
|
|
23513
|
+
}
|
|
23514
|
+
const escritas = React127.useRef(/* @__PURE__ */ new Map());
|
|
23515
|
+
function queueWrite(id, mudanca, antes) {
|
|
23516
|
+
const atual = escritas.current.get(id);
|
|
23517
|
+
const entry = atual ?? { mudanca: {}, antes, fila: Promise.resolve() };
|
|
23518
|
+
entry.mudanca = { ...entry.mudanca, ...mudanca };
|
|
23519
|
+
if (entry.timer) clearTimeout(entry.timer);
|
|
23520
|
+
entry.timer = setTimeout(() => flushWrite(id), 400);
|
|
23521
|
+
escritas.current.set(id, entry);
|
|
23522
|
+
}
|
|
23523
|
+
function flushWrite(id) {
|
|
23524
|
+
const entry = escritas.current.get(id);
|
|
23525
|
+
if (!entry || !Object.keys(entry.mudanca).length) return;
|
|
23526
|
+
const { mudanca, antes } = entry;
|
|
23527
|
+
entry.mudanca = {};
|
|
23528
|
+
entry.timer = void 0;
|
|
23529
|
+
entry.fila = entry.fila.then(async () => {
|
|
23530
|
+
try {
|
|
23531
|
+
await provider2.update(id, mudanca);
|
|
23532
|
+
} catch (e) {
|
|
23533
|
+
setRows((prev) => prev.map((r) => r.id === id ? antes : r));
|
|
23534
|
+
toast.error(errorMessage(e));
|
|
23535
|
+
}
|
|
23536
|
+
});
|
|
23537
|
+
const fila = entry.fila;
|
|
23538
|
+
void fila.then(() => {
|
|
23539
|
+
const e = escritas.current.get(id);
|
|
23540
|
+
if (e && e.fila === fila && !e.timer) escritas.current.delete(id);
|
|
23541
|
+
});
|
|
23488
23542
|
}
|
|
23543
|
+
React127.useEffect(() => () => {
|
|
23544
|
+
for (const [id, e] of escritas.current) {
|
|
23545
|
+
if (e.timer) {
|
|
23546
|
+
clearTimeout(e.timer);
|
|
23547
|
+
flushWrite(id);
|
|
23548
|
+
}
|
|
23549
|
+
}
|
|
23550
|
+
}, []);
|
|
23489
23551
|
const required = child.fields.filter((f) => f.required);
|
|
23552
|
+
const criando = React127.useRef(false);
|
|
23490
23553
|
async function commitDraft(key, next, price) {
|
|
23491
23554
|
const completo = { ...next, ...heranca(key, price, next) };
|
|
23492
23555
|
setDraft(completo);
|
|
@@ -23495,17 +23558,36 @@ function RelatedSection({ parentId, related, compact }) {
|
|
|
23495
23558
|
);
|
|
23496
23559
|
const pronto = { ...defaults, ...completo };
|
|
23497
23560
|
if (required.some((f) => pronto[f.key] == null || pronto[f.key] === "")) return;
|
|
23561
|
+
if (criando.current) return;
|
|
23498
23562
|
if (orfa) {
|
|
23499
23563
|
setRows((prev) => [...prev, { id: `draft-${prev.length}-${completo[key]}`, ...pronto }]);
|
|
23500
23564
|
setDraft(null);
|
|
23501
23565
|
return;
|
|
23502
23566
|
}
|
|
23567
|
+
criando.current = true;
|
|
23503
23568
|
try {
|
|
23504
23569
|
await provider2.create(pronto);
|
|
23505
23570
|
setDraft(null);
|
|
23506
23571
|
await load();
|
|
23507
23572
|
} catch (e) {
|
|
23508
23573
|
toast.error(errorMessage(e));
|
|
23574
|
+
} finally {
|
|
23575
|
+
criando.current = false;
|
|
23576
|
+
}
|
|
23577
|
+
}
|
|
23578
|
+
async function duplicate(row) {
|
|
23579
|
+
const copia = Object.fromEntries(
|
|
23580
|
+
child.fields.filter((f) => row[f.key] !== void 0).map((f) => [f.key, row[f.key]])
|
|
23581
|
+
);
|
|
23582
|
+
if (orfa) {
|
|
23583
|
+
setRows((prev) => [...prev, { ...copia, id: `draft-${prev.length}-copy` }]);
|
|
23584
|
+
return;
|
|
23585
|
+
}
|
|
23586
|
+
try {
|
|
23587
|
+
await provider2.create(copia);
|
|
23588
|
+
await load();
|
|
23589
|
+
} catch (e) {
|
|
23590
|
+
toast.error(errorMessage(e));
|
|
23509
23591
|
}
|
|
23510
23592
|
}
|
|
23511
23593
|
function heranca(fieldKey, price, linha) {
|
|
@@ -23608,25 +23690,57 @@ function RelatedSection({ parentId, related, compact }) {
|
|
|
23608
23690
|
error ? /* @__PURE__ */ jsx("p", { className: "rounded-lg border border-destructive/30 bg-destructive-soft px-3 py-2 text-xs text-destructive-soft-foreground", children: error }) : loading ? /* @__PURE__ */ jsx("div", { className: "h-8 w-40 animate-pulse rounded bg-muted/40" }) : rows.length === 0 && draft === null ? /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(CardContent, { className: compact ? "py-3" : "py-4", children: /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: related.emptyHint ?? "\u2014" }) }) }) : /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(CardContent, { className: "overflow-x-auto p-0", children: /* @__PURE__ */ jsxs("table", { className: "w-full min-w-[26rem] text-xs", children: [
|
|
23609
23691
|
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "border-b text-left text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: [
|
|
23610
23692
|
shown.map((f) => /* @__PURE__ */ jsx("th", { className: "px-3 py-2 font-medium", children: f.label }, f.key)),
|
|
23611
|
-
/* @__PURE__ */ jsx("th", { className: "w-10 px-3 py-2" })
|
|
23693
|
+
/* @__PURE__ */ jsx("th", { className: related.duplicable ? "w-16 px-3 py-2" : "w-10 px-3 py-2" })
|
|
23612
23694
|
] }) }),
|
|
23613
23695
|
/* @__PURE__ */ jsxs("tbody", { children: [
|
|
23614
23696
|
rows.map((row) => /* @__PURE__ */ jsxs("tr", { className: "border-b last:border-0", children: [
|
|
23615
|
-
shown.map((f) => /* @__PURE__ */
|
|
23616
|
-
|
|
23617
|
-
|
|
23618
|
-
|
|
23619
|
-
|
|
23620
|
-
|
|
23621
|
-
|
|
23622
|
-
|
|
23623
|
-
|
|
23624
|
-
|
|
23625
|
-
|
|
23626
|
-
|
|
23627
|
-
|
|
23628
|
-
|
|
23629
|
-
|
|
23697
|
+
shown.map((f) => /* @__PURE__ */ jsxs("td", { className: "px-3 py-1.5 align-middle", children: [
|
|
23698
|
+
cell(f, row[f.key], (next, price) => {
|
|
23699
|
+
void patch(row.id, f.key, next, price);
|
|
23700
|
+
}, row),
|
|
23701
|
+
lastEdit?.id === row.id && lastEdit?.key === f.key && siblingsToSync(row, f.key).length > 0 && /* @__PURE__ */ jsxs(
|
|
23702
|
+
"button",
|
|
23703
|
+
{
|
|
23704
|
+
type: "button",
|
|
23705
|
+
onClick: () => {
|
|
23706
|
+
void applyToSiblings(row, f.key);
|
|
23707
|
+
},
|
|
23708
|
+
className: "mt-1 text-[11px] font-medium text-primary hover:underline",
|
|
23709
|
+
children: [
|
|
23710
|
+
"Aplicar para todos (",
|
|
23711
|
+
siblingsToSync(row, f.key).length,
|
|
23712
|
+
")"
|
|
23713
|
+
]
|
|
23714
|
+
}
|
|
23715
|
+
)
|
|
23716
|
+
] }, f.key)),
|
|
23717
|
+
/* @__PURE__ */ jsxs("td", { className: "whitespace-nowrap px-3 py-1.5 text-right", children: [
|
|
23718
|
+
related.duplicable && /* @__PURE__ */ jsx(
|
|
23719
|
+
"button",
|
|
23720
|
+
{
|
|
23721
|
+
type: "button",
|
|
23722
|
+
"aria-label": `${label3}: duplicar`,
|
|
23723
|
+
title: "Duplicar",
|
|
23724
|
+
onClick: () => {
|
|
23725
|
+
void duplicate(row);
|
|
23726
|
+
},
|
|
23727
|
+
className: "rounded-md p-1 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
23728
|
+
children: /* @__PURE__ */ jsx(Copy, { className: "h-3.5 w-3.5" })
|
|
23729
|
+
}
|
|
23730
|
+
),
|
|
23731
|
+
/* @__PURE__ */ jsx(
|
|
23732
|
+
"button",
|
|
23733
|
+
{
|
|
23734
|
+
type: "button",
|
|
23735
|
+
"aria-label": `${label3}: remover`,
|
|
23736
|
+
onClick: () => {
|
|
23737
|
+
void remove(row.id);
|
|
23738
|
+
},
|
|
23739
|
+
className: "rounded-md p-1 text-muted-foreground transition-colors hover:bg-muted hover:text-destructive",
|
|
23740
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5" })
|
|
23741
|
+
}
|
|
23742
|
+
)
|
|
23743
|
+
] })
|
|
23630
23744
|
] }, row.id)),
|
|
23631
23745
|
draft !== null && /* @__PURE__ */ jsxs("tr", { className: "border-b last:border-0 bg-muted/20", children: [
|
|
23632
23746
|
shown.map((f) => /* @__PURE__ */ jsx("td", { className: "px-3 py-1.5 align-middle", children: cell(
|
|
@@ -23698,6 +23812,27 @@ function RelatedSection({ parentId, related, compact }) {
|
|
|
23698
23812
|
)
|
|
23699
23813
|
] });
|
|
23700
23814
|
}
|
|
23815
|
+
async function copyRelatedRows(related, fromParentId, toParentId) {
|
|
23816
|
+
const data = related.entity.data;
|
|
23817
|
+
if (!data) return;
|
|
23818
|
+
const fk = columnOf(related.entity, related.foreignKey);
|
|
23819
|
+
const reader = resolveDataProvider(
|
|
23820
|
+
{ ...related.entity, data: { ...data, filters: { ...data.filters ?? {}, [fk]: fromParentId } } },
|
|
23821
|
+
[],
|
|
23822
|
+
{ cache: false }
|
|
23823
|
+
);
|
|
23824
|
+
const writer = resolveDataProvider(
|
|
23825
|
+
{ ...related.entity, data: { ...data, defaults: { ...data.defaults ?? {}, [fk]: toParentId } } },
|
|
23826
|
+
[],
|
|
23827
|
+
{ cache: false }
|
|
23828
|
+
);
|
|
23829
|
+
const result = await reader.list({ page: 1, pageSize: 500 });
|
|
23830
|
+
const keys = related.entity.fields.map((f) => f.key).filter((k) => k !== related.foreignKey);
|
|
23831
|
+
for (const row of result?.data ?? []) {
|
|
23832
|
+
const copia = Object.fromEntries(keys.filter((k) => row[k] !== void 0).map((k) => [k, row[k]]));
|
|
23833
|
+
await writer.create({ ...copia, [related.foreignKey]: toParentId });
|
|
23834
|
+
}
|
|
23835
|
+
}
|
|
23701
23836
|
var PRICING_FIELDS = /* @__PURE__ */ new Set(["price", "cost", "currency", "unit"]);
|
|
23702
23837
|
var STOCK_FIELDS = /* @__PURE__ */ new Set(["stock", "minStock"]);
|
|
23703
23838
|
var SKIP_FIELDS2 = /* @__PURE__ */ new Set(["status", "isActive", "tags", "imageUrl", "name", "description", "sku", "category"]);
|
|
@@ -24391,6 +24526,8 @@ function BankField({
|
|
|
24391
24526
|
const t = useTranslation();
|
|
24392
24527
|
const v = value ?? {};
|
|
24393
24528
|
const withMethod = { ...v, method: v.method ?? payeeMethodOf(v) };
|
|
24529
|
+
const canEdit = usePermissionOptional()("financial", "edit");
|
|
24530
|
+
if (!canEdit) return null;
|
|
24394
24531
|
return /* @__PURE__ */ jsxs(
|
|
24395
24532
|
AttachedFieldSection,
|
|
24396
24533
|
{
|
|
@@ -25757,6 +25894,8 @@ function useUnitFilter(options = {}) {
|
|
|
25757
25894
|
const myUnitIds = useUnitStore((s) => s.myUnitIds);
|
|
25758
25895
|
const activeUnitId = useUnitStore((s) => s.activeUnitId);
|
|
25759
25896
|
const beginSwitch = useUnitSwitchingStore((s) => s.begin);
|
|
25897
|
+
const can = usePermissionOptional();
|
|
25898
|
+
const canManageUnits = can("units", "manage");
|
|
25760
25899
|
const reachable = React127.useMemo(() => unitFilterOptions(units, myUnitIds), [units, myUnitIds]);
|
|
25761
25900
|
const [local2, setLocal] = React127.useState(activeUnitId);
|
|
25762
25901
|
React127.useEffect(() => {
|
|
@@ -25783,8 +25922,13 @@ function useUnitFilter(options = {}) {
|
|
|
25783
25922
|
options: reachable.map((u) => ({ value: u.id, label: u.name })),
|
|
25784
25923
|
value,
|
|
25785
25924
|
onChange: setValue,
|
|
25786
|
-
|
|
25787
|
-
|
|
25925
|
+
// Unit names are typed, not scrolled for — search even for a short list.
|
|
25926
|
+
searchable: true,
|
|
25927
|
+
searchPlaceholder: label(t, "units.search", "Buscar unidade"),
|
|
25928
|
+
manage: canManageUnits ? { label: label(t, "units.manage", "Gerenciar unidades"), onSelect: () => {
|
|
25929
|
+
window.location.hash = "#/settings/locations";
|
|
25930
|
+
} } : void 0
|
|
25931
|
+
} : null, [visible, filterLabel, allLabel, reachable, value, setValue, canManageUnits, t]);
|
|
25788
25932
|
return { visible, value: visible ? value : unitMode ? activeUnitId : void 0, setValue, options: reachable, label: filterLabel, allLabel, def };
|
|
25789
25933
|
}
|
|
25790
25934
|
var ALL_TAB = "__all__";
|
|
@@ -26467,6 +26611,13 @@ function useCrudColumns(entityDef, options) {
|
|
|
26467
26611
|
onSelect: () => setCrudHash(options.basePath, id, "edit"),
|
|
26468
26612
|
hidden: options.feature ? !can(options.feature, "edit") : false
|
|
26469
26613
|
},
|
|
26614
|
+
...options.onDuplicate ? [{
|
|
26615
|
+
id: "duplicate",
|
|
26616
|
+
label: t("crud.list.duplicate"),
|
|
26617
|
+
icon: Copy,
|
|
26618
|
+
onSelect: () => options.onDuplicate(row.original),
|
|
26619
|
+
hidden: options.feature ? !can(options.feature, "create") : false
|
|
26620
|
+
}] : [],
|
|
26470
26621
|
...options.onDelete ? [{
|
|
26471
26622
|
id: "delete",
|
|
26472
26623
|
label: t("common.delete"),
|
|
@@ -26481,7 +26632,7 @@ function useCrudColumns(entityDef, options) {
|
|
|
26481
26632
|
});
|
|
26482
26633
|
}
|
|
26483
26634
|
return tanCols;
|
|
26484
|
-
}, [cols, displayField, options?.basePath, options?.onDelete, options?.feature, options?.readOnly, t, can]);
|
|
26635
|
+
}, [cols, displayField, options?.basePath, options?.onDelete, options?.onDuplicate, options?.feature, options?.readOnly, t, can]);
|
|
26485
26636
|
}
|
|
26486
26637
|
function CrudPage({ entityDef: rawEntityDef, useStore: useStore2, basePath, display, feature, readOnly, navTabs, activeNavTab, stats, embedded, emptyHint, aiCreate }) {
|
|
26487
26638
|
const store = useStore2();
|
|
@@ -26572,7 +26723,33 @@ function CrudPage({ entityDef: rawEntityDef, useStore: useStore2, basePath, disp
|
|
|
26572
26723
|
const handleInlineUpdate = useCallback(async (id, field, value) => {
|
|
26573
26724
|
await store.update(id, { [field]: value });
|
|
26574
26725
|
}, [store]);
|
|
26575
|
-
const
|
|
26726
|
+
const handleDuplicate = useCallback(async (row) => {
|
|
26727
|
+
try {
|
|
26728
|
+
const display2 = entityDef.displayField ?? entityDef.fields[0]?.key;
|
|
26729
|
+
const copia = Object.fromEntries(
|
|
26730
|
+
entityDef.fields.filter((f) => f.showInForm !== false && row[f.key] !== void 0).map((f) => [f.key, row[f.key]])
|
|
26731
|
+
);
|
|
26732
|
+
if (display2 && typeof copia[display2] === "string") copia[display2] = `${copia[display2]} ${t("crud.list.copySuffix")}`;
|
|
26733
|
+
const created = await store.create(copia);
|
|
26734
|
+
for (const related of entityDef.relatedSections ?? []) {
|
|
26735
|
+
await copyRelatedRows(related, row.id, created.id);
|
|
26736
|
+
}
|
|
26737
|
+
toast.success(t("crud.list.duplicated", { entity: entityDef.name }));
|
|
26738
|
+
setCrudHash(normalizedBasePath, created.id, "edit");
|
|
26739
|
+
} catch (err) {
|
|
26740
|
+
toast.error(err instanceof Error ? err.message : String(err));
|
|
26741
|
+
}
|
|
26742
|
+
}, [entityDef, store, t, normalizedBasePath]);
|
|
26743
|
+
const tanColumns = useCrudColumns(entityDef, {
|
|
26744
|
+
basePath: normalizedBasePath,
|
|
26745
|
+
onDelete: readOnly ? void 0 : (item) => setDeleteItem(item),
|
|
26746
|
+
onDuplicate: readOnly || !entityDef.duplicable ? void 0 : (item) => {
|
|
26747
|
+
void handleDuplicate(item);
|
|
26748
|
+
},
|
|
26749
|
+
onInlineUpdate: handleInlineUpdate,
|
|
26750
|
+
feature,
|
|
26751
|
+
readOnly
|
|
26752
|
+
});
|
|
26576
26753
|
const currentOrgId = useOrganizationStore((s) => s.currentOrg?.id);
|
|
26577
26754
|
const guardImport = useLimitGuard(entityDef.limitKey ?? "");
|
|
26578
26755
|
useEffect(() => {
|
|
@@ -27850,7 +28027,7 @@ function PersonAvailabilityTab({ item }) {
|
|
|
27850
28027
|
] }) });
|
|
27851
28028
|
}
|
|
27852
28029
|
var ScheduleEditor2 = React127__default.lazy(
|
|
27853
|
-
() => import('./ScheduleEditor-
|
|
28030
|
+
() => import('./ScheduleEditor-VGDE57L2.js').then((m) => ({ default: m.ScheduleEditor }))
|
|
27854
28031
|
);
|
|
27855
28032
|
var PersonTimeline2 = React127__default.lazy(
|
|
27856
28033
|
() => import('./timeline-LECYQ4IA.js').then((m) => ({ default: m.PersonTimeline }))
|
|
@@ -35854,7 +36031,7 @@ function OrderDetailView(props) {
|
|
|
35854
36031
|
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: tile.label }),
|
|
35855
36032
|
tile.icon && /* @__PURE__ */ jsx(tile.icon, { className: "h-4 w-4 shrink-0 text-muted-foreground/70" })
|
|
35856
36033
|
] }),
|
|
35857
|
-
/* @__PURE__ */ jsx("
|
|
36034
|
+
/* @__PURE__ */ jsx("div", { className: "mt-1 truncate text-lg font-semibold", children: tile.value })
|
|
35858
36035
|
] }, tile.id ?? i)) }),
|
|
35859
36036
|
banner && /* @__PURE__ */ jsxs("div", { className: banner.tone === "warning" ? "flex items-center gap-3 rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-900" : "flex items-center gap-3 rounded-lg border border-border bg-muted/40 px-4 py-3 text-sm", children: [
|
|
35860
36037
|
/* @__PURE__ */ jsx(AlertTriangle, { className: "h-4 w-4 shrink-0" }),
|
|
@@ -36130,7 +36307,8 @@ var ITEM_LABELS = {
|
|
|
36130
36307
|
done: "Conclu\xEDdo",
|
|
36131
36308
|
create: "Cadastrar",
|
|
36132
36309
|
clear: "Limpar",
|
|
36133
|
-
edit: "Editar"
|
|
36310
|
+
edit: "Editar",
|
|
36311
|
+
manage: "Gerenciar cadastro"
|
|
36134
36312
|
};
|
|
36135
36313
|
function OrderFormItemRow({
|
|
36136
36314
|
index,
|
|
@@ -36167,6 +36345,11 @@ function OrderFormItemRow({
|
|
|
36167
36345
|
() => (extraFieldGroups ?? []).filter((g) => g.filled).map((g) => g.id)
|
|
36168
36346
|
);
|
|
36169
36347
|
const lookup = entityLookups[itemKind];
|
|
36348
|
+
const awaitingCode = !!lookup?.byCode && !referenceId;
|
|
36349
|
+
const pickOnlyRow = pickOnly || awaitingCode;
|
|
36350
|
+
const can = usePermissionOptional();
|
|
36351
|
+
const manage = lookup?.manage;
|
|
36352
|
+
const canManage = !!manage && (!manage.permission || can(manage.permission.feature, manage.permission.action ?? "edit"));
|
|
36170
36353
|
const itemCreate = useLookupCreate(lookup, (created) => {
|
|
36171
36354
|
onChange({
|
|
36172
36355
|
referenceId: created.id,
|
|
@@ -36205,12 +36388,12 @@ function OrderFormItemRow({
|
|
|
36205
36388
|
},
|
|
36206
36389
|
g.id
|
|
36207
36390
|
)),
|
|
36208
|
-
!
|
|
36391
|
+
!pickOnlyRow && /* @__PURE__ */ jsxs("span", { className: "fz-tight-hide shrink-0 text-xs text-muted-foreground tabular-nums", children: [
|
|
36209
36392
|
quantity,
|
|
36210
36393
|
" \xD7 ",
|
|
36211
36394
|
formatMoney(unitPrice)
|
|
36212
36395
|
] }),
|
|
36213
|
-
!
|
|
36396
|
+
!pickOnlyRow && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-right text-sm font-semibold tabular-nums", children: formatMoney(total) }),
|
|
36214
36397
|
!readOnly && /* @__PURE__ */ jsx(
|
|
36215
36398
|
"button",
|
|
36216
36399
|
{
|
|
@@ -36239,7 +36422,20 @@ function OrderFormItemRow({
|
|
|
36239
36422
|
tp.value
|
|
36240
36423
|
)) }),
|
|
36241
36424
|
/* @__PURE__ */ jsxs("div", { className: "fz-fields fz-fields-2", children: [
|
|
36242
|
-
/* @__PURE__ */ jsx("div", { className: "min-w-0", children: lookup ? /* @__PURE__ */ jsx(
|
|
36425
|
+
/* @__PURE__ */ jsx("div", { className: "min-w-0", children: lookup?.byCode ? /* @__PURE__ */ jsx(
|
|
36426
|
+
CodeLookupField,
|
|
36427
|
+
{
|
|
36428
|
+
byCode: lookup.byCode,
|
|
36429
|
+
resolvedLabel: referenceId ? lookup.byCode.display?.({ description }) ?? description : null,
|
|
36430
|
+
clearLabel: l.clear,
|
|
36431
|
+
onResolved: (r) => onChange({
|
|
36432
|
+
referenceId: r.id,
|
|
36433
|
+
description: r.label,
|
|
36434
|
+
...r.price != null ? { unitPrice: r.price } : {}
|
|
36435
|
+
}),
|
|
36436
|
+
onClear: () => onChange({ referenceId: void 0, description: "", unitPrice: 0 })
|
|
36437
|
+
}
|
|
36438
|
+
) : lookup ? /* @__PURE__ */ jsx(
|
|
36243
36439
|
SearchSelect,
|
|
36244
36440
|
{
|
|
36245
36441
|
label: l.item,
|
|
@@ -36263,6 +36459,8 @@ function OrderFormItemRow({
|
|
|
36263
36459
|
onCreate: itemCreate.onCreate,
|
|
36264
36460
|
onEdit: itemCreate.onEdit,
|
|
36265
36461
|
editLabel: l.edit,
|
|
36462
|
+
onManage: canManage ? () => navigateTo(manage.route) : void 0,
|
|
36463
|
+
manageLabel: manage?.label ?? l.manage,
|
|
36266
36464
|
placeholder: `${l.item}\u2026`,
|
|
36267
36465
|
renderOption: (opt) => /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
36268
36466
|
/* @__PURE__ */ jsx("p", { className: "truncate text-sm", children: opt.label }),
|
|
@@ -36284,7 +36482,7 @@ function OrderFormItemRow({
|
|
|
36284
36482
|
}
|
|
36285
36483
|
)
|
|
36286
36484
|
] }) }),
|
|
36287
|
-
!
|
|
36485
|
+
!pickOnlyRow && /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 gap-3", children: [
|
|
36288
36486
|
/* @__PURE__ */ jsxs("div", { className: "w-16 shrink-0", children: [
|
|
36289
36487
|
/* @__PURE__ */ jsx("label", { className: "text-[10px] font-medium text-muted-foreground", children: l.qty }),
|
|
36290
36488
|
/* @__PURE__ */ jsx(
|
|
@@ -36312,7 +36510,7 @@ function OrderFormItemRow({
|
|
|
36312
36510
|
) })
|
|
36313
36511
|
] })
|
|
36314
36512
|
] }),
|
|
36315
|
-
showAdjustments && !
|
|
36513
|
+
showAdjustments && !pickOnlyRow && /* @__PURE__ */ jsxs("div", { className: "flex items-end gap-3", children: [
|
|
36316
36514
|
/* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(
|
|
36317
36515
|
CurrencyInput,
|
|
36318
36516
|
{
|
|
@@ -36350,7 +36548,7 @@ function OrderFormItemRow({
|
|
|
36350
36548
|
)
|
|
36351
36549
|
] }),
|
|
36352
36550
|
extraFields,
|
|
36353
|
-
!
|
|
36551
|
+
!pickOnlyRow && (!showAdjustments || (extraFieldGroups ?? []).some((g) => !openExtras.includes(g.id))) && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-x-4 gap-y-1.5", children: [
|
|
36354
36552
|
!showAdjustments && /* @__PURE__ */ jsxs(
|
|
36355
36553
|
"button",
|
|
36356
36554
|
{
|
|
@@ -36379,7 +36577,7 @@ function OrderFormItemRow({
|
|
|
36379
36577
|
g.id
|
|
36380
36578
|
))
|
|
36381
36579
|
] }),
|
|
36382
|
-
!
|
|
36580
|
+
!pickOnlyRow && (extraFieldGroups ?? []).filter((g) => openExtras.includes(g.id)).map((g) => /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
|
|
36383
36581
|
/* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: g.field }),
|
|
36384
36582
|
g.onClear && /* @__PURE__ */ jsx(
|
|
36385
36583
|
"button",
|
|
@@ -36395,7 +36593,7 @@ function OrderFormItemRow({
|
|
|
36395
36593
|
}
|
|
36396
36594
|
)
|
|
36397
36595
|
] }, g.id)),
|
|
36398
|
-
!
|
|
36596
|
+
!pickOnlyRow && /* @__PURE__ */ jsx("div", { className: "flex justify-end pt-1", children: /* @__PURE__ */ jsxs(
|
|
36399
36597
|
"button",
|
|
36400
36598
|
{
|
|
36401
36599
|
type: "button",
|
|
@@ -36412,6 +36610,73 @@ function OrderFormItemRow({
|
|
|
36412
36610
|
] });
|
|
36413
36611
|
}
|
|
36414
36612
|
OrderFormItemRow.displayName = "OrderFormItemRow";
|
|
36613
|
+
function CodeLookupField({ byCode, resolvedLabel, clearLabel, onResolved, onClear }) {
|
|
36614
|
+
const [code, setCode] = React127.useState("");
|
|
36615
|
+
const [busy, setBusy] = React127.useState(false);
|
|
36616
|
+
const [error, setError] = React127.useState(null);
|
|
36617
|
+
async function submit() {
|
|
36618
|
+
if (!code.trim() || busy) return;
|
|
36619
|
+
setBusy(true);
|
|
36620
|
+
setError(null);
|
|
36621
|
+
try {
|
|
36622
|
+
onResolved(await byCode.resolve(code));
|
|
36623
|
+
setCode("");
|
|
36624
|
+
} catch (e) {
|
|
36625
|
+
setError(e instanceof Error ? e.message : String(e));
|
|
36626
|
+
} finally {
|
|
36627
|
+
setBusy(false);
|
|
36628
|
+
}
|
|
36629
|
+
}
|
|
36630
|
+
if (resolvedLabel) {
|
|
36631
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
36632
|
+
/* @__PURE__ */ jsx("label", { className: "text-[10px] font-medium text-muted-foreground", children: byCode.label }),
|
|
36633
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-0.5 flex items-center gap-2 rounded-input border border-input bg-muted/40 px-2.5 py-1.5", children: [
|
|
36634
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate font-mono text-sm", children: resolvedLabel }),
|
|
36635
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: onClear, "aria-label": clearLabel, className: "p-0.5 text-muted-foreground transition-colors hover:text-destructive", children: /* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5" }) })
|
|
36636
|
+
] })
|
|
36637
|
+
] });
|
|
36638
|
+
}
|
|
36639
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
36640
|
+
/* @__PURE__ */ jsx("label", { className: "text-[10px] font-medium text-muted-foreground", children: byCode.label }),
|
|
36641
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-0.5 flex gap-2", children: [
|
|
36642
|
+
/* @__PURE__ */ jsx(
|
|
36643
|
+
"input",
|
|
36644
|
+
{
|
|
36645
|
+
type: "text",
|
|
36646
|
+
value: code,
|
|
36647
|
+
autoFocus: true,
|
|
36648
|
+
autoComplete: "off",
|
|
36649
|
+
inputMode: "numeric",
|
|
36650
|
+
onChange: (e) => {
|
|
36651
|
+
setCode(e.target.value);
|
|
36652
|
+
setError(null);
|
|
36653
|
+
},
|
|
36654
|
+
onKeyDown: (e) => {
|
|
36655
|
+
if (e.key === "Enter") {
|
|
36656
|
+
e.preventDefault();
|
|
36657
|
+
void submit();
|
|
36658
|
+
}
|
|
36659
|
+
},
|
|
36660
|
+
placeholder: byCode.placeholder,
|
|
36661
|
+
"aria-invalid": !!error,
|
|
36662
|
+
className: "min-w-0 flex-1 rounded-input border border-input bg-card px-2.5 py-1.5 font-mono text-sm shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] focus:outline-none focus:ring-2 focus:ring-ring aria-[invalid=true]:border-destructive"
|
|
36663
|
+
}
|
|
36664
|
+
),
|
|
36665
|
+
/* @__PURE__ */ jsx(
|
|
36666
|
+
"button",
|
|
36667
|
+
{
|
|
36668
|
+
type: "button",
|
|
36669
|
+
onClick: () => void submit(),
|
|
36670
|
+
disabled: busy || !code.trim(),
|
|
36671
|
+
"aria-label": byCode.label,
|
|
36672
|
+
className: "fz-tap inline-flex shrink-0 items-center rounded-button border border-input bg-card px-2.5 text-muted-foreground transition-colors hover:text-foreground disabled:opacity-50",
|
|
36673
|
+
children: busy ? /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx(Search, { className: "h-4 w-4" })
|
|
36674
|
+
}
|
|
36675
|
+
)
|
|
36676
|
+
] }),
|
|
36677
|
+
error ? /* @__PURE__ */ jsx("p", { role: "alert", className: "mt-1 text-[11px] text-destructive", children: error }) : byCode.hint && /* @__PURE__ */ jsx("p", { className: "mt-1 text-[11px] text-muted-foreground", children: byCode.hint })
|
|
36678
|
+
] });
|
|
36679
|
+
}
|
|
36415
36680
|
function OrderFormAddItemStep({ itemTypes, onSelect, onCancel, label: label3 = "Que tipo de item?", cancelLabel = "Cancelar" }) {
|
|
36416
36681
|
return /* @__PURE__ */ jsxs("div", { className: "animate-in fade-in-0 slide-in-from-top-1 border-b bg-primary/5 px-4 py-3", children: [
|
|
36417
36682
|
/* @__PURE__ */ jsx("p", { className: "mb-2 text-xs font-medium text-muted-foreground", children: label3 }),
|