@burdenoff/microfe-workspaces 2026.625.4 → 2026.626.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 (35) hide show
  1. package/dist/hooks/useMemberMutations.js +6 -6
  2. package/dist/hooks/useMemberMutations.js.map +1 -1
  3. package/dist/pages/ActivityListPage.js +94 -90
  4. package/dist/pages/ActivityListPage.js.map +1 -1
  5. package/dist/pages/CreateWorkspacePage.js +68 -63
  6. package/dist/pages/CreateWorkspacePage.js.map +1 -1
  7. package/dist/pages/InviteAcceptancePage.js +101 -96
  8. package/dist/pages/InviteAcceptancePage.js.map +1 -1
  9. package/dist/pages/MembersListPage.js +185 -184
  10. package/dist/pages/MembersListPage.js.map +1 -1
  11. package/dist/pages/PendingInvitesPage.js +70 -68
  12. package/dist/pages/PendingInvitesPage.js.map +1 -1
  13. package/dist/pages/ProjectDetailPage.js +119 -78
  14. package/dist/pages/ProjectDetailPage.js.map +1 -1
  15. package/dist/pages/ProjectMembersPage.js +105 -104
  16. package/dist/pages/ProjectMembersPage.js.map +1 -1
  17. package/dist/pages/ProjectsListPage.js +158 -157
  18. package/dist/pages/ProjectsListPage.js.map +1 -1
  19. package/dist/pages/WorkspaceDetailPage.js +236 -198
  20. package/dist/pages/WorkspaceDetailPage.js.map +1 -1
  21. package/dist/pages/WorkspaceInvitePage.js +341 -300
  22. package/dist/pages/WorkspaceInvitePage.js.map +1 -1
  23. package/dist/pages/WorkspaceSettingsPage.js +87 -85
  24. package/dist/pages/WorkspaceSettingsPage.js.map +1 -1
  25. package/dist/pages/WorkspacesListPage.js +122 -121
  26. package/dist/pages/WorkspacesListPage.js.map +1 -1
  27. package/dist/pages/dashboard/DashboardPage.js +55 -51
  28. package/dist/pages/dashboard/DashboardPage.js.map +1 -1
  29. package/dist/pages/dashboard/widgets/GroupsWidget.js +16 -17
  30. package/dist/pages/dashboard/widgets/GroupsWidget.js.map +1 -1
  31. package/dist/pages/dashboard/widgets/TagCloudWidget.js +18 -19
  32. package/dist/pages/dashboard/widgets/TagCloudWidget.js.map +1 -1
  33. package/dist/pages/dashboard/widgets/WorkflowStatsWidget.js +10 -11
  34. package/dist/pages/dashboard/widgets/WorkflowStatsWidget.js.map +1 -1
  35. package/package.json +2 -2
@@ -2,23 +2,23 @@ import { useWorkspacesContext as e } from "../providers/WorkspacesProvider.js";
2
2
  import { useScopedNavigation as t } from "../hooks/useScopedNavigation.js";
3
3
  import { tWithFallback as n } from "../utils/i18n.js";
4
4
  import { useWorkspacesPageView as r } from "../hooks/useWorkspacesPageView.js";
5
- import { nativeConfirm as i, nativeImpact as ee, nativeNotify as a } from "../utils/nativeBridge.js";
6
- import { useWorkspacePermissions as o } from "../hooks/useWorkspacePermissions.js";
7
- import { useProject as te } from "../hooks/useProjects.js";
8
- import { formatRelativeTime as s } from "../utils/formatters.js";
9
- import { useRemoveProjectMember as ne } from "../hooks/useProjectMemberMutations.js";
10
- import { useInfiniteProjectMembers as re } from "../hooks/useProjectMembers.js";
11
- import { ProjectMemberPickerDialog as ie } from "../components/ProjectMemberPickerDialog.js";
12
- import { useMemo as c, useState as l } from "react";
13
- import { ArrowLeft as ae, Search as oe, UserMinus as se, UserPlus as u } from "lucide-react";
14
- import { jsx as d, jsxs as f } from "react/jsx-runtime";
15
- import { Badge as p, Button as m, IllustratedEmptyState as h, Input as g, PageContainer as _, Skeleton as v } from "@burdenoff/fe-libs/ui";
16
- import { useNavigate as y, useParams as b } from "react-router-dom";
17
- import { useI18n as x } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
18
- import { ActorIdentity as S, useActorProfiles as C } from "@burdenoff/fe-libs/shared";
5
+ import { nativeConfirm as i, nativeImpact as a, nativeNotify as o } from "../utils/nativeBridge.js";
6
+ import { useWorkspacePermissions as s } from "../hooks/useWorkspacePermissions.js";
7
+ import { useProject as ee } from "../hooks/useProjects.js";
8
+ import { formatRelativeTime as te } from "../utils/formatters.js";
9
+ import { useRemoveProjectMember as c } from "../hooks/useProjectMemberMutations.js";
10
+ import { useInfiniteProjectMembers as l } from "../hooks/useProjectMembers.js";
11
+ import { ProjectMemberPickerDialog as u } from "../components/ProjectMemberPickerDialog.js";
12
+ import { useMemo as d, useState as f } from "react";
13
+ import { ArrowLeft as ne, Search as re, UserMinus as ie, UserPlus as p } from "lucide-react";
14
+ import { jsx as m, jsxs as h } from "react/jsx-runtime";
15
+ import { Badge as g, Button as _, IllustratedEmptyState as v, Input as y, PageContainer as b, PagePurpose as x, Skeleton as S } from "@burdenoff/fe-libs/ui";
16
+ import { useNavigate as ae, useParams as oe } from "react-router-dom";
17
+ import { useI18n as se } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
18
+ import { ActorIdentity as ce, useActorProfiles as le } from "@burdenoff/fe-libs/shared";
19
19
  //#region src/pages/ProjectMembersPage.tsx
