@burdenoff/microfe-workspaces 2026.625.2 → 2026.625.4

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 (33) hide show
  1. package/dist/pages/ActivityListPage.js +32 -48
  2. package/dist/pages/ActivityListPage.js.map +1 -1
  3. package/dist/pages/MembersListPage.js +196 -241
  4. package/dist/pages/MembersListPage.js.map +1 -1
  5. package/dist/pages/PendingInvitesPage.js +69 -78
  6. package/dist/pages/PendingInvitesPage.js.map +1 -1
  7. package/dist/pages/ProjectDetailPage.js +37 -52
  8. package/dist/pages/ProjectDetailPage.js.map +1 -1
  9. package/dist/pages/ProjectMembersPage.js +74 -87
  10. package/dist/pages/ProjectMembersPage.js.map +1 -1
  11. package/dist/pages/ProjectsListPage.js +103 -118
  12. package/dist/pages/ProjectsListPage.js.map +1 -1
  13. package/dist/pages/WorkspaceDetailPage.js +74 -76
  14. package/dist/pages/WorkspaceDetailPage.js.map +1 -1
  15. package/dist/pages/WorkspacesListPage.js +167 -178
  16. package/dist/pages/WorkspacesListPage.js.map +1 -1
  17. package/dist/pages/dashboard/widgets/AgentsWidget.js +21 -22
  18. package/dist/pages/dashboard/widgets/AgentsWidget.js.map +1 -1
  19. package/dist/pages/dashboard/widgets/ProjectsWidget.js +26 -27
  20. package/dist/pages/dashboard/widgets/ProjectsWidget.js.map +1 -1
  21. package/dist/pages/dashboard/widgets/RecentActivityWidget.js +19 -23
  22. package/dist/pages/dashboard/widgets/RecentActivityWidget.js.map +1 -1
  23. package/dist/pages/dashboard/widgets/SessionsWidget.js +30 -32
  24. package/dist/pages/dashboard/widgets/SessionsWidget.js.map +1 -1
  25. package/dist/pages/dashboard/widgets/UpcomingEventsWidget.js +18 -20
  26. package/dist/pages/dashboard/widgets/UpcomingEventsWidget.js.map +1 -1
  27. package/dist/pages/dashboard/widgets/VibesWidget.js +18 -19
  28. package/dist/pages/dashboard/widgets/VibesWidget.js.map +1 -1
  29. package/dist/pages/dashboard/widgets/WelcomeWidget.js +14 -12
  30. package/dist/pages/dashboard/widgets/WelcomeWidget.js.map +1 -1
  31. package/dist/pages/dashboard/widgets/WorkspacesWidget.js +20 -21
  32. package/dist/pages/dashboard/widgets/WorkspacesWidget.js.map +1 -1
  33. package/package.json +2 -2
@@ -4,15 +4,15 @@ import { tWithFallback as n } from "../utils/i18n.js";
4
4
  import { useWorkspacesPageView as r } from "../hooks/useWorkspacesPageView.js";
5
5
  import { nativeConfirm as i, nativeImpact as ee, nativeNotify as a } from "../utils/nativeBridge.js";
6
6
  import { useWorkspacePermissions as o } from "../hooks/useWorkspacePermissions.js";
7
- import { useProject as s } from "../hooks/useProjects.js";
8
- import { formatRelativeTime as c } from "../utils/formatters.js";
9
- import { useRemoveProjectMember as te } from "../hooks/useProjectMemberMutations.js";
10
- import { useInfiniteProjectMembers as ne } from "../hooks/useProjectMembers.js";
11
- import { ProjectMemberPickerDialog as re } from "../components/ProjectMemberPickerDialog.js";
12
- import { useMemo as l, useState as u } from "react";
13
- import { ArrowLeft as ie, Search as ae, UserMinus as oe, UserPlus as d, Users as se } from "lucide-react";
14
- import { jsx as f, jsxs as p } from "react/jsx-runtime";
15
- import { Badge as m, Button as h, Input as g, PageContainer as _, Skeleton as v } from "@burdenoff/fe-libs/ui";
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
16
  import { useNavigate as y, useParams as b } from "react-router-dom";
