@carlonicora/nextjs-jsonapi 1.124.3 → 1.125.1
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/{BlockNoteEditor-BEZWZXUH.js → BlockNoteEditor-EFAIYNH2.js} +9 -9
- package/dist/{BlockNoteEditor-BEZWZXUH.js.map → BlockNoteEditor-EFAIYNH2.js.map} +1 -1
- package/dist/{BlockNoteEditor-4HYQUEYC.mjs → BlockNoteEditor-YEEQH7UB.mjs} +2 -2
- package/dist/billing/index.js +299 -299
- package/dist/billing/index.mjs +1 -1
- package/dist/{chunk-QWZI4N7S.js → chunk-JBWBIMZF.js} +864 -754
- package/dist/chunk-JBWBIMZF.js.map +1 -0
- package/dist/{chunk-5FQJB5QR.mjs → chunk-LRLVHDFA.mjs} +2763 -2653
- package/dist/chunk-LRLVHDFA.mjs.map +1 -0
- package/dist/client/index.js +2 -2
- package/dist/client/index.mjs +1 -1
- package/dist/components/index.d.mts +51 -2
- package/dist/components/index.d.ts +51 -2
- package/dist/components/index.js +12 -2
- package/dist/components/index.js.map +1 -1
- package/dist/components/index.mjs +11 -1
- package/dist/contexts/index.d.mts +1 -1
- package/dist/contexts/index.d.ts +1 -1
- package/dist/contexts/index.js +2 -2
- package/dist/contexts/index.mjs +1 -1
- package/dist/features/help/index.js +30 -30
- package/dist/features/help/index.mjs +1 -1
- package/package.json +1 -1
- package/src/components/EditableAvatar.tsx +11 -6
- package/src/components/containers/RoundPageContainer.tsx +20 -12
- package/src/components/forms/CommonDeleter.tsx +7 -2
- package/src/components/hero/EntityHero.tsx +19 -0
- package/src/components/hero/EntityHeroAvatar.tsx +63 -0
- package/src/components/hero/EntityHeroLayout.tsx +13 -0
- package/src/components/hero/EntityHeroMetaRow.tsx +19 -0
- package/src/components/hero/EntitySection.tsx +33 -0
- package/src/components/hero/index.ts +5 -0
- package/src/components/index.ts +1 -0
- package/src/features/user/components/details/UserContent.tsx +3 -1
- package/dist/chunk-5FQJB5QR.mjs.map +0 -1
- package/dist/chunk-QWZI4N7S.js.map +0 -1
- /package/dist/{BlockNoteEditor-4HYQUEYC.mjs.map → BlockNoteEditor-YEEQH7UB.mjs.map} +0 -0
|
@@ -21,7 +21,7 @@ var _chunkYBZVWLPHjs = require('../../chunk-YBZVWLPH.js');
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
var
|
|
24
|
+
var _chunkJBWBIMZFjs = require('../../chunk-JBWBIMZF.js');
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
var _chunkJO5BLONKjs = require('../../chunk-JO5BLONK.js');
|
|
@@ -73,29 +73,29 @@ var _lucidereact = require('lucide-react');
|
|
|
73
73
|
|
|
74
74
|
|
|
75
75
|
function HelpAssistantSheet({ open, onOpenChange }) {
|
|
76
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
77
|
-
|
|
76
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJBWBIMZFjs.Sheet, { open, onOpenChange, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
77
|
+
_chunkJBWBIMZFjs.SheetContent,
|
|
78
78
|
{
|
|
79
79
|
side: "right",
|
|
80
80
|
className: "flex w-full flex-col data-[side=right]:sm:max-w-2xl data-[side=right]:lg:max-w-3xl",
|
|
81
|
-
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
81
|
+
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJBWBIMZFjs.AssistantProvider, { manageUrl: false, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, HelpAssistantSheetBody, {}) })
|
|
82
82
|
}
|
|
83
83
|
) });
|
|
84
84
|
}
|
|
85
85
|
_chunk7QVYU63Ejs.__name.call(void 0, HelpAssistantSheet, "HelpAssistantSheet");
|
|
86
86
|
function HelpAssistantSheetBody() {
|
|
87
87
|
const t = _nextintl.useTranslations.call(void 0, );
|
|
88
|
-
const ctx =
|
|
88
|
+
const ctx = _chunkJBWBIMZFjs.useAssistantContext.call(void 0, );
|
|
89
89
|
const showThread = !!ctx.assistant || ctx.sending || ctx.messages.length > 0;
|
|
90
90
|
const send = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, (content) => ctx.sendMessage(content, { howToMode: true }), "send");
|
|
91
91
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
92
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
93
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
94
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
92
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkJBWBIMZFjs.SheetHeader, { children: [
|
|
93
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJBWBIMZFjs.SheetTitle, { children: t("help.askAi.sheet.title") }),
|
|
94
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJBWBIMZFjs.SheetDescription, { children: t("help.askAi.sheet.subtitle") })
|
|
95
95
|
] }),
|
|
96
|
-
!showThread ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
96
|
+
!showThread ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJBWBIMZFjs.AssistantEmptyState, { onSend: send }) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
97
97
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
98
|
-
|
|
98
|
+
_chunkJBWBIMZFjs.AssistantThread,
|
|
99
99
|
{
|
|
100
100
|
messages: ctx.messages,
|
|
101
101
|
sending: ctx.sending,
|
|
@@ -105,7 +105,7 @@ function HelpAssistantSheetBody() {
|
|
|
105
105
|
onRetry: ctx.retrySend
|
|
106
106
|
}
|
|
107
107
|
),
|
|
108
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
108
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJBWBIMZFjs.AssistantComposer, { onSend: send, disabled: ctx.sending })
|
|
109
109
|
] })
|
|
110
110
|
] });
|
|
111
111
|
}
|
|
@@ -115,20 +115,20 @@ _chunk7QVYU63Ejs.__name.call(void 0, HelpAssistantSheetBody, "HelpAssistantSheet
|
|
|
115
115
|
|
|
116
116
|
function HelpAskAi() {
|
|
117
117
|
const t = _nextintl.useTranslations.call(void 0, );
|
|
118
|
-
const { currentUser } =
|
|
118
|
+
const { currentUser } = _chunkJBWBIMZFjs.useCurrentUserContext.call(void 0, );
|
|
119
119
|
const [open, setOpen] = _react.useState.call(void 0, false);
|
|
120
120
|
const disabled = !currentUser;
|
|
121
121
|
if (disabled) {
|
|
122
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
123
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
122
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkJBWBIMZFjs.Tooltip, { children: [
|
|
123
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkJBWBIMZFjs.TooltipTrigger, { render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJBWBIMZFjs.Button, { variant: "outline", size: "sm", disabled: true }), children: [
|
|
124
124
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.SparklesIcon, { className: "h-4 w-4" }),
|
|
125
125
|
t("help.askAi.button")
|
|
126
126
|
] }),
|
|
127
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
127
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJBWBIMZFjs.TooltipContent, { children: t("help.askAi.loginTooltip") })
|
|
128
128
|
] });
|
|
129
129
|
}
|
|
130
130
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
131
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
131
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkJBWBIMZFjs.Button, { variant: "outline", size: "sm", onClick: () => setOpen(true), children: [
|
|
132
132
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.SparklesIcon, { className: "h-4 w-4" }),
|
|
133
133
|
t("help.askAi.button")
|
|
134
134
|
] }),
|
|
@@ -141,7 +141,7 @@ _chunk7QVYU63Ejs.__name.call(void 0, HelpAskAi, "HelpAskAi");
|
|
|
141
141
|
|
|
142
142
|
function HelpHeader() {
|
|
143
143
|
const t = _nextintl.useTranslations.call(void 0, );
|
|
144
|
-
const { currentUser } =
|
|
144
|
+
const { currentUser } = _chunkJBWBIMZFjs.useCurrentUserContext.call(void 0, );
|
|
145
145
|
const { brand } = useHelp();
|
|
146
146
|
const logo = _optionalChain([brand, 'optionalAccess', _ => _.logo]);
|
|
147
147
|
const label = _nullishCoalesce(_optionalChain([brand, 'optionalAccess', _2 => _2.label]), () => ( "Help"));
|
|
@@ -157,7 +157,7 @@ function HelpHeader() {
|
|
|
157
157
|
] }),
|
|
158
158
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-2", children: [
|
|
159
159
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, HelpAskAi, {}),
|
|
160
|
-
currentUser ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
160
|
+
currentUser ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJBWBIMZFjs.Button, { render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _link2.default, { href: appHref }), nativeButton: false, variant: "outline", size: "sm", children: t("help.header.openApp") }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJBWBIMZFjs.Button, { render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _link2.default, { href: "/login" }), nativeButton: false, variant: "outline", size: "sm", children: t("help.header.login") })
|
|
161
161
|
] })
|
|
162
162
|
] });
|
|
163
163
|
}
|
|
@@ -199,7 +199,7 @@ _chunk7QVYU63Ejs.__name.call(void 0, useHelpFilter, "useHelpFilter");
|
|
|
199
199
|
|
|
200
200
|
function HelpSideNav() {
|
|
201
201
|
const t = _nextintl.useTranslations.call(void 0, );
|
|
202
|
-
const generateUrl =
|
|
202
|
+
const generateUrl = _chunkJBWBIMZFjs.usePageUrlGenerator.call(void 0, );
|
|
203
203
|
const pathname = _navigation.usePathname.call(void 0, );
|
|
204
204
|
const [articles, setArticles] = _react.useState.call(void 0, []);
|
|
205
205
|
_react.useEffect.call(void 0, () => {
|
|
@@ -280,7 +280,7 @@ _chunk7QVYU63Ejs.__name.call(void 0, HelpSideNav, "HelpSideNav");
|
|
|
280
280
|
function HelpArticleBody(props) {
|
|
281
281
|
const t = _nextintl.useTranslations.call(void 0, );
|
|
282
282
|
const format = _nextintl.useFormatter.call(void 0, );
|
|
283
|
-
const generateUrl =
|
|
283
|
+
const generateUrl = _chunkJBWBIMZFjs.usePageUrlGenerator.call(void 0, );
|
|
284
284
|
const { howToType, title, summary, updatedAt, prev, next, children } = props;
|
|
285
285
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "article", { className: "prose dark:prose-invert max-w-none", children: [
|
|
286
286
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "nav", { className: "text-muted-foreground mb-2 text-xs", children: [
|
|
@@ -358,7 +358,7 @@ _chunk7QVYU63Ejs.__name.call(void 0, HelpTOC, "HelpTOC");
|
|
|
358
358
|
|
|
359
359
|
function HelpHint({ contextKey }) {
|
|
360
360
|
const t = _nextintl.useTranslations.call(void 0, );
|
|
361
|
-
const generateUrl =
|
|
361
|
+
const generateUrl = _chunkJBWBIMZFjs.usePageUrlGenerator.call(void 0, );
|
|
362
362
|
const [open, setOpen] = _react.useState.call(void 0, false);
|
|
363
363
|
const [picked, setPicked] = _react.useState.call(void 0, null);
|
|
364
364
|
const [articles, setArticles] = _react.useState.call(void 0, []);
|
|
@@ -376,7 +376,7 @@ function HelpHint({ contextKey }) {
|
|
|
376
376
|
if (matches.length === 0) return null;
|
|
377
377
|
const active = _nullishCoalesce(picked, () => ( (matches.length === 1 ? matches[0] : null)));
|
|
378
378
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
379
|
-
|
|
379
|
+
_chunkJBWBIMZFjs.Sheet,
|
|
380
380
|
{
|
|
381
381
|
open,
|
|
382
382
|
onOpenChange: (o) => {
|
|
@@ -384,11 +384,11 @@ function HelpHint({ contextKey }) {
|
|
|
384
384
|
if (!o) setPicked(null);
|
|
385
385
|
},
|
|
386
386
|
children: [
|
|
387
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
388
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
389
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
390
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
391
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
387
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJBWBIMZFjs.SheetTrigger, { render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJBWBIMZFjs.Button, { variant: "ghost", size: "icon-sm", "aria-label": t("help.hint.trigger") }), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.HelpCircleIcon, { className: "h-4 w-4" }) }),
|
|
388
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkJBWBIMZFjs.SheetContent, { side: "right", className: "w-full max-w-md sm:max-w-lg", children: [
|
|
389
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkJBWBIMZFjs.SheetHeader, { children: [
|
|
390
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJBWBIMZFjs.SheetTitle, { children: active ? active.name : t("help.hint.pickArticle") }),
|
|
391
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJBWBIMZFjs.SheetDescription, { children: _nullishCoalesce(_optionalChain([active, 'optionalAccess', _4 => _4.summary]), () => ( "")) })
|
|
392
392
|
] }),
|
|
393
393
|
active ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mt-4 space-y-3", children: [
|
|
394
394
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-muted-foreground text-sm", children: active.summary }),
|
|
@@ -420,7 +420,7 @@ _chunk7QVYU63Ejs.__name.call(void 0, HelpHint, "HelpHint");
|
|
|
420
420
|
|
|
421
421
|
function HelpSearchResultRow({ result, onSelect }) {
|
|
422
422
|
const t = _nextintl.useTranslations.call(void 0, );
|
|
423
|
-
const generateUrl =
|
|
423
|
+
const generateUrl = _chunkJBWBIMZFjs.usePageUrlGenerator.call(void 0, );
|
|
424
424
|
const [article, setArticle] = _react.useState.call(void 0, null);
|
|
425
425
|
_react.useEffect.call(void 0, () => {
|
|
426
426
|
let active = true;
|
|
@@ -431,7 +431,7 @@ function HelpSearchResultRow({ result, onSelect }) {
|
|
|
431
431
|
}, [result.id]);
|
|
432
432
|
if (!article) {
|
|
433
433
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
434
|
-
|
|
434
|
+
_chunkJBWBIMZFjs.CommandItem,
|
|
435
435
|
{
|
|
436
436
|
value: result.id,
|
|
437
437
|
disabled: true,
|
|
@@ -440,7 +440,7 @@ function HelpSearchResultRow({ result, onSelect }) {
|
|
|
440
440
|
}
|
|
441
441
|
);
|
|
442
442
|
}
|
|
443
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
443
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJBWBIMZFjs.CommandItem, { value: result.id, onSelect, className: "cursor-pointer p-0", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
444
444
|
_link2.default,
|
|
445
445
|
{
|
|
446
446
|
href: generateUrl({ page: `/help/${article.howToType}/${article.slug}` }),
|
package/package.json
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { Avatar, AvatarFallback, AvatarImage } from "../shadcnui";
|
|
4
|
-
import { useCurrentUserContext } from "../contexts";
|
|
5
4
|
import { S3Interface } from "../features/s3/data/s3.interface";
|
|
6
5
|
import { S3Service } from "../features/s3/data/s3.service";
|
|
7
6
|
import { ModuleWithPermissions } from "../permissions";
|
|
@@ -20,6 +19,12 @@ type EditableAvatarProps = {
|
|
|
20
19
|
patchImage: (imageKey: string) => Promise<void>;
|
|
21
20
|
className?: string;
|
|
22
21
|
fallbackClassName?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Company id used to namespace the S3 upload key. Supplied by the caller from
|
|
24
|
+
* whichever current-user context the host app instantiates, so this leaf
|
|
25
|
+
* component does not depend on a specific provider being mounted.
|
|
26
|
+
*/
|
|
27
|
+
companyId: string;
|
|
23
28
|
};
|
|
24
29
|
|
|
25
30
|
export function EditableAvatar({
|
|
@@ -31,8 +36,8 @@ export function EditableAvatar({
|
|
|
31
36
|
patchImage,
|
|
32
37
|
className,
|
|
33
38
|
fallbackClassName,
|
|
39
|
+
companyId,
|
|
34
40
|
}: EditableAvatarProps) {
|
|
35
|
-
const { company } = useCurrentUserContext();
|
|
36
41
|
const t = useTranslations();
|
|
37
42
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
38
43
|
|
|
@@ -46,15 +51,15 @@ export function EditableAvatar({
|
|
|
46
51
|
(file: File) => {
|
|
47
52
|
const ext = file.type.split("/").pop() ?? "";
|
|
48
53
|
const ts = new Date().toISOString().replace(/[-:T]/g, "").split(".")[0];
|
|
49
|
-
return `companies/${
|
|
54
|
+
return `companies/${companyId}/${module.name}/${entityId}/${entityId}.${ts}.${ext}`;
|
|
50
55
|
},
|
|
51
|
-
[
|
|
56
|
+
[companyId, module.name, entityId],
|
|
52
57
|
);
|
|
53
58
|
|
|
54
59
|
const handleFile = useCallback(
|
|
55
60
|
async (file: File) => {
|
|
56
61
|
if (isUploading) return;
|
|
57
|
-
if (!
|
|
62
|
+
if (!companyId) return;
|
|
58
63
|
|
|
59
64
|
const previousImage = image;
|
|
60
65
|
const previewUrl = URL.createObjectURL(file);
|
|
@@ -90,7 +95,7 @@ export function EditableAvatar({
|
|
|
90
95
|
setIsUploading(false);
|
|
91
96
|
}
|
|
92
97
|
},
|
|
93
|
-
[
|
|
98
|
+
[companyId, generateS3Key, image, isUploading, patchImage, t],
|
|
94
99
|
);
|
|
95
100
|
|
|
96
101
|
const handleRemove = useCallback(async () => {
|
|
@@ -237,20 +237,28 @@ export function RoundPageContainer({
|
|
|
237
237
|
<div
|
|
238
238
|
className={cn(
|
|
239
239
|
`min-w-0 grow`,
|
|
240
|
-
activeFillHeight ? `flex flex-col overflow-hidden` : `overflow-y-auto`,
|
|
240
|
+
activeFillHeight ? `flex flex-col overflow-hidden` : `overflow-y-auto p-4`,
|
|
241
241
|
)}
|
|
242
242
|
>
|
|
243
|
-
{
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
243
|
+
{/* Centre and constrain rail content (like the non-rail
|
|
244
|
+
layout). Fill-height tabs keep the full width. */}
|
|
245
|
+
<div
|
|
246
|
+
className={cn(
|
|
247
|
+
activeFillHeight ? `flex min-h-0 w-full flex-1 flex-col` : `mx-auto w-full max-w-6xl`,
|
|
248
|
+
)}
|
|
249
|
+
>
|
|
250
|
+
{header}
|
|
251
|
+
{tabs.map((tab) => (
|
|
252
|
+
<TabsContent
|
|
253
|
+
key={tab.label}
|
|
254
|
+
value={tabValue(tab)}
|
|
255
|
+
className={tab.fillHeight ? `flex min-h-0 w-full flex-1 flex-col` : ``}
|
|
256
|
+
>
|
|
257
|
+
{tab.content}
|
|
258
|
+
</TabsContent>
|
|
259
|
+
))}
|
|
260
|
+
{children && <div className="flex">{children}</div>}
|
|
261
|
+
</div>
|
|
254
262
|
</div>
|
|
255
263
|
</div>
|
|
256
264
|
</Tabs>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { LoaderCircleIcon, Trash2Icon } from "lucide-react";
|
|
4
|
-
import { ReactNode, useState } from "react";
|
|
4
|
+
import { isValidElement, ReactNode, useState } from "react";
|
|
5
5
|
import { useI18nRouter, useI18nTranslations } from "../../i18n";
|
|
6
6
|
import {
|
|
7
7
|
AlertDialog,
|
|
@@ -68,7 +68,12 @@ export function CommonDeleter({
|
|
|
68
68
|
|
|
69
69
|
return (
|
|
70
70
|
<AlertDialog open={open} onOpenChange={setOpen}>
|
|
71
|
-
{forceShow ? null : (
|
|
71
|
+
{forceShow ? null : isValidElement(trigger) ? (
|
|
72
|
+
// A caller-supplied element trigger must REPLACE the trigger's own
|
|
73
|
+
// <button> via `render` — wrapping it as a child would nest a <button>
|
|
74
|
+
// inside AlertDialogTrigger's <button> (invalid HTML / hydration error).
|
|
75
|
+
<AlertDialogTrigger render={trigger} />
|
|
76
|
+
) : (
|
|
72
77
|
<AlertDialogTrigger>
|
|
73
78
|
{trigger || (
|
|
74
79
|
<Button
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { ReactNode } from "react";
|
|
4
|
+
import { cn } from "../../utils";
|
|
5
|
+
|
|
6
|
+
type EntityHeroProps = {
|
|
7
|
+
avatar?: ReactNode;
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
className?: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export function EntityHero({ avatar, children, className }: EntityHeroProps) {
|
|
13
|
+
return (
|
|
14
|
+
<div className={cn("flex items-start gap-x-6", className)}>
|
|
15
|
+
{avatar}
|
|
16
|
+
<div className="flex flex-col gap-y-2">{children}</div>
|
|
17
|
+
</div>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { EditableAvatar } from "../EditableAvatar";
|
|
4
|
+
import { EntityAvatar } from "../EntityAvatar";
|
|
5
|
+
import { ModuleWithPermissions } from "../../permissions";
|
|
6
|
+
import { cn, getInitials } from "../../utils";
|
|
7
|
+
|
|
8
|
+
type EntityHeroAvatarProps = {
|
|
9
|
+
module: ModuleWithPermissions;
|
|
10
|
+
entityId: string;
|
|
11
|
+
name: string;
|
|
12
|
+
image?: string;
|
|
13
|
+
patchImage?: (imageKey: string) => Promise<void>;
|
|
14
|
+
/** Required when `patchImage` is set — namespaces the S3 upload key. */
|
|
15
|
+
companyId?: string;
|
|
16
|
+
variant?: "image" | "initials" | "icon";
|
|
17
|
+
className?: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export function EntityHeroAvatar({
|
|
21
|
+
module,
|
|
22
|
+
entityId,
|
|
23
|
+
name,
|
|
24
|
+
image,
|
|
25
|
+
patchImage,
|
|
26
|
+
companyId,
|
|
27
|
+
variant,
|
|
28
|
+
className = "h-24 w-24",
|
|
29
|
+
}: EntityHeroAvatarProps) {
|
|
30
|
+
const resolved = variant ?? (patchImage || image ? "image" : "icon");
|
|
31
|
+
|
|
32
|
+
if (patchImage) {
|
|
33
|
+
return (
|
|
34
|
+
<EditableAvatar
|
|
35
|
+
entityId={entityId}
|
|
36
|
+
module={module}
|
|
37
|
+
image={image}
|
|
38
|
+
fallback={getInitials(name)}
|
|
39
|
+
alt={name}
|
|
40
|
+
patchImage={patchImage}
|
|
41
|
+
companyId={companyId ?? ""}
|
|
42
|
+
className={className}
|
|
43
|
+
fallbackClassName="text-2xl"
|
|
44
|
+
/>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (resolved === "image" || resolved === "initials") {
|
|
49
|
+
return <EntityAvatar image={resolved === "image" ? image : undefined} name={name} className={className} />;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const Icon = module.icon;
|
|
53
|
+
// Not every module declares an icon; fall back to initials so the hero never
|
|
54
|
+
// renders an empty circle.
|
|
55
|
+
if (!Icon) {
|
|
56
|
+
return <EntityAvatar name={name} className={className} />;
|
|
57
|
+
}
|
|
58
|
+
return (
|
|
59
|
+
<div className={cn("bg-muted flex shrink-0 items-center justify-center rounded-full", className)}>
|
|
60
|
+
<Icon className="text-primary h-10 w-10" />
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { ReactNode } from "react";
|
|
4
|
+
import { cn } from "../../utils";
|
|
5
|
+
|
|
6
|
+
type EntityHeroLayoutProps = {
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
className?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export function EntityHeroLayout({ children, className }: EntityHeroLayoutProps) {
|
|
12
|
+
return <div className={cn("flex w-full flex-col gap-y-8", className)}>{children}</div>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { ComponentType, ReactNode } from "react";
|
|
4
|
+
import { cn } from "../../utils";
|
|
5
|
+
|
|
6
|
+
type EntityHeroMetaRowProps = {
|
|
7
|
+
icon?: ComponentType<{ className?: string }>;
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
className?: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export function EntityHeroMetaRow({ icon: Icon, children, className }: EntityHeroMetaRowProps) {
|
|
13
|
+
return (
|
|
14
|
+
<div className={cn("text-muted-foreground flex items-center gap-x-2 text-sm", className)}>
|
|
15
|
+
{Icon ? <Icon className="h-4 w-4 shrink-0" /> : null}
|
|
16
|
+
{children}
|
|
17
|
+
</div>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { ReactNode } from "react";
|
|
4
|
+
import { cn } from "../../utils";
|
|
5
|
+
|
|
6
|
+
type EntitySectionProps = {
|
|
7
|
+
title: string;
|
|
8
|
+
columns?: 2 | 3 | 4;
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
className?: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function EntitySection({ title, columns, children, className }: EntitySectionProps) {
|
|
14
|
+
return (
|
|
15
|
+
<div className={cn("flex w-full flex-col gap-y-3", className)}>
|
|
16
|
+
<h3 className="text-muted-foreground text-xs font-semibold tracking-wider uppercase">{title}</h3>
|
|
17
|
+
{columns ? (
|
|
18
|
+
<div
|
|
19
|
+
className={cn(
|
|
20
|
+
"grid grid-cols-1 gap-4",
|
|
21
|
+
columns === 2 && "md:grid-cols-2",
|
|
22
|
+
columns === 3 && "md:grid-cols-3",
|
|
23
|
+
columns === 4 && "md:grid-cols-4",
|
|
24
|
+
)}
|
|
25
|
+
>
|
|
26
|
+
{children}
|
|
27
|
+
</div>
|
|
28
|
+
) : (
|
|
29
|
+
<div className="flex flex-col gap-y-4">{children}</div>
|
|
30
|
+
)}
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
}
|
package/src/components/index.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { Badge, Link } from "../../../../shadcnui";
|
|
|
10
10
|
import { RoleInterface } from "../../../role";
|
|
11
11
|
import { UserInterface } from "../../data";
|
|
12
12
|
import { UserService } from "../../data/user.service";
|
|
13
|
-
import { useUserContext } from "../../contexts";
|
|
13
|
+
import { useCurrentUserContext, useUserContext } from "../../contexts";
|
|
14
14
|
import { BriefcaseIcon, MailIcon, PhoneIcon } from "lucide-react";
|
|
15
15
|
|
|
16
16
|
type UserContentProps = {
|
|
@@ -21,6 +21,7 @@ export function UserContent({ user }: UserContentProps) {
|
|
|
21
21
|
const t = useTranslations();
|
|
22
22
|
const generateUrl = usePageUrlGenerator();
|
|
23
23
|
const { setUser } = useUserContext();
|
|
24
|
+
const { company } = useCurrentUserContext();
|
|
24
25
|
|
|
25
26
|
const hasBio = !!user.bio;
|
|
26
27
|
|
|
@@ -38,6 +39,7 @@ export function UserContent({ user }: UserContentProps) {
|
|
|
38
39
|
const updated = await UserService.patchAvatar({ id: user.id, avatar: imageKey });
|
|
39
40
|
setUser(updated);
|
|
40
41
|
}}
|
|
42
|
+
companyId={company?.id ?? ""}
|
|
41
43
|
className="h-24 w-24"
|
|
42
44
|
fallbackClassName="text-2xl"
|
|
43
45
|
/>
|