20
- var ce = 100;
21
- function w(e, t) {
20
+ var ue = 100;
21
+ function C(e, t) {
22
22
  let n = e[t.userId];
23
23
  return n ? {
24
24
  name: n.displayName,
@@ -28,25 +28,25 @@ function w(e, t) {
28
28
  email: void 0
29
29
  };
30
30
  }
31
- function T() {
32
- let { t: T } = x(), le = y(), { workspaceId: E, projectId: D } = b(), { basePath: ue = "/workspaces", apiGatewayUrl: de, authToken: O, organizationId: k } = e(), { withCurrentSearch: A } = t(), [j, M] = l(""), [N, P] = l(!1), [F, I] = l(null), [L, R] = l(null);
31
+ function w() {
32
+ let { t: w } = se(), de = ae(), { workspaceId: T, projectId: E } = oe(), { basePath: fe = "/workspaces", apiGatewayUrl: D, authToken: O, organizationId: k } = e(), { withCurrentSearch: A } = t(), [j, M] = f(""), [N, P] = f(!1), [F, I] = f(null), [L, R] = f(null);
33
33
  r("workspaces.project-members", {
34
- workspaceId: E,
35
- projectId: D,
34
+ workspaceId: T,
35
+ projectId: E,
36
36
  requireParams: !0
37
37
  });
38
- let { data: z, isLoading: B, error: V } = te(D || "", E), { data: H, isLoading: fe, error: U, hasNextPage: W, fetchNextPage: G, isFetchingNextPage: K } = re(D || "", E, ce), { mutate: pe, isPending: q } = ne(E), { canViewProject: me, canListProjectMembers: he, canAddProjectMember: J, canRemoveProjectMember: ge, isLoading: Y } = o(), X = c(() => H?.pages.flatMap((e) => e.items) ?? [], [H?.pages]), Z = H?.pages[0]?.total ?? X.length, Q = C(c(() => X.map((e) => ({
38
+ let { data: z, isLoading: B, error: V } = ee(E || "", T), { data: H, isLoading: pe, error: U, hasNextPage: W, fetchNextPage: G, isFetchingNextPage: K } = l(E || "", T, ue), { mutate: me, isPending: q } = c(T), { canViewProject: he, canListProjectMembers: ge, canAddProjectMember: J, canRemoveProjectMember: _e, isLoading: Y } = s(), X = d(() => H?.pages.flatMap((e) => e.items) ?? [], [H?.pages]), Z = H?.pages[0]?.total ?? X.length, Q = le(d(() => X.map((e) => ({
39
39
  actorId: e.userId,
40
40
  actorType: "user"
41
41
  })), [X]), {
42
- apiGatewayUrl: de,
42
+ apiGatewayUrl: D,
43
43
  authToken: O,
44
44
  orgId: k,
45
- workspaceId: E
46
- }), $ = c(() => {
45
+ workspaceId: T
46
+ }), $ = d(() => {
47
47
  let e = j.trim().toLowerCase();
48
48
  return e ? X.filter((t) => {
49
- let n = w(Q, t);
49
+ let n = C(Q, t);
50
50
  return n.name.toLowerCase().includes(e) || n.email?.toLowerCase().includes(e) || t.userId.toLowerCase().includes(e);
51
51
  }) : X;
52
52
  }, [
@@ -54,171 +54,172 @@ function T() {
54
54
  X,
55
55
  j
56
56
  ]);
57
- if (Y) return /* @__PURE__ */ f("div", {
57
+ if (Y) return /* @__PURE__ */ h("div", {
58
58
  className: "space-y-4 p-6",
59
59
  children: [
60
- /* @__PURE__ */ d(v, { className: "h-10 w-40" }),
61
- /* @__PURE__ */ d(v, { className: "h-10 w-64" }),
62
- /* @__PURE__ */ d(v, { className: "h-40 w-full" })
60
+ /* @__PURE__ */ m(S, { className: "h-10 w-40" }),
61
+ /* @__PURE__ */ m(S, { className: "h-10 w-64" }),
62
+ /* @__PURE__ */ m(S, { className: "h-40 w-full" })
63
63
  ]
64
64
  });
65
- if (!me || !he) return /* @__PURE__ */ d("div", {
65
+ if (!he || !ge) return /* @__PURE__ */ m("div", {
66
66
  className: "flex min-h-[400px] items-center justify-center",
67
- children: /* @__PURE__ */ f("div", {
67
+ children: /* @__PURE__ */ h("div", {
68
68
  className: "space-y-2 text-center",
69
- children: [/* @__PURE__ */ d("h2", {
69
+ children: [/* @__PURE__ */ m("h2", {
70
70
  className: "text-lg font-semibold",
71
- children: n(T, "projectMembers.accessDenied", "Access Denied")
72
- }), /* @__PURE__ */ d("p", {
71
+ children: n(w, "projectMembers.accessDenied", "Access Denied")
72
+ }), /* @__PURE__ */ m("p", {
73
73
  className: "text-sm text-text-secondary",
74
- children: n(T, "projectMembers.noPermission", "You don't have permission to manage project members.")
74
+ children: n(w, "projectMembers.noPermission", "You don't have permission to manage project members.")
75
75
  })]
76
76
  })
77
77
  });
78
- let _e = () => {
79
- le(A(`${ue}/${E}/projects/${D}`));
80
- }, ve = async (e) => {
81
- let t = w(Q, e);
82
- ee("medium"), R(null);
83
- let r = `${n(T, "projectMembers.removeConfirmPrefix", "Remove")} ${t.name} ${n(T, "projectMembers.removeConfirmSuffix", "from this project?")}`, o = await i({
84
- title: n(T, "projectMembers.removeConfirmTitle", "Remove project member"),
78
+ let ve = () => {
79
+ de(A(`${fe}/${T}/projects/${E}`));
80
+ }, ye = async (e) => {
81
+ let t = C(Q, e);
82
+ a("medium"), R(null);
83
+ let r = `${n(w, "projectMembers.removeConfirmPrefix", "Remove")} ${t.name} ${n(w, "projectMembers.removeConfirmSuffix", "from this project?")}`, s = await i({
84
+ title: n(w, "projectMembers.removeConfirmTitle", "Remove project member"),
85
85
  message: r,
86
- okButtonTitle: n(T, "projectMembers.removeAction", "Remove"),
87
- cancelButtonTitle: n(T, "projectMembers.cancel", "Cancel")
86
+ okButtonTitle: n(w, "projectMembers.removeAction", "Remove"),
87
+ cancelButtonTitle: n(w, "projectMembers.cancel", "Cancel")
88
88
  });
89
- (o === null ? window.confirm(r) : o) && (I(e.userId), pe({
89
+ (s === null ? window.confirm(r) : s) && (I(e.userId), me({
90
90
  projectId: e.projectId,
91
91
  userId: e.userId
92
92
  }, {
93
93
  onSuccess: () => {
94
- a("success"), I(null);
94
+ o("success"), I(null);
95
95
  },
96
96
  onError: () => {
97
- a("error"), R(n(T, "projectMembers.removeError", "Failed to remove project member. Please try again.")), I(null);
97
+ o("error"), R(n(w, "projectMembers.removeError", "Failed to remove project member. Please try again.")), I(null);
98
98
  }
99
99
  }));
100
100
  };
101
- return /* @__PURE__ */ d(_, {
101
+ return /* @__PURE__ */ m(b, {
102
102
  padded: !1,
103
- children: /* @__PURE__ */ f("div", {
103
+ children: /* @__PURE__ */ h("div", {
104
104
  className: "space-y-4 p-3 sm:space-y-6 sm:p-6",
105
105
  children: [
106
- /* @__PURE__ */ f("div", {
106
+ /* @__PURE__ */ h("div", {
107
107
  className: "flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between",
108
- children: [/* @__PURE__ */ f("div", { children: [
109
- /* @__PURE__ */ f(m, {
108
+ children: [/* @__PURE__ */ h("div", { children: [
109
+ /* @__PURE__ */ h(_, {
110
110
  variant: "ghost",
111
- onClick: _e,
111
+ onClick: ve,
112
112
  className: "mb-2 -ml-2 gap-2",
113
- children: [/* @__PURE__ */ d(ae, { size: 20 }), n(T, "projectMembers.backToProject", "Back to Project")]
113
+ children: [/* @__PURE__ */ m(ne, { size: 20 }), n(w, "projectMembers.backToProject", "Back to Project")]
114
114
  }),
115
- /* @__PURE__ */ d("h1", {
115
+ /* @__PURE__ */ m("h1", {
116
116
  className: "text-2xl font-bold sm:text-3xl",
117
- children: n(T, "projectMembers.pageTitle", "Project Members")
117
+ children: n(w, "projectMembers.pageTitle", "Project Members")
118
118
  }),
119
- /* @__PURE__ */ d("p", {
119
+ /* @__PURE__ */ m("p", {
120
120
  className: "text-sm text-text-secondary sm:text-base",
121
- children: z?.name ? `${z.name} · ${n(T, "projectMembers.pageSubtitle", "Only existing workspace members can be added to this project.")}` : n(T, "projectMembers.pageSubtitle", "Only existing workspace members can be added to this project.")
121
+ children: z?.name ? `${z.name} · ${n(w, "projectMembers.pageSubtitle", "Only existing workspace members can be added to this project.")}` : n(w, "projectMembers.pageSubtitle", "Only existing workspace members can be added to this project.")
122
122
  })
123
- ] }), /* @__PURE__ */ f("div", {
123
+ ] }), /* @__PURE__ */ h("div", {
124
124
  className: "flex items-center gap-2",
125
- children: [/* @__PURE__ */ d(p, {
125
+ children: [/* @__PURE__ */ m(g, {
126
126
  variant: "secondary",
127
127
  children: Z
128
- }), J ? /* @__PURE__ */ f(m, {
128
+ }), J ? /* @__PURE__ */ h(_, {
129
129
  onClick: () => P(!0),
130
- disabled: !E || !D,
131
- children: [/* @__PURE__ */ d(u, { className: "mr-2 size-4" }), n(T, "projectMembers.addMember", "Add Member")]
130
+ disabled: !T || !E,
131
+ children: [/* @__PURE__ */ m(p, { className: "mr-2 size-4" }), n(w, "projectMembers.addMember", "Add Member")]
132
132
  }) : null]
133
133
  })]
134
134
  }),
135
- /* @__PURE__ */ f("div", {
135
+ /* @__PURE__ */ m(x, { children: n(w, "projectMembers.purpose", "This is the subset of workspace members who can work on this specific project. Add people here to give them project-level access, search to find someone, or remove members who have moved on. Only existing workspace members can be added.") }),
136
+ /* @__PURE__ */ h("div", {
136
137
  className: "relative",
137
- children: [/* @__PURE__ */ d(oe, { className: "absolute left-3 top-1/2 size-4 -translate-y-1/2 text-text-secondary" }), /* @__PURE__ */ d(g, {
138
+ children: [/* @__PURE__ */ m(re, { className: "absolute left-3 top-1/2 size-4 -translate-y-1/2 text-text-secondary" }), /* @__PURE__ */ m(y, {
138
139
  value: j,
139
140
  onChange: (e) => M(e.target.value),
140
- placeholder: n(T, "projectMembers.searchPlaceholder", "Search project members"),
141
+ placeholder: n(w, "projectMembers.searchPlaceholder", "Search project members"),
141
142
  className: "pl-9"
142
143
  })]
143
144
  }),
144
- L ? /* @__PURE__ */ d("div", {
145
+ L ? /* @__PURE__ */ m("div", {
145
146
  className: "rounded-lg border border-status-error-border/20 bg-status-error-bg/10 p-4 text-sm text-status-error-text",
146
147
  children: L
147
148
  }) : null,
148
- B || fe ? /* @__PURE__ */ d("div", {
149
+ B || pe ? /* @__PURE__ */ m("div", {
149
150
  className: "space-y-4",
150
- children: Array.from({ length: 4 }).map((e, t) => /* @__PURE__ */ f("div", {
151
+ children: Array.from({ length: 4 }).map((e, t) => /* @__PURE__ */ h("div", {
151
152
  className: "rounded-lg border border-border-seam bg-bg-surface p-4",
152
- children: [/* @__PURE__ */ d(v, { className: "h-5 w-40" }), /* @__PURE__ */ d(v, { className: "mt-2 h-4 w-56" })]
153
+ children: [/* @__PURE__ */ m(S, { className: "h-5 w-40" }), /* @__PURE__ */ m(S, { className: "mt-2 h-4 w-56" })]
153
154
  }, t))
154
- }) : V || U ? /* @__PURE__ */ d("div", {
155
+ }) : V || U ? /* @__PURE__ */ m("div", {
155
156
  className: "rounded-lg border border-status-error-border/20 bg-status-error-bg/10 p-4 text-sm text-status-error-text",
156
- children: U instanceof Error && U.message || V instanceof Error && V.message || n(T, "projectMembers.loadError", "Failed to load project members")
157
- }) : $.length === 0 ? /* @__PURE__ */ d(h, {
157
+ children: U instanceof Error && U.message || V instanceof Error && V.message || n(w, "projectMembers.loadError", "Failed to load project members")
158
+ }) : $.length === 0 ? /* @__PURE__ */ m(v, {
158
159
  illustration: j ? "empty-search" : "empty-people",
159
- title: j ? n(T, "projectMembers.noResultsTitle", "No matching members found") : n(T, "projectMembers.emptyTitle", "No project members yet"),
160
- description: j ? n(T, "projectMembers.noResultsSubtitle", "Try a different search to find a project member.") : n(T, "projectMembers.emptySubtitle", "Add workspace members to this project so they can collaborate here."),
161
- action: W || !j && J ? /* @__PURE__ */ f("div", {
160
+ title: j ? n(w, "projectMembers.noResultsTitle", "No matching members found") : n(w, "projectMembers.emptyTitle", "No project members yet"),
161
+ description: j ? n(w, "projectMembers.noResultsSubtitle", "Try a different search to find a project member.") : n(w, "projectMembers.emptySubtitle", "Add workspace members to this project so they can collaborate here."),
162
+ action: W || !j && J ? /* @__PURE__ */ h("div", {
162
163
  className: "flex flex-wrap items-center justify-center gap-2",
163
- children: [W ? /* @__PURE__ */ d(m, {
164
+ children: [W ? /* @__PURE__ */ m(_, {
164
165
  variant: "outline",
165
166
  onClick: () => void G(),
166
167
  disabled: K,
167
168
  children: K ? "Loading more…" : "Load More Members"
168
- }) : null, !j && J ? /* @__PURE__ */ f(m, {
169
+ }) : null, !j && J ? /* @__PURE__ */ h(_, {
169
170
  onClick: () => P(!0),
170
- children: [/* @__PURE__ */ d(u, { className: "mr-2 size-4" }), n(T, "projectMembers.addFirstMember", "Add First Member")]
171
+ children: [/* @__PURE__ */ m(p, { className: "mr-2 size-4" }), n(w, "projectMembers.addFirstMember", "Add First Member")]
171
172
  }) : null]
172
173
  }) : void 0
173
- }) : /* @__PURE__ */ f("div", {
174
+ }) : /* @__PURE__ */ h("div", {
174
175
  className: "space-y-3",
175
176
  children: [$.map((e) => {
176
- let t = Q[e.userId], r = w(Q, e), i = q && F === e.userId;
177
- return /* @__PURE__ */ f("div", {
177
+ let t = Q[e.userId], r = C(Q, e), i = q && F === e.userId;
178
+ return /* @__PURE__ */ h("div", {
178
179
  className: "flex items-center justify-between gap-4 rounded-card border border-border-seam bg-bg-surface p-4 shadow-elevation-1 transition-[box-shadow,transform] duration-200 ease-[var(--motion-easing-out)] hover:shadow-elevation-2 [@media(hover:none)]:",
179
- children: [/* @__PURE__ */ f("div", {
180
+ children: [/* @__PURE__ */ h("div", {
180
181
  className: "min-w-0 flex-1",
181
- children: [t ? /* @__PURE__ */ d(S, {
182
+ children: [t ? /* @__PURE__ */ m(ce, {
182
183
  profile: t,
183
184
  variant: "cell"
184
- }) : /* @__PURE__ */ f("div", {
185
+ }) : /* @__PURE__ */ h("div", {
185
186
  className: "min-w-0",
186
- children: [/* @__PURE__ */ d("p", {
187
+ children: [/* @__PURE__ */ m("p", {
187
188
  className: "truncate font-medium",
188
189
  children: r.name
189
- }), r.email ? /* @__PURE__ */ d("p", {
190
+ }), r.email ? /* @__PURE__ */ m("p", {
190
191
  className: "truncate text-sm text-text-secondary",
191
192
  children: r.email
192
- }) : /* @__PURE__ */ d("p", {
193
+ }) : /* @__PURE__ */ m("p", {
193
194
  className: "truncate text-xs text-text-secondary",
194
195
  children: e.userId
195
196
  })]
196
- }), /* @__PURE__ */ f("div", {
197
+ }), /* @__PURE__ */ h("div", {
197
198
  className: "mt-1 flex flex-wrap items-center gap-2",
198
- children: [/* @__PURE__ */ d(p, {
199
+ children: [/* @__PURE__ */ m(g, {
199
200
  variant: "secondary",
200
201
  className: "text-xs",
201
- children: n(T, "projectMembers.memberBadge", "Project member")
202
- }), /* @__PURE__ */ f("span", {
202
+ children: n(w, "projectMembers.memberBadge", "Project member")
203
+ }), /* @__PURE__ */ h("span", {
203
204
  className: "text-xs text-text-secondary",
204
205
  children: [
205
- n(T, "projectMembers.addedLabel", "Added"),
206
+ n(w, "projectMembers.addedLabel", "Added"),
206
207
  " ",
207
- s(e.createdAt)
208
+ te(e.createdAt)
208
209
  ]
209
210
  })]
210
211
  })]
211
- }), ge ? /* @__PURE__ */ f(m, {
212
+ }), _e ? /* @__PURE__ */ h(_, {
212
213
  variant: "outline",
213
214
  size: "sm",
214
- onClick: () => void ve(e),
215
+ onClick: () => void ye(e),
215
216
  disabled: q,
216
- children: [/* @__PURE__ */ d(se, { className: "mr-2 size-4" }), i ? n(T, "projectMembers.removing", "Removing...") : n(T, "projectMembers.removeAction", "Remove")]
217
+ children: [/* @__PURE__ */ m(ie, { className: "mr-2 size-4" }), i ? n(w, "projectMembers.removing", "Removing...") : n(w, "projectMembers.removeAction", "Remove")]
217
218
  }) : null]
218
219
  }, e.id);
219
- }), W ? /* @__PURE__ */ f("div", {
220
+ }), W ? /* @__PURE__ */ h("div", {
220
221
  className: "flex flex-col items-center gap-2 rounded-lg border border-dashed border-border-seam bg-bg-sunken/20 p-4 text-center",
221
- children: [/* @__PURE__ */ f("p", {
222
+ children: [/* @__PURE__ */ h("p", {
222
223
  className: "text-sm text-text-secondary",
223
224
  children: [
224
225
  "Showing ",
@@ -227,7 +228,7 @@ function T() {
227
228
  Z,
228
229
  " project members."
229
230
  ]
230
- }), /* @__PURE__ */ d(m, {
231
+ }), /* @__PURE__ */ m(_, {
231
232
  variant: "outline",
232
233
  onClick: () => void G(),
233
234
  disabled: K,
@@ -235,11 +236,11 @@ function T() {
235
236
  })]
236
237
  }) : null]
237
238
  }),
238
- E && D && N ? /* @__PURE__ */ d(ie, {
239
+ T && E && N ? /* @__PURE__ */ m(u, {
239
240
  open: N,
240
241
  onOpenChange: P,
241
- workspaceId: E,
242
- projectId: D,
242
+ workspaceId: T,
243
+ projectId: E,
243
244
  projectName: z?.name
244
245
  }) : null
245
246
  ]
@@ -247,6 +248,6 @@ function T() {
247
248
  });
248
249
  }
249
250
  //#endregion
250
- export { T as ProjectMembersPage };
251
+ export { w as ProjectMembersPage };
251
252
 
252
253
  //# sourceMappingURL=ProjectMembersPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ProjectMembersPage.js","names":[],"sources":["../../src/pages/ProjectMembersPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useNavigate, useParams } from 'react-router-dom';\nimport { ArrowLeft, Search, UserMinus, UserPlus } from 'lucide-react';\nimport {\n ActorIdentity,\n useActorProfiles,\n type ActorInput,\n type ActorProfileMap,\n} from '@burdenoff/fe-libs/shared';\nimport {\n Badge,\n Button,\n Input,\n PageContainer,\n Skeleton,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { ProjectMemberPickerDialog } from '../components/ProjectMemberPickerDialog';\nimport { useInfiniteProjectMembers } from '../hooks/useProjectMembers';\nimport { useProject } from '../hooks/useProjects';\nimport { useRemoveProjectMember } from '../hooks/useProjectMemberMutations';\nimport { useScopedNavigation } from '../hooks/useScopedNavigation';\nimport { useWorkspacePermissions } from '../hooks/useWorkspacePermissions';\nimport { useWorkspacesContext } from '../providers/WorkspacesProvider';\nimport { formatRelativeTime } from '../utils/formatters';\nimport { tWithFallback } from '../utils/i18n';\nimport { nativeConfirm, nativeImpact, nativeNotify } from '../utils/nativeBridge';\nimport { useWorkspacesPageView } from '../hooks/useWorkspacesPageView';\nimport type { ProjectMember } from '../types';\n\nconst PROJECT_MEMBER_PAGE_SIZE = 100;\n\nfunction getMemberFallback(profileMap: ActorProfileMap, member: ProjectMember) {\n const profile = profileMap[member.userId];\n if (profile) {\n return {\n name: profile.displayName,\n email: profile.email ?? undefined,\n };\n }\n\n return {\n name: member.userId,\n email: undefined,\n };\n}\n\nexport function ProjectMembersPage() {\n const { t } = useI18n();\n const navigate = useNavigate();\n const { workspaceId, projectId } = useParams<{ workspaceId: string; projectId: string }>();\n const {\n basePath = '/workspaces',\n apiGatewayUrl,\n authToken,\n organizationId,\n } = useWorkspacesContext();\n const { withCurrentSearch } = useScopedNavigation();\n const [searchValue, setSearchValue] = useState('');\n const [isAddDialogOpen, setIsAddDialogOpen] = useState(false);\n const [removingUserId, setRemovingUserId] = useState<string | null>(null);\n const [removeError, setRemoveError] = useState<string | null>(null);\n\n useWorkspacesPageView('workspaces.project-members', {\n workspaceId,\n projectId,\n requireParams: true,\n });\n\n const {\n data: project,\n isLoading: isLoadingProject,\n error: projectError,\n } = useProject(projectId || '', workspaceId);\n const {\n data: projectMembersPages,\n isLoading: isLoadingMembers,\n error: membersError,\n hasNextPage: hasMoreProjectMembers,\n fetchNextPage: fetchNextProjectMembersPage,\n isFetchingNextPage: isFetchingNextProjectMembersPage,\n } = useInfiniteProjectMembers(projectId || '', workspaceId, PROJECT_MEMBER_PAGE_SIZE);\n const { mutate: removeProjectMember, isPending: isRemovingProjectMember } =\n useRemoveProjectMember(workspaceId);\n\n const {\n canViewProject,\n canListProjectMembers,\n canAddProjectMember,\n canRemoveProjectMember,\n isLoading: permissionsLoading,\n } = useWorkspacePermissions();\n\n const projectMembers = useMemo(\n () => projectMembersPages?.pages.flatMap((page) => page.items) ?? [],\n [projectMembersPages?.pages]\n );\n const totalProjectMembers = projectMembersPages?.pages[0]?.total ?? projectMembers.length;\n const actors = useMemo<ActorInput[]>(\n () => projectMembers.map((member) => ({ actorId: member.userId, actorType: 'user' })),\n [projectMembers]\n );\n const profileMap: ActorProfileMap = useActorProfiles(actors, {\n apiGatewayUrl,\n authToken,\n orgId: organizationId,\n workspaceId,\n });\n\n const filteredMembers = useMemo(() => {\n const needle = searchValue.trim().toLowerCase();\n if (!needle) {\n return projectMembers;\n }\n\n return projectMembers.filter((member) => {\n const fallback = getMemberFallback(profileMap, member);\n return (\n fallback.name.toLowerCase().includes(needle) ||\n fallback.email?.toLowerCase().includes(needle) ||\n member.userId.toLowerCase().includes(needle)\n );\n });\n }, [profileMap, projectMembers, searchValue]);\n\n if (permissionsLoading) {\n return (\n <div className=\"space-y-4 p-6\">\n <Skeleton className=\"h-10 w-40\" />\n <Skeleton className=\"h-10 w-64\" />\n <Skeleton className=\"h-40 w-full\" />\n </div>\n );\n }\n\n if (!canViewProject || !canListProjectMembers) {\n return (\n <div className=\"flex min-h-[400px] items-center justify-center\">\n <div className=\"space-y-2 text-center\">\n <h2 className=\"text-lg font-semibold\">\n {tWithFallback(t, 'projectMembers.accessDenied', 'Access Denied')}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tWithFallback(\n t,\n 'projectMembers.noPermission',\n \"You don't have permission to manage project members.\"\n )}\n </p>\n </div>\n </div>\n );\n }\n\n const handleBack = () => {\n navigate(withCurrentSearch(`${basePath}/${workspaceId}/projects/${projectId}`));\n };\n\n const handleRemoveMember = async (member: ProjectMember) => {\n const fallback = getMemberFallback(profileMap, member);\n void nativeImpact('medium');\n setRemoveError(null);\n const message = `${tWithFallback(t, 'projectMembers.removeConfirmPrefix', 'Remove')} ${fallback.name} ${tWithFallback(t, 'projectMembers.removeConfirmSuffix', 'from this project?')}`;\n const native = await nativeConfirm({\n title: tWithFallback(t, 'projectMembers.removeConfirmTitle', 'Remove project member'),\n message,\n okButtonTitle: tWithFallback(t, 'projectMembers.removeAction', 'Remove'),\n cancelButtonTitle: tWithFallback(t, 'projectMembers.cancel', 'Cancel'),\n });\n const confirmed = native === null ? window.confirm(message) : native;\n if (!confirmed) {\n return;\n }\n\n setRemovingUserId(member.userId);\n removeProjectMember(\n { projectId: member.projectId, userId: member.userId },\n {\n onSuccess: () => {\n void nativeNotify('success');\n setRemovingUserId(null);\n },\n onError: () => {\n void nativeNotify('error');\n setRemoveError(\n tWithFallback(\n t,\n 'projectMembers.removeError',\n 'Failed to remove project member. Please try again.'\n )\n );\n setRemovingUserId(null);\n },\n }\n );\n };\n\n return (\n <PageContainer padded={false}>\n <div className=\"space-y-4 p-3 sm:space-y-6 sm:p-6\">\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n <div>\n <Button variant=\"ghost\" onClick={handleBack} className=\"mb-2 -ml-2 gap-2\">\n <ArrowLeft size={20} />\n {tWithFallback(t, 'projectMembers.backToProject', 'Back to Project')}\n </Button>\n <h1 className=\"text-2xl font-bold sm:text-3xl\">\n {tWithFallback(t, 'projectMembers.pageTitle', 'Project Members')}\n </h1>\n <p className=\"text-sm text-text-secondary sm:text-base\">\n {project?.name\n ? `${project.name} · ${tWithFallback(\n t,\n 'projectMembers.pageSubtitle',\n 'Only existing workspace members can be added to this project.'\n )}`\n : tWithFallback(\n t,\n 'projectMembers.pageSubtitle',\n 'Only existing workspace members can be added to this project.'\n )}\n </p>\n </div>\n\n <div className=\"flex items-center gap-2\">\n <Badge variant=\"secondary\">{totalProjectMembers}</Badge>\n {canAddProjectMember ? (\n <Button\n onClick={() => setIsAddDialogOpen(true)}\n disabled={!workspaceId || !projectId}\n >\n <UserPlus className=\"mr-2 size-4\" />\n {tWithFallback(t, 'projectMembers.addMember', 'Add Member')}\n </Button>\n ) : null}\n </div>\n </div>\n\n <div className=\"relative\">\n <Search className=\"absolute left-3 top-1/2 size-4 -translate-y-1/2 text-text-secondary\" />\n <Input\n value={searchValue}\n onChange={(event) => setSearchValue(event.target.value)}\n placeholder={tWithFallback(\n t,\n 'projectMembers.searchPlaceholder',\n 'Search project members'\n )}\n className=\"pl-9\"\n />\n </div>\n\n {removeError ? (\n <div className=\"rounded-lg border border-status-error-border/20 bg-status-error-bg/10 p-4 text-sm text-status-error-text\">\n {removeError}\n </div>\n ) : null}\n\n {isLoadingProject || isLoadingMembers ? (\n <div className=\"space-y-4\">\n {Array.from({ length: 4 }).map((_, index) => (\n <div key={index} className=\"rounded-lg border border-border-seam bg-bg-surface p-4\">\n <Skeleton className=\"h-5 w-40\" />\n <Skeleton className=\"mt-2 h-4 w-56\" />\n </div>\n ))}\n </div>\n ) : projectError || membersError ? (\n <div className=\"rounded-lg border border-status-error-border/20 bg-status-error-bg/10 p-4 text-sm text-status-error-text\">\n {(membersError instanceof Error && membersError.message) ||\n (projectError instanceof Error && projectError.message) ||\n tWithFallback(t, 'projectMembers.loadError', 'Failed to load project members')}\n </div>\n ) : filteredMembers.length === 0 ? (\n <IllustratedEmptyState\n illustration={searchValue ? 'empty-search' : 'empty-people'}\n title={\n searchValue\n ? tWithFallback(t, 'projectMembers.noResultsTitle', 'No matching members found')\n : tWithFallback(t, 'projectMembers.emptyTitle', 'No project members yet')\n }\n description={\n searchValue\n ? tWithFallback(\n t,\n 'projectMembers.noResultsSubtitle',\n 'Try a different search to find a project member.'\n )\n : tWithFallback(\n t,\n 'projectMembers.emptySubtitle',\n 'Add workspace members to this project so they can collaborate here.'\n )\n }\n action={\n hasMoreProjectMembers || (!searchValue && canAddProjectMember) ? (\n <div className=\"flex flex-wrap items-center justify-center gap-2\">\n {hasMoreProjectMembers ? (\n <Button\n variant=\"outline\"\n onClick={() => void fetchNextProjectMembersPage()}\n disabled={isFetchingNextProjectMembersPage}\n >\n {isFetchingNextProjectMembersPage ? 'Loading more…' : 'Load More Members'}\n </Button>\n ) : null}\n {!searchValue && canAddProjectMember ? (\n <Button onClick={() => setIsAddDialogOpen(true)}>\n <UserPlus className=\"mr-2 size-4\" />\n {tWithFallback(t, 'projectMembers.addFirstMember', 'Add First Member')}\n </Button>\n ) : null}\n </div>\n ) : undefined\n }\n />\n ) : (\n <div className=\"space-y-3\">\n {filteredMembers.map((member) => {\n const profile = profileMap[member.userId];\n const fallback = getMemberFallback(profileMap, member);\n const isRemoving = isRemovingProjectMember && removingUserId === member.userId;\n\n return (\n <div\n key={member.id}\n className=\"flex items-center justify-between gap-4 rounded-card border border-border-seam bg-bg-surface p-4 shadow-elevation-1 transition-[box-shadow,transform] duration-200 ease-[var(--motion-easing-out)] hover:shadow-elevation-2 [@media(hover:none)]:\"\n >\n <div className=\"min-w-0 flex-1\">\n {profile ? (\n <ActorIdentity profile={profile} variant=\"cell\" />\n ) : (\n <div className=\"min-w-0\">\n <p className=\"truncate font-medium\">{fallback.name}</p>\n {fallback.email ? (\n <p className=\"truncate text-sm text-text-secondary\">{fallback.email}</p>\n ) : (\n <p className=\"truncate text-xs text-text-secondary\">{member.userId}</p>\n )}\n </div>\n )}\n\n <div className=\"mt-1 flex flex-wrap items-center gap-2\">\n <Badge variant=\"secondary\" className=\"text-xs\">\n {tWithFallback(t, 'projectMembers.memberBadge', 'Project member')}\n </Badge>\n <span className=\"text-xs text-text-secondary\">\n {tWithFallback(t, 'projectMembers.addedLabel', 'Added')}{' '}\n {formatRelativeTime(member.createdAt)}\n </span>\n </div>\n </div>\n\n {canRemoveProjectMember ? (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => void handleRemoveMember(member)}\n disabled={isRemovingProjectMember}\n >\n <UserMinus className=\"mr-2 size-4\" />\n {isRemoving\n ? tWithFallback(t, 'projectMembers.removing', 'Removing...')\n : tWithFallback(t, 'projectMembers.removeAction', 'Remove')}\n </Button>\n ) : null}\n </div>\n );\n })}\n\n {hasMoreProjectMembers ? (\n <div className=\"flex flex-col items-center gap-2 rounded-lg border border-dashed border-border-seam bg-bg-sunken/20 p-4 text-center\">\n <p className=\"text-sm text-text-secondary\">\n Showing {projectMembers.length} of {totalProjectMembers} project members.\n </p>\n <Button\n variant=\"outline\"\n onClick={() => void fetchNextProjectMembersPage()}\n disabled={isFetchingNextProjectMembersPage}\n >\n {isFetchingNextProjectMembersPage ? 'Loading more…' : 'Load More Members'}\n </Button>\n </div>\n ) : null}\n </div>\n )}\n\n {workspaceId && projectId && isAddDialogOpen ? (\n <ProjectMemberPickerDialog\n open={isAddDialogOpen}\n onOpenChange={setIsAddDialogOpen}\n workspaceId={workspaceId}\n projectId={projectId}\n projectName={project?.name}\n />\n ) : null}\n </div>\n </PageContainer>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA+BA,IAAM,KAA2B;AAEjC,SAAS,EAAkB,GAA6B,GAAuB;CAC7E,IAAM,IAAU,EAAW,EAAO;AAQlC,QAPI,IACK;EACL,MAAM,EAAQ;EACd,OAAO,EAAQ,SAAS,KAAA;EACzB,GAGI;EACL,MAAM,EAAO;EACb,OAAO,KAAA;EACR;;AAGH,SAAgB,IAAqB;CACnC,IAAM,EAAE,SAAM,GAAS,EACjB,KAAW,GAAa,EACxB,EAAE,gBAAa,iBAAc,GAAuD,EACpF,EACJ,eAAW,eACX,mBACA,cACA,sBACE,GAAsB,EACpB,EAAE,yBAAsB,GAAqB,EAC7C,CAAC,GAAa,KAAkB,EAAS,GAAG,EAC5C,CAAC,GAAiB,KAAsB,EAAS,GAAM,EACvD,CAAC,GAAgB,KAAqB,EAAwB,KAAK,EACnE,CAAC,GAAa,KAAkB,EAAwB,KAAK;AAEnE,GAAsB,8BAA8B;EAClD;EACA;EACA,eAAe;EAChB,CAAC;CAEF,IAAM,EACJ,MAAM,GACN,WAAW,GACX,OAAO,MACL,GAAW,KAAa,IAAI,EAAY,EACtC,EACJ,MAAM,GACN,WAAW,IACX,OAAO,GACP,aAAa,GACb,eAAe,GACf,oBAAoB,MAClB,GAA0B,KAAa,IAAI,GAAa,GAAyB,EAC/E,EAAE,QAAQ,IAAqB,WAAW,MAC9C,GAAuB,EAAY,EAE/B,EACJ,oBACA,2BACA,wBACA,4BACA,WAAW,MACT,GAAyB,EAEvB,IAAiB,QACf,GAAqB,MAAM,SAAS,MAAS,EAAK,MAAM,IAAI,EAAE,EACpE,CAAC,GAAqB,MAAM,CAC7B,EACK,IAAsB,GAAqB,MAAM,IAAI,SAAS,EAAe,QAK7E,IAA8B,EAJrB,QACP,EAAe,KAAK,OAAY;EAAE,SAAS,EAAO;EAAQ,WAAW;EAAQ,EAAE,EACrF,CAAC,EAAe,CACjB,EAC4D;EAC3D;EACA;EACA,OAAO;EACP;EACD,CAAC,EAEI,IAAkB,QAAc;EACpC,IAAM,IAAS,EAAY,MAAM,CAAC,aAAa;AAK/C,SAJK,IAIE,EAAe,QAAQ,MAAW;GACvC,IAAM,IAAW,EAAkB,GAAY,EAAO;AACtD,UACE,EAAS,KAAK,aAAa,CAAC,SAAS,EAAO,IAC5C,EAAS,OAAO,aAAa,CAAC,SAAS,EAAO,IAC9C,EAAO,OAAO,aAAa,CAAC,SAAS,EAAO;IAE9C,GAVO;IAWR;EAAC;EAAY;EAAgB;EAAY,CAAC;AAE7C,KAAI,EACF,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,GAAD,EAAU,WAAU,aAAc,CAAA;GAClC,kBAAC,GAAD,EAAU,WAAU,aAAc,CAAA;GAClC,kBAAC,GAAD,EAAU,WAAU,eAAgB,CAAA;GAChC;;AAIV,KAAI,CAAC,MAAkB,CAAC,GACtB,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,MAAD;IAAI,WAAU;cACX,EAAc,GAAG,+BAA+B,gBAAgB;IAC9D,CAAA,EACL,kBAAC,KAAD;IAAG,WAAU;cACV,EACC,GACA,+BACA,uDACD;IACC,CAAA,CACA;;EACF,CAAA;CAIV,IAAM,WAAmB;AACvB,KAAS,EAAkB,GAAG,GAAS,GAAG,EAAY,YAAY,IAAY,CAAC;IAG3E,KAAqB,OAAO,MAA0B;EAC1D,IAAM,IAAW,EAAkB,GAAY,EAAO;AAEtD,EADK,GAAa,SAAS,EAC3B,EAAe,KAAK;EACpB,IAAM,IAAU,GAAG,EAAc,GAAG,sCAAsC,SAAS,CAAC,GAAG,EAAS,KAAK,GAAG,EAAc,GAAG,sCAAsC,qBAAqB,IAC9K,IAAS,MAAM,EAAc;GACjC,OAAO,EAAc,GAAG,qCAAqC,wBAAwB;GACrF;GACA,eAAe,EAAc,GAAG,+BAA+B,SAAS;GACxE,mBAAmB,EAAc,GAAG,yBAAyB,SAAS;GACvE,CAAC;AACgB,SAAW,OAAO,OAAO,QAAQ,EAAQ,GAAG,OAK9D,EAAkB,EAAO,OAAO,EAChC,GACE;GAAE,WAAW,EAAO;GAAW,QAAQ,EAAO;GAAQ,EACtD;GACE,iBAAiB;AAEf,IADK,EAAa,UAAU,EAC5B,EAAkB,KAAK;;GAEzB,eAAe;AASb,IARK,EAAa,QAAQ,EAC1B,EACE,EACE,GACA,8BACA,qDACD,CACF,EACD,EAAkB,KAAK;;GAE1B,CACF;;AAGH,QACE,kBAAC,GAAD;EAAe,QAAQ;YACrB,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD,EAAA,UAAA;MACE,kBAAC,GAAD;OAAQ,SAAQ;OAAQ,SAAS;OAAY,WAAU;iBAAvD,CACE,kBAAC,IAAD,EAAW,MAAM,IAAM,CAAA,EACtB,EAAc,GAAG,gCAAgC,kBAAkB,CAC7D;;MACT,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAc,GAAG,4BAA4B,kBAAkB;OAC7D,CAAA;MACL,kBAAC,KAAD;OAAG,WAAU;iBACV,GAAS,OACN,GAAG,EAAQ,KAAK,KAAK,EACnB,GACA,+BACA,gEACD,KACD,EACE,GACA,+BACA,gEACD;OACH,CAAA;MACA,EAAA,CAAA,EAEN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD;OAAO,SAAQ;iBAAa;OAA4B,CAAA,EACvD,IACC,kBAAC,GAAD;OACE,eAAe,EAAmB,GAAK;OACvC,UAAU,CAAC,KAAe,CAAC;iBAF7B,CAIE,kBAAC,GAAD,EAAU,WAAU,eAAgB,CAAA,EACnC,EAAc,GAAG,4BAA4B,aAAa,CACpD;WACP,KACA;QACF;;IAEN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,IAAD,EAAQ,WAAU,uEAAwE,CAAA,EAC1F,kBAAC,GAAD;MACE,OAAO;MACP,WAAW,MAAU,EAAe,EAAM,OAAO,MAAM;MACvD,aAAa,EACX,GACA,oCACA,yBACD;MACD,WAAU;MACV,CAAA,CACE;;IAEL,IACC,kBAAC,OAAD;KAAK,WAAU;eACZ;KACG,CAAA,GACJ;IAEH,KAAoB,KACnB,kBAAC,OAAD;KAAK,WAAU;eACZ,MAAM,KAAK,EAAE,QAAQ,GAAG,CAAC,CAAC,KAAK,GAAG,MACjC,kBAAC,OAAD;MAAiB,WAAU;gBAA3B,CACE,kBAAC,GAAD,EAAU,WAAU,YAAa,CAAA,EACjC,kBAAC,GAAD,EAAU,WAAU,iBAAkB,CAAA,CAClC;QAHI,EAGJ,CACN;KACE,CAAA,GACJ,KAAgB,IAClB,kBAAC,OAAD;KAAK,WAAU;eACX,aAAwB,SAAS,EAAa,WAC7C,aAAwB,SAAS,EAAa,WAC/C,EAAc,GAAG,4BAA4B,iCAAiC;KAC5E,CAAA,GACJ,EAAgB,WAAW,IAC7B,kBAAC,GAAD;KACE,cAAc,IAAc,iBAAiB;KAC7C,OACE,IACI,EAAc,GAAG,iCAAiC,4BAA4B,GAC9E,EAAc,GAAG,6BAA6B,yBAAyB;KAE7E,aACE,IACI,EACE,GACA,oCACA,mDACD,GACD,EACE,GACA,gCACA,sEACD;KAEP,QACE,KAA0B,CAAC,KAAe,IACxC,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACG,IACC,kBAAC,GAAD;OACE,SAAQ;OACR,eAAe,KAAK,GAA6B;OACjD,UAAU;iBAET,IAAmC,kBAAkB;OAC/C,CAAA,GACP,MACH,CAAC,KAAe,IACf,kBAAC,GAAD;OAAQ,eAAe,EAAmB,GAAK;iBAA/C,CACE,kBAAC,GAAD,EAAU,WAAU,eAAgB,CAAA,EACnC,EAAc,GAAG,iCAAiC,mBAAmB,CAC/D;WACP,KACA;UACJ,KAAA;KAEN,CAAA,GAEF,kBAAC,OAAD;KAAK,WAAU;eAAf,CACG,EAAgB,KAAK,MAAW;MAC/B,IAAM,IAAU,EAAW,EAAO,SAC5B,IAAW,EAAkB,GAAY,EAAO,EAChD,IAAa,KAA2B,MAAmB,EAAO;AAExE,aACE,kBAAC,OAAD;OAEE,WAAU;iBAFZ,CAIE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACG,IACC,kBAAC,GAAD;SAAwB;SAAS,SAAQ;SAAS,CAAA,GAElD,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,KAAD;UAAG,WAAU;oBAAwB,EAAS;UAAS,CAAA,EACtD,EAAS,QACR,kBAAC,KAAD;UAAG,WAAU;oBAAwC,EAAS;UAAU,CAAA,GAExE,kBAAC,KAAD;UAAG,WAAU;oBAAwC,EAAO;UAAW,CAAA,CAErE;YAGR,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD;UAAO,SAAQ;UAAY,WAAU;oBAClC,EAAc,GAAG,8BAA8B,iBAAiB;UAC3D,CAAA,EACR,kBAAC,QAAD;UAAM,WAAU;oBAAhB;WACG,EAAc,GAAG,6BAA6B,QAAQ;WAAE;WACxD,EAAmB,EAAO,UAAU;WAChC;YACH;WACF;WAEL,KACC,kBAAC,GAAD;QACE,SAAQ;QACR,MAAK;QACL,eAAe,KAAK,GAAmB,EAAO;QAC9C,UAAU;kBAJZ,CAME,kBAAC,IAAD,EAAW,WAAU,eAAgB,CAAA,EACpC,IACG,EAAc,GAAG,2BAA2B,cAAc,GAC1D,EAAc,GAAG,+BAA+B,SAAS,CACtD;YACP,KACA;SAzCC,EAAO,GAyCR;OAER,EAED,IACC,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,KAAD;OAAG,WAAU;iBAAb;QAA2C;QAChC,EAAe;QAAO;QAAK;QAAoB;QACtD;UACJ,kBAAC,GAAD;OACE,SAAQ;OACR,eAAe,KAAK,GAA6B;OACjD,UAAU;iBAET,IAAmC,kBAAkB;OAC/C,CAAA,CACL;UACJ,KACA;;IAGP,KAAe,KAAa,IAC3B,kBAAC,IAAD;KACE,MAAM;KACN,cAAc;KACD;KACF;KACX,aAAa,GAAS;KACtB,CAAA,GACA;IACA;;EACQ,CAAA"}
1
+ {"version":3,"file":"ProjectMembersPage.js","names":[],"sources":["../../src/pages/ProjectMembersPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useNavigate, useParams } from 'react-router-dom';\nimport { ArrowLeft, Search, UserMinus, UserPlus } from 'lucide-react';\nimport {\n ActorIdentity,\n useActorProfiles,\n type ActorInput,\n type ActorProfileMap,\n} from '@burdenoff/fe-libs/shared';\nimport {\n Badge,\n Button,\n Input,\n PageContainer,\n Skeleton,\n IllustratedEmptyState,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { ProjectMemberPickerDialog } from '../components/ProjectMemberPickerDialog';\nimport { useInfiniteProjectMembers } from '../hooks/useProjectMembers';\nimport { useProject } from '../hooks/useProjects';\nimport { useRemoveProjectMember } from '../hooks/useProjectMemberMutations';\nimport { useScopedNavigation } from '../hooks/useScopedNavigation';\nimport { useWorkspacePermissions } from '../hooks/useWorkspacePermissions';\nimport { useWorkspacesContext } from '../providers/WorkspacesProvider';\nimport { formatRelativeTime } from '../utils/formatters';\nimport { tWithFallback } from '../utils/i18n';\nimport { nativeConfirm, nativeImpact, nativeNotify } from '../utils/nativeBridge';\nimport { useWorkspacesPageView } from '../hooks/useWorkspacesPageView';\nimport type { ProjectMember } from '../types';\n\nconst PROJECT_MEMBER_PAGE_SIZE = 100;\n\nfunction getMemberFallback(profileMap: ActorProfileMap, member: ProjectMember) {\n const profile = profileMap[member.userId];\n if (profile) {\n return {\n name: profile.displayName,\n email: profile.email ?? undefined,\n };\n }\n\n return {\n name: member.userId,\n email: undefined,\n };\n}\n\nexport function ProjectMembersPage() {\n const { t } = useI18n();\n const navigate = useNavigate();\n const { workspaceId, projectId } = useParams<{ workspaceId: string; projectId: string }>();\n const {\n basePath = '/workspaces',\n apiGatewayUrl,\n authToken,\n organizationId,\n } = useWorkspacesContext();\n const { withCurrentSearch } = useScopedNavigation();\n const [searchValue, setSearchValue] = useState('');\n const [isAddDialogOpen, setIsAddDialogOpen] = useState(false);\n const [removingUserId, setRemovingUserId] = useState<string | null>(null);\n const [removeError, setRemoveError] = useState<string | null>(null);\n\n useWorkspacesPageView('workspaces.project-members', {\n workspaceId,\n projectId,\n requireParams: true,\n });\n\n const {\n data: project,\n isLoading: isLoadingProject,\n error: projectError,\n } = useProject(projectId || '', workspaceId);\n const {\n data: projectMembersPages,\n isLoading: isLoadingMembers,\n error: membersError,\n hasNextPage: hasMoreProjectMembers,\n fetchNextPage: fetchNextProjectMembersPage,\n isFetchingNextPage: isFetchingNextProjectMembersPage,\n } = useInfiniteProjectMembers(projectId || '', workspaceId, PROJECT_MEMBER_PAGE_SIZE);\n const { mutate: removeProjectMember, isPending: isRemovingProjectMember } =\n useRemoveProjectMember(workspaceId);\n\n const {\n canViewProject,\n canListProjectMembers,\n canAddProjectMember,\n canRemoveProjectMember,\n isLoading: permissionsLoading,\n } = useWorkspacePermissions();\n\n const projectMembers = useMemo(\n () => projectMembersPages?.pages.flatMap((page) => page.items) ?? [],\n [projectMembersPages?.pages]\n );\n const totalProjectMembers = projectMembersPages?.pages[0]?.total ?? projectMembers.length;\n const actors = useMemo<ActorInput[]>(\n () => projectMembers.map((member) => ({ actorId: member.userId, actorType: 'user' })),\n [projectMembers]\n );\n const profileMap: ActorProfileMap = useActorProfiles(actors, {\n apiGatewayUrl,\n authToken,\n orgId: organizationId,\n workspaceId,\n });\n\n const filteredMembers = useMemo(() => {\n const needle = searchValue.trim().toLowerCase();\n if (!needle) {\n return projectMembers;\n }\n\n return projectMembers.filter((member) => {\n const fallback = getMemberFallback(profileMap, member);\n return (\n fallback.name.toLowerCase().includes(needle) ||\n fallback.email?.toLowerCase().includes(needle) ||\n member.userId.toLowerCase().includes(needle)\n );\n });\n }, [profileMap, projectMembers, searchValue]);\n\n if (permissionsLoading) {\n return (\n <div className=\"space-y-4 p-6\">\n <Skeleton className=\"h-10 w-40\" />\n <Skeleton className=\"h-10 w-64\" />\n <Skeleton className=\"h-40 w-full\" />\n </div>\n );\n }\n\n if (!canViewProject || !canListProjectMembers) {\n return (\n <div className=\"flex min-h-[400px] items-center justify-center\">\n <div className=\"space-y-2 text-center\">\n <h2 className=\"text-lg font-semibold\">\n {tWithFallback(t, 'projectMembers.accessDenied', 'Access Denied')}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tWithFallback(\n t,\n 'projectMembers.noPermission',\n \"You don't have permission to manage project members.\"\n )}\n </p>\n </div>\n </div>\n );\n }\n\n const handleBack = () => {\n navigate(withCurrentSearch(`${basePath}/${workspaceId}/projects/${projectId}`));\n };\n\n const handleRemoveMember = async (member: ProjectMember) => {\n const fallback = getMemberFallback(profileMap, member);\n void nativeImpact('medium');\n setRemoveError(null);\n const message = `${tWithFallback(t, 'projectMembers.removeConfirmPrefix', 'Remove')} ${fallback.name} ${tWithFallback(t, 'projectMembers.removeConfirmSuffix', 'from this project?')}`;\n const native = await nativeConfirm({\n title: tWithFallback(t, 'projectMembers.removeConfirmTitle', 'Remove project member'),\n message,\n okButtonTitle: tWithFallback(t, 'projectMembers.removeAction', 'Remove'),\n cancelButtonTitle: tWithFallback(t, 'projectMembers.cancel', 'Cancel'),\n });\n const confirmed = native === null ? window.confirm(message) : native;\n if (!confirmed) {\n return;\n }\n\n setRemovingUserId(member.userId);\n removeProjectMember(\n { projectId: member.projectId, userId: member.userId },\n {\n onSuccess: () => {\n void nativeNotify('success');\n setRemovingUserId(null);\n },\n onError: () => {\n void nativeNotify('error');\n setRemoveError(\n tWithFallback(\n t,\n 'projectMembers.removeError',\n 'Failed to remove project member. Please try again.'\n )\n );\n setRemovingUserId(null);\n },\n }\n );\n };\n\n return (\n <PageContainer padded={false}>\n <div className=\"space-y-4 p-3 sm:space-y-6 sm:p-6\">\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n <div>\n <Button variant=\"ghost\" onClick={handleBack} className=\"mb-2 -ml-2 gap-2\">\n <ArrowLeft size={20} />\n {tWithFallback(t, 'projectMembers.backToProject', 'Back to Project')}\n </Button>\n <h1 className=\"text-2xl font-bold sm:text-3xl\">\n {tWithFallback(t, 'projectMembers.pageTitle', 'Project Members')}\n </h1>\n <p className=\"text-sm text-text-secondary sm:text-base\">\n {project?.name\n ? `${project.name} · ${tWithFallback(\n t,\n 'projectMembers.pageSubtitle',\n 'Only existing workspace members can be added to this project.'\n )}`\n : tWithFallback(\n t,\n 'projectMembers.pageSubtitle',\n 'Only existing workspace members can be added to this project.'\n )}\n </p>\n </div>\n\n <div className=\"flex items-center gap-2\">\n <Badge variant=\"secondary\">{totalProjectMembers}</Badge>\n {canAddProjectMember ? (\n <Button\n onClick={() => setIsAddDialogOpen(true)}\n disabled={!workspaceId || !projectId}\n >\n <UserPlus className=\"mr-2 size-4\" />\n {tWithFallback(t, 'projectMembers.addMember', 'Add Member')}\n </Button>\n ) : null}\n </div>\n </div>\n\n <PagePurpose>\n {tWithFallback(\n t,\n 'projectMembers.purpose',\n 'This is the subset of workspace members who can work on this specific project. Add people here to give them project-level access, search to find someone, or remove members who have moved on. Only existing workspace members can be added.'\n )}\n </PagePurpose>\n\n <div className=\"relative\">\n <Search className=\"absolute left-3 top-1/2 size-4 -translate-y-1/2 text-text-secondary\" />\n <Input\n value={searchValue}\n onChange={(event) => setSearchValue(event.target.value)}\n placeholder={tWithFallback(\n t,\n 'projectMembers.searchPlaceholder',\n 'Search project members'\n )}\n className=\"pl-9\"\n />\n </div>\n\n {removeError ? (\n <div className=\"rounded-lg border border-status-error-border/20 bg-status-error-bg/10 p-4 text-sm text-status-error-text\">\n {removeError}\n </div>\n ) : null}\n\n {isLoadingProject || isLoadingMembers ? (\n <div className=\"space-y-4\">\n {Array.from({ length: 4 }).map((_, index) => (\n <div key={index} className=\"rounded-lg border border-border-seam bg-bg-surface p-4\">\n <Skeleton className=\"h-5 w-40\" />\n <Skeleton className=\"mt-2 h-4 w-56\" />\n </div>\n ))}\n </div>\n ) : projectError || membersError ? (\n <div className=\"rounded-lg border border-status-error-border/20 bg-status-error-bg/10 p-4 text-sm text-status-error-text\">\n {(membersError instanceof Error && membersError.message) ||\n (projectError instanceof Error && projectError.message) ||\n tWithFallback(t, 'projectMembers.loadError', 'Failed to load project members')}\n </div>\n ) : filteredMembers.length === 0 ? (\n <IllustratedEmptyState\n illustration={searchValue ? 'empty-search' : 'empty-people'}\n title={\n searchValue\n ? tWithFallback(t, 'projectMembers.noResultsTitle', 'No matching members found')\n : tWithFallback(t, 'projectMembers.emptyTitle', 'No project members yet')\n }\n description={\n searchValue\n ? tWithFallback(\n t,\n 'projectMembers.noResultsSubtitle',\n 'Try a different search to find a project member.'\n )\n : tWithFallback(\n t,\n 'projectMembers.emptySubtitle',\n 'Add workspace members to this project so they can collaborate here.'\n )\n }\n action={\n hasMoreProjectMembers || (!searchValue && canAddProjectMember) ? (\n <div className=\"flex flex-wrap items-center justify-center gap-2\">\n {hasMoreProjectMembers ? (\n <Button\n variant=\"outline\"\n onClick={() => void fetchNextProjectMembersPage()}\n disabled={isFetchingNextProjectMembersPage}\n >\n {isFetchingNextProjectMembersPage ? 'Loading more…' : 'Load More Members'}\n </Button>\n ) : null}\n {!searchValue && canAddProjectMember ? (\n <Button onClick={() => setIsAddDialogOpen(true)}>\n <UserPlus className=\"mr-2 size-4\" />\n {tWithFallback(t, 'projectMembers.addFirstMember', 'Add First Member')}\n </Button>\n ) : null}\n </div>\n ) : undefined\n }\n />\n ) : (\n <div className=\"space-y-3\">\n {filteredMembers.map((member) => {\n const profile = profileMap[member.userId];\n const fallback = getMemberFallback(profileMap, member);\n const isRemoving = isRemovingProjectMember && removingUserId === member.userId;\n\n return (\n <div\n key={member.id}\n className=\"flex items-center justify-between gap-4 rounded-card border border-border-seam bg-bg-surface p-4 shadow-elevation-1 transition-[box-shadow,transform] duration-200 ease-[var(--motion-easing-out)] hover:shadow-elevation-2 [@media(hover:none)]:\"\n >\n <div className=\"min-w-0 flex-1\">\n {profile ? (\n <ActorIdentity profile={profile} variant=\"cell\" />\n ) : (\n <div className=\"min-w-0\">\n <p className=\"truncate font-medium\">{fallback.name}</p>\n {fallback.email ? (\n <p className=\"truncate text-sm text-text-secondary\">{fallback.email}</p>\n ) : (\n <p className=\"truncate text-xs text-text-secondary\">{member.userId}</p>\n )}\n </div>\n )}\n\n <div className=\"mt-1 flex flex-wrap items-center gap-2\">\n <Badge variant=\"secondary\" className=\"text-xs\">\n {tWithFallback(t, 'projectMembers.memberBadge', 'Project member')}\n </Badge>\n <span className=\"text-xs text-text-secondary\">\n {tWithFallback(t, 'projectMembers.addedLabel', 'Added')}{' '}\n {formatRelativeTime(member.createdAt)}\n </span>\n </div>\n </div>\n\n {canRemoveProjectMember ? (\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => void handleRemoveMember(member)}\n disabled={isRemovingProjectMember}\n >\n <UserMinus className=\"mr-2 size-4\" />\n {isRemoving\n ? tWithFallback(t, 'projectMembers.removing', 'Removing...')\n : tWithFallback(t, 'projectMembers.removeAction', 'Remove')}\n </Button>\n ) : null}\n </div>\n );\n })}\n\n {hasMoreProjectMembers ? (\n <div className=\"flex flex-col items-center gap-2 rounded-lg border border-dashed border-border-seam bg-bg-sunken/20 p-4 text-center\">\n <p className=\"text-sm text-text-secondary\">\n Showing {projectMembers.length} of {totalProjectMembers} project members.\n </p>\n <Button\n variant=\"outline\"\n onClick={() => void fetchNextProjectMembersPage()}\n disabled={isFetchingNextProjectMembersPage}\n >\n {isFetchingNextProjectMembersPage ? 'Loading more…' : 'Load More Members'}\n </Button>\n </div>\n ) : null}\n </div>\n )}\n\n {workspaceId && projectId && isAddDialogOpen ? (\n <ProjectMemberPickerDialog\n open={isAddDialogOpen}\n onOpenChange={setIsAddDialogOpen}\n workspaceId={workspaceId}\n projectId={projectId}\n projectName={project?.name}\n />\n ) : null}\n </div>\n </PageContainer>\n );\n}\n"],"mappings":"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"}