17
17
  import { useI18n as x } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
18
18
  import { ActorIdentity as S, useActorProfiles as C } from "@burdenoff/fe-libs/shared";
@@ -29,13 +29,13 @@ function w(e, t) {
29
29
  };
30
30
  }
31
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] = u(""), [N, P] = u(!1), [F, I] = u(null), [L, R] = u(null);
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);
33
33
  r("workspaces.project-members", {
34
34
  workspaceId: E,
35
35
  projectId: D,
36
36
  requireParams: !0
37
37
  });
38
- let { data: z, isLoading: B, error: V } = s(D || "", E), { data: H, isLoading: fe, error: U, hasNextPage: W, fetchNextPage: G, isFetchingNextPage: K } = ne(D || "", E, ce), { mutate: pe, isPending: q } = te(E), { canViewProject: me, canListProjectMembers: he, canAddProjectMember: J, canRemoveProjectMember: ge, isLoading: Y } = o(), X = l(() => H?.pages.flatMap((e) => e.items) ?? [], [H?.pages]), Z = H?.pages[0]?.total ?? X.length, Q = C(l(() => X.map((e) => ({
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) => ({
39
39
  actorId: e.userId,
40
40
  actorType: "user"
41
41
  })), [X]), {
@@ -43,7 +43,7 @@ function T() {
43
43
  authToken: O,
44
44
  orgId: k,
45
45
  workspaceId: E
46
- }), $ = l(() => {
46
+ }), $ = c(() => {
47
47
  let e = j.trim().toLowerCase();
48
48
  return e ? X.filter((t) => {
49
49
  let n = w(Q, t);
@@ -54,22 +54,22 @@ function T() {
54
54
  X,
55
55
  j
56
56
  ]);
57
- if (Y) return /* @__PURE__ */ p("div", {
57
+ if (Y) return /* @__PURE__ */ f("div", {
58
58
  className: "space-y-4 p-6",
59
59
  children: [
60
- /* @__PURE__ */ f(v, { className: "h-10 w-40" }),
61
- /* @__PURE__ */ f(v, { className: "h-10 w-64" }),
62
- /* @__PURE__ */ f(v, { className: "h-40 w-full" })
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" })
63
63
  ]
64
64
  });
65
- if (!me || !he) return /* @__PURE__ */ f("div", {
65
+ if (!me || !he) return /* @__PURE__ */ d("div", {
66
66
  className: "flex min-h-[400px] items-center justify-center",
67
- children: /* @__PURE__ */ p("div", {
67
+ children: /* @__PURE__ */ f("div", {
68
68
  className: "space-y-2 text-center",
69
- children: [/* @__PURE__ */ f("h2", {
69
+ children: [/* @__PURE__ */ d("h2", {
70
70
  className: "text-lg font-semibold",
71
71
  children: n(T, "projectMembers.accessDenied", "Access Denied")
72
- }), /* @__PURE__ */ f("p", {
72
+ }), /* @__PURE__ */ d("p", {
73
73
  className: "text-sm text-text-secondary",
74
74
  children: n(T, "projectMembers.noPermission", "You don't have permission to manage project members.")
75
75
  })]
@@ -98,140 +98,127 @@ function T() {
98
98
  }
99
99
  }));
100
100
  };
101
- return /* @__PURE__ */ f(_, {
101
+ return /* @__PURE__ */ d(_, {
102
102
  padded: !1,
103
- children: /* @__PURE__ */ p("div", {
103
+ children: /* @__PURE__ */ f("div", {
104
104
  className: "space-y-4 p-3 sm:space-y-6 sm:p-6",
105
105
  children: [
106
- /* @__PURE__ */ p("div", {
106
+ /* @__PURE__ */ f("div", {
107
107
  className: "flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between",
108
- children: [/* @__PURE__ */ p("div", { children: [
109
- /* @__PURE__ */ p(h, {
108
+ children: [/* @__PURE__ */ f("div", { children: [
109
+ /* @__PURE__ */ f(m, {
110
110
  variant: "ghost",
111
111
  onClick: _e,
112
112
  className: "mb-2 -ml-2 gap-2",
113
- children: [/* @__PURE__ */ f(ie, { size: 20 }), n(T, "projectMembers.backToProject", "Back to Project")]
113
+ children: [/* @__PURE__ */ d(ae, { size: 20 }), n(T, "projectMembers.backToProject", "Back to Project")]
114
114
  }),
115
- /* @__PURE__ */ f("h1", {
115
+ /* @__PURE__ */ d("h1", {
116
116
  className: "text-2xl font-bold sm:text-3xl",
117
117
  children: n(T, "projectMembers.pageTitle", "Project Members")
118
118
  }),
119
- /* @__PURE__ */ f("p", {
119
+ /* @__PURE__ */ d("p", {
120
120
  className: "text-sm text-text-secondary sm:text-base",
121
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.")
122
122
  })
123
- ] }), /* @__PURE__ */ p("div", {
123
+ ] }), /* @__PURE__ */ f("div", {
124
124
  className: "flex items-center gap-2",
125
- children: [/* @__PURE__ */ f(m, {
125
+ children: [/* @__PURE__ */ d(p, {
126
126
  variant: "secondary",
127
127
  children: Z
128
- }), J ? /* @__PURE__ */ p(h, {
128
+ }), J ? /* @__PURE__ */ f(m, {
129
129
  onClick: () => P(!0),
130
130
  disabled: !E || !D,
131
- children: [/* @__PURE__ */ f(d, { className: "mr-2 size-4" }), n(T, "projectMembers.addMember", "Add Member")]
131
+ children: [/* @__PURE__ */ d(u, { className: "mr-2 size-4" }), n(T, "projectMembers.addMember", "Add Member")]
132
132
  }) : null]
133
133
  })]
134
134
  }),
135
- /* @__PURE__ */ p("div", {
135
+ /* @__PURE__ */ f("div", {
136
136
  className: "relative",
137
- children: [/* @__PURE__ */ f(ae, { className: "absolute left-3 top-1/2 size-4 -translate-y-1/2 text-text-secondary" }), /* @__PURE__ */ f(g, {
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
138
  value: j,
139
139
  onChange: (e) => M(e.target.value),
140
140
  placeholder: n(T, "projectMembers.searchPlaceholder", "Search project members"),
141
141
  className: "pl-9"
142
142
  })]
143
143
  }),
144
- L ? /* @__PURE__ */ f("div", {
144
+ L ? /* @__PURE__ */ d("div", {
145
145
  className: "rounded-lg border border-status-error-border/20 bg-status-error-bg/10 p-4 text-sm text-status-error-text",
146
146
  children: L
147
147
  }) : null,
148
- B || fe ? /* @__PURE__ */ f("div", {
148
+ B || fe ? /* @__PURE__ */ d("div", {
149
149
  className: "space-y-4",
150
- children: Array.from({ length: 4 }).map((e, t) => /* @__PURE__ */ p("div", {
150
+ children: Array.from({ length: 4 }).map((e, t) => /* @__PURE__ */ f("div", {
151
151
  className: "rounded-lg border border-border-seam bg-bg-surface p-4",
152
- children: [/* @__PURE__ */ f(v, { className: "h-5 w-40" }), /* @__PURE__ */ f(v, { className: "mt-2 h-4 w-56" })]
152
+ children: [/* @__PURE__ */ d(v, { className: "h-5 w-40" }), /* @__PURE__ */ d(v, { className: "mt-2 h-4 w-56" })]
153
153
  }, t))
154
- }) : V || U ? /* @__PURE__ */ f("div", {
154
+ }) : V || U ? /* @__PURE__ */ d("div", {
155
155
  className: "rounded-lg border border-status-error-border/20 bg-status-error-bg/10 p-4 text-sm text-status-error-text",
156
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__ */ p("div", {
158
- className: "rounded-lg border border-border-seam bg-bg-surface p-10 text-center",
159
- children: [
160
- /* @__PURE__ */ f(se, { className: "mx-auto mb-4 size-12 text-text-secondary" }),
161
- /* @__PURE__ */ f("h2", {
162
- className: "text-xl font-semibold",
163
- children: j ? n(T, "projectMembers.noResultsTitle", "No matching members found") : n(T, "projectMembers.emptyTitle", "No project members yet")
164
- }),
165
- /* @__PURE__ */ f("p", {
166
- className: "mt-2 text-text-secondary",
167
- children: 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.")
168
- }),
169
- W ? /* @__PURE__ */ f("div", {
170
- className: "mt-4",
171
- children: /* @__PURE__ */ f(h, {
172
- variant: "outline",
173
- onClick: () => void G(),
174
- disabled: K,
175
- children: K ? "Loading more…" : "Load More Members"
176
- })
177
- }) : null,
178
- !j && J ? /* @__PURE__ */ f("div", {
179
- className: "mt-4",
180
- children: /* @__PURE__ */ p(h, {
181
- onClick: () => P(!0),
182
- children: [/* @__PURE__ */ f(d, { className: "mr-2 size-4" }), n(T, "projectMembers.addFirstMember", "Add First Member")]
183
- })
184
- }) : null
185
- ]
186
- }) : /* @__PURE__ */ p("div", {
157
+ }) : $.length === 0 ? /* @__PURE__ */ d(h, {
158
+ 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", {
162
+ className: "flex flex-wrap items-center justify-center gap-2",
163
+ children: [W ? /* @__PURE__ */ d(m, {
164
+ variant: "outline",
165
+ onClick: () => void G(),
166
+ disabled: K,
167
+ children: K ? "Loading more…" : "Load More Members"
168
+ }) : null, !j && J ? /* @__PURE__ */ f(m, {
169
+ onClick: () => P(!0),
170
+ children: [/* @__PURE__ */ d(u, { className: "mr-2 size-4" }), n(T, "projectMembers.addFirstMember", "Add First Member")]
171
+ }) : null]
172
+ }) : void 0
173
+ }) : /* @__PURE__ */ f("div", {
187
174
  className: "space-y-3",
188
175
  children: [$.map((e) => {
189
176
  let t = Q[e.userId], r = w(Q, e), i = q && F === e.userId;
190
- return /* @__PURE__ */ p("div", {
191
- 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)] motion-safe:hover:translate-y-[var(--pop-lift-y)] hover:shadow-elevation-2 [@media(hover:none)]:hover:translate-y-0",
192
- children: [/* @__PURE__ */ p("div", {
177
+ return /* @__PURE__ */ f("div", {
178
+ 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", {
193
180
  className: "min-w-0 flex-1",
194
- children: [t ? /* @__PURE__ */ f(S, {
181
+ children: [t ? /* @__PURE__ */ d(S, {
195
182
  profile: t,
196
183
  variant: "cell"
197
- }) : /* @__PURE__ */ p("div", {
184
+ }) : /* @__PURE__ */ f("div", {
198
185
  className: "min-w-0",
199
- children: [/* @__PURE__ */ f("p", {
186
+ children: [/* @__PURE__ */ d("p", {
200
187
  className: "truncate font-medium",
201
188
  children: r.name
202
- }), r.email ? /* @__PURE__ */ f("p", {
189
+ }), r.email ? /* @__PURE__ */ d("p", {
203
190
  className: "truncate text-sm text-text-secondary",
204
191
  children: r.email
205
- }) : /* @__PURE__ */ f("p", {
192
+ }) : /* @__PURE__ */ d("p", {
206
193
  className: "truncate text-xs text-text-secondary",
207
194
  children: e.userId
208
195
  })]
209
- }), /* @__PURE__ */ p("div", {
196
+ }), /* @__PURE__ */ f("div", {
210
197
  className: "mt-1 flex flex-wrap items-center gap-2",
211
- children: [/* @__PURE__ */ f(m, {
198
+ children: [/* @__PURE__ */ d(p, {
212
199
  variant: "secondary",
213
200
  className: "text-xs",
214
201
  children: n(T, "projectMembers.memberBadge", "Project member")
215
- }), /* @__PURE__ */ p("span", {
202
+ }), /* @__PURE__ */ f("span", {
216
203
  className: "text-xs text-text-secondary",
217
204
  children: [
218
205
  n(T, "projectMembers.addedLabel", "Added"),
219
206
  " ",
220
- c(e.createdAt)
207
+ s(e.createdAt)
221
208
  ]
222
209
  })]
223
210
  })]
224
- }), ge ? /* @__PURE__ */ p(h, {
211
+ }), ge ? /* @__PURE__ */ f(m, {
225
212
  variant: "outline",
226
213
  size: "sm",
227
214
  onClick: () => void ve(e),
228
215
  disabled: q,
229
- children: [/* @__PURE__ */ f(oe, { className: "mr-2 size-4" }), i ? n(T, "projectMembers.removing", "Removing...") : n(T, "projectMembers.removeAction", "Remove")]
216
+ children: [/* @__PURE__ */ d(se, { className: "mr-2 size-4" }), i ? n(T, "projectMembers.removing", "Removing...") : n(T, "projectMembers.removeAction", "Remove")]
230
217
  }) : null]
231
218
  }, e.id);
232
- }), W ? /* @__PURE__ */ p("div", {
219
+ }), W ? /* @__PURE__ */ f("div", {
233
220
  className: "flex flex-col items-center gap-2 rounded-lg border border-dashed border-border-seam bg-bg-sunken/20 p-4 text-center",
234
- children: [/* @__PURE__ */ p("p", {
221
+ children: [/* @__PURE__ */ f("p", {
235
222
  className: "text-sm text-text-secondary",
236
223
  children: [
237
224
  "Showing ",
@@ -240,7 +227,7 @@ function T() {
240
227
  Z,
241
228
  " project members."
242
229
  ]
243
- }), /* @__PURE__ */ f(h, {
230
+ }), /* @__PURE__ */ d(m, {
244
231
  variant: "outline",
245
232
  onClick: () => void G(),
246
233
  disabled: K,
@@ -248,7 +235,7 @@ function T() {
248
235
  })]
249
236
  }) : null]
250
237
  }),
251
- E && D && N ? /* @__PURE__ */ f(re, {
238
+ E && D && N ? /* @__PURE__ */ d(ie, {
252
239
  open: N,
253
240
  onOpenChange: P,
254
241
  workspaceId: E,
@@ -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, Users } from 'lucide-react';\nimport {\n ActorIdentity,\n useActorProfiles,\n type ActorInput,\n type ActorProfileMap,\n} from '@burdenoff/fe-libs/shared';\nimport { Badge, Button, Input, PageContainer, Skeleton } 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 <div className=\"rounded-lg border border-border-seam bg-bg-surface p-10 text-center\">\n <Users className=\"mx-auto mb-4 size-12 text-text-secondary\" />\n <h2 className=\"text-xl font-semibold\">\n {searchValue\n ? tWithFallback(t, 'projectMembers.noResultsTitle', 'No matching members found')\n : tWithFallback(t, 'projectMembers.emptyTitle', 'No project members yet')}\n </h2>\n <p className=\"mt-2 text-text-secondary\">\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 </p>\n {hasMoreProjectMembers ? (\n <div className=\"mt-4\">\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 {!searchValue && canAddProjectMember ? (\n <div className=\"mt-4\">\n <Button onClick={() => setIsAddDialogOpen(true)}>\n <UserPlus className=\"mr-2 size-4\" />\n {tWithFallback(t, 'projectMembers.addFirstMember', 'Add First Member')}\n </Button>\n </div>\n ) : null}\n </div>\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)] motion-safe:hover:translate-y-[var(--pop-lift-y)] hover:shadow-elevation-2 [@media(hover:none)]:hover:translate-y-0\"\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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"}
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":"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"}