@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.
- package/dist/{CommandPalette-B5PMQFDG.js → CommandPalette-XDJJ5E3O.js} +3 -3
- package/dist/{CommandPalette-B5PMQFDG.js.map → CommandPalette-XDJJ5E3O.js.map} +1 -1
- package/dist/ConnectedBrandingSettings-43ZM3HCI.js +680 -0
- package/dist/ConnectedBrandingSettings-43ZM3HCI.js.map +1 -0
- package/dist/ConnectedCompanySettings-I4MALI2Q.js +197 -0
- package/dist/ConnectedCompanySettings-I4MALI2Q.js.map +1 -0
- package/dist/ConnectedModulesSettings-A2VJ5BMJ.js +563 -0
- package/dist/ConnectedModulesSettings-A2VJ5BMJ.js.map +1 -0
- package/dist/ConnectedSecuritySettings-25AHA4HJ.js +189 -0
- package/dist/ConnectedSecuritySettings-25AHA4HJ.js.map +1 -0
- package/dist/ConnectedUserProfile-E7USJRUE.js +424 -0
- package/dist/ConnectedUserProfile-E7USJRUE.js.map +1 -0
- package/dist/FieldRulesEditor-YGIPKI5T.js +129 -0
- package/dist/FieldRulesEditor-YGIPKI5T.js.map +1 -0
- package/dist/GettingStartedWidget-HMIJ3Y24.js +12 -0
- package/dist/GettingStartedWidget-HMIJ3Y24.js.map +1 -0
- package/dist/PermissionProfilesTab-3ZPRCHMZ.js +548 -0
- package/dist/PermissionProfilesTab-3ZPRCHMZ.js.map +1 -0
- package/dist/PersonTimeline-HQZT527S.js +3 -0
- package/dist/{PersonTimeline-X7JTPUWJ.js.map → PersonTimeline-HQZT527S.js.map} +1 -1
- package/dist/ProjectsSettings-7O2F27MD.js +5 -0
- package/dist/ProjectsSettings-7O2F27MD.js.map +1 -0
- package/dist/ScheduleEditor-54ELWR45.js +8 -0
- package/dist/{ScheduleEditor-L2UJXKMY.js.map → ScheduleEditor-54ELWR45.js.map} +1 -1
- package/dist/SeuSiteWidget-QLSUVC63.js +6 -0
- package/dist/SeuSiteWidget-QLSUVC63.js.map +1 -0
- package/dist/SubscriptionPage-5GE5HFJK.js +17 -0
- package/dist/{SubscriptionPage-IDVEFLZ5.js.map → SubscriptionPage-5GE5HFJK.js.map} +1 -1
- package/dist/TeamTab-6RAULFLW.js +502 -0
- package/dist/TeamTab-6RAULFLW.js.map +1 -0
- package/dist/TrialWidget-Z6CLUCU3.js +7 -0
- package/dist/TrialWidget-Z6CLUCU3.js.map +1 -0
- package/dist/app/AdminShell.d.ts.map +1 -1
- package/dist/app/admin-app.d.ts.map +1 -1
- package/dist/app/config.d.ts +14 -0
- package/dist/app/config.d.ts.map +1 -1
- package/dist/app/routing.d.ts +6 -0
- package/dist/app/routing.d.ts.map +1 -1
- package/dist/app/scaffold.d.ts.map +1 -1
- package/dist/billing/index.js +9 -4
- package/dist/chunk-2H46WDG5.js +53 -0
- package/dist/chunk-2H46WDG5.js.map +1 -0
- package/dist/chunk-3HLX7YB2.js +94 -0
- package/dist/chunk-3HLX7YB2.js.map +1 -0
- package/dist/chunk-3OUD4XBK.js +3 -0
- package/dist/chunk-3OUD4XBK.js.map +1 -0
- package/dist/{chunk-IXSY4GPK.js → chunk-5D5QLMOQ.js} +5 -3
- package/dist/chunk-5D5QLMOQ.js.map +1 -0
- package/dist/chunk-5WR62X2R.js +1081 -0
- package/dist/chunk-5WR62X2R.js.map +1 -0
- package/dist/{chunk-KPYRTOCK.js → chunk-6CQFGMEO.js} +4 -140
- package/dist/chunk-6CQFGMEO.js.map +1 -0
- package/dist/chunk-6MMSYC2I.js +116 -0
- package/dist/chunk-6MMSYC2I.js.map +1 -0
- package/dist/chunk-6QFOE3UD.js +1466 -0
- package/dist/chunk-6QFOE3UD.js.map +1 -0
- package/dist/chunk-6UUFVQ2E.js +283 -0
- package/dist/chunk-6UUFVQ2E.js.map +1 -0
- package/dist/chunk-7WNLL3F6.js +7889 -0
- package/dist/chunk-7WNLL3F6.js.map +1 -0
- package/dist/chunk-A74IHAQE.js +439 -0
- package/dist/chunk-A74IHAQE.js.map +1 -0
- package/dist/{chunk-JOBRLBIQ.js → chunk-AFA6IO23.js} +4 -3
- package/dist/chunk-AFA6IO23.js.map +1 -0
- package/dist/{chunk-P5UIGQFY.js → chunk-ALCSIN3Z.js} +5 -5
- package/dist/chunk-ALCSIN3Z.js.map +1 -0
- package/dist/chunk-AWM4AMBS.js +39 -0
- package/dist/chunk-AWM4AMBS.js.map +1 -0
- package/dist/{chunk-OQARLKZN.js → chunk-BG5Z6KLN.js} +6 -18
- package/dist/chunk-BG5Z6KLN.js.map +1 -0
- package/dist/chunk-DPNFZONC.js +19 -0
- package/dist/chunk-DPNFZONC.js.map +1 -0
- package/dist/chunk-DRCV643L.js +193 -0
- package/dist/chunk-DRCV643L.js.map +1 -0
- package/dist/chunk-E6DF3VR6.js +206 -0
- package/dist/chunk-E6DF3VR6.js.map +1 -0
- package/dist/chunk-ENHCVGXZ.js +120 -0
- package/dist/chunk-ENHCVGXZ.js.map +1 -0
- package/dist/chunk-FK6RHGI7.js +56 -0
- package/dist/chunk-FK6RHGI7.js.map +1 -0
- package/dist/chunk-G5HNA5QK.js +233 -0
- package/dist/chunk-G5HNA5QK.js.map +1 -0
- package/dist/chunk-HCFO4Z6A.js +53 -0
- package/dist/chunk-HCFO4Z6A.js.map +1 -0
- package/dist/chunk-JFIU6NQP.js +51 -0
- package/dist/chunk-JFIU6NQP.js.map +1 -0
- package/dist/chunk-JRZJBMOY.js +3 -0
- package/dist/chunk-JRZJBMOY.js.map +1 -0
- package/dist/{chunk-3YP7KW47.js → chunk-JVVOL4BB.js} +41 -512
- package/dist/chunk-JVVOL4BB.js.map +1 -0
- package/dist/chunk-KAQ3UIAA.js +415 -0
- package/dist/chunk-KAQ3UIAA.js.map +1 -0
- package/dist/{chunk-P6XUDT2P.js → chunk-KJELMULA.js} +4 -51
- package/dist/chunk-KJELMULA.js.map +1 -0
- package/dist/chunk-KLO7DKXX.js +1651 -0
- package/dist/chunk-KLO7DKXX.js.map +1 -0
- package/dist/chunk-M2CMDWUI.js +75 -0
- package/dist/chunk-M2CMDWUI.js.map +1 -0
- package/dist/chunk-PQ47MLTH.js +255 -0
- package/dist/chunk-PQ47MLTH.js.map +1 -0
- package/dist/{chunk-VX3WJLKK.js → chunk-QD7BMUDF.js} +17 -8
- package/dist/chunk-QD7BMUDF.js.map +1 -0
- package/dist/{chunk-E4MESMNR.js → chunk-QTSKCPSW.js} +7 -10
- package/dist/chunk-QTSKCPSW.js.map +1 -0
- package/dist/chunk-S56FQKPL.js +186 -0
- package/dist/chunk-S56FQKPL.js.map +1 -0
- package/dist/chunk-SGAFPNMA.js +75 -0
- package/dist/chunk-SGAFPNMA.js.map +1 -0
- package/dist/{chunk-OD7P4L3D.js → chunk-SOKCLVM4.js} +3 -3
- package/dist/{chunk-OD7P4L3D.js.map → chunk-SOKCLVM4.js.map} +1 -1
- package/dist/chunk-TL42NKTH.js +3 -0
- package/dist/chunk-TL42NKTH.js.map +1 -0
- package/dist/chunk-U6ZCO2PS.js +2964 -0
- package/dist/chunk-U6ZCO2PS.js.map +1 -0
- package/dist/chunk-VSXNROYH.js +16 -0
- package/dist/chunk-VSXNROYH.js.map +1 -0
- package/dist/chunk-WPFZCYZL.js +619 -0
- package/dist/chunk-WPFZCYZL.js.map +1 -0
- package/dist/chunk-XFTNIBDW.js +23 -0
- package/dist/chunk-XFTNIBDW.js.map +1 -0
- package/dist/chunk-Y66JDL6I.js +1020 -0
- package/dist/chunk-Y66JDL6I.js.map +1 -0
- package/dist/chunk-YEHIBPIX.js +137 -0
- package/dist/chunk-YEHIBPIX.js.map +1 -0
- package/dist/chunk-YKPPCV2Z.js +53 -0
- package/dist/chunk-YKPPCV2Z.js.map +1 -0
- package/dist/components/chat/markdown.d.ts.map +1 -1
- package/dist/components/plugins/PluginSettingsPanel.d.ts.map +1 -1
- package/dist/components/settings/SettingsPage.d.ts.map +1 -1
- package/dist/connect-XKQJOWR7.js +18 -0
- package/dist/connect-XKQJOWR7.js.map +1 -0
- package/dist/crud/CrudDetailPage.d.ts.map +1 -1
- package/dist/crud/CrudListView.d.ts.map +1 -1
- package/dist/crud/CrudPage.d.ts.map +1 -1
- package/dist/crud/RelatedListTab.d.ts.map +1 -1
- package/dist/crud/archetypes/EntityLink.d.ts +1 -1
- package/dist/crud/archetypes/EntityLink.d.ts.map +1 -1
- package/dist/crud/record-chrome.d.ts.map +1 -1
- package/dist/entity-routes-PGU7EHAD.js +4 -0
- package/dist/{entity-routes-LXOBW5IB.js.map → entity-routes-PGU7EHAD.js.map} +1 -1
- package/dist/hooks/useModuleNavigation.d.ts.map +1 -1
- package/dist/impersonation/ImpersonateDialog.d.ts.map +1 -1
- package/dist/impersonation/session.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11902 -33551
- package/dist/index.js.map +1 -1
- package/dist/lib/entity-routes.d.ts.map +1 -1
- package/dist/org/index.js +4 -2
- package/dist/plugins/PluginRegistryManager.d.ts.map +1 -1
- package/dist/settings/MessageTemplateRow.d.ts.map +1 -1
- package/dist/timeline/PersonTimeline.d.ts.map +1 -1
- package/dist/timeline/TimelineList.d.ts.map +1 -1
- package/dist/units/UnitRailPage.d.ts.map +1 -1
- package/dist/units/useUnitFilter.d.ts.map +1 -1
- package/package.json +5 -5
- package/dist/PersonTimeline-X7JTPUWJ.js +0 -3
- package/dist/ScheduleEditor-L2UJXKMY.js +0 -6
- package/dist/SubscriptionPage-IDVEFLZ5.js +0 -8
- package/dist/chunk-3YP7KW47.js.map +0 -1
- package/dist/chunk-E4MESMNR.js.map +0 -1
- package/dist/chunk-IXSY4GPK.js.map +0 -1
- package/dist/chunk-JOBRLBIQ.js.map +0 -1
- package/dist/chunk-KPYRTOCK.js.map +0 -1
- package/dist/chunk-OQARLKZN.js.map +0 -1
- package/dist/chunk-P5UIGQFY.js.map +0 -1
- package/dist/chunk-P6XUDT2P.js.map +0 -1
- package/dist/chunk-VX3WJLKK.js.map +0 -1
- package/dist/entity-routes-LXOBW5IB.js +0 -4
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
import { useMyPersonId, fetchMyPersonRecord, CrudDetailPage, findMyPersonCandidate, linkPersonToLogin } from './chunk-7WNLL3F6.js';
|
|
2
|
+
import './chunk-AWM4AMBS.js';
|
|
3
|
+
import './chunk-6QFOE3UD.js';
|
|
4
|
+
import './chunk-FK6RHGI7.js';
|
|
5
|
+
import './chunk-PQ47MLTH.js';
|
|
6
|
+
import { useUnitBootstrap } from './chunk-DPNFZONC.js';
|
|
7
|
+
import './chunk-E6DF3VR6.js';
|
|
8
|
+
import './chunk-HCFO4Z6A.js';
|
|
9
|
+
import './chunk-S56FQKPL.js';
|
|
10
|
+
import { useTranslation } from './chunk-YUHCC7JY.js';
|
|
11
|
+
import { toast } from './chunk-3OUD4XBK.js';
|
|
12
|
+
import './chunk-VSXNROYH.js';
|
|
13
|
+
import './chunk-M2CMDWUI.js';
|
|
14
|
+
import './chunk-6CQFGMEO.js';
|
|
15
|
+
import './chunk-ALCSIN3Z.js';
|
|
16
|
+
import './chunk-BG5Z6KLN.js';
|
|
17
|
+
import './chunk-SGAFPNMA.js';
|
|
18
|
+
import './chunk-KLO7DKXX.js';
|
|
19
|
+
import './chunk-TL42NKTH.js';
|
|
20
|
+
import { dedup, useUnitStore } from './chunk-5D5QLMOQ.js';
|
|
21
|
+
import { usePermissionsStore } from './chunk-UQ2NTFQC.js';
|
|
22
|
+
import { getFayzSupabaseClientOptional, getFayzSupabaseClient } from './chunk-KJELMULA.js';
|
|
23
|
+
import { cn } from './chunk-JRZJBMOY.js';
|
|
24
|
+
import { useOrganizationStore } from './chunk-YKPPCV2Z.js';
|
|
25
|
+
import './chunk-QD7BMUDF.js';
|
|
26
|
+
import * as React2 from 'react';
|
|
27
|
+
import { Camera, Save, AlertTriangle, Building2, Layers, Link2 } from 'lucide-react';
|
|
28
|
+
import { Skeleton, Badge, Card, CardHeader, CardTitle, CardDescription, CardContent, Avatar, AvatarImage, AvatarFallback, Button, Input, CardFooter } from '@fayz-ai/ui';
|
|
29
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
30
|
+
import { useAuthStore } from '@fayz-ai/auth';
|
|
31
|
+
import { getEntityByKey, resolveDataProvider } from '@fayz-ai/core';
|
|
32
|
+
|
|
33
|
+
function getInitials(name) {
|
|
34
|
+
return name.split(" ").map((part) => part[0]).filter(Boolean).slice(0, 2).join("").toUpperCase();
|
|
35
|
+
}
|
|
36
|
+
function UserProfile({ user, onSave, onAvatarChange }) {
|
|
37
|
+
const { t } = useTranslation();
|
|
38
|
+
const [fullName, setFullName] = React2.useState(user?.fullName ?? "");
|
|
39
|
+
const [saving, setSaving] = React2.useState(false);
|
|
40
|
+
const fileInputRef = React2.useRef(null);
|
|
41
|
+
React2.useEffect(() => {
|
|
42
|
+
if (user) {
|
|
43
|
+
setFullName(user.fullName);
|
|
44
|
+
}
|
|
45
|
+
}, [user]);
|
|
46
|
+
const handleAvatarClick = () => {
|
|
47
|
+
fileInputRef.current?.click();
|
|
48
|
+
};
|
|
49
|
+
const handleFileChange = (e) => {
|
|
50
|
+
const file = e.target.files?.[0];
|
|
51
|
+
if (file && onAvatarChange) {
|
|
52
|
+
onAvatarChange(file);
|
|
53
|
+
}
|
|
54
|
+
if (e.target) {
|
|
55
|
+
e.target.value = "";
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const handleSubmit = async (e) => {
|
|
59
|
+
e.preventDefault();
|
|
60
|
+
if (!onSave) return;
|
|
61
|
+
setSaving(true);
|
|
62
|
+
try {
|
|
63
|
+
await onSave({ fullName });
|
|
64
|
+
} finally {
|
|
65
|
+
setSaving(false);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
return /* @__PURE__ */ jsx("form", { onSubmit: handleSubmit, className: "space-y-6", children: /* @__PURE__ */ jsxs(Card, { children: [
|
|
69
|
+
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
70
|
+
/* @__PURE__ */ jsx(CardTitle, { className: "text-lg", children: t("settings.profile.title") }),
|
|
71
|
+
/* @__PURE__ */ jsx(CardDescription, { children: t("settings.profile.subtitle") })
|
|
72
|
+
] }),
|
|
73
|
+
/* @__PURE__ */ jsxs(CardContent, { className: "space-y-6", children: [
|
|
74
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-6", children: [
|
|
75
|
+
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
76
|
+
/* @__PURE__ */ jsxs(Avatar, { className: "h-20 w-20", children: [
|
|
77
|
+
/* @__PURE__ */ jsx(AvatarImage, { src: user?.avatarUrl, alt: user?.fullName }),
|
|
78
|
+
/* @__PURE__ */ jsx(AvatarFallback, { className: "text-lg", children: user?.fullName ? getInitials(user.fullName) : "?" })
|
|
79
|
+
] }),
|
|
80
|
+
onAvatarChange && /* @__PURE__ */ jsx(
|
|
81
|
+
Button,
|
|
82
|
+
{
|
|
83
|
+
variant: "bare",
|
|
84
|
+
size: "bare",
|
|
85
|
+
type: "button",
|
|
86
|
+
onClick: handleAvatarClick,
|
|
87
|
+
className: cn(
|
|
88
|
+
"absolute -bottom-1 -right-1 flex h-8 w-8 items-center justify-center rounded-full",
|
|
89
|
+
"border-2 border-background bg-primary text-primary-foreground",
|
|
90
|
+
"transition-colors hover:bg-primary/90"
|
|
91
|
+
),
|
|
92
|
+
"aria-label": "Change avatar",
|
|
93
|
+
children: /* @__PURE__ */ jsx(Camera, { className: "h-3.5 w-3.5" })
|
|
94
|
+
}
|
|
95
|
+
),
|
|
96
|
+
/* @__PURE__ */ jsx(
|
|
97
|
+
"input",
|
|
98
|
+
{
|
|
99
|
+
ref: fileInputRef,
|
|
100
|
+
type: "file",
|
|
101
|
+
accept: "image/*",
|
|
102
|
+
className: "hidden",
|
|
103
|
+
onChange: handleFileChange
|
|
104
|
+
}
|
|
105
|
+
)
|
|
106
|
+
] }),
|
|
107
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
108
|
+
/* @__PURE__ */ jsx("p", { className: "font-medium", children: user?.fullName ?? "User" }),
|
|
109
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: user?.email })
|
|
110
|
+
] })
|
|
111
|
+
] }),
|
|
112
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
113
|
+
/* @__PURE__ */ jsx("label", { htmlFor: "full-name", className: "text-sm font-medium", children: t("settings.profile.fullName") }),
|
|
114
|
+
/* @__PURE__ */ jsx(
|
|
115
|
+
Input,
|
|
116
|
+
{
|
|
117
|
+
id: "full-name",
|
|
118
|
+
value: fullName,
|
|
119
|
+
onChange: (e) => setFullName(e.target.value),
|
|
120
|
+
placeholder: "John Doe"
|
|
121
|
+
}
|
|
122
|
+
)
|
|
123
|
+
] }),
|
|
124
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
125
|
+
/* @__PURE__ */ jsx("label", { htmlFor: "email", className: "text-sm font-medium", children: t("settings.profile.email") }),
|
|
126
|
+
/* @__PURE__ */ jsx(
|
|
127
|
+
Input,
|
|
128
|
+
{
|
|
129
|
+
id: "email",
|
|
130
|
+
type: "email",
|
|
131
|
+
value: user?.email ?? "",
|
|
132
|
+
disabled: true,
|
|
133
|
+
className: "bg-muted"
|
|
134
|
+
}
|
|
135
|
+
),
|
|
136
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("settings.profile.emailHelp") })
|
|
137
|
+
] })
|
|
138
|
+
] }),
|
|
139
|
+
/* @__PURE__ */ jsx(CardFooter, { className: "justify-end", children: /* @__PURE__ */ jsxs(Button, { type: "submit", disabled: saving, children: [
|
|
140
|
+
/* @__PURE__ */ jsx(Save, { className: "mr-2 h-4 w-4" }),
|
|
141
|
+
saving ? t("common.saving") : t("settings.profile.saveProfile")
|
|
142
|
+
] }) })
|
|
143
|
+
] }) });
|
|
144
|
+
}
|
|
145
|
+
var REASON_TEXT = {
|
|
146
|
+
device: "foi a \xFAltima unidade aberta neste computador",
|
|
147
|
+
account: "foi a \xFAltima unidade que voc\xEA abriu, em outro aparelho",
|
|
148
|
+
only: "\xE9 a \xFAnica que voc\xEA alcan\xE7a",
|
|
149
|
+
manual: "voc\xEA escolheu",
|
|
150
|
+
nearest: "foi a mais perto de voc\xEA",
|
|
151
|
+
all: "voc\xEA n\xE3o estreitou nada"
|
|
152
|
+
};
|
|
153
|
+
function Field({ label, children }) {
|
|
154
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 px-6 py-4 sm:flex-row sm:items-start sm:gap-4", children: [
|
|
155
|
+
/* @__PURE__ */ jsx("span", { className: "w-28 shrink-0 pt-0.5 text-sm text-muted-foreground", children: label }),
|
|
156
|
+
/* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children })
|
|
157
|
+
] });
|
|
158
|
+
}
|
|
159
|
+
function MyWorkspaceCard() {
|
|
160
|
+
useUnitBootstrap();
|
|
161
|
+
const user = useAuthStore((s) => s.user);
|
|
162
|
+
const currentOrg = useOrganizationStore((s) => s.currentOrg);
|
|
163
|
+
const members = useOrganizationStore((s) => s.members);
|
|
164
|
+
const staffKinds = useOrganizationStore((s) => s.teamPersonKinds);
|
|
165
|
+
const profiles = usePermissionsStore((s) => s.profiles);
|
|
166
|
+
const unitMode = useUnitStore((s) => s.unitMode);
|
|
167
|
+
const byId = useUnitStore((s) => s.byId);
|
|
168
|
+
const bindings = useUnitStore((s) => s.myBindings);
|
|
169
|
+
const myUnitIds = useUnitStore((s) => s.myUnitIds);
|
|
170
|
+
const activeUnitId = useUnitStore((s) => s.activeUnitId);
|
|
171
|
+
const entryReason = useUnitStore((s) => s.entryReason);
|
|
172
|
+
const [person, setPerson] = React2.useState(void 0);
|
|
173
|
+
const [candidate, setCandidate] = React2.useState(null);
|
|
174
|
+
const [linking, setLinking] = React2.useState(false);
|
|
175
|
+
const orgId = currentOrg?.id;
|
|
176
|
+
const userId = user?.id;
|
|
177
|
+
const load = React2.useCallback(async () => {
|
|
178
|
+
if (!orgId || !userId) return;
|
|
179
|
+
const linked = await fetchMyPersonRecord(orgId, userId);
|
|
180
|
+
setPerson(linked);
|
|
181
|
+
setCandidate(linked ? null : await findMyPersonCandidate(orgId, user?.email, staffKinds));
|
|
182
|
+
}, [orgId, userId, user?.email, staffKinds]);
|
|
183
|
+
React2.useEffect(() => {
|
|
184
|
+
void load();
|
|
185
|
+
}, [load]);
|
|
186
|
+
if (!currentOrg) return null;
|
|
187
|
+
const myRole = members.find((m) => m.userId === userId)?.profileName;
|
|
188
|
+
async function link() {
|
|
189
|
+
if (!orgId || !userId || !candidate) return;
|
|
190
|
+
setLinking(true);
|
|
191
|
+
try {
|
|
192
|
+
await linkPersonToLogin(orgId, userId, candidate.id);
|
|
193
|
+
toast.success(`Login ligado ao cadastro de ${candidate.name}`);
|
|
194
|
+
await load();
|
|
195
|
+
} catch (err) {
|
|
196
|
+
toast.error("S\xF3 um administrador pode ligar um login a um cadastro", { description: err?.message });
|
|
197
|
+
} finally {
|
|
198
|
+
setLinking(false);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
const boundUnits = bindings.map((b) => ({ unit: byId[b.locationId], role: b.role })).filter((x) => Boolean(x.unit));
|
|
202
|
+
const activeUnit = activeUnitId ? byId[activeUnitId] : void 0;
|
|
203
|
+
const worthExplaining = myUnitIds.length > 1 && Boolean(REASON_TEXT[entryReason]);
|
|
204
|
+
return /* @__PURE__ */ jsxs(Card, { children: [
|
|
205
|
+
/* @__PURE__ */ jsxs(CardHeader, { children: [
|
|
206
|
+
/* @__PURE__ */ jsxs(CardTitle, { className: "text-lg", children: [
|
|
207
|
+
"Voc\xEA em ",
|
|
208
|
+
currentOrg.name
|
|
209
|
+
] }),
|
|
210
|
+
/* @__PURE__ */ jsx(CardDescription, { children: "O que vale s\xF3 aqui \u2014 sua conta em si vale em todo espa\xE7o de trabalho em que voc\xEA entra." })
|
|
211
|
+
] }),
|
|
212
|
+
/* @__PURE__ */ jsxs(CardContent, { className: "divide-y divide-border p-0", children: [
|
|
213
|
+
/* @__PURE__ */ jsx(Field, { label: "Fun\xE7\xE3o", children: /* @__PURE__ */ jsx(Badge, { variant: "secondary", children: myRole || "sem fun\xE7\xE3o definida" }) }),
|
|
214
|
+
unitMode && /* @__PURE__ */ jsx(Field, { label: boundUnits.length === 1 ? "Unidade" : "Unidades", children: boundUnits.length === 0 ? (
|
|
215
|
+
// O aviso que evita o chamado "sumiu tudo". Quem não tem vínculo
|
|
216
|
+
// com a gestão ligada não vê nada carimbado, e a tela precisa
|
|
217
|
+
// dizer isso antes da pessoa concluir que o sistema quebrou.
|
|
218
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2.5 rounded-lg border border-amber-400/40 bg-amber-400/10 p-3 text-sm", children: [
|
|
219
|
+
/* @__PURE__ */ jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-600 dark:text-amber-400" }),
|
|
220
|
+
/* @__PURE__ */ jsx("p", { children: "Voc\xEA n\xE3o est\xE1 em nenhuma unidade. Enquanto for assim, n\xE3o v\xEA agendamento, pedido nem caixa de lugar nenhum \u2014 s\xF3 o que \xE9 da organiza\xE7\xE3o inteira. Pe\xE7a a um administrador para te incluir." })
|
|
221
|
+
] })
|
|
222
|
+
) : /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
223
|
+
boundUnits.map(({ unit, role }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 text-sm", children: [
|
|
224
|
+
/* @__PURE__ */ jsx(Building2, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
|
|
225
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: unit.name }),
|
|
226
|
+
unit.id === activeUnitId && /* @__PURE__ */ jsx(Badge, { variant: "outline", className: "shrink-0 text-[10px] font-normal", children: "vendo agora" }),
|
|
227
|
+
unit.kind === "region" && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs text-muted-foreground", children: "regi\xE3o \u2014 alcan\xE7a as de dentro" }),
|
|
228
|
+
role && /* @__PURE__ */ jsxs(Badge, { variant: "secondary", className: "shrink-0 text-[10px] font-normal", children: [
|
|
229
|
+
profiles.find((p) => p.id === role)?.name ?? role,
|
|
230
|
+
" aqui"
|
|
231
|
+
] })
|
|
232
|
+
] }, unit.id)),
|
|
233
|
+
myUnitIds.length > boundUnits.length && /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
|
|
234
|
+
"Ao todo voc\xEA alcan\xE7a ",
|
|
235
|
+
myUnitIds.length,
|
|
236
|
+
" unidades, contando as que est\xE3o dentro das regi\xF5es acima."
|
|
237
|
+
] }),
|
|
238
|
+
!activeUnit && myUnitIds.length > 1 && /* @__PURE__ */ jsxs("p", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
|
|
239
|
+
/* @__PURE__ */ jsx(Layers, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
240
|
+
"Vendo todas as unidades."
|
|
241
|
+
] }),
|
|
242
|
+
worthExplaining && /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
|
|
243
|
+
activeUnit ? "Abriu aqui porque " : "Est\xE1 assim porque ",
|
|
244
|
+
REASON_TEXT[entryReason],
|
|
245
|
+
"."
|
|
246
|
+
] })
|
|
247
|
+
] }) }),
|
|
248
|
+
person === null && /* @__PURE__ */ jsx(Field, { label: "Cadastro", children: candidate ? (
|
|
249
|
+
// O caso que motivou tudo isto: a mesma pessoa existe como login e
|
|
250
|
+
// como ficha, e ninguém disse ao sistema que são a mesma. Nunca
|
|
251
|
+
// automático — o mesmo e-mail costuma estar em várias fichas.
|
|
252
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
253
|
+
/* @__PURE__ */ jsx(Link2, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
|
|
254
|
+
/* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1 text-sm", children: [
|
|
255
|
+
"Existe um cadastro de ",
|
|
256
|
+
/* @__PURE__ */ jsx("strong", { className: "font-medium", children: candidate.name }),
|
|
257
|
+
" com o seu e-mail. \xC9 voc\xEA?"
|
|
258
|
+
] }),
|
|
259
|
+
/* @__PURE__ */ jsx(Button, { size: "sm", variant: "outline", disabled: linking, onClick: () => void link(), children: linking ? "Ligando\u2026" : "Sim, sou eu" })
|
|
260
|
+
] })
|
|
261
|
+
) : /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Seu login n\xE3o est\xE1 ligado a nenhum cadastro de pessoa. \xC9 o normal para quem administra e n\xE3o atende \u2014 escala, comiss\xE3o e documentos vivem na ficha de quem atende." }) })
|
|
262
|
+
] })
|
|
263
|
+
] });
|
|
264
|
+
}
|
|
265
|
+
async function syncLoginName(fullName) {
|
|
266
|
+
try {
|
|
267
|
+
const supabase = getFayzSupabaseClientOptional();
|
|
268
|
+
if (!supabase) return;
|
|
269
|
+
const { data } = await supabase.auth.getUser();
|
|
270
|
+
const id = data?.user?.id;
|
|
271
|
+
if (!id) return;
|
|
272
|
+
await supabase.from("profiles").upsert({ id, full_name: fullName }, { onConflict: "id" });
|
|
273
|
+
await supabase.auth.updateUser({ data: { full_name: fullName } });
|
|
274
|
+
useAuthStore.getState().setUser({ ...useAuthStore.getState().user, fullName });
|
|
275
|
+
} catch {
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
function MyRecordPanel() {
|
|
279
|
+
const orgId = useOrganizationStore((s) => s.currentOrg?.id);
|
|
280
|
+
const userId = useAuthStore((s) => s.user?.id);
|
|
281
|
+
const members = useOrganizationStore((s) => s.members);
|
|
282
|
+
const myRole = members.find((m) => m.userId === userId)?.profileName;
|
|
283
|
+
const [state, setState] = React2.useState({ status: "loading" });
|
|
284
|
+
const load = React2.useCallback(async () => {
|
|
285
|
+
if (!orgId || !userId) return;
|
|
286
|
+
const person = await dedup(`self:record:${orgId}:${userId}`, () => fetchMyPersonRecord(orgId, userId));
|
|
287
|
+
if (!person) return setState({ status: "none" });
|
|
288
|
+
const registered = person.kind ? getEntityByKey(`person:${person.kind}`) : void 0;
|
|
289
|
+
const entityDef = registered?.entityDef;
|
|
290
|
+
if (!entityDef) return setState({ status: "none" });
|
|
291
|
+
try {
|
|
292
|
+
const provider = resolveDataProvider(entityDef);
|
|
293
|
+
const { data } = await provider.list({ filters: { id: person.id }, pageSize: 1, countMode: "none" });
|
|
294
|
+
const item = data?.[0];
|
|
295
|
+
if (!item) return setState({ status: "none" });
|
|
296
|
+
setState({ status: "ready", entityDef, item });
|
|
297
|
+
} catch {
|
|
298
|
+
setState({ status: "none" });
|
|
299
|
+
}
|
|
300
|
+
}, [orgId, userId]);
|
|
301
|
+
React2.useEffect(() => {
|
|
302
|
+
void load();
|
|
303
|
+
}, [load]);
|
|
304
|
+
const changePhoto = React2.useCallback(async (file) => {
|
|
305
|
+
if (state.status !== "ready") return;
|
|
306
|
+
const supabase = getFayzSupabaseClientOptional();
|
|
307
|
+
if (!supabase) return;
|
|
308
|
+
const { data: auth } = await supabase.auth.getUser();
|
|
309
|
+
const id = auth?.user?.id;
|
|
310
|
+
if (!id) return;
|
|
311
|
+
const ext = file.name.split(".").pop();
|
|
312
|
+
const path = `avatars/${id}.${ext}`;
|
|
313
|
+
const { error: uploadError } = await supabase.storage.from("avatars").upload(path, file, { upsert: true });
|
|
314
|
+
if (uploadError) {
|
|
315
|
+
toast.error("N\xE3o deu para enviar a foto", { description: uploadError.message });
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
const url = supabase.storage.from("avatars").getPublicUrl(path).data.publicUrl;
|
|
319
|
+
await supabase.from("profiles").upsert({ id, avatar_url: url }, { onConflict: "id" });
|
|
320
|
+
await supabase.auth.updateUser({ data: { avatar_url: url } });
|
|
321
|
+
useAuthStore.getState().setUser({ ...useAuthStore.getState().user, avatarUrl: url });
|
|
322
|
+
const imageField = state.entityDef.imageField;
|
|
323
|
+
if (imageField) {
|
|
324
|
+
const provider = resolveDataProvider(state.entityDef);
|
|
325
|
+
const updated = await provider.update(state.item.id, { [imageField]: url });
|
|
326
|
+
setState({ ...state, item: { ...state.item, ...updated } });
|
|
327
|
+
}
|
|
328
|
+
toast.success("Foto atualizada");
|
|
329
|
+
}, [state]);
|
|
330
|
+
if (state.status === "loading") return /* @__PURE__ */ jsx(Skeleton, { className: "h-40 w-full" });
|
|
331
|
+
if (state.status === "none") return null;
|
|
332
|
+
return /* @__PURE__ */ jsx(
|
|
333
|
+
CrudDetailPage,
|
|
334
|
+
{
|
|
335
|
+
entityDef: state.entityDef,
|
|
336
|
+
item: state.item,
|
|
337
|
+
namePlural: state.entityDef.namePlural ?? state.entityDef.name,
|
|
338
|
+
basePath: "",
|
|
339
|
+
embedded: true,
|
|
340
|
+
onBack: () => {
|
|
341
|
+
},
|
|
342
|
+
badges: myRole ? /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "shrink-0", children: myRole }) : null,
|
|
343
|
+
onImageChange: changePhoto,
|
|
344
|
+
onFieldSave: async (key, value) => {
|
|
345
|
+
const provider = resolveDataProvider(state.entityDef);
|
|
346
|
+
const updated = await provider.update(state.item.id, { [key]: value });
|
|
347
|
+
setState({ ...state, item: { ...state.item, ...updated } });
|
|
348
|
+
if (key === (state.entityDef.displayField ?? "name") && typeof value === "string") {
|
|
349
|
+
await syncLoginName(value);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
function ConnectedUserProfile() {
|
|
356
|
+
const user = useAuthStore((s) => s.user);
|
|
357
|
+
const myPersonId = useMyPersonId();
|
|
358
|
+
const hasRecord = Boolean(myPersonId);
|
|
359
|
+
const setUser = useAuthStore((s) => s.setUser);
|
|
360
|
+
const [profile, setProfile] = React2.useState(null);
|
|
361
|
+
React2.useEffect(() => {
|
|
362
|
+
const supabase = getFayzSupabaseClientOptional();
|
|
363
|
+
if (!user || !supabase) return;
|
|
364
|
+
let cancelled = false;
|
|
365
|
+
void supabase.from("profiles").select("full_name, avatar_url, email").eq("id", user.id).maybeSingle().then(({ data }) => {
|
|
366
|
+
if (!cancelled && data) setProfile(data);
|
|
367
|
+
});
|
|
368
|
+
return () => {
|
|
369
|
+
cancelled = true;
|
|
370
|
+
};
|
|
371
|
+
}, [user?.id]);
|
|
372
|
+
const handleSave = async (data) => {
|
|
373
|
+
if (!user) return;
|
|
374
|
+
try {
|
|
375
|
+
const supabase = getFayzSupabaseClient();
|
|
376
|
+
const { error: profileError } = await supabase.from("profiles").upsert({ id: user.id, full_name: data.fullName, email: user.email }, { onConflict: "id" });
|
|
377
|
+
if (profileError) throw profileError;
|
|
378
|
+
const { error: metaError } = await supabase.auth.updateUser({ data: { full_name: data.fullName } });
|
|
379
|
+
if (metaError) throw metaError;
|
|
380
|
+
setUser({ ...user, fullName: data.fullName });
|
|
381
|
+
setProfile({ full_name: data.fullName, avatar_url: profile?.avatar_url ?? null, email: user.email });
|
|
382
|
+
toast.success("Perfil atualizado");
|
|
383
|
+
} catch (err) {
|
|
384
|
+
toast.error("Falha ao atualizar", { description: err?.message });
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
const handleAvatarChange = async (file) => {
|
|
388
|
+
if (!user) return;
|
|
389
|
+
try {
|
|
390
|
+
const supabase = getFayzSupabaseClient();
|
|
391
|
+
const ext = file.name.split(".").pop();
|
|
392
|
+
const path = `avatars/${user.id}.${ext}`;
|
|
393
|
+
const { error: uploadError } = await supabase.storage.from("avatars").upload(path, file, { upsert: true });
|
|
394
|
+
if (uploadError) throw uploadError;
|
|
395
|
+
const { data: urlData } = supabase.storage.from("avatars").getPublicUrl(path);
|
|
396
|
+
const avatarUrl = urlData.publicUrl;
|
|
397
|
+
const { error: profileError } = await supabase.from("profiles").upsert({ id: user.id, avatar_url: avatarUrl, email: user.email }, { onConflict: "id" });
|
|
398
|
+
if (profileError) throw profileError;
|
|
399
|
+
await supabase.auth.updateUser({ data: { avatar_url: avatarUrl } });
|
|
400
|
+
setUser({ ...user, avatarUrl });
|
|
401
|
+
setProfile({ full_name: profile?.full_name ?? null, avatar_url: avatarUrl, email: user.email });
|
|
402
|
+
toast.success("Avatar atualizado");
|
|
403
|
+
} catch (err) {
|
|
404
|
+
toast.error("Falha ao enviar avatar", { description: err?.message });
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
const merged = user ? { ...user, fullName: profile?.full_name ?? user.fullName, avatarUrl: profile?.avatar_url ?? user.avatarUrl } : null;
|
|
408
|
+
return (
|
|
409
|
+
// Com ficha, a tela É a ficha: ela já tem a foto (que grava nos dois
|
|
410
|
+
// lugares), o nome no cabeçalho, a função ao lado dele e uma aba de
|
|
411
|
+
// unidades. Qualquer cartão acima dela repetiria alguma dessas coisas.
|
|
412
|
+
//
|
|
413
|
+
// Sem ficha, nada disso existe — e aí voltam o formulário da conta e o
|
|
414
|
+
// resumo, que é onde mora o convite para ligar as duas.
|
|
415
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-6", children: hasRecord ? /* @__PURE__ */ jsx(MyRecordPanel, {}) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
416
|
+
/* @__PURE__ */ jsx(UserProfile, { user: merged, onSave: handleSave, onAvatarChange: handleAvatarChange }),
|
|
417
|
+
/* @__PURE__ */ jsx(MyWorkspaceCard, {})
|
|
418
|
+
] }) })
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
export { ConnectedUserProfile };
|
|
423
|
+
//# sourceMappingURL=ConnectedUserProfile-E7USJRUE.js.map
|
|
424
|
+
//# sourceMappingURL=ConnectedUserProfile-E7USJRUE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/settings/UserProfile.tsx","../src/components/settings/MyWorkspaceCard.tsx","../src/components/settings/MyRecordPanel.tsx","../src/components/settings/ConnectedUserProfile.tsx"],"names":["React","jsxs","jsx","Card","CardHeader","CardTitle","CardDescription","CardContent","Button","useAuthStore","React3","Badge","React4"],"mappings":"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","file":"ConnectedUserProfile-E7USJRUE.js","sourcesContent":["import * as React from 'react'\nimport { Camera, Save } from 'lucide-react'\nimport { cn } from '../../lib/cn'\nimport { Button } from '@fayz-ai/ui'\nimport { Input } from '@fayz-ai/ui'\nimport { Avatar, AvatarFallback, AvatarImage } from '@fayz-ai/ui'\nimport { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@fayz-ai/ui'\nimport { useTranslation } from '../../hooks/useTranslation'\nimport type { AuthUser } from '../../types/auth'\n\ninterface UserProfileProps {\n user?: AuthUser | null\n onSave?: (data: { fullName: string }) => void\n onAvatarChange?: (file: File) => void\n}\n\nfunction getInitials(name: string): string {\n return name\n .split(' ')\n .map((part) => part[0])\n .filter(Boolean)\n .slice(0, 2)\n .join('')\n .toUpperCase()\n}\n\nexport function UserProfile({ user, onSave, onAvatarChange }: UserProfileProps) {\n const { t } = useTranslation()\n const [fullName, setFullName] = React.useState(user?.fullName ?? '')\n const [saving, setSaving] = React.useState(false)\n const fileInputRef = React.useRef<HTMLInputElement>(null)\n\n React.useEffect(() => {\n if (user) {\n setFullName(user.fullName)\n }\n }, [user])\n\n const handleAvatarClick = () => {\n fileInputRef.current?.click()\n }\n\n const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0]\n if (file && onAvatarChange) {\n onAvatarChange(file)\n }\n if (e.target) {\n e.target.value = ''\n }\n }\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n if (!onSave) return\n\n setSaving(true)\n try {\n await onSave({ fullName })\n } finally {\n setSaving(false)\n }\n }\n\n return (\n <form onSubmit={handleSubmit} className=\"space-y-6\">\n <Card>\n <CardHeader>\n <CardTitle className=\"text-lg\">{t('settings.profile.title')}</CardTitle>\n <CardDescription>\n {t('settings.profile.subtitle')}\n </CardDescription>\n </CardHeader>\n\n <CardContent className=\"space-y-6\">\n <div className=\"flex items-center gap-6\">\n <div className=\"relative\">\n <Avatar className=\"h-20 w-20\">\n <AvatarImage src={user?.avatarUrl} alt={user?.fullName} />\n <AvatarFallback className=\"text-lg\">\n {user?.fullName ? getInitials(user.fullName) : '?'}\n </AvatarFallback>\n </Avatar>\n {onAvatarChange && (\n <Button\n variant=\"bare\"\n size=\"bare\"\n type=\"button\"\n onClick={handleAvatarClick}\n className={cn(\n 'absolute -bottom-1 -right-1 flex h-8 w-8 items-center justify-center rounded-full',\n 'border-2 border-background bg-primary text-primary-foreground',\n 'transition-colors hover:bg-primary/90'\n )}\n aria-label=\"Change avatar\"\n >\n <Camera className=\"h-3.5 w-3.5\" />\n </Button>\n )}\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n className=\"hidden\"\n onChange={handleFileChange}\n />\n </div>\n\n <div className=\"space-y-1\">\n <p className=\"font-medium\">{user?.fullName ?? 'User'}</p>\n <p className=\"text-sm text-muted-foreground\">{user?.email}</p>\n </div>\n </div>\n\n <div className=\"space-y-2\">\n <label htmlFor=\"full-name\" className=\"text-sm font-medium\">\n {t('settings.profile.fullName')}\n </label>\n <Input\n id=\"full-name\"\n value={fullName}\n onChange={(e) => setFullName(e.target.value)}\n placeholder=\"John Doe\"\n />\n </div>\n\n <div className=\"space-y-2\">\n <label htmlFor=\"email\" className=\"text-sm font-medium\">\n {t('settings.profile.email')}\n </label>\n <Input\n id=\"email\"\n type=\"email\"\n value={user?.email ?? ''}\n disabled\n className=\"bg-muted\"\n />\n <p className=\"text-xs text-muted-foreground\">\n {t('settings.profile.emailHelp')}\n </p>\n </div>\n </CardContent>\n\n <CardFooter className=\"justify-end\">\n <Button type=\"submit\" disabled={saving}>\n <Save className=\"mr-2 h-4 w-4\" />\n {saving ? t('common.saving') : t('settings.profile.saveProfile')}\n </Button>\n </CardFooter>\n </Card>\n </form>\n )\n}\n","import * as React from 'react'\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle, Button, Badge } from '@fayz-ai/ui'\nimport { AlertTriangle, Building2, Contact, Layers, Link2 } from 'lucide-react'\nimport { useAuthStore } from '@fayz-ai/auth'\nimport { useOrganizationStore } from '../../org/store'\nimport { useUnitStore } from '../../units/store'\nimport { useUnitBootstrap } from '../../units/useUnitBootstrap'\nimport { usePermissionsStore } from '../../permissions'\nimport { fetchMyPersonRecord, findMyPersonCandidate, linkPersonToLogin, type LinkedPerson } from '../../org/self'\nimport { toast } from '../notifications/ToastProvider'\n\n// ---------------------------------------------------------------------------\n// \"Você aqui\" — o que é verdade sobre você NESTE espaço de trabalho.\n//\n// A tela de perfil sabia nome, e-mail e foto: fatos da sua conta, iguais em\n// qualquer lugar. Não sabia nada do que decide o seu dia — que função você tem,\n// em quais unidades você entra, qual delas você está vendo agora, e se você tem\n// ficha profissional. Era por isso que ela parecia uma tela apartada: ela é o\n// único lugar do sistema que não fala do trabalho.\n//\n// As unidades vêm da store que o seletor já carregou, então isto não custa\n// requisição nenhuma. Quando a gestão por unidades está desligada, a seção\n// inteira desaparece: um fato que não se aplica é ruído, não informação.\n// ---------------------------------------------------------------------------\n\n/** Por que a unidade ativa é a que é. A resolução automática cria a pergunta\n * \"por que abriu na Ipanema?\", e este é o lugar onde ela é respondida. */\nconst REASON_TEXT: Record<string, string> = {\n device: 'foi a última unidade aberta neste computador',\n account: 'foi a última unidade que você abriu, em outro aparelho',\n only: 'é a única que você alcança',\n manual: 'você escolheu',\n nearest: 'foi a mais perto de você',\n all: 'você não estreitou nada',\n}\n\n/**\n * Uma linha rótulo/resposta. O rótulo tem largura fixa para as três respostas\n * começarem na mesma coluna — é o alinhamento que faz o cartão ser lido de uma\n * vez em vez de seção por seção. Abaixo de `sm` empilha: rótulo de 7rem ao lado\n * de um texto de duas linhas num celular é pior do que não alinhar nada.\n *\n * Flex com `w-28`, e não `grid-cols-[7rem_1fr]`, por um motivo que não é\n * estética. O Tailwind gera uma utility só quando a encontra LITERALMENTE num\n * arquivo varrido, e os apps consomem este pacote pelo source com o dev server\n * ligado há horas — uma classe que existe só aqui simplesmente não aparece no\n * CSS deles, e o sintoma não é erro nenhum: é o layout empilhado como se o\n * código estivesse errado. Aconteceu com este cartão. Utilities que o SDK já\n * emite em outros lugares não têm esse problema.\n */\nfunction Field({ label, children }: { label: string; children: React.ReactNode }) {\n return (\n <div className=\"flex flex-col gap-1 px-6 py-4 sm:flex-row sm:items-start sm:gap-4\">\n <span className=\"w-28 shrink-0 pt-0.5 text-sm text-muted-foreground\">{label}</span>\n <div className=\"min-w-0 flex-1\">{children}</div>\n </div>\n )\n}\n\nexport function MyWorkspaceCard() {\n useUnitBootstrap()\n const user = useAuthStore((s) => s.user)\n const currentOrg = useOrganizationStore((s) => s.currentOrg)\n const members = useOrganizationStore((s) => s.members)\n const staffKinds = useOrganizationStore((s) => s.teamPersonKinds)\n const profiles = usePermissionsStore((s) => s.profiles)\n\n const unitMode = useUnitStore((s) => s.unitMode)\n const byId = useUnitStore((s) => s.byId)\n const bindings = useUnitStore((s) => s.myBindings)\n const myUnitIds = useUnitStore((s) => s.myUnitIds)\n const activeUnitId = useUnitStore((s) => s.activeUnitId)\n const entryReason = useUnitStore((s) => s.entryReason)\n\n const [person, setPerson] = React.useState<LinkedPerson | null | undefined>(undefined)\n const [candidate, setCandidate] = React.useState<LinkedPerson | null>(null)\n const [linking, setLinking] = React.useState(false)\n\n const orgId = currentOrg?.id\n const userId = user?.id\n\n const load = React.useCallback(async () => {\n if (!orgId || !userId) return\n const linked = await fetchMyPersonRecord(orgId, userId)\n setPerson(linked)\n // Só procura candidato quando não há vínculo — uma sugestão ao lado de um\n // vínculo que já existe é um convite a trocar por engano.\n setCandidate(linked ? null : await findMyPersonCandidate(orgId, user?.email, staffKinds))\n }, [orgId, userId, user?.email, staffKinds])\n\n React.useEffect(() => { void load() }, [load])\n\n if (!currentOrg) return null\n\n const myRole = members.find((m) => m.userId === userId)?.profileName\n\n async function link() {\n if (!orgId || !userId || !candidate) return\n setLinking(true)\n try {\n await linkPersonToLogin(orgId, userId, candidate.id)\n toast.success(`Login ligado ao cadastro de ${candidate.name}`)\n await load()\n } catch (err: any) {\n // A policy da 001 deixa escrever em `tenant_members` só para\n // administrador. Traduzir em vez de repetir o erro do banco: quem não é\n // administrador não precisa saber o que é uma policy, precisa saber a\n // quem pedir.\n toast.error('Só um administrador pode ligar um login a um cadastro', { description: err?.message })\n } finally {\n setLinking(false)\n }\n }\n\n // Só as filiais: uma região é agrupamento, e listá-la ao lado das unidades\n // faria parecer que a pessoa \"trabalha na região Rio\".\n const boundUnits = bindings\n .map((b) => ({ unit: byId[b.locationId], role: b.role }))\n .filter((x): x is { unit: NonNullable<typeof x.unit>; role: string | null } => Boolean(x.unit))\n\n const activeUnit = activeUnitId ? byId[activeUnitId] : undefined\n // Com uma unidade só não há o que explicar: \"vendo agora, porque é a única\"\n // é uma frase que ocupa uma linha para dizer o óbvio. A explicação só ganha\n // o seu espaço quando havia escolha a fazer.\n const worthExplaining = myUnitIds.length > 1 && Boolean(REASON_TEXT[entryReason])\n\n return (\n <Card>\n <CardHeader>\n <CardTitle className=\"text-lg\">Você em {currentOrg.name}</CardTitle>\n <CardDescription>\n O que vale só aqui — sua conta em si vale em todo espaço de trabalho em que você entra.\n </CardDescription>\n </CardHeader>\n\n {/* Rótulo à esquerda, resposta à direita — a mesma forma três vezes.\n Antes cada seção tinha o próprio cabeçalho com ícone e o próprio\n espaçamento, e três blocos soltos custam mais leitura do que três\n linhas alinhadas. O divisor entre elas faz o trabalho que o espaço\n em branco estava tentando fazer. */}\n <CardContent className=\"divide-y divide-border p-0\">\n <Field label=\"Função\">\n <Badge variant=\"secondary\">{myRole || 'sem função definida'}</Badge>\n </Field>\n\n {unitMode && (\n <Field label={boundUnits.length === 1 ? 'Unidade' : 'Unidades'}>\n {boundUnits.length === 0 ? (\n // O aviso que evita o chamado \"sumiu tudo\". Quem não tem vínculo\n // com a gestão ligada não vê nada carimbado, e a tela precisa\n // dizer isso antes da pessoa concluir que o sistema quebrou.\n <div className=\"flex gap-2.5 rounded-lg border border-amber-400/40 bg-amber-400/10 p-3 text-sm\">\n <AlertTriangle className=\"mt-0.5 h-4 w-4 shrink-0 text-amber-600 dark:text-amber-400\" />\n <p>\n Você não está em nenhuma unidade. Enquanto for assim, não vê agendamento, pedido\n nem caixa de lugar nenhum — só o que é da organização inteira. Peça a um\n administrador para te incluir.\n </p>\n </div>\n ) : (\n <div className=\"space-y-1\">\n {boundUnits.map(({ unit, role }) => (\n <div key={unit.id} className=\"flex flex-wrap items-center gap-2 text-sm\">\n <Building2 className=\"h-4 w-4 shrink-0 text-muted-foreground\" />\n <span className=\"min-w-0 truncate\">{unit.name}</span>\n {/* A unidade ativa marcada NA LINHA dela. Antes isto era uma\n faixa cinza abaixo da lista repetindo o mesmo nome logo\n acima — duas vezes a mesma informação, e a segunda mais\n pesada que a primeira. */}\n {unit.id === activeUnitId && (\n <Badge variant=\"outline\" className=\"shrink-0 text-[10px] font-normal\">\n vendo agora\n </Badge>\n )}\n {unit.kind === 'region' && (\n <span className=\"shrink-0 text-xs text-muted-foreground\">\n região — alcança as de dentro\n </span>\n )}\n {role && (\n <Badge variant=\"secondary\" className=\"shrink-0 text-[10px] font-normal\">\n {profiles.find((p) => p.id === role)?.name ?? role} aqui\n </Badge>\n )}\n </div>\n ))}\n\n {/* Vínculo numa região alcança as filhas; sem dizer isso, a\n conta \"1 vínculo, 4 unidades\" não fecha para quem lê. */}\n {myUnitIds.length > boundUnits.length && (\n <p className=\"text-xs text-muted-foreground\">\n Ao todo você alcança {myUnitIds.length} unidades, contando as que estão dentro\n das regiões acima.\n </p>\n )}\n\n {!activeUnit && myUnitIds.length > 1 && (\n <p className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <Layers className=\"h-3.5 w-3.5 shrink-0\" />\n Vendo todas as unidades.\n </p>\n )}\n\n {worthExplaining && (\n <p className=\"text-xs text-muted-foreground\">\n {activeUnit ? 'Abriu aqui porque ' : 'Está assim porque '}\n {REASON_TEXT[entryReason]}.\n </p>\n )}\n </div>\n )}\n </Field>\n )}\n\n {/* Só enquanto não há ficha ligada. Quando há, ela está desenhada logo\n abaixo neste mesmo perfil, e repetir o nome dela aqui é dizer a\n mesma coisa duas vezes com uma linha de distância. */}\n {person === null && (\n <Field label=\"Cadastro\">\n {candidate ? (\n // O caso que motivou tudo isto: a mesma pessoa existe como login e\n // como ficha, e ninguém disse ao sistema que são a mesma. Nunca\n // automático — o mesmo e-mail costuma estar em várias fichas.\n <div className=\"flex flex-wrap items-center gap-2\">\n <Link2 className=\"h-4 w-4 shrink-0 text-muted-foreground\" />\n <span className=\"min-w-0 flex-1 text-sm\">\n Existe um cadastro de <strong className=\"font-medium\">{candidate.name}</strong> com o\n seu e-mail. É você?\n </span>\n <Button size=\"sm\" variant=\"outline\" disabled={linking} onClick={() => void link()}>\n {linking ? 'Ligando…' : 'Sim, sou eu'}\n </Button>\n </div>\n ) : (\n <p className=\"text-xs text-muted-foreground\">\n Seu login não está ligado a nenhum cadastro de pessoa. É o normal para quem administra\n e não atende — escala, comissão e documentos vivem na ficha de quem atende.\n </p>\n )}\n </Field>\n )}\n </CardContent>\n </Card>\n )\n}\n","import * as React from 'react'\nimport { Badge, Skeleton } from '@fayz-ai/ui'\nimport { getEntityByKey, resolveDataProvider, type EntityDef } from '@fayz-ai/core'\nimport { useAuthStore } from '@fayz-ai/auth'\nimport { useOrganizationStore } from '../../org/store'\nimport { fetchMyPersonRecord } from '../../org/self'\nimport { CrudDetailPage } from '../../crud/CrudDetailPage'\nimport { dedup } from '../../lib/dedup'\nimport { getSupabaseClientSafe } from '../../lib/supabase'\nimport { toast } from '../notifications/ToastProvider'\n\n/** Mantém `profiles`, o metadado do login e a sessão em pé com o nome da ficha.\n * Silencioso: a gravação que importava já aconteceu, e um aviso de que o\n * espelho falhou não ajuda ninguém no meio de renomear a si mesmo. */\nasync function syncLoginName(fullName: string): Promise<void> {\n try {\n const supabase = getSupabaseClientSafe()\n if (!supabase) return\n const { data } = await supabase.auth.getUser()\n const id = data?.user?.id\n if (!id) return\n await supabase.from('profiles').upsert({ id, full_name: fullName }, { onConflict: 'id' })\n await supabase.auth.updateUser({ data: { full_name: fullName } })\n useAuthStore.getState().setUser({ ...(useAuthStore.getState().user as any), fullName })\n } catch {\n // ver acima\n }\n}\n\n// ---------------------------------------------------------------------------\n// A sua ficha, dentro do seu perfil.\n//\n// Eram duas páginas para a mesma pessoa: uma com foto, nome e e-mail do login,\n// outra com escala, unidades, endereços, documentos e extrato. Quem abria a\n// primeira não achava nada do próprio trabalho; quem abria a segunda não sabia\n// que era a própria ficha.\n//\n// A ficha continua tendo página própria — é a mesma tela pela qual um\n// administrador abre a ficha da Solange, e isso não é duplicação: é a mesma\n// tela para outra pessoa. O que mudou é que a SUA não exige ir procurá-la.\n//\n// É a MESMA `CrudDetailPage` da tela de cadastros, no modo embutido, com a\n// mesma definição de entidade que o app registrou. Reescrever as abas aqui\n// criaria uma segunda ficha para divergir da primeira, que é exatamente o\n// problema que isto veio resolver.\n// ---------------------------------------------------------------------------\n\n\nexport function MyRecordPanel() {\n const orgId = useOrganizationStore((s) => s.currentOrg?.id)\n const userId = useAuthStore((s) => s.user?.id)\n\n const members = useOrganizationStore((s) => s.members)\n const myRole = members.find((m) => m.userId === userId)?.profileName\n\n const [state, setState] = React.useState<\n { status: 'loading' } | { status: 'none' } | { status: 'ready'; entityDef: EntityDef; item: Record<string, any> }\n >({ status: 'loading' })\n\n const load = React.useCallback(async () => {\n if (!orgId || !userId) return\n const person = await dedup(`self:record:${orgId}:${userId}`, () => fetchMyPersonRecord(orgId, userId))\n if (!person) return setState({ status: 'none' })\n\n // A chave que o registro usa é `<arquétipo>:<kind>`, e o app registra cada\n // entidade de CRUD na avaliação do módulo. Sem registro — app com dados\n // simulados, kind que ninguém cadastrou — não há ficha para desenhar, e a\n // tela some em vez de inventar uma.\n const registered = person.kind ? getEntityByKey(`person:${person.kind}`) : undefined\n const entityDef = registered?.entityDef\n if (!entityDef) return setState({ status: 'none' })\n\n try {\n const provider = resolveDataProvider(entityDef as any)\n const { data } = await provider.list({ filters: { id: person.id }, pageSize: 1, countMode: 'none' })\n const item = data?.[0]\n if (!item) return setState({ status: 'none' })\n setState({ status: 'ready', entityDef, item: item as Record<string, any> })\n } catch {\n // A ficha é um extra desta tela, não o conteúdo dela. Um erro aqui não\n // pode derrubar o perfil inteiro — some, e o resto continua.\n setState({ status: 'none' })\n }\n }, [orgId, userId])\n\n React.useEffect(() => { void load() }, [load])\n\n /**\n * Trocar a foto — uma foto, dois donos.\n *\n * `profiles.avatar_url` é a que a barra de cima mostra e que vale em toda\n * conta em que a pessoa entra; a da ficha é a que a equipe vê na lista. São a\n * mesma cara, e deixar uma para trás é a mesma divergência do nome, só que\n * visível. Grava nas duas quando a entidade declara um campo de imagem.\n */\n const changePhoto = React.useCallback(async (file: File) => {\n if (state.status !== 'ready') return\n const supabase = getSupabaseClientSafe()\n if (!supabase) return\n const { data: auth } = await supabase.auth.getUser()\n const id = auth?.user?.id\n if (!id) return\n\n const ext = file.name.split('.').pop()\n const path = `avatars/${id}.${ext}`\n const { error: uploadError } = await supabase.storage.from('avatars').upload(path, file, { upsert: true })\n if (uploadError) {\n toast.error('Não deu para enviar a foto', { description: uploadError.message })\n return\n }\n const url = supabase.storage.from('avatars').getPublicUrl(path).data.publicUrl\n\n await supabase.from('profiles').upsert({ id, avatar_url: url }, { onConflict: 'id' })\n await supabase.auth.updateUser({ data: { avatar_url: url } })\n useAuthStore.getState().setUser({ ...(useAuthStore.getState().user as any), avatarUrl: url })\n\n const imageField = state.entityDef.imageField\n if (imageField) {\n const provider = resolveDataProvider(state.entityDef as any)\n const updated = await provider.update(state.item.id, { [imageField]: url } as any)\n setState({ ...state, item: { ...state.item, ...(updated as Record<string, any>) } })\n }\n toast.success('Foto atualizada')\n }, [state])\n\n if (state.status === 'loading') return <Skeleton className=\"h-40 w-full\" />\n if (state.status === 'none') return null\n\n return (\n <CrudDetailPage\n entityDef={state.entityDef}\n item={state.item}\n namePlural={state.entityDef.namePlural ?? state.entityDef.name}\n basePath=\"\"\n embedded\n onBack={() => {}}\n // A função é da associação à conta, não da ficha — não existe campo de\n // onde renderizá-la, e o lado do nome é o único lugar honesto para ela.\n badges={myRole ? <Badge variant=\"secondary\" className=\"shrink-0\">{myRole}</Badge> : null}\n onImageChange={changePhoto}\n // Edição campo a campo, sim; excluir, não. Apagar a própria ficha a\n // partir das configurações não é uma coisa que alguém queira fazer sem\n // querer, e o botão existe na página de cadastros para quem precisar.\n onFieldSave={async (key, value) => {\n const provider = resolveDataProvider(state.entityDef as any)\n const updated = await provider.update(state.item.id, { [key]: value } as any)\n setState({ ...state, item: { ...state.item, ...(updated as Record<string, any>) } })\n\n // O nome da ficha e o nome do login são a mesma pessoa em duas linhas.\n // Corrigir um e deixar o outro é como a divergência começa: a barra de\n // cima continuaria chamando você pelo nome antigo. Aqui só acontece\n // porque esta ficha é comprovadamente a sua.\n if (key === (state.entityDef.displayField ?? 'name') && typeof value === 'string') {\n await syncLoginName(value)\n }\n }}\n />\n )\n}\n","import * as React from 'react'\nimport { UserProfile } from './UserProfile'\nimport { MyWorkspaceCard } from './MyWorkspaceCard'\nimport { MyRecordPanel } from './MyRecordPanel'\nimport { useMyPersonId } from '../../org/self'\n// The signed-in user lives in @fayz-ai/auth's store (the one AuthProvider fills) —\n// the shell stores/auth.store is a separate, unpopulated store.\nimport { useAuthStore } from '@fayz-ai/auth'\nimport { getSupabaseClient, getSupabaseClientSafe } from '../../lib/supabase'\nimport { toast } from '../notifications/ToastProvider'\n\ninterface ProfileRow {\n full_name: string | null\n avatar_url: string | null\n email: string | null\n}\n\n// The \"/me\" surface: the current user's canonical profile = the auth user (id,\n// e-mail) merged with their profiles row (name, avatar). Reads/writes go\n// to public.profiles (RLS: id = auth.uid(), so a user only ever sees/edits their\n// own), and keep the auth-user metadata in sync so both stay coherent.\nexport function ConnectedUserProfile() {\n const user = useAuthStore((s) => s.user)\n // Quando o login tem ficha, ela é desenhada logo abaixo e já edita nome,\n // e-mail e telefone. Manter o formulário de cima seria pedir a mesma coisa\n // duas vezes na mesma tela, gravando em linhas diferentes — o começo exato de\n // uma divergir da outra. Sobra a foto, que é do login e não da ficha.\n const myPersonId = useMyPersonId()\n const hasRecord = Boolean(myPersonId)\n const setUser = useAuthStore((s) => s.setUser)\n const [profile, setProfile] = React.useState<ProfileRow | null>(null)\n\n // Fill: load the canonical profile row on mount (falls back to auth metadata).\n React.useEffect(() => {\n const supabase = getSupabaseClientSafe()\n if (!user || !supabase) return // mock/no-backend: just use the auth-store user\n let cancelled = false\n void supabase\n .from('profiles')\n .select('full_name, avatar_url, email')\n .eq('id', user.id)\n .maybeSingle()\n .then(({ data }) => {\n if (!cancelled && data) setProfile(data as ProfileRow)\n })\n return () => {\n cancelled = true\n }\n }, [user?.id])\n\n const handleSave = async (data: { fullName: string }) => {\n if (!user) return\n try {\n const supabase = getSupabaseClient()\n // Upsert the canonical row (INSERT if the profile doesn't exist yet).\n const { error: profileError } = await supabase\n .from('profiles')\n .upsert({ id: user.id, full_name: data.fullName, email: user.email }, { onConflict: 'id' })\n if (profileError) throw profileError\n\n // Keep the auth-user metadata in sync (used across the app's session).\n const { error: metaError } = await supabase.auth.updateUser({ data: { full_name: data.fullName } })\n if (metaError) throw metaError\n\n setUser({ ...user, fullName: data.fullName })\n setProfile({ full_name: data.fullName, avatar_url: profile?.avatar_url ?? null, email: user.email })\n toast.success('Perfil atualizado')\n } catch (err: any) {\n toast.error('Falha ao atualizar', { description: err?.message })\n }\n }\n\n const handleAvatarChange = async (file: File) => {\n if (!user) return\n try {\n const supabase = getSupabaseClient()\n const ext = file.name.split('.').pop()\n const path = `avatars/${user.id}.${ext}`\n\n const { error: uploadError } = await supabase.storage\n .from('avatars')\n .upload(path, file, { upsert: true })\n if (uploadError) throw uploadError\n\n const { data: urlData } = supabase.storage.from('avatars').getPublicUrl(path)\n const avatarUrl = urlData.publicUrl\n\n const { error: profileError } = await supabase\n .from('profiles')\n .upsert({ id: user.id, avatar_url: avatarUrl, email: user.email }, { onConflict: 'id' })\n if (profileError) throw profileError\n\n await supabase.auth.updateUser({ data: { avatar_url: avatarUrl } })\n setUser({ ...user, avatarUrl })\n setProfile({ full_name: profile?.full_name ?? null, avatar_url: avatarUrl, email: user.email })\n toast.success('Avatar atualizado')\n } catch (err: any) {\n toast.error('Falha ao enviar avatar', { description: err?.message })\n }\n }\n\n // Merge: prefer the canonical profile row, fall back to auth metadata.\n const merged = user\n ? { ...user, fullName: profile?.full_name ?? user.fullName, avatarUrl: profile?.avatar_url ?? user.avatarUrl }\n : null\n\n // Duas coisas, na ordem em que a pessoa pergunta: quem eu sou (a conta, igual\n // em todo espaço de trabalho) e o que eu sou aqui (função, unidades, ficha).\n // A segunda faltava, e era por isso que esta tela parecia desligada do resto.\n return (\n // Com ficha, a tela É a ficha: ela já tem a foto (que grava nos dois\n // lugares), o nome no cabeçalho, a função ao lado dele e uma aba de\n // unidades. Qualquer cartão acima dela repetiria alguma dessas coisas.\n //\n // Sem ficha, nada disso existe — e aí voltam o formulário da conta e o\n // resumo, que é onde mora o convite para ligar as duas.\n <div className=\"space-y-6\">\n {hasRecord ? (\n <MyRecordPanel />\n ) : (\n <>\n <UserProfile user={merged as any} onSave={handleSave} onAvatarChange={handleAvatarChange} />\n <MyWorkspaceCard />\n </>\n )}\n </div>\n )\n}\n"]}
|