@burdenoff/microfe-workspaces 2026.830.1 → 2026.915.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/components/CreateProjectDialog.js +65 -61
- package/dist/components/CreateProjectDialog.js.map +1 -1
- package/dist/components/CreateWorkspaceDialog.js +93 -90
- package/dist/components/CreateWorkspaceDialog.js.map +1 -1
- package/dist/components/InviteMemberDialog.js +122 -111
- package/dist/components/InviteMemberDialog.js.map +1 -1
- package/dist/components/MemberListItem.js +55 -58
- package/dist/components/MemberListItem.js.map +1 -1
- package/dist/components/ProjectCard.js +93 -92
- package/dist/components/ProjectCard.js.map +1 -1
- package/dist/components/ProjectMemberPickerDialog.js +78 -93
- package/dist/components/ProjectMemberPickerDialog.js.map +1 -1
- package/dist/components/RenameProjectDialog.js +47 -44
- package/dist/components/RenameProjectDialog.js.map +1 -1
- package/dist/components/WorkspaceCard.js +42 -43
- package/dist/components/WorkspaceCard.js.map +1 -1
- package/dist/components/WorkspacesErrorBoundary.js +43 -34
- package/dist/components/WorkspacesErrorBoundary.js.map +1 -1
- package/dist/components/tags/ProjectTagsWidget.js +75 -77
- package/dist/components/tags/ProjectTagsWidget.js.map +1 -1
- package/dist/hooks/useTr.js +14 -0
- package/dist/hooks/useTr.js.map +1 -0
- package/dist/index.js +2 -1
- package/dist/pages/ActivityListPage.js +3 -3
- package/dist/pages/CreateWorkspacePage.js +10 -10
- package/dist/pages/InviteAcceptancePage.js +49 -49
- package/dist/pages/InviteAcceptancePage.js.map +1 -1
- package/dist/pages/MembersListPage.js +6 -6
- package/dist/pages/PendingInvitesPage.js +3 -3
- package/dist/pages/ProjectDetailPage.js +4 -4
- package/dist/pages/ProjectDetailPage.js.map +1 -1
- package/dist/pages/ProjectMembersPage.js +3 -3
- package/dist/pages/ProjectsListPage.js +5 -5
- package/dist/pages/WorkspaceDetailPage.js +4 -4
- package/dist/pages/WorkspaceInvitePage.js +4 -4
- package/dist/pages/WorkspaceSettingsPage.js +7 -7
- package/dist/pages/WorkspacesListPage.js +9 -9
- package/dist/pages/dashboard/widgets/RecentActivityWidget.js +4 -4
- package/dist/pages/dashboard/widgets/StorageWidget.js +3 -3
- package/dist/pages/dashboard/widgets/WelcomeWidget.js +26 -16
- package/dist/pages/dashboard/widgets/WelcomeWidget.js.map +1 -1
- package/dist/translations/en.js +908 -0
- package/dist/translations/en.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,105 +1,102 @@
|
|
|
1
1
|
import { useWorkspacesContext as e } from "../providers/WorkspacesProvider.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
2
|
+
import { useTr as t } from "../hooks/useTr.js";
|
|
3
|
+
import { nativeImpact as n, nativeNotify as r } from "../utils/nativeBridge.js";
|
|
4
|
+
import { useRemoveWorkspaceMember as i } from "../hooks/useMemberMutations.js";
|
|
5
|
+
import { formatRelativeTime as a } from "../utils/formatters.js";
|
|
6
|
+
import { useMemo as o, useState as s } from "react";
|
|
7
|
+
import { MoreHorizontal as c, UserMinus as l } from "lucide-react";
|
|
8
|
+
import { Fragment as u, jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
9
|
+
import { AlertDialog as p, AlertDialogAction as m, AlertDialogCancel as h, AlertDialogContent as g, AlertDialogDescription as _, AlertDialogFooter as v, AlertDialogHeader as y, AlertDialogTitle as b, Badge as x, Button as S, CardContent as C, DropdownMenu as w, DropdownMenuContent as T, DropdownMenuTrigger as E, GlassCard as D } from "@burdenoff/fe-libs/ui";
|
|
10
|
+
import { ActorIdentity as O, useActorProfiles as k } from "@burdenoff/fe-libs/shared";
|
|
10
11
|
//#region src/components/MemberListItem.tsx
|
|
11
|
-
function
|
|
12
|
-
let [
|
|
13
|
-
actorId:
|
|
12
|
+
function A({ member: A, selected: j = !1, onToggleSelect: M, canRemove: N = !1 }) {
|
|
13
|
+
let P = t(), [F, I] = s(!1), { mutate: L, isPending: R } = i(A.workspaceId), { apiGatewayUrl: z, authToken: B, organizationId: V } = e(), H = k(o(() => [{
|
|
14
|
+
actorId: A.userId,
|
|
14
15
|
actorType: "user"
|
|
15
|
-
}], [
|
|
16
|
-
apiGatewayUrl:
|
|
17
|
-
authToken:
|
|
18
|
-
orgId:
|
|
19
|
-
workspaceId:
|
|
20
|
-
})[
|
|
21
|
-
return /* @__PURE__ */
|
|
16
|
+
}], [A.userId]), {
|
|
17
|
+
apiGatewayUrl: z,
|
|
18
|
+
authToken: B,
|
|
19
|
+
orgId: V,
|
|
20
|
+
workspaceId: A.workspaceId
|
|
21
|
+
})[A.userId];
|
|
22
|
+
return /* @__PURE__ */ f(u, { children: [/* @__PURE__ */ d(D, {
|
|
22
23
|
treatment: "plain",
|
|
23
|
-
className: `border-border-seam ${
|
|
24
|
-
children: /* @__PURE__ */
|
|
24
|
+
className: `border-border-seam ${j ? "ring-2 ring-action-primary-bg/25 border-action-primary-bg/50" : ""}`,
|
|
25
|
+
children: /* @__PURE__ */ d(C, {
|
|
25
26
|
className: "p-4",
|
|
26
|
-
children: /* @__PURE__ */
|
|
27
|
+
children: /* @__PURE__ */ f("div", {
|
|
27
28
|
className: "flex items-center justify-between gap-4",
|
|
28
|
-
children: [/* @__PURE__ */
|
|
29
|
+
children: [/* @__PURE__ */ f("div", {
|
|
29
30
|
className: "flex items-center gap-3 flex-1 min-w-0",
|
|
30
|
-
children: [
|
|
31
|
+
children: [M && /* @__PURE__ */ d("input", {
|
|
31
32
|
type: "checkbox",
|
|
32
|
-
checked:
|
|
33
|
-
onChange: (e) =>
|
|
33
|
+
checked: j,
|
|
34
|
+
onChange: (e) => M(e.target.checked),
|
|
34
35
|
className: "size-4 rounded border-border-default text-action-primary-bg",
|
|
35
|
-
"aria-label":
|
|
36
|
-
}), /* @__PURE__ */
|
|
36
|
+
"aria-label": P("memberListItem.selectMemberAriaLabel", "Select member {{name}}", { name: H?.displayName ?? "" })
|
|
37
|
+
}), /* @__PURE__ */ f("div", {
|
|
37
38
|
className: "flex-1 min-w-0",
|
|
38
|
-
children: [
|
|
39
|
-
profile:
|
|
39
|
+
children: [H ? /* @__PURE__ */ d(O, {
|
|
40
|
+
profile: H,
|
|
40
41
|
variant: "cell"
|
|
41
|
-
}) : null, /* @__PURE__ */
|
|
42
|
+
}) : null, /* @__PURE__ */ f("div", {
|
|
42
43
|
className: "mt-1 flex items-center gap-2",
|
|
43
|
-
children: [/* @__PURE__ */
|
|
44
|
+
children: [/* @__PURE__ */ d(x, {
|
|
44
45
|
variant: "secondary",
|
|
45
46
|
className: "text-xs",
|
|
46
|
-
children: "Workspace member"
|
|
47
|
+
children: P("memberListItem.workspaceMember", "Workspace member")
|
|
47
48
|
}), /* @__PURE__ */ d("span", {
|
|
48
49
|
className: "text-xs text-text-secondary",
|
|
49
|
-
children:
|
|
50
|
+
children: P("memberListItem.joined", "Joined {{time}}", { time: a(A.createdAt) })
|
|
50
51
|
})]
|
|
51
52
|
})]
|
|
52
53
|
})]
|
|
53
|
-
}),
|
|
54
|
+
}), N && /* @__PURE__ */ f(w, { children: [/* @__PURE__ */ d(E, {
|
|
54
55
|
asChild: !0,
|
|
55
|
-
children: /* @__PURE__ */
|
|
56
|
+
children: /* @__PURE__ */ f(S, {
|
|
56
57
|
variant: "ghost",
|
|
57
58
|
size: "icon",
|
|
58
59
|
className: "size-8 flex-shrink-0",
|
|
59
|
-
children: [/* @__PURE__ */
|
|
60
|
+
children: [/* @__PURE__ */ d(c, { className: "size-4" }), /* @__PURE__ */ d("span", {
|
|
60
61
|
className: "sr-only",
|
|
61
|
-
children: "Open member actions"
|
|
62
|
+
children: P("memberListItem.openActions", "Open member actions")
|
|
62
63
|
})]
|
|
63
64
|
})
|
|
64
|
-
}), /* @__PURE__ */
|
|
65
|
+
}), /* @__PURE__ */ d(T, {
|
|
65
66
|
align: "end",
|
|
66
|
-
children: /* @__PURE__ */
|
|
67
|
+
children: /* @__PURE__ */ f("button", {
|
|
67
68
|
type: "button",
|
|
68
|
-
onClick: () =>
|
|
69
|
+
onClick: () => I(!0),
|
|
69
70
|
className: "flex w-full items-center rounded-sm px-2 py-1.5 text-sm text-status-danger-text outline-none transition-colors hover:bg-action-ghost-bg-hover focus:bg-action-ghost-bg-hover",
|
|
70
|
-
children: [/* @__PURE__ */
|
|
71
|
+
children: [/* @__PURE__ */ d(l, { className: "mr-2 size-4" }), P("memberListItem.removeMember", "Remove Member")]
|
|
71
72
|
})
|
|
72
73
|
})] })]
|
|
73
74
|
})
|
|
74
75
|
})
|
|
75
|
-
}), /* @__PURE__ */
|
|
76
|
-
open:
|
|
77
|
-
onOpenChange:
|
|
78
|
-
children: /* @__PURE__ */
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
] })] }), /* @__PURE__ */ d(_, { children: [/* @__PURE__ */ u(m, {
|
|
83
|
-
disabled: I,
|
|
84
|
-
children: "Cancel"
|
|
85
|
-
}), /* @__PURE__ */ u(p, {
|
|
76
|
+
}), /* @__PURE__ */ d(p, {
|
|
77
|
+
open: F,
|
|
78
|
+
onOpenChange: I,
|
|
79
|
+
children: /* @__PURE__ */ f(g, { children: [/* @__PURE__ */ f(y, { children: [/* @__PURE__ */ d(b, { children: P("memberListItem.removeTitle", "Remove Member") }), /* @__PURE__ */ d(_, { children: P("memberListItem.removeDescription", "Are you sure you want to remove {{name}} from the workspace? This action cannot be undone.", { name: H?.displayName ?? P("memberListItem.thisMemberFallback", "this member") }) })] }), /* @__PURE__ */ f(v, { children: [/* @__PURE__ */ d(h, {
|
|
80
|
+
disabled: R,
|
|
81
|
+
children: P("common.cancel", "Cancel")
|
|
82
|
+
}), /* @__PURE__ */ d(m, {
|
|
86
83
|
onClick: () => {
|
|
87
|
-
|
|
84
|
+
n("medium"), L(A.id, {
|
|
88
85
|
onSuccess: () => {
|
|
89
|
-
|
|
86
|
+
r("success"), I(!1);
|
|
90
87
|
},
|
|
91
88
|
onError: () => {
|
|
92
|
-
|
|
89
|
+
r("error");
|
|
93
90
|
}
|
|
94
91
|
});
|
|
95
92
|
},
|
|
96
|
-
disabled:
|
|
93
|
+
disabled: R,
|
|
97
94
|
className: "bg-status-danger-bg text-status-danger-text hover:bg-status-danger-bg/90",
|
|
98
|
-
children:
|
|
95
|
+
children: R ? P("memberListItem.removing", "Removing...") : P("memberListItem.removeButton", "Remove Member")
|
|
99
96
|
})] })] })
|
|
100
97
|
})] });
|
|
101
98
|
}
|
|
102
99
|
//#endregion
|
|
103
|
-
export {
|
|
100
|
+
export { A as MemberListItem };
|
|
104
101
|
|
|
105
102
|
//# sourceMappingURL=MemberListItem.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MemberListItem.js","names":[],"sources":["../../src/components/MemberListItem.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport {\n GlassCard,\n CardContent,\n Button,\n Badge,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuTrigger,\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n} from '@burdenoff/fe-libs/ui';\nimport { MoreHorizontal, UserMinus } from 'lucide-react';\nimport { ActorIdentity, useActorProfiles, type ActorInput } from '@burdenoff/fe-libs/shared';\nimport { useRemoveWorkspaceMember } from '../hooks/useMemberMutations';\nimport { nativeImpact, nativeNotify } from '../utils/nativeBridge';\nimport { formatRelativeTime } from '../utils/formatters';\nimport { useWorkspacesContext } from '../providers/WorkspacesProvider';\nimport type { WorkspaceMember } from '../types';\n\nexport interface MemberListItemProps {\n member: WorkspaceMember;\n onUpdateRoles?: (memberId: string, roleIds: string[]) => void;\n selected?: boolean;\n onToggleSelect?: (checked: boolean) => void;\n canRemove?: boolean;\n}\n\nexport function MemberListItem({\n member,\n selected = false,\n onToggleSelect,\n canRemove = false,\n}: MemberListItemProps) {\n const [showRemoveDialog, setShowRemoveDialog] = useState(false);\n const { mutate: removeMember, isPending: isRemoving } = useRemoveWorkspaceMember(\n member.workspaceId\n );\n const { apiGatewayUrl, authToken, organizationId } = useWorkspacesContext();\n\n // Resolve userId → displayName + email via the shared actor profile cache.\n // UUIDs must never headline a row — the resolved identity goes in primary\n // position; the raw ID lives in the drill-down inside ActorIdentity.\n const actors = useMemo<ActorInput[]>(\n () => [{ actorId: member.userId, actorType: 'user' }],\n [member.userId]\n );\n const profileMap = useActorProfiles(actors, {\n apiGatewayUrl,\n authToken,\n orgId: organizationId,\n workspaceId: member.workspaceId,\n });\n const profile = profileMap[member.userId];\n\n const handleRemove = () => {\n void nativeImpact('medium');\n removeMember(member.id, {\n onSuccess: () => {\n void nativeNotify('success');\n setShowRemoveDialog(false);\n },\n onError: () => {\n void nativeNotify('error');\n },\n });\n };\n\n return (\n <>\n <GlassCard\n treatment=\"plain\"\n className={`border-border-seam ${\n selected ? 'ring-2 ring-action-primary-bg/25 border-action-primary-bg/50' : ''\n }`}\n >\n <CardContent className=\"p-4\">\n <div className=\"flex items-center justify-between gap-4\">\n <div className=\"flex items-center gap-3 flex-1 min-w-0\">\n {onToggleSelect && (\n <input\n type=\"checkbox\"\n checked={selected}\n onChange={(event) => onToggleSelect(event.target.checked)}\n className=\"size-4 rounded border-border-default text-action-primary-bg\"\n aria-label={
|
|
1
|
+
{"version":3,"file":"MemberListItem.js","names":[],"sources":["../../src/components/MemberListItem.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport {\n GlassCard,\n CardContent,\n Button,\n Badge,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuTrigger,\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n} from '@burdenoff/fe-libs/ui';\nimport { MoreHorizontal, UserMinus } from 'lucide-react';\nimport { ActorIdentity, useActorProfiles, type ActorInput } from '@burdenoff/fe-libs/shared';\nimport { useRemoveWorkspaceMember } from '../hooks/useMemberMutations';\nimport { nativeImpact, nativeNotify } from '../utils/nativeBridge';\nimport { formatRelativeTime } from '../utils/formatters';\nimport { useWorkspacesContext } from '../providers/WorkspacesProvider';\nimport { useTr } from '../hooks/useTr';\nimport type { WorkspaceMember } from '../types';\n\nexport interface MemberListItemProps {\n member: WorkspaceMember;\n onUpdateRoles?: (memberId: string, roleIds: string[]) => void;\n selected?: boolean;\n onToggleSelect?: (checked: boolean) => void;\n canRemove?: boolean;\n}\n\nexport function MemberListItem({\n member,\n selected = false,\n onToggleSelect,\n canRemove = false,\n}: MemberListItemProps) {\n const tr = useTr();\n const [showRemoveDialog, setShowRemoveDialog] = useState(false);\n const { mutate: removeMember, isPending: isRemoving } = useRemoveWorkspaceMember(\n member.workspaceId\n );\n const { apiGatewayUrl, authToken, organizationId } = useWorkspacesContext();\n\n // Resolve userId → displayName + email via the shared actor profile cache.\n // UUIDs must never headline a row — the resolved identity goes in primary\n // position; the raw ID lives in the drill-down inside ActorIdentity.\n const actors = useMemo<ActorInput[]>(\n () => [{ actorId: member.userId, actorType: 'user' }],\n [member.userId]\n );\n const profileMap = useActorProfiles(actors, {\n apiGatewayUrl,\n authToken,\n orgId: organizationId,\n workspaceId: member.workspaceId,\n });\n const profile = profileMap[member.userId];\n\n const handleRemove = () => {\n void nativeImpact('medium');\n removeMember(member.id, {\n onSuccess: () => {\n void nativeNotify('success');\n setShowRemoveDialog(false);\n },\n onError: () => {\n void nativeNotify('error');\n },\n });\n };\n\n return (\n <>\n <GlassCard\n treatment=\"plain\"\n className={`border-border-seam ${\n selected ? 'ring-2 ring-action-primary-bg/25 border-action-primary-bg/50' : ''\n }`}\n >\n <CardContent className=\"p-4\">\n <div className=\"flex items-center justify-between gap-4\">\n <div className=\"flex items-center gap-3 flex-1 min-w-0\">\n {onToggleSelect && (\n <input\n type=\"checkbox\"\n checked={selected}\n onChange={(event) => onToggleSelect(event.target.checked)}\n className=\"size-4 rounded border-border-default text-action-primary-bg\"\n aria-label={tr('memberListItem.selectMemberAriaLabel', 'Select member {{name}}', {\n name: profile?.displayName ?? '',\n })}\n />\n )}\n\n <div className=\"flex-1 min-w-0\">\n {profile ? <ActorIdentity profile={profile} variant=\"cell\" /> : null}\n <div className=\"mt-1 flex items-center gap-2\">\n <Badge variant=\"secondary\" className=\"text-xs\">\n {tr('memberListItem.workspaceMember', 'Workspace member')}\n </Badge>\n <span className=\"text-xs text-text-secondary\">\n {tr('memberListItem.joined', 'Joined {{time}}', {\n time: formatRelativeTime(member.createdAt),\n })}\n </span>\n </div>\n </div>\n </div>\n\n {canRemove && (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" className=\"size-8 flex-shrink-0\">\n <MoreHorizontal className=\"size-4\" />\n <span className=\"sr-only\">\n {tr('memberListItem.openActions', 'Open member actions')}\n </span>\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <button\n type=\"button\"\n onClick={() => setShowRemoveDialog(true)}\n className=\"flex w-full items-center rounded-sm px-2 py-1.5 text-sm text-status-danger-text outline-none transition-colors hover:bg-action-ghost-bg-hover focus:bg-action-ghost-bg-hover\"\n >\n <UserMinus className=\"mr-2 size-4\" />\n {tr('memberListItem.removeMember', 'Remove Member')}\n </button>\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n </div>\n </CardContent>\n </GlassCard>\n\n <AlertDialog open={showRemoveDialog} onOpenChange={setShowRemoveDialog}>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>{tr('memberListItem.removeTitle', 'Remove Member')}</AlertDialogTitle>\n <AlertDialogDescription>\n {tr(\n 'memberListItem.removeDescription',\n 'Are you sure you want to remove {{name}} from the workspace? This action cannot be undone.',\n {\n name:\n profile?.displayName ?? tr('memberListItem.thisMemberFallback', 'this member'),\n }\n )}\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={isRemoving}>\n {tr('common.cancel', 'Cancel')}\n </AlertDialogCancel>\n <AlertDialogAction\n onClick={handleRemove}\n disabled={isRemoving}\n className=\"bg-status-danger-bg text-status-danger-text hover:bg-status-danger-bg/90\"\n >\n {isRemoving\n ? tr('memberListItem.removing', 'Removing...')\n : tr('memberListItem.removeButton', 'Remove Member')}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,195 +1,196 @@
|
|
|
1
1
|
import { useWorkspacesContext as e } from "../providers/WorkspacesProvider.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
2
|
+
import { useTr as t } from "../hooks/useTr.js";
|
|
3
|
+
import { getProjectStatusClasses as n } from "../utils/tokenHelpers.js";
|
|
4
|
+
import { useScopedNavigation as r } from "../hooks/useScopedNavigation.js";
|
|
5
|
+
import { nativeConfirm as i, nativeImpact as a } from "../utils/nativeBridge.js";
|
|
6
|
+
import { useArchiveProject as o, useDeleteProject as s, useUnarchiveProject as c } from "../hooks/useProjectMutations.js";
|
|
7
|
+
import { formatDate as l } from "../utils/formatters.js";
|
|
8
|
+
import { getProjectDisplayTags as u } from "../utils/projectTags.js";
|
|
9
|
+
import { RenameProjectDialog as d } from "./RenameProjectDialog.js";
|
|
10
|
+
import { useState as f } from "react";
|
|
11
|
+
import { Archive as p, Fingerprint as m, FolderKanban as h, MoreVertical as g, Pencil as _ } from "lucide-react";
|
|
12
|
+
import { Fragment as v, jsx as y, jsxs as b } from "react/jsx-runtime";
|
|
13
|
+
import { Badge as x, Button as S, CardContent as C, CardHeader as w, CardTitle as T, DropdownMenu as E, DropdownMenuContent as D, DropdownMenuItem as O, DropdownMenuTrigger as k, EntityIdModal as A, GlassCard as j, useEntityIdModal as M } from "@burdenoff/fe-libs/ui";
|
|
14
|
+
import { useNavigate as N } from "react-router";
|
|
15
|
+
import { TagBadge as P } from "@burdenoff/fe-libs/tag";
|
|
15
16
|
//#region src/components/ProjectCard.tsx
|
|
16
|
-
function
|
|
17
|
-
let
|
|
18
|
-
|
|
17
|
+
function F({ project: F, selected: I = !1, onToggleSelect: L, onTagClick: R, canArchive: z = !1, canDelete: B = !1, canRename: V = !1 }) {
|
|
18
|
+
let H = N(), { basePath: U = "/workspaces" } = e(), { withCurrentSearch: W } = r(), { mutate: G } = o(F.workspaceId), { mutate: K } = c(F.workspaceId), { mutate: q } = s(F.workspaceId), J = M(), [Y, X] = f(!1), Z = u(F), Q = t(), $ = () => {
|
|
19
|
+
H(W(`${U}/${F.workspaceId}/projects/${F.id}`));
|
|
19
20
|
};
|
|
20
|
-
return /* @__PURE__ */
|
|
21
|
-
/* @__PURE__ */
|
|
21
|
+
return /* @__PURE__ */ b(v, { children: [
|
|
22
|
+
/* @__PURE__ */ b(j, {
|
|
22
23
|
treatment: "insight",
|
|
23
|
-
className: `cursor-pointer relative focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg/50 ${
|
|
24
|
-
onClick:
|
|
24
|
+
className: `cursor-pointer relative focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg/50 ${I ? "ring-2 ring-primary/25 border-primary/50" : ""}`,
|
|
25
|
+
onClick: $,
|
|
25
26
|
onKeyDown: (e) => {
|
|
26
|
-
(e.key === "Enter" || e.key === " ") && (e.preventDefault(),
|
|
27
|
+
(e.key === "Enter" || e.key === " ") && (e.preventDefault(), $());
|
|
27
28
|
},
|
|
28
29
|
role: "button",
|
|
29
30
|
tabIndex: 0,
|
|
30
|
-
"aria-label":
|
|
31
|
-
children: [/* @__PURE__ */
|
|
31
|
+
"aria-label": Q("projectCard.openProjectAriaLabel", "Open project {{name}}", { name: F.name }),
|
|
32
|
+
children: [/* @__PURE__ */ y(w, { children: /* @__PURE__ */ b("div", {
|
|
32
33
|
className: "flex items-start justify-between",
|
|
33
|
-
children: [/* @__PURE__ */
|
|
34
|
+
children: [/* @__PURE__ */ b("div", {
|
|
34
35
|
className: "flex items-center gap-3 flex-1",
|
|
35
36
|
children: [
|
|
36
|
-
|
|
37
|
+
L && /* @__PURE__ */ y("input", {
|
|
37
38
|
type: "checkbox",
|
|
38
|
-
checked:
|
|
39
|
-
onChange: (e) =>
|
|
39
|
+
checked: I,
|
|
40
|
+
onChange: (e) => L(e.target.checked),
|
|
40
41
|
onClick: (e) => e.stopPropagation(),
|
|
41
|
-
"aria-label":
|
|
42
|
+
"aria-label": Q("projectCard.selectProjectAriaLabel", "Select project {{name}}", { name: F.name }),
|
|
42
43
|
className: "mt-1 size-4 rounded border-border-subtle text-primary"
|
|
43
44
|
}),
|
|
44
|
-
/* @__PURE__ */
|
|
45
|
+
/* @__PURE__ */ y("div", {
|
|
45
46
|
className: "p-3 rounded-lg bg-action-primary-bg/10 transition-colors",
|
|
46
|
-
children: /* @__PURE__ */
|
|
47
|
+
children: /* @__PURE__ */ y(h, {
|
|
47
48
|
className: "text-primary",
|
|
48
49
|
size: 24
|
|
49
50
|
})
|
|
50
51
|
}),
|
|
51
|
-
/* @__PURE__ */
|
|
52
|
+
/* @__PURE__ */ b("div", {
|
|
52
53
|
className: "flex-1 min-w-0",
|
|
53
|
-
children: [/* @__PURE__ */
|
|
54
|
+
children: [/* @__PURE__ */ y(T, {
|
|
54
55
|
className: "truncate",
|
|
55
|
-
children:
|
|
56
|
-
}), /* @__PURE__ */
|
|
56
|
+
children: F.name
|
|
57
|
+
}), /* @__PURE__ */ y("p", {
|
|
57
58
|
className: "truncate text-sm text-text-secondary",
|
|
58
|
-
children:
|
|
59
|
+
children: F.key
|
|
59
60
|
})]
|
|
60
61
|
})
|
|
61
62
|
]
|
|
62
|
-
}), /* @__PURE__ */
|
|
63
|
+
}), /* @__PURE__ */ b(E, { children: [/* @__PURE__ */ y(k, {
|
|
63
64
|
asChild: !0,
|
|
64
65
|
onClick: (e) => e.stopPropagation(),
|
|
65
|
-
children: /* @__PURE__ */
|
|
66
|
+
children: /* @__PURE__ */ b(S, {
|
|
66
67
|
variant: "ghost",
|
|
67
68
|
size: "sm",
|
|
68
69
|
className: "size-8 p-0",
|
|
69
|
-
children: [/* @__PURE__ */
|
|
70
|
+
children: [/* @__PURE__ */ y(g, { size: 16 }), /* @__PURE__ */ y("span", {
|
|
70
71
|
className: "sr-only",
|
|
71
|
-
children: "Open project actions"
|
|
72
|
+
children: Q("projectCard.openActions", "Open project actions")
|
|
72
73
|
})]
|
|
73
74
|
})
|
|
74
|
-
}), /* @__PURE__ */
|
|
75
|
+
}), /* @__PURE__ */ b(D, {
|
|
75
76
|
align: "end",
|
|
76
77
|
children: [
|
|
77
|
-
/* @__PURE__ */
|
|
78
|
+
/* @__PURE__ */ b(O, {
|
|
78
79
|
onClick: (e) => {
|
|
79
|
-
e.stopPropagation(),
|
|
80
|
-
id:
|
|
81
|
-
name:
|
|
80
|
+
e.stopPropagation(), J.show({
|
|
81
|
+
id: F.id,
|
|
82
|
+
name: F.name,
|
|
82
83
|
type: "Project",
|
|
83
84
|
details: [{
|
|
84
|
-
label: "Key",
|
|
85
|
-
value:
|
|
85
|
+
label: Q("projectCard.keyLabel", "Key"),
|
|
86
|
+
value: F.key
|
|
86
87
|
}, {
|
|
87
|
-
label: "Workspace ID",
|
|
88
|
-
value:
|
|
88
|
+
label: Q("projectCard.workspaceIdLabel", "Workspace ID"),
|
|
89
|
+
value: F.workspaceId
|
|
89
90
|
}]
|
|
90
91
|
});
|
|
91
92
|
},
|
|
92
|
-
children: [/* @__PURE__ */
|
|
93
|
+
children: [/* @__PURE__ */ y(m, {
|
|
93
94
|
size: 16,
|
|
94
95
|
className: "mr-2"
|
|
95
|
-
}), "Get ID"]
|
|
96
|
+
}), Q("projectCard.getId", "Get ID")]
|
|
96
97
|
}),
|
|
97
|
-
|
|
98
|
+
V && /* @__PURE__ */ b(O, {
|
|
98
99
|
onClick: (e) => {
|
|
99
|
-
e.stopPropagation(),
|
|
100
|
+
e.stopPropagation(), X(!0);
|
|
100
101
|
},
|
|
101
|
-
children: [/* @__PURE__ */
|
|
102
|
+
children: [/* @__PURE__ */ y(_, {
|
|
102
103
|
size: 16,
|
|
103
104
|
className: "mr-2"
|
|
104
|
-
}), "Rename"]
|
|
105
|
+
}), Q("projectCard.rename", "Rename")]
|
|
105
106
|
}),
|
|
106
|
-
|
|
107
|
+
z && /* @__PURE__ */ b(O, {
|
|
107
108
|
onClick: (e) => {
|
|
108
|
-
e.stopPropagation(),
|
|
109
|
+
e.stopPropagation(), F.archived ? K(F.id) : G(F.id);
|
|
109
110
|
},
|
|
110
|
-
children: [/* @__PURE__ */
|
|
111
|
+
children: [/* @__PURE__ */ y(p, {
|
|
111
112
|
size: 16,
|
|
112
113
|
className: "mr-2"
|
|
113
|
-
}),
|
|
114
|
+
}), F.archived ? Q("projectCard.unarchive", "Unarchive") : Q("projectCard.archive", "Archive")]
|
|
114
115
|
}),
|
|
115
|
-
|
|
116
|
+
B && /* @__PURE__ */ y(O, {
|
|
116
117
|
onClick: async (e) => {
|
|
117
|
-
e.stopPropagation(),
|
|
118
|
-
let t = await
|
|
119
|
-
title: "Delete project",
|
|
120
|
-
message:
|
|
121
|
-
okButtonTitle: "Delete",
|
|
122
|
-
cancelButtonTitle: "Cancel"
|
|
118
|
+
e.stopPropagation(), a("medium");
|
|
119
|
+
let t = await i({
|
|
120
|
+
title: Q("projectCard.deleteTitle", "Delete project"),
|
|
121
|
+
message: Q("projectCard.deleteMessage", "Are you sure you want to delete \"{{name}}\"?", { name: F.name }),
|
|
122
|
+
okButtonTitle: Q("common.delete", "Delete"),
|
|
123
|
+
cancelButtonTitle: Q("common.cancel", "Cancel")
|
|
123
124
|
});
|
|
124
|
-
(t === null ? confirm(
|
|
125
|
+
(t === null ? confirm(Q("projectCard.deleteMessage", "Are you sure you want to delete \"{{name}}\"?", { name: F.name })) : t) && q(F.id);
|
|
125
126
|
},
|
|
126
127
|
className: "text-status-error-text",
|
|
127
|
-
children: "Delete"
|
|
128
|
+
children: Q("projectCard.delete", "Delete")
|
|
128
129
|
})
|
|
129
130
|
]
|
|
130
131
|
})] })]
|
|
131
|
-
}) }), /* @__PURE__ */
|
|
132
|
+
}) }), /* @__PURE__ */ b(C, {
|
|
132
133
|
className: "space-y-3",
|
|
133
134
|
children: [
|
|
134
|
-
/* @__PURE__ */
|
|
135
|
+
/* @__PURE__ */ b("div", {
|
|
135
136
|
className: "flex items-center gap-2",
|
|
136
|
-
children: [/* @__PURE__ */
|
|
137
|
-
className: `border ${
|
|
138
|
-
children:
|
|
139
|
-
}),
|
|
137
|
+
children: [/* @__PURE__ */ y(x, {
|
|
138
|
+
className: `border ${n(F.status)}`,
|
|
139
|
+
children: F.status
|
|
140
|
+
}), F.archived && /* @__PURE__ */ b(x, {
|
|
140
141
|
variant: "outline",
|
|
141
142
|
className: "border-workspace-archived-border text-workspace-archived-text",
|
|
142
|
-
children: [/* @__PURE__ */
|
|
143
|
+
children: [/* @__PURE__ */ y(p, {
|
|
143
144
|
size: 12,
|
|
144
145
|
className: "mr-1"
|
|
145
|
-
}), "Archived"]
|
|
146
|
+
}), Q("projectCard.archivedLabel", "Archived")]
|
|
146
147
|
})]
|
|
147
148
|
}),
|
|
148
149
|
/* @__PURE__ */ y("div", {
|
|
149
150
|
className: "text-xs text-text-secondary",
|
|
150
|
-
children:
|
|
151
|
+
children: Q("projectCard.created", "Created {{date}}", { date: l(F.createdAt) })
|
|
151
152
|
}),
|
|
152
|
-
|
|
153
|
+
Z.length > 0 && /* @__PURE__ */ b("div", {
|
|
153
154
|
className: "flex flex-wrap gap-1.5",
|
|
154
|
-
"aria-label": "Project tags",
|
|
155
|
-
children: [
|
|
156
|
-
...
|
|
155
|
+
"aria-label": Q("projectCard.projectTagsAriaLabel", "Project tags"),
|
|
156
|
+
children: [Z.slice(0, 4).map((e) => /* @__PURE__ */ y("span", {
|
|
157
|
+
...R ? {
|
|
157
158
|
role: "button",
|
|
158
159
|
tabIndex: 0,
|
|
159
160
|
onClick: (t) => {
|
|
160
|
-
t.stopPropagation(),
|
|
161
|
+
t.stopPropagation(), R(e);
|
|
161
162
|
},
|
|
162
163
|
onKeyDown: (t) => {
|
|
163
|
-
(t.key === "Enter" || t.key === " ") && (t.preventDefault(), t.stopPropagation(),
|
|
164
|
+
(t.key === "Enter" || t.key === " ") && (t.preventDefault(), t.stopPropagation(), R(e));
|
|
164
165
|
}
|
|
165
166
|
} : {},
|
|
166
|
-
children: /* @__PURE__ */
|
|
167
|
+
children: /* @__PURE__ */ y(P, {
|
|
167
168
|
id: e.tagId,
|
|
168
169
|
label: e.label,
|
|
169
170
|
color: e.color ?? void 0,
|
|
170
171
|
icon: e.icon ?? void 0,
|
|
171
172
|
description: e.description ?? void 0,
|
|
172
173
|
size: "sm",
|
|
173
|
-
className:
|
|
174
|
+
className: R ? "cursor-pointer" : void 0
|
|
174
175
|
})
|
|
175
|
-
}, e.tagId)),
|
|
176
|
+
}, e.tagId)), Z.length > 4 && /* @__PURE__ */ b(x, {
|
|
176
177
|
variant: "outline",
|
|
177
178
|
className: "text-xs",
|
|
178
|
-
children: ["+",
|
|
179
|
+
children: ["+", Z.length - 4]
|
|
179
180
|
})]
|
|
180
181
|
})
|
|
181
182
|
]
|
|
182
183
|
})]
|
|
183
184
|
}),
|
|
184
|
-
/* @__PURE__ */
|
|
185
|
-
|
|
186
|
-
project:
|
|
187
|
-
open:
|
|
188
|
-
onOpenChange:
|
|
185
|
+
/* @__PURE__ */ y(A, { control: J }),
|
|
186
|
+
Y && /* @__PURE__ */ y(d, {
|
|
187
|
+
project: F,
|
|
188
|
+
open: Y,
|
|
189
|
+
onOpenChange: X
|
|
189
190
|
})
|
|
190
191
|
] });
|
|
191
192
|
}
|
|
192
193
|
//#endregion
|
|
193
|
-
export {
|
|
194
|
+
export { F as ProjectCard };
|
|
194
195
|
|
|
195
196
|
//# sourceMappingURL=ProjectCard.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectCard.js","names":[],"sources":["../../src/components/ProjectCard.tsx"],"sourcesContent":["import type React from 'react';\nimport { useState } from 'react';\nimport { FolderKanban, Archive, MoreVertical, Fingerprint, Pencil } from 'lucide-react';\nimport { useNavigate } from 'react-router';\nimport {\n GlassCard,\n CardContent,\n CardHeader,\n CardTitle,\n Badge,\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n EntityIdModal,\n useEntityIdModal,\n} from '@burdenoff/fe-libs/ui';\nimport { TagBadge } from '@burdenoff/fe-libs/tag';\n\nimport type { Project, ProjectTag } from '../types';\nimport { formatDate } from '../utils/formatters';\nimport { getProjectDisplayTags } from '../utils/projectTags';\nimport { getProjectStatusClasses } from '../utils/tokenHelpers';\nimport {\n useArchiveProject,\n useUnarchiveProject,\n useDeleteProject,\n} from '../hooks/useProjectMutations';\nimport { useWorkspacesContext } from '../providers/WorkspacesProvider';\nimport { useScopedNavigation } from '../hooks/useScopedNavigation';\nimport { nativeConfirm, nativeImpact } from '../utils/nativeBridge';\nimport { RenameProjectDialog } from './RenameProjectDialog';\n\ninterface ProjectCardProps {\n project: Project;\n selected?: boolean;\n onToggleSelect?: (checked: boolean) => void;\n onTagClick?: (tag: ProjectTag) => void;\n canArchive?: boolean;\n canDelete?: boolean;\n canRename?: boolean;\n}\n\nexport function ProjectCard({\n project,\n selected = false,\n onToggleSelect,\n onTagClick,\n canArchive = false,\n canDelete = false,\n canRename = false,\n}: ProjectCardProps) {\n const navigate = useNavigate();\n const { basePath = '/workspaces' } = useWorkspacesContext();\n const { withCurrentSearch } = useScopedNavigation();\n const { mutate: archiveProject } = useArchiveProject(project.workspaceId);\n const { mutate: unarchiveProject } = useUnarchiveProject(project.workspaceId);\n const { mutate: deleteProject } = useDeleteProject(project.workspaceId);\n const idModal = useEntityIdModal();\n const [showRenameDialog, setShowRenameDialog] = useState(false);\n const projectTags = getProjectDisplayTags(project);\n\n const handleCardClick = () => {\n navigate(withCurrentSearch(`${basePath}/${project.workspaceId}/projects/${project.id}`));\n };\n\n const handleArchive = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (project.archived) {\n unarchiveProject(project.id);\n } else {\n archiveProject(project.id);\n }\n };\n\n const handleDelete = async (e: React.MouseEvent) => {\n e.stopPropagation();\n void nativeImpact('medium');\n const native = await nativeConfirm({\n title: 'Delete project',\n message: `Are you sure you want to delete \"${project.name}\"?`,\n okButtonTitle: 'Delete',\n cancelButtonTitle: 'Cancel',\n });\n const ok =\n native === null ? confirm(`Are you sure you want to delete \"${project.name}\"?`) : native;\n if (ok) {\n deleteProject(project.id);\n }\n };\n\n const handleCardKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n handleCardClick();\n }\n };\n\n return (\n <>\n <GlassCard\n treatment=\"insight\"\n className={`cursor-pointer relative focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg/50 ${\n selected ? 'ring-2 ring-primary/25 border-primary/50' : ''\n }`}\n onClick={handleCardClick}\n onKeyDown={handleCardKeyDown}\n role=\"button\"\n tabIndex={0}\n aria-label={`Open project ${project.name}`}\n >\n <CardHeader>\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-center gap-3 flex-1\">\n {onToggleSelect && (\n <input\n type=\"checkbox\"\n checked={selected}\n onChange={(event) => onToggleSelect(event.target.checked)}\n onClick={(event) => event.stopPropagation()}\n aria-label={`Select project ${project.name}`}\n className=\"mt-1 size-4 rounded border-border-subtle text-primary\"\n />\n )}\n <div className=\"p-3 rounded-lg bg-action-primary-bg/10 transition-colors\">\n <FolderKanban className=\"text-primary\" size={24} />\n </div>\n <div className=\"flex-1 min-w-0\">\n <CardTitle className=\"truncate\">{project.name}</CardTitle>\n <p className=\"truncate text-sm text-text-secondary\">{project.key}</p>\n </div>\n </div>\n <DropdownMenu>\n <DropdownMenuTrigger asChild onClick={(e) => e.stopPropagation()}>\n <Button variant=\"ghost\" size=\"sm\" className=\"size-8 p-0\">\n <MoreVertical size={16} />\n <span className=\"sr-only\">Open project actions</span>\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem\n onClick={(e) => {\n e.stopPropagation();\n idModal.show({\n id: project.id,\n name: project.name,\n type: 'Project',\n details: [\n { label: 'Key', value: project.key },\n { label: 'Workspace ID', value: project.workspaceId },\n ],\n });\n }}\n >\n <Fingerprint size={16} className=\"mr-2\" />\n Get ID\n </DropdownMenuItem>\n {canRename && (\n <DropdownMenuItem\n onClick={(e) => {\n e.stopPropagation();\n setShowRenameDialog(true);\n }}\n >\n <Pencil size={16} className=\"mr-2\" />\n Rename\n </DropdownMenuItem>\n )}\n {canArchive && (\n <DropdownMenuItem onClick={handleArchive}>\n <Archive size={16} className=\"mr-2\" />\n {project.archived ? 'Unarchive' : 'Archive'}\n </DropdownMenuItem>\n )}\n {canDelete && (\n <DropdownMenuItem onClick={handleDelete} className=\"text-status-error-text\">\n Delete\n </DropdownMenuItem>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n <Badge className={`border ${getProjectStatusClasses(project.status)}`}>\n {project.status}\n </Badge>\n {project.archived && (\n <Badge\n variant=\"outline\"\n className=\"border-workspace-archived-border text-workspace-archived-text\"\n >\n <Archive size={12} className=\"mr-1\" />\n Archived\n </Badge>\n )}\n </div>\n <div className=\"text-xs text-text-secondary\">Created {formatDate(project.createdAt)}</div>\n {projectTags.length > 0 && (\n <div className=\"flex flex-wrap gap-1.5\" aria-label=\"Project tags\">\n {projectTags.slice(0, 4).map((tag) => (\n <span\n key={tag.tagId}\n {...(onTagClick\n ? {\n role: 'button',\n tabIndex: 0,\n onClick: (event: React.MouseEvent<HTMLSpanElement>) => {\n event.stopPropagation();\n onTagClick(tag);\n },\n onKeyDown: (event: React.KeyboardEvent<HTMLSpanElement>) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n event.stopPropagation();\n onTagClick(tag);\n }\n },\n }\n : {})}\n >\n <TagBadge\n id={tag.tagId}\n label={tag.label}\n color={tag.color ?? undefined}\n icon={tag.icon ?? undefined}\n description={tag.description ?? undefined}\n size=\"sm\"\n className={onTagClick ? 'cursor-pointer' : undefined}\n />\n </span>\n ))}\n {projectTags.length > 4 && (\n <Badge variant=\"outline\" className=\"text-xs\">\n +{projectTags.length - 4}\n </Badge>\n )}\n </div>\n )}\n </CardContent>\n </GlassCard>\n <EntityIdModal control={idModal} />\n {showRenameDialog && (\n <RenameProjectDialog\n project={project}\n open={showRenameDialog}\n onOpenChange={setShowRenameDialog}\n />\n )}\n </>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ProjectCard.js","names":[],"sources":["../../src/components/ProjectCard.tsx"],"sourcesContent":["import type React from 'react';\nimport { useState } from 'react';\nimport { FolderKanban, Archive, MoreVertical, Fingerprint, Pencil } from 'lucide-react';\nimport { useNavigate } from 'react-router';\nimport {\n GlassCard,\n CardContent,\n CardHeader,\n CardTitle,\n Badge,\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n EntityIdModal,\n useEntityIdModal,\n} from '@burdenoff/fe-libs/ui';\nimport { TagBadge } from '@burdenoff/fe-libs/tag';\n\nimport type { Project, ProjectTag } from '../types';\nimport { formatDate } from '../utils/formatters';\nimport { getProjectDisplayTags } from '../utils/projectTags';\nimport { getProjectStatusClasses } from '../utils/tokenHelpers';\nimport {\n useArchiveProject,\n useUnarchiveProject,\n useDeleteProject,\n} from '../hooks/useProjectMutations';\nimport { useWorkspacesContext } from '../providers/WorkspacesProvider';\nimport { useScopedNavigation } from '../hooks/useScopedNavigation';\nimport { nativeConfirm, nativeImpact } from '../utils/nativeBridge';\nimport { RenameProjectDialog } from './RenameProjectDialog';\nimport { useTr } from '../hooks/useTr';\n\ninterface ProjectCardProps {\n project: Project;\n selected?: boolean;\n onToggleSelect?: (checked: boolean) => void;\n onTagClick?: (tag: ProjectTag) => void;\n canArchive?: boolean;\n canDelete?: boolean;\n canRename?: boolean;\n}\n\nexport function ProjectCard({\n project,\n selected = false,\n onToggleSelect,\n onTagClick,\n canArchive = false,\n canDelete = false,\n canRename = false,\n}: ProjectCardProps) {\n const navigate = useNavigate();\n const { basePath = '/workspaces' } = useWorkspacesContext();\n const { withCurrentSearch } = useScopedNavigation();\n const { mutate: archiveProject } = useArchiveProject(project.workspaceId);\n const { mutate: unarchiveProject } = useUnarchiveProject(project.workspaceId);\n const { mutate: deleteProject } = useDeleteProject(project.workspaceId);\n const idModal = useEntityIdModal();\n const [showRenameDialog, setShowRenameDialog] = useState(false);\n const projectTags = getProjectDisplayTags(project);\n const tr = useTr();\n\n const handleCardClick = () => {\n navigate(withCurrentSearch(`${basePath}/${project.workspaceId}/projects/${project.id}`));\n };\n\n const handleArchive = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (project.archived) {\n unarchiveProject(project.id);\n } else {\n archiveProject(project.id);\n }\n };\n\n const handleDelete = async (e: React.MouseEvent) => {\n e.stopPropagation();\n void nativeImpact('medium');\n const native = await nativeConfirm({\n title: tr('projectCard.deleteTitle', 'Delete project'),\n message: tr('projectCard.deleteMessage', 'Are you sure you want to delete \"{{name}}\"?', {\n name: project.name,\n }),\n okButtonTitle: tr('common.delete', 'Delete'),\n cancelButtonTitle: tr('common.cancel', 'Cancel'),\n });\n const ok =\n native === null\n ? confirm(\n tr('projectCard.deleteMessage', 'Are you sure you want to delete \"{{name}}\"?', {\n name: project.name,\n })\n )\n : native;\n if (ok) {\n deleteProject(project.id);\n }\n };\n\n const handleCardKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n handleCardClick();\n }\n };\n\n return (\n <>\n <GlassCard\n treatment=\"insight\"\n className={`cursor-pointer relative focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg/50 ${\n selected ? 'ring-2 ring-primary/25 border-primary/50' : ''\n }`}\n onClick={handleCardClick}\n onKeyDown={handleCardKeyDown}\n role=\"button\"\n tabIndex={0}\n aria-label={tr('projectCard.openProjectAriaLabel', 'Open project {{name}}', {\n name: project.name,\n })}\n >\n <CardHeader>\n <div className=\"flex items-start justify-between\">\n <div className=\"flex items-center gap-3 flex-1\">\n {onToggleSelect && (\n <input\n type=\"checkbox\"\n checked={selected}\n onChange={(event) => onToggleSelect(event.target.checked)}\n onClick={(event) => event.stopPropagation()}\n aria-label={tr('projectCard.selectProjectAriaLabel', 'Select project {{name}}', {\n name: project.name,\n })}\n className=\"mt-1 size-4 rounded border-border-subtle text-primary\"\n />\n )}\n <div className=\"p-3 rounded-lg bg-action-primary-bg/10 transition-colors\">\n <FolderKanban className=\"text-primary\" size={24} />\n </div>\n <div className=\"flex-1 min-w-0\">\n <CardTitle className=\"truncate\">{project.name}</CardTitle>\n <p className=\"truncate text-sm text-text-secondary\">{project.key}</p>\n </div>\n </div>\n <DropdownMenu>\n <DropdownMenuTrigger asChild onClick={(e) => e.stopPropagation()}>\n <Button variant=\"ghost\" size=\"sm\" className=\"size-8 p-0\">\n <MoreVertical size={16} />\n <span className=\"sr-only\">\n {tr('projectCard.openActions', 'Open project actions')}\n </span>\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem\n onClick={(e) => {\n e.stopPropagation();\n idModal.show({\n id: project.id,\n name: project.name,\n type: 'Project',\n details: [\n { label: tr('projectCard.keyLabel', 'Key'), value: project.key },\n {\n label: tr('projectCard.workspaceIdLabel', 'Workspace ID'),\n value: project.workspaceId,\n },\n ],\n });\n }}\n >\n <Fingerprint size={16} className=\"mr-2\" />\n {tr('projectCard.getId', 'Get ID')}\n </DropdownMenuItem>\n {canRename && (\n <DropdownMenuItem\n onClick={(e) => {\n e.stopPropagation();\n setShowRenameDialog(true);\n }}\n >\n <Pencil size={16} className=\"mr-2\" />\n {tr('projectCard.rename', 'Rename')}\n </DropdownMenuItem>\n )}\n {canArchive && (\n <DropdownMenuItem onClick={handleArchive}>\n <Archive size={16} className=\"mr-2\" />\n {project.archived\n ? tr('projectCard.unarchive', 'Unarchive')\n : tr('projectCard.archive', 'Archive')}\n </DropdownMenuItem>\n )}\n {canDelete && (\n <DropdownMenuItem onClick={handleDelete} className=\"text-status-error-text\">\n {tr('projectCard.delete', 'Delete')}\n </DropdownMenuItem>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n <Badge className={`border ${getProjectStatusClasses(project.status)}`}>\n {project.status}\n </Badge>\n {project.archived && (\n <Badge\n variant=\"outline\"\n className=\"border-workspace-archived-border text-workspace-archived-text\"\n >\n <Archive size={12} className=\"mr-1\" />\n {tr('projectCard.archivedLabel', 'Archived')}\n </Badge>\n )}\n </div>\n <div className=\"text-xs text-text-secondary\">\n {tr('projectCard.created', 'Created {{date}}', { date: formatDate(project.createdAt) })}\n </div>\n {projectTags.length > 0 && (\n <div\n className=\"flex flex-wrap gap-1.5\"\n aria-label={tr('projectCard.projectTagsAriaLabel', 'Project tags')}\n >\n {projectTags.slice(0, 4).map((tag) => (\n <span\n key={tag.tagId}\n {...(onTagClick\n ? {\n role: 'button',\n tabIndex: 0,\n onClick: (event: React.MouseEvent<HTMLSpanElement>) => {\n event.stopPropagation();\n onTagClick(tag);\n },\n onKeyDown: (event: React.KeyboardEvent<HTMLSpanElement>) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n event.stopPropagation();\n onTagClick(tag);\n }\n },\n }\n : {})}\n >\n <TagBadge\n id={tag.tagId}\n label={tag.label}\n color={tag.color ?? undefined}\n icon={tag.icon ?? undefined}\n description={tag.description ?? undefined}\n size=\"sm\"\n className={onTagClick ? 'cursor-pointer' : undefined}\n />\n </span>\n ))}\n {projectTags.length > 4 && (\n <Badge variant=\"outline\" className=\"text-xs\">\n +{projectTags.length - 4}\n </Badge>\n )}\n </div>\n )}\n </CardContent>\n </GlassCard>\n <EntityIdModal control={idModal} />\n {showRenameDialog && (\n <RenameProjectDialog\n project={project}\n open={showRenameDialog}\n onOpenChange={setShowRenameDialog}\n />\n )}\n </>\n );\n}\n"],"mappings":"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"}
|