@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.
Files changed (44) hide show
  1. package/dist/components/CreateProjectDialog.js +65 -61
  2. package/dist/components/CreateProjectDialog.js.map +1 -1
  3. package/dist/components/CreateWorkspaceDialog.js +93 -90
  4. package/dist/components/CreateWorkspaceDialog.js.map +1 -1
  5. package/dist/components/InviteMemberDialog.js +122 -111
  6. package/dist/components/InviteMemberDialog.js.map +1 -1
  7. package/dist/components/MemberListItem.js +55 -58
  8. package/dist/components/MemberListItem.js.map +1 -1
  9. package/dist/components/ProjectCard.js +93 -92
  10. package/dist/components/ProjectCard.js.map +1 -1
  11. package/dist/components/ProjectMemberPickerDialog.js +78 -93
  12. package/dist/components/ProjectMemberPickerDialog.js.map +1 -1
  13. package/dist/components/RenameProjectDialog.js +47 -44
  14. package/dist/components/RenameProjectDialog.js.map +1 -1
  15. package/dist/components/WorkspaceCard.js +42 -43
  16. package/dist/components/WorkspaceCard.js.map +1 -1
  17. package/dist/components/WorkspacesErrorBoundary.js +43 -34
  18. package/dist/components/WorkspacesErrorBoundary.js.map +1 -1
  19. package/dist/components/tags/ProjectTagsWidget.js +75 -77
  20. package/dist/components/tags/ProjectTagsWidget.js.map +1 -1
  21. package/dist/hooks/useTr.js +14 -0
  22. package/dist/hooks/useTr.js.map +1 -0
  23. package/dist/index.js +2 -1
  24. package/dist/pages/ActivityListPage.js +3 -3
  25. package/dist/pages/CreateWorkspacePage.js +10 -10
  26. package/dist/pages/InviteAcceptancePage.js +49 -49
  27. package/dist/pages/InviteAcceptancePage.js.map +1 -1
  28. package/dist/pages/MembersListPage.js +6 -6
  29. package/dist/pages/PendingInvitesPage.js +3 -3
  30. package/dist/pages/ProjectDetailPage.js +4 -4
  31. package/dist/pages/ProjectDetailPage.js.map +1 -1
  32. package/dist/pages/ProjectMembersPage.js +3 -3
  33. package/dist/pages/ProjectsListPage.js +5 -5
  34. package/dist/pages/WorkspaceDetailPage.js +4 -4
  35. package/dist/pages/WorkspaceInvitePage.js +4 -4
  36. package/dist/pages/WorkspaceSettingsPage.js +7 -7
  37. package/dist/pages/WorkspacesListPage.js +9 -9
  38. package/dist/pages/dashboard/widgets/RecentActivityWidget.js +4 -4
  39. package/dist/pages/dashboard/widgets/StorageWidget.js +3 -3
  40. package/dist/pages/dashboard/widgets/WelcomeWidget.js +26 -16
  41. package/dist/pages/dashboard/widgets/WelcomeWidget.js.map +1 -1
  42. package/dist/translations/en.js +908 -0
  43. package/dist/translations/en.js.map +1 -0
  44. package/package.json +1 -1
@@ -1,105 +1,102 @@
1
1
  import { useWorkspacesContext as e } from "../providers/WorkspacesProvider.js";
2
- import { nativeImpact as t, nativeNotify as n } from "../utils/nativeBridge.js";
3
- import { useRemoveWorkspaceMember as r } from "../hooks/useMemberMutations.js";
4
- import { formatRelativeTime as i } from "../utils/formatters.js";
5
- import { useMemo as a, useState as o } from "react";
6
- import { MoreHorizontal as s, UserMinus as c } from "lucide-react";
7
- import { Fragment as l, jsx as u, jsxs as d } from "react/jsx-runtime";
8
- import { AlertDialog as f, AlertDialogAction as p, AlertDialogCancel as m, AlertDialogContent as h, AlertDialogDescription as g, AlertDialogFooter as _, AlertDialogHeader as v, AlertDialogTitle as y, Badge as b, Button as x, CardContent as S, DropdownMenu as C, DropdownMenuContent as w, DropdownMenuTrigger as T, GlassCard as E } from "@burdenoff/fe-libs/ui";
9
- import { ActorIdentity as D, useActorProfiles as O } from "@burdenoff/fe-libs/shared";
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 k({ member: k, selected: A = !1, onToggleSelect: j, canRemove: M = !1 }) {
12
- let [N, P] = o(!1), { mutate: F, isPending: I } = r(k.workspaceId), { apiGatewayUrl: L, authToken: R, organizationId: z } = e(), B = O(a(() => [{
13
- actorId: k.userId,
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
- }], [k.userId]), {
16
- apiGatewayUrl: L,
17
- authToken: R,
18
- orgId: z,
19
- workspaceId: k.workspaceId
20
- })[k.userId];
21
- return /* @__PURE__ */ d(l, { children: [/* @__PURE__ */ u(E, {
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 ${A ? "ring-2 ring-action-primary-bg/25 border-action-primary-bg/50" : ""}`,
24
- children: /* @__PURE__ */ u(S, {
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__ */ d("div", {
27
+ children: /* @__PURE__ */ f("div", {
27
28
  className: "flex items-center justify-between gap-4",
28
- children: [/* @__PURE__ */ d("div", {
29
+ children: [/* @__PURE__ */ f("div", {
29
30
  className: "flex items-center gap-3 flex-1 min-w-0",
30
- children: [j && /* @__PURE__ */ u("input", {
31
+ children: [M && /* @__PURE__ */ d("input", {
31
32
  type: "checkbox",
32
- checked: A,
33
- onChange: (e) => j(e.target.checked),
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": `Select member ${B?.displayName ?? ""}`
36
- }), /* @__PURE__ */ d("div", {
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: [B ? /* @__PURE__ */ u(D, {
39
- profile: B,
39
+ children: [H ? /* @__PURE__ */ d(O, {
40
+ profile: H,
40
41
  variant: "cell"
41
- }) : null, /* @__PURE__ */ d("div", {
42
+ }) : null, /* @__PURE__ */ f("div", {
42
43
  className: "mt-1 flex items-center gap-2",
43
- children: [/* @__PURE__ */ u(b, {
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: ["Joined ", i(k.createdAt)]
50
+ children: P("memberListItem.joined", "Joined {{time}}", { time: a(A.createdAt) })
50
51
  })]
51
52
  })]
52
53
  })]
53
- }), M && /* @__PURE__ */ d(C, { children: [/* @__PURE__ */ u(T, {
54
+ }), N && /* @__PURE__ */ f(w, { children: [/* @__PURE__ */ d(E, {
54
55
  asChild: !0,
55
- children: /* @__PURE__ */ d(x, {
56
+ children: /* @__PURE__ */ f(S, {
56
57
  variant: "ghost",
57
58
  size: "icon",
58
59
  className: "size-8 flex-shrink-0",
59
- children: [/* @__PURE__ */ u(s, { className: "size-4" }), /* @__PURE__ */ u("span", {
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__ */ u(w, {
65
+ }), /* @__PURE__ */ d(T, {
65
66
  align: "end",
66
- children: /* @__PURE__ */ d("button", {
67
+ children: /* @__PURE__ */ f("button", {
67
68
  type: "button",
68
- onClick: () => P(!0),
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__ */ u(c, { className: "mr-2 size-4" }), "Remove Member"]
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__ */ u(f, {
76
- open: N,
77
- onOpenChange: P,
78
- children: /* @__PURE__ */ d(h, { children: [/* @__PURE__ */ d(v, { children: [/* @__PURE__ */ u(y, { children: "Remove Member" }), /* @__PURE__ */ d(g, { children: [
79
- "Are you sure you want to remove ",
80
- B?.displayName ?? "this member",
81
- " from the workspace? This action cannot be undone."
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
- t("medium"), F(k.id, {
84
+ n("medium"), L(A.id, {
88
85
  onSuccess: () => {
89
- n("success"), P(!1);
86
+ r("success"), I(!1);
90
87
  },
91
88
  onError: () => {
92
- n("error");
89
+ r("error");
93
90
  }
94
91
  });
95
92
  },
96
- disabled: I,
93
+ disabled: R,
97
94
  className: "bg-status-danger-bg text-status-danger-text hover:bg-status-danger-bg/90",
98
- children: I ? "Removing..." : "Remove Member"
95
+ children: R ? P("memberListItem.removing", "Removing...") : P("memberListItem.removeButton", "Remove Member")
99
96
  })] })] })
100
97
  })] });
101
98
  }
102
99
  //#endregion
103
- export { k as MemberListItem };
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={`Select member ${profile?.displayName ?? ''}`}\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 Workspace member\n </Badge>\n <span className=\"text-xs text-text-secondary\">\n Joined {formatRelativeTime(member.createdAt)}\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\">Open member actions</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 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>Remove Member</AlertDialogTitle>\n <AlertDialogDescription>\n Are you sure you want to remove {profile?.displayName ?? 'this member'} from the\n workspace? This action cannot be undone.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={isRemoving}>Cancel</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 ? 'Removing...' : 'Remove Member'}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </>\n );\n}\n"],"mappings":";;;;;;;;;;AAkCA,SAAgB,EAAe,EAC7B,WACA,cAAW,IACX,mBACA,eAAY,MACU;CACtB,IAAM,CAAC,GAAkB,KAAuB,EAAS,GAAM,EACzD,EAAE,QAAQ,GAAc,WAAW,MAAe,EACtD,EAAO,YACR,EACK,EAAE,kBAAe,cAAW,sBAAmB,GAAsB,EAerE,IANa,EAJJ,QACP,CAAC;EAAE,SAAS,EAAO;EAAQ,WAAW;EAAQ,CAAC,EACrD,CAAC,EAAO,OAAO,CAChB,EAC2C;EAC1C;EACA;EACA,OAAO;EACP,aAAa,EAAO;EACrB,CAAC,CACyB,EAAO;AAelC,QACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;EACE,WAAU;EACV,WAAW,sBACT,IAAW,iEAAiE;YAG9E,kBAAC,GAAD;GAAa,WAAU;aACrB,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACG,KACC,kBAAC,SAAD;MACE,MAAK;MACL,SAAS;MACT,WAAW,MAAU,EAAe,EAAM,OAAO,QAAQ;MACzD,WAAU;MACV,cAAY,iBAAiB,GAAS,eAAe;MACrD,CAAA,EAGJ,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACG,IAAU,kBAAC,GAAD;OAAwB;OAAS,SAAQ;OAAS,CAAA,GAAG,MAChE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QAAO,SAAQ;QAAY,WAAU;kBAAU;QAEvC,CAAA,EACR,kBAAC,QAAD;QAAM,WAAU;kBAAhB,CAA8C,WACpC,EAAmB,EAAO,UAAU,CACvC;UACH;SACF;QACF;QAEL,KACC,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;KAAqB,SAAA;eACnB,kBAAC,GAAD;MAAQ,SAAQ;MAAQ,MAAK;MAAO,WAAU;gBAA9C,CACE,kBAAC,GAAD,EAAgB,WAAU,UAAW,CAAA,EACrC,kBAAC,QAAD;OAAM,WAAU;iBAAU;OAA0B,CAAA,CAC7C;;KACW,CAAA,EACtB,kBAAC,GAAD;KAAqB,OAAM;eACzB,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,EAAoB,GAAK;MACxC,WAAU;gBAHZ,CAKE,kBAAC,GAAD,EAAW,WAAU,eAAgB,CAAA,EAAA,gBAE9B;;KACW,CAAA,CACT,EAAA,CAAA,CAEb;;GACM,CAAA;EACJ,CAAA,EAEZ,kBAAC,GAAD;EAAa,MAAM;EAAkB,cAAc;YACjD,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAkB,iBAAgC,CAAA,EAClD,kBAAC,GAAD,EAAA,UAAA;GAAwB;GACW,GAAS,eAAe;GAAc;GAEhD,EAAA,CAAA,CACP,EAAA,CAAA,EACpB,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;GAAmB,UAAU;aAAY;GAA0B,CAAA,EACnE,kBAAC,GAAD;GACE,eAnFe;AAEzB,IADK,EAAa,SAAS,EAC3B,EAAa,EAAO,IAAI;KACtB,iBAAiB;AAEf,MADK,EAAa,UAAU,EAC5B,EAAoB,GAAM;;KAE5B,eAAe;AACR,QAAa,QAAQ;;KAE7B,CAAC;;GA0EQ,UAAU;GACV,WAAU;aAET,IAAa,gBAAgB;GACZ,CAAA,CACF,EAAA,CAAA,CACD,EAAA,CAAA;EACT,CAAA,CACb,EAAA,CAAA"}
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 { getProjectStatusClasses as t } from "../utils/tokenHelpers.js";
3
- import { useScopedNavigation as n } from "../hooks/useScopedNavigation.js";
4
- import { nativeConfirm as r, nativeImpact as i } from "../utils/nativeBridge.js";
5
- import { useArchiveProject as a, useDeleteProject as o, useUnarchiveProject as s } from "../hooks/useProjectMutations.js";
6
- import { formatDate as c } from "../utils/formatters.js";
7
- import { getProjectDisplayTags as l } from "../utils/projectTags.js";
8
- import { RenameProjectDialog as u } from "./RenameProjectDialog.js";
9
- import { useState as d } from "react";
10
- import { Archive as f, Fingerprint as p, FolderKanban as m, MoreVertical as h, Pencil as g } from "lucide-react";
11
- import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
12
- import { Badge as b, Button as x, CardContent as S, CardHeader as C, CardTitle as w, DropdownMenu as T, DropdownMenuContent as E, DropdownMenuItem as D, DropdownMenuTrigger as O, EntityIdModal as k, GlassCard as A, useEntityIdModal as j } from "@burdenoff/fe-libs/ui";
13
- import { useNavigate as M } from "react-router";
14
- import { TagBadge as N } from "@burdenoff/fe-libs/tag";
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 P({ project: P, selected: F = !1, onToggleSelect: I, onTagClick: L, canArchive: R = !1, canDelete: z = !1, canRename: B = !1 }) {
17
- let V = M(), { basePath: H = "/workspaces" } = e(), { withCurrentSearch: U } = n(), { mutate: W } = a(P.workspaceId), { mutate: G } = s(P.workspaceId), { mutate: K } = o(P.workspaceId), q = j(), [J, Y] = d(!1), X = l(P), Z = () => {
18
- V(U(`${H}/${P.workspaceId}/projects/${P.id}`));
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__ */ y(_, { children: [
21
- /* @__PURE__ */ y(A, {
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 ${F ? "ring-2 ring-primary/25 border-primary/50" : ""}`,
24
- onClick: Z,
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(), Z());
27
+ (e.key === "Enter" || e.key === " ") && (e.preventDefault(), $());
27
28
  },
28
29
  role: "button",
29
30
  tabIndex: 0,
30
- "aria-label": `Open project ${P.name}`,
31
- children: [/* @__PURE__ */ v(C, { children: /* @__PURE__ */ y("div", {
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__ */ y("div", {
34
+ children: [/* @__PURE__ */ b("div", {
34
35
  className: "flex items-center gap-3 flex-1",
35
36
  children: [
36
- I && /* @__PURE__ */ v("input", {
37
+ L && /* @__PURE__ */ y("input", {
37
38
  type: "checkbox",
38
- checked: F,
39
- onChange: (e) => I(e.target.checked),
39
+ checked: I,
40
+ onChange: (e) => L(e.target.checked),
40
41
  onClick: (e) => e.stopPropagation(),
41
- "aria-label": `Select project ${P.name}`,
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__ */ v("div", {
45
+ /* @__PURE__ */ y("div", {
45
46
  className: "p-3 rounded-lg bg-action-primary-bg/10 transition-colors",
46
- children: /* @__PURE__ */ v(m, {
47
+ children: /* @__PURE__ */ y(h, {
47
48
  className: "text-primary",
48
49
  size: 24
49
50
  })
50
51
  }),
51
- /* @__PURE__ */ y("div", {
52
+ /* @__PURE__ */ b("div", {
52
53
  className: "flex-1 min-w-0",
53
- children: [/* @__PURE__ */ v(w, {
54
+ children: [/* @__PURE__ */ y(T, {
54
55
  className: "truncate",
55
- children: P.name
56
- }), /* @__PURE__ */ v("p", {
56
+ children: F.name
57
+ }), /* @__PURE__ */ y("p", {
57
58
  className: "truncate text-sm text-text-secondary",
58
- children: P.key
59
+ children: F.key
59
60
  })]
60
61
  })
61
62
  ]
62
- }), /* @__PURE__ */ y(T, { children: [/* @__PURE__ */ v(O, {
63
+ }), /* @__PURE__ */ b(E, { children: [/* @__PURE__ */ y(k, {
63
64
  asChild: !0,
64
65
  onClick: (e) => e.stopPropagation(),
65
- children: /* @__PURE__ */ y(x, {
66
+ children: /* @__PURE__ */ b(S, {
66
67
  variant: "ghost",
67
68
  size: "sm",
68
69
  className: "size-8 p-0",
69
- children: [/* @__PURE__ */ v(h, { size: 16 }), /* @__PURE__ */ v("span", {
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__ */ y(E, {
75
+ }), /* @__PURE__ */ b(D, {
75
76
  align: "end",
76
77
  children: [
77
- /* @__PURE__ */ y(D, {
78
+ /* @__PURE__ */ b(O, {
78
79
  onClick: (e) => {
79
- e.stopPropagation(), q.show({
80
- id: P.id,
81
- name: P.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: P.key
85
+ label: Q("projectCard.keyLabel", "Key"),
86
+ value: F.key
86
87
  }, {
87
- label: "Workspace ID",
88
- value: P.workspaceId
88
+ label: Q("projectCard.workspaceIdLabel", "Workspace ID"),
89
+ value: F.workspaceId
89
90
  }]
90
91
  });
91
92
  },
92
- children: [/* @__PURE__ */ v(p, {
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
- B && /* @__PURE__ */ y(D, {
98
+ V && /* @__PURE__ */ b(O, {
98
99
  onClick: (e) => {
99
- e.stopPropagation(), Y(!0);
100
+ e.stopPropagation(), X(!0);
100
101
  },
101
- children: [/* @__PURE__ */ v(g, {
102
+ children: [/* @__PURE__ */ y(_, {
102
103
  size: 16,
103
104
  className: "mr-2"
104
- }), "Rename"]
105
+ }), Q("projectCard.rename", "Rename")]
105
106
  }),
106
- R && /* @__PURE__ */ y(D, {
107
+ z && /* @__PURE__ */ b(O, {
107
108
  onClick: (e) => {
108
- e.stopPropagation(), P.archived ? G(P.id) : W(P.id);
109
+ e.stopPropagation(), F.archived ? K(F.id) : G(F.id);
109
110
  },
110
- children: [/* @__PURE__ */ v(f, {
111
+ children: [/* @__PURE__ */ y(p, {
111
112
  size: 16,
112
113
  className: "mr-2"
113
- }), P.archived ? "Unarchive" : "Archive"]
114
+ }), F.archived ? Q("projectCard.unarchive", "Unarchive") : Q("projectCard.archive", "Archive")]
114
115
  }),
115
- z && /* @__PURE__ */ v(D, {
116
+ B && /* @__PURE__ */ y(O, {
116
117
  onClick: async (e) => {
117
- e.stopPropagation(), i("medium");
118
- let t = await r({
119
- title: "Delete project",
120
- message: `Are you sure you want to delete "${P.name}"?`,
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(`Are you sure you want to delete "${P.name}"?`) : t) && K(P.id);
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__ */ y(S, {
132
+ }) }), /* @__PURE__ */ b(C, {
132
133
  className: "space-y-3",
133
134
  children: [
134
- /* @__PURE__ */ y("div", {
135
+ /* @__PURE__ */ b("div", {
135
136
  className: "flex items-center gap-2",
136
- children: [/* @__PURE__ */ v(b, {
137
- className: `border ${t(P.status)}`,
138
- children: P.status
139
- }), P.archived && /* @__PURE__ */ y(b, {
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__ */ v(f, {
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: ["Created ", c(P.createdAt)]
151
+ children: Q("projectCard.created", "Created {{date}}", { date: l(F.createdAt) })
151
152
  }),
152
- X.length > 0 && /* @__PURE__ */ y("div", {
153
+ Z.length > 0 && /* @__PURE__ */ b("div", {
153
154
  className: "flex flex-wrap gap-1.5",
154
- "aria-label": "Project tags",
155
- children: [X.slice(0, 4).map((e) => /* @__PURE__ */ v("span", {
156
- ...L ? {
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(), L(e);
161
+ t.stopPropagation(), R(e);
161
162
  },
162
163
  onKeyDown: (t) => {
163
- (t.key === "Enter" || t.key === " ") && (t.preventDefault(), t.stopPropagation(), L(e));
164
+ (t.key === "Enter" || t.key === " ") && (t.preventDefault(), t.stopPropagation(), R(e));
164
165
  }
165
166
  } : {},
166
- children: /* @__PURE__ */ v(N, {
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: L ? "cursor-pointer" : void 0
174
+ className: R ? "cursor-pointer" : void 0
174
175
  })
175
- }, e.tagId)), X.length > 4 && /* @__PURE__ */ y(b, {
176
+ }, e.tagId)), Z.length > 4 && /* @__PURE__ */ b(x, {
176
177
  variant: "outline",
177
178
  className: "text-xs",
178
- children: ["+", X.length - 4]
179
+ children: ["+", Z.length - 4]
179
180
  })]
180
181
  })
181
182
  ]
182
183
  })]
183
184
  }),
184
- /* @__PURE__ */ v(k, { control: q }),
185
- J && /* @__PURE__ */ v(u, {
186
- project: P,
187
- open: J,
188
- onOpenChange: Y
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 { P as ProjectCard };
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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"}