@burdenoff/microfe-organization 2026.530.1 → 2026.601.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/generated/global-operations.js +101 -73
- package/dist/generated/global-operations.js.map +1 -1
- package/dist/organization-management/AdminOrganizationRoutes.js +6 -2
- package/dist/organization-management/AdminOrganizationRoutes.js.map +1 -1
- package/dist/organization-management/UserOrganizationRoutes.js +6 -2
- package/dist/organization-management/UserOrganizationRoutes.js.map +1 -1
- package/dist/organization-management/modules/members/hooks/useWorkspaceInvites.js +113 -0
- package/dist/organization-management/modules/members/hooks/useWorkspaceInvites.js.map +1 -0
- package/dist/organization-management/modules/members/pages/MyInvitesPage.js +368 -62
- package/dist/organization-management/modules/members/pages/MyInvitesPage.js.map +1 -1
- package/dist/organization-management/modules/members/utils/workspaceInvitationDisplay.js +29 -0
- package/dist/organization-management/modules/members/utils/workspaceInvitationDisplay.js.map +1 -0
- package/dist/organization-management/modules/organizations/pages/OrganizationsListPage.js +3 -3
- package/dist/organization-management/modules/organizations/pages/OrganizationsListPage.js.map +1 -1
- package/dist/organization-management/modules/workspaces/hooks/useWorkspaces.js +38 -29
- package/dist/organization-management/modules/workspaces/hooks/useWorkspaces.js.map +1 -1
- package/dist/organization-management/modules/workspaces/pages/WorkspacesListPage.js +217 -205
- package/dist/organization-management/modules/workspaces/pages/WorkspacesListPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,107 +1,413 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
1
|
+
import { useOrgConsole as e } from "../../../providers/OrgConsoleProvider.js";
|
|
2
|
+
import { useAcceptInvite as t, useMyInvites as n, useRejectInvite as r } from "../hooks/useInvites.js";
|
|
3
|
+
import { InviteStatus as i } from "../../../../generated/global-types.js";
|
|
4
|
+
import { useTr as a } from "../../../shared/hooks/useTr.js";
|
|
5
|
+
import { LoadingState as o } from "../../../shared/components/feedback/LoadingState.js";
|
|
6
|
+
import { useOrganizationPageView as s } from "../../../hooks/useOrganizationPageView.js";
|
|
7
|
+
import { useAcceptWorkspaceInvite as ee, useMyWorkspaceInvites as te, useRejectWorkspaceInvite as c } from "../hooks/useWorkspaceInvites.js";
|
|
8
|
+
import { MyInviteCard as l } from "../components/MyInviteCard.js";
|
|
9
|
+
import { getProjectDisplayNames as u, getRoleDisplayNames as ne, getWorkspaceDisplayName as d } from "../utils/workspaceInvitationDisplay.js";
|
|
10
|
+
import { useMemo as f, useState as p } from "react";
|
|
11
|
+
import { AlertCircle as re, BriefcaseBusiness as m, Building2 as h, Loader2 as g, Mail as _ } from "lucide-react";
|
|
12
|
+
import { Badge as v } from "@burdenoff/fe-libs/ui";
|
|
13
|
+
import { usePermissions as ie } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
14
|
+
import { jsx as y, jsxs as b } from "react/jsx-runtime";
|
|
15
|
+
import { NavLink as x } from "react-router-dom";
|
|
16
|
+
import { ActorIdentity as S, useActorProfiles as C } from "@burdenoff/fe-libs/shared";
|
|
11
17
|
//#region src/organization-management/modules/members/pages/MyInvitesPage.tsx
|
|
12
|
-
function
|
|
13
|
-
|
|
14
|
-
let
|
|
18
|
+
function w(e) {
|
|
19
|
+
if (!e) return null;
|
|
20
|
+
let t = new Date(e);
|
|
21
|
+
return Number.isNaN(t.getTime()) ? null : t.toLocaleDateString(void 0, {
|
|
22
|
+
year: "numeric",
|
|
23
|
+
month: "short",
|
|
24
|
+
day: "numeric",
|
|
25
|
+
hour: "2-digit",
|
|
26
|
+
minute: "2-digit"
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
function T(e, t) {
|
|
30
|
+
return (e.endsWith("/") ? e.slice(0, -1) : e) + (t.startsWith("/") ? t : `/${t}`);
|
|
31
|
+
}
|
|
32
|
+
function E({ activeTab: e, basePath: t, tr: n }) {
|
|
33
|
+
let r = (e) => ["border-b-2 px-4 py-2 text-sm font-medium transition-colors", e ? "border-[var(--color-border-focus)] text-[var(--color-text-primary)]" : "border-transparent text-[var(--color-text-muted)] hover:text-[var(--color-text-primary)]"].join(" ");
|
|
34
|
+
return /* @__PURE__ */ b("div", {
|
|
35
|
+
className: "mb-6 flex gap-2 border-b border-[var(--color-border-default)]",
|
|
36
|
+
children: [/* @__PURE__ */ y(x, {
|
|
37
|
+
to: T(t, "/invites"),
|
|
38
|
+
end: !0,
|
|
39
|
+
className: r(e === "workspace"),
|
|
40
|
+
children: n("members.myInvites.workspaceTab", "Workspace Invites")
|
|
41
|
+
}), /* @__PURE__ */ y(x, {
|
|
42
|
+
to: T(t, "/invites/organizations"),
|
|
43
|
+
className: r(e === "organization"),
|
|
44
|
+
children: n("members.myInvites.organizationTab", "Organization Invites")
|
|
45
|
+
})]
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
function D({ activeTab: x = "workspace" }) {
|
|
49
|
+
s(x === "workspace" ? "organizations.my-workspace-invites" : "organizations.my-organization-invites");
|
|
50
|
+
let T = a(), { isLoading: D } = ie(), { basePath: O = "/organizations", currentUser: k, authToken: ae, apiGatewayUrl: oe } = e(), A = x === "organization", j = x === "workspace", { invites: M, loading: N, error: P, total: F } = n(i.Pending, 20, 0, A), { invites: I, loading: L, error: R, total: z, refetch: B } = te(k?.email, j), { acceptInvite: V, loading: H } = t(), { rejectInvite: U, loading: W } = r(), { acceptInvite: G, loading: K } = ee(), { rejectInvite: se, loading: ce } = c(), [q, J] = p(null), Y = q?.tab === x ? q.message : null, [X, Z] = p(null), le = C(f(() => I.flatMap((e) => e.invitedById ? [{
|
|
51
|
+
actorId: e.invitedById,
|
|
52
|
+
actorType: "user"
|
|
53
|
+
}] : []), [I]), {
|
|
54
|
+
apiGatewayUrl: oe,
|
|
55
|
+
authToken: ae
|
|
56
|
+
}), Q = f(() => [...I].sort((e, t) => new Date(t.createdAt).getTime() - new Date(e.createdAt).getTime()), [I]), $ = x === "workspace" ? z : F, ue = async (e) => {
|
|
15
57
|
try {
|
|
16
|
-
|
|
58
|
+
J(null), await V(e);
|
|
17
59
|
} catch (e) {
|
|
18
|
-
|
|
60
|
+
J({
|
|
61
|
+
tab: "organization",
|
|
62
|
+
message: e instanceof Error ? e.message : T("members.myInvites.acceptFailed", "Failed to accept invite")
|
|
63
|
+
});
|
|
19
64
|
}
|
|
20
|
-
},
|
|
65
|
+
}, de = async (e) => {
|
|
21
66
|
try {
|
|
22
|
-
|
|
67
|
+
J(null), await U(e);
|
|
23
68
|
} catch (e) {
|
|
24
|
-
|
|
69
|
+
J({
|
|
70
|
+
tab: "organization",
|
|
71
|
+
message: e instanceof Error ? e.message : T("members.myInvites.rejectFailed", "Failed to reject invite")
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}, fe = async (e) => {
|
|
75
|
+
try {
|
|
76
|
+
Z({
|
|
77
|
+
inviteId: e,
|
|
78
|
+
action: "accept"
|
|
79
|
+
}), J(null), await G(e), await B().catch(() => void 0);
|
|
80
|
+
} catch (e) {
|
|
81
|
+
J({
|
|
82
|
+
tab: "workspace",
|
|
83
|
+
message: e instanceof Error ? e.message : T("members.myInvites.workspaceAcceptFailed", "Failed to accept workspace invite")
|
|
84
|
+
});
|
|
85
|
+
} finally {
|
|
86
|
+
Z((t) => t?.inviteId === e && t.action === "accept" ? null : t);
|
|
87
|
+
}
|
|
88
|
+
}, pe = async (e) => {
|
|
89
|
+
try {
|
|
90
|
+
Z({
|
|
91
|
+
inviteId: e,
|
|
92
|
+
action: "reject"
|
|
93
|
+
}), J(null), await se(e), await B().catch(() => void 0);
|
|
94
|
+
} catch (e) {
|
|
95
|
+
J({
|
|
96
|
+
tab: "workspace",
|
|
97
|
+
message: e instanceof Error ? e.message : T("members.myInvites.workspaceRejectFailed", "Failed to reject workspace invite")
|
|
98
|
+
});
|
|
99
|
+
} finally {
|
|
100
|
+
Z((t) => t?.inviteId === e && t.action === "reject" ? null : t);
|
|
25
101
|
}
|
|
26
102
|
};
|
|
27
|
-
return
|
|
103
|
+
return D ? /* @__PURE__ */ y("div", {
|
|
28
104
|
className: "min-h-full bg-[var(--color-bg-canvas)] p-6",
|
|
29
|
-
children: /* @__PURE__ */
|
|
30
|
-
}) :
|
|
31
|
-
className: "
|
|
32
|
-
children: /* @__PURE__ */
|
|
33
|
-
|
|
34
|
-
|
|
105
|
+
children: /* @__PURE__ */ y(o, { message: T("common.loadingPermissions", "Loading permissions...") })
|
|
106
|
+
}) : j && !k?.email ? /* @__PURE__ */ y("div", {
|
|
107
|
+
className: "min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6",
|
|
108
|
+
children: /* @__PURE__ */ b("div", {
|
|
109
|
+
className: "max-w-4xl mx-auto",
|
|
110
|
+
children: [
|
|
111
|
+
/* @__PURE__ */ b("div", {
|
|
112
|
+
className: "mb-6 flex items-center gap-3",
|
|
113
|
+
children: [/* @__PURE__ */ y(_, {
|
|
114
|
+
size: 24,
|
|
115
|
+
className: "text-[var(--color-text-primary)]"
|
|
116
|
+
}), /* @__PURE__ */ y("h1", {
|
|
117
|
+
className: "text-2xl font-bold text-[var(--color-text-primary)]",
|
|
118
|
+
children: T("members.myInvites.title", "My Invites")
|
|
119
|
+
})]
|
|
120
|
+
}),
|
|
121
|
+
/* @__PURE__ */ y(E, {
|
|
122
|
+
activeTab: x,
|
|
123
|
+
basePath: O,
|
|
124
|
+
tr: T
|
|
125
|
+
}),
|
|
126
|
+
/* @__PURE__ */ y("div", {
|
|
127
|
+
className: "rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] p-6 text-center",
|
|
128
|
+
children: /* @__PURE__ */ y("p", {
|
|
129
|
+
className: "text-[var(--color-text-secondary)]",
|
|
130
|
+
children: T("members.myInvites.signInWorkspace", "Sign in to view your workspace invites.")
|
|
131
|
+
})
|
|
132
|
+
})
|
|
133
|
+
]
|
|
134
|
+
})
|
|
135
|
+
}) : A && N && M.length === 0 || j && L && I.length === 0 ? /* @__PURE__ */ y("div", {
|
|
136
|
+
className: "min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6",
|
|
137
|
+
children: /* @__PURE__ */ b("div", {
|
|
138
|
+
className: "max-w-4xl mx-auto",
|
|
139
|
+
children: [
|
|
140
|
+
/* @__PURE__ */ b("div", {
|
|
141
|
+
className: "mb-6 flex items-center gap-3",
|
|
142
|
+
children: [/* @__PURE__ */ y(_, {
|
|
143
|
+
size: 24,
|
|
144
|
+
className: "text-[var(--color-text-primary)]"
|
|
145
|
+
}), /* @__PURE__ */ y("h1", {
|
|
146
|
+
className: "text-2xl font-bold text-[var(--color-text-primary)]",
|
|
147
|
+
children: T("members.myInvites.title", "My Invites")
|
|
148
|
+
})]
|
|
149
|
+
}),
|
|
150
|
+
/* @__PURE__ */ y(E, {
|
|
151
|
+
activeTab: x,
|
|
152
|
+
basePath: O,
|
|
153
|
+
tr: T
|
|
154
|
+
}),
|
|
155
|
+
/* @__PURE__ */ y("div", {
|
|
156
|
+
className: "flex items-center justify-center min-h-[300px] rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)]",
|
|
157
|
+
children: /* @__PURE__ */ y(g, {
|
|
158
|
+
size: 24,
|
|
159
|
+
className: "animate-spin text-[var(--color-text-muted)]"
|
|
160
|
+
})
|
|
161
|
+
})
|
|
162
|
+
]
|
|
35
163
|
})
|
|
36
|
-
}) :
|
|
164
|
+
}) : A && P ? /* @__PURE__ */ y("div", {
|
|
37
165
|
className: "min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6",
|
|
38
|
-
children: /* @__PURE__ */
|
|
39
|
-
className: "max-w-
|
|
40
|
-
children:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
166
|
+
children: /* @__PURE__ */ b("div", {
|
|
167
|
+
className: "max-w-4xl mx-auto",
|
|
168
|
+
children: [
|
|
169
|
+
/* @__PURE__ */ b("div", {
|
|
170
|
+
className: "mb-6 flex items-center gap-3",
|
|
171
|
+
children: [/* @__PURE__ */ y(_, {
|
|
172
|
+
size: 24,
|
|
173
|
+
className: "text-[var(--color-text-primary)]"
|
|
174
|
+
}), /* @__PURE__ */ y("h1", {
|
|
175
|
+
className: "text-2xl font-bold text-[var(--color-text-primary)]",
|
|
176
|
+
children: T("members.myInvites.title", "My Invites")
|
|
177
|
+
})]
|
|
178
|
+
}),
|
|
179
|
+
/* @__PURE__ */ y(E, {
|
|
180
|
+
activeTab: x,
|
|
181
|
+
basePath: O,
|
|
182
|
+
tr: T
|
|
183
|
+
}),
|
|
184
|
+
/* @__PURE__ */ y("div", {
|
|
185
|
+
className: "rounded-xl border border-[var(--color-status-error-border)] bg-[var(--color-status-error-bgSubtle)] p-6 text-center",
|
|
186
|
+
children: /* @__PURE__ */ b("p", {
|
|
187
|
+
className: "text-[var(--color-status-error-text)]",
|
|
188
|
+
children: [
|
|
189
|
+
T("members.myInvites.loadFailed", "Failed to load invites"),
|
|
190
|
+
": ",
|
|
191
|
+
P.message
|
|
192
|
+
]
|
|
193
|
+
})
|
|
194
|
+
})
|
|
195
|
+
]
|
|
196
|
+
})
|
|
197
|
+
}) : j && R ? /* @__PURE__ */ y("div", {
|
|
198
|
+
className: "min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6",
|
|
199
|
+
children: /* @__PURE__ */ b("div", {
|
|
200
|
+
className: "max-w-4xl mx-auto",
|
|
201
|
+
children: [
|
|
202
|
+
/* @__PURE__ */ b("div", {
|
|
203
|
+
className: "mb-6 flex items-center gap-3",
|
|
204
|
+
children: [/* @__PURE__ */ y(_, {
|
|
205
|
+
size: 24,
|
|
206
|
+
className: "text-[var(--color-text-primary)]"
|
|
207
|
+
}), /* @__PURE__ */ y("h1", {
|
|
208
|
+
className: "text-2xl font-bold text-[var(--color-text-primary)]",
|
|
209
|
+
children: T("members.myInvites.title", "My Invites")
|
|
210
|
+
})]
|
|
211
|
+
}),
|
|
212
|
+
/* @__PURE__ */ y(E, {
|
|
213
|
+
activeTab: x,
|
|
214
|
+
basePath: O,
|
|
215
|
+
tr: T
|
|
216
|
+
}),
|
|
217
|
+
/* @__PURE__ */ y("div", {
|
|
218
|
+
className: "rounded-xl border border-[var(--color-status-error-border)] bg-[var(--color-status-error-bgSubtle)] p-6 text-center",
|
|
219
|
+
children: /* @__PURE__ */ b("p", {
|
|
220
|
+
className: "text-[var(--color-status-error-text)]",
|
|
221
|
+
children: [
|
|
222
|
+
T("members.myInvites.workspaceLoadFailed", "Failed to load workspace invites"),
|
|
223
|
+
":",
|
|
224
|
+
" ",
|
|
225
|
+
R.message
|
|
226
|
+
]
|
|
227
|
+
})
|
|
228
|
+
})
|
|
229
|
+
]
|
|
48
230
|
})
|
|
49
|
-
}) : /* @__PURE__ */
|
|
231
|
+
}) : /* @__PURE__ */ y("div", {
|
|
50
232
|
className: "min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6",
|
|
51
|
-
children: /* @__PURE__ */
|
|
52
|
-
className: "max-w-
|
|
233
|
+
children: /* @__PURE__ */ b("div", {
|
|
234
|
+
className: "max-w-4xl mx-auto",
|
|
53
235
|
children: [
|
|
54
|
-
/* @__PURE__ */
|
|
236
|
+
/* @__PURE__ */ b("div", {
|
|
55
237
|
className: "flex items-center gap-3 mb-6",
|
|
56
238
|
children: [
|
|
57
|
-
/* @__PURE__ */
|
|
239
|
+
/* @__PURE__ */ y(_, {
|
|
58
240
|
size: 24,
|
|
59
241
|
className: "text-[var(--color-text-primary)]"
|
|
60
242
|
}),
|
|
61
|
-
/* @__PURE__ */
|
|
243
|
+
/* @__PURE__ */ y("h1", {
|
|
62
244
|
className: "text-2xl font-bold text-[var(--color-text-primary)]",
|
|
63
|
-
children:
|
|
245
|
+
children: T("members.myInvites.title", "My Invites")
|
|
64
246
|
}),
|
|
65
|
-
|
|
247
|
+
$ > 0 && /* @__PURE__ */ y("span", {
|
|
66
248
|
className: "px-2.5 py-0.5 rounded-full text-xs font-medium bg-[var(--color-action-primary-bg)] text-[var(--color-action-primary-text)]",
|
|
67
|
-
children:
|
|
249
|
+
children: $
|
|
68
250
|
})
|
|
69
251
|
]
|
|
70
252
|
}),
|
|
71
|
-
|
|
253
|
+
/* @__PURE__ */ y(E, {
|
|
254
|
+
activeTab: x,
|
|
255
|
+
basePath: O,
|
|
256
|
+
tr: T
|
|
257
|
+
}),
|
|
258
|
+
Y && /* @__PURE__ */ b("div", {
|
|
72
259
|
className: "mb-4 flex items-center gap-2 rounded-lg border border-[var(--color-status-error-border)] bg-[var(--color-status-error-bgSubtle)] p-3",
|
|
73
|
-
children: [/* @__PURE__ */
|
|
260
|
+
children: [/* @__PURE__ */ y(re, {
|
|
74
261
|
size: 16,
|
|
75
262
|
className: "shrink-0 text-[var(--color-status-error-text)]"
|
|
76
|
-
}), /* @__PURE__ */
|
|
263
|
+
}), /* @__PURE__ */ y("p", {
|
|
77
264
|
className: "text-sm text-[var(--color-status-error-text)]",
|
|
78
|
-
children:
|
|
265
|
+
children: Y
|
|
79
266
|
})]
|
|
80
267
|
}),
|
|
81
|
-
|
|
268
|
+
j ? Q.length === 0 ? /* @__PURE__ */ b("div", {
|
|
269
|
+
className: "text-center py-12 bg-[var(--color-bg-surface)] rounded-xl border border-[var(--color-border-default)]",
|
|
270
|
+
children: [
|
|
271
|
+
/* @__PURE__ */ y(m, {
|
|
272
|
+
size: 48,
|
|
273
|
+
className: "mx-auto mb-4 text-[var(--color-text-muted)] opacity-50"
|
|
274
|
+
}),
|
|
275
|
+
/* @__PURE__ */ y("h3", {
|
|
276
|
+
className: "text-lg font-medium text-[var(--color-text-primary)] mb-1",
|
|
277
|
+
children: T("members.myInvites.workspaceEmptyTitle", "No pending workspace invites")
|
|
278
|
+
}),
|
|
279
|
+
/* @__PURE__ */ y("p", {
|
|
280
|
+
className: "text-sm text-[var(--color-text-muted)]",
|
|
281
|
+
children: T("members.myInvites.workspaceEmptyDescription", "When someone invites you to a workspace, it will appear here.")
|
|
282
|
+
})
|
|
283
|
+
]
|
|
284
|
+
}) : /* @__PURE__ */ y("div", {
|
|
285
|
+
className: "space-y-3",
|
|
286
|
+
children: Q.map((e) => {
|
|
287
|
+
let t = d(e), n = ne(e), r = u(e), i = e.invitedById ? le[e.invitedById] : void 0, a = i?.displayName || i?.email || T("members.myInvites.invitedByFallback", "Someone"), o = X?.inviteId === e.id && X?.action === "accept" && K, s = X?.inviteId === e.id && X?.action === "reject" && ce;
|
|
288
|
+
return /* @__PURE__ */ y("div", {
|
|
289
|
+
className: "rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] p-5",
|
|
290
|
+
children: /* @__PURE__ */ b("div", {
|
|
291
|
+
className: "flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between",
|
|
292
|
+
children: [/* @__PURE__ */ b("div", {
|
|
293
|
+
className: "min-w-0 space-y-3",
|
|
294
|
+
children: [
|
|
295
|
+
/* @__PURE__ */ b("div", {
|
|
296
|
+
className: "flex items-start gap-3",
|
|
297
|
+
children: [/* @__PURE__ */ y("div", {
|
|
298
|
+
className: "rounded-lg bg-[var(--color-bg-subtle)] p-2",
|
|
299
|
+
children: /* @__PURE__ */ y(m, {
|
|
300
|
+
size: 20,
|
|
301
|
+
className: "text-[var(--color-text-secondary)]"
|
|
302
|
+
})
|
|
303
|
+
}), /* @__PURE__ */ b("div", {
|
|
304
|
+
className: "min-w-0",
|
|
305
|
+
children: [/* @__PURE__ */ y("h3", {
|
|
306
|
+
className: "font-semibold text-[var(--color-text-primary)] break-words",
|
|
307
|
+
children: t
|
|
308
|
+
}), /* @__PURE__ */ y("p", {
|
|
309
|
+
className: "mt-1 text-sm text-[var(--color-text-secondary)] break-all",
|
|
310
|
+
children: e.email
|
|
311
|
+
})]
|
|
312
|
+
})]
|
|
313
|
+
}),
|
|
314
|
+
/* @__PURE__ */ b("div", {
|
|
315
|
+
className: "flex flex-wrap items-center gap-2",
|
|
316
|
+
children: [/* @__PURE__ */ y(v, {
|
|
317
|
+
variant: "secondary",
|
|
318
|
+
children: e.status
|
|
319
|
+
}), n.map((t) => /* @__PURE__ */ y(v, {
|
|
320
|
+
variant: "outline",
|
|
321
|
+
children: t
|
|
322
|
+
}, `${e.id}-${t}`))]
|
|
323
|
+
}),
|
|
324
|
+
/* @__PURE__ */ b("dl", {
|
|
325
|
+
className: "grid gap-3 text-sm text-[var(--color-text-secondary)] sm:grid-cols-2",
|
|
326
|
+
children: [
|
|
327
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("dt", {
|
|
328
|
+
className: "font-medium text-[var(--color-text-primary)]",
|
|
329
|
+
children: T("members.myInvites.invitedByLabel", "Invited by")
|
|
330
|
+
}), /* @__PURE__ */ y("dd", {
|
|
331
|
+
className: "break-all",
|
|
332
|
+
children: i ? /* @__PURE__ */ y(S, {
|
|
333
|
+
profile: i,
|
|
334
|
+
variant: "inline",
|
|
335
|
+
hideIdDrilldown: !0
|
|
336
|
+
}) : a
|
|
337
|
+
})] }),
|
|
338
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("dt", {
|
|
339
|
+
className: "font-medium text-[var(--color-text-primary)]",
|
|
340
|
+
children: T("members.myInvites.receivedLabel", "Received")
|
|
341
|
+
}), /* @__PURE__ */ y("dd", { children: w(e.createdAt) ?? "—" })] }),
|
|
342
|
+
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("dt", {
|
|
343
|
+
className: "font-medium text-[var(--color-text-primary)]",
|
|
344
|
+
children: T("members.myInvites.expiresLabel", "Expires")
|
|
345
|
+
}), /* @__PURE__ */ y("dd", { children: w(e.expiresAt) ?? "—" })] }),
|
|
346
|
+
r.length > 0 ? /* @__PURE__ */ b("div", {
|
|
347
|
+
className: "sm:col-span-2",
|
|
348
|
+
children: [/* @__PURE__ */ y("dt", {
|
|
349
|
+
className: "font-medium text-[var(--color-text-primary)]",
|
|
350
|
+
children: T("members.myInvites.projectsLabel", "Projects")
|
|
351
|
+
}), /* @__PURE__ */ y("dd", {
|
|
352
|
+
className: "mt-1 flex flex-wrap gap-2",
|
|
353
|
+
children: r.map((t) => /* @__PURE__ */ y(v, {
|
|
354
|
+
variant: "outline",
|
|
355
|
+
children: t
|
|
356
|
+
}, `${e.id}-${t}`))
|
|
357
|
+
})]
|
|
358
|
+
}) : null
|
|
359
|
+
]
|
|
360
|
+
})
|
|
361
|
+
]
|
|
362
|
+
}), /* @__PURE__ */ b("div", {
|
|
363
|
+
className: "flex flex-wrap items-center gap-2 shrink-0",
|
|
364
|
+
children: [/* @__PURE__ */ b("button", {
|
|
365
|
+
type: "button",
|
|
366
|
+
onClick: () => void fe(e.id),
|
|
367
|
+
disabled: o || s,
|
|
368
|
+
className: "inline-flex items-center gap-1.5 rounded-lg bg-[var(--color-status-success-bg)] px-4 py-2 text-sm font-medium text-[var(--color-text-inverse)] transition-all duration-200 hover:opacity-90 active:scale-[0.98] disabled:cursor-not-allowed disabled:opacity-50",
|
|
369
|
+
children: [o ? /* @__PURE__ */ y(g, {
|
|
370
|
+
size: 14,
|
|
371
|
+
className: "animate-spin"
|
|
372
|
+
}) : null, T("members.myInvites.accept", "Accept")]
|
|
373
|
+
}), /* @__PURE__ */ b("button", {
|
|
374
|
+
type: "button",
|
|
375
|
+
onClick: () => void pe(e.id),
|
|
376
|
+
disabled: o || s,
|
|
377
|
+
className: "inline-flex items-center gap-1.5 rounded-lg border border-[var(--color-border-default)] bg-transparent px-4 py-2 text-sm font-medium text-[var(--color-text-primary)] transition-all duration-200 hover:border-[var(--color-status-error-border)] hover:bg-[var(--color-status-error-bgSubtle)] hover:text-[var(--color-status-error-text)] active:scale-[0.98] disabled:cursor-not-allowed disabled:opacity-50",
|
|
378
|
+
children: [s ? /* @__PURE__ */ y(g, {
|
|
379
|
+
size: 14,
|
|
380
|
+
className: "animate-spin"
|
|
381
|
+
}) : null, T("members.myInvites.decline", "Decline")]
|
|
382
|
+
})]
|
|
383
|
+
})]
|
|
384
|
+
})
|
|
385
|
+
}, e.id);
|
|
386
|
+
})
|
|
387
|
+
}) : M.length === 0 ? /* @__PURE__ */ b("div", {
|
|
82
388
|
className: "text-center py-12 bg-[var(--color-bg-surface)] rounded-xl border border-[var(--color-border-default)]",
|
|
83
389
|
children: [
|
|
84
|
-
/* @__PURE__ */
|
|
390
|
+
/* @__PURE__ */ y(h, {
|
|
85
391
|
size: 48,
|
|
86
392
|
className: "mx-auto mb-4 text-[var(--color-text-muted)] opacity-50"
|
|
87
393
|
}),
|
|
88
|
-
/* @__PURE__ */
|
|
394
|
+
/* @__PURE__ */ y("h3", {
|
|
89
395
|
className: "text-lg font-medium text-[var(--color-text-primary)] mb-1",
|
|
90
|
-
children:
|
|
396
|
+
children: T("members.myInvites.emptyTitle", "No pending invites")
|
|
91
397
|
}),
|
|
92
|
-
/* @__PURE__ */
|
|
398
|
+
/* @__PURE__ */ y("p", {
|
|
93
399
|
className: "text-sm text-[var(--color-text-muted)]",
|
|
94
|
-
children:
|
|
400
|
+
children: T("members.myInvites.emptyDescription", "When someone invites you to an organization, it will appear here.")
|
|
95
401
|
})
|
|
96
402
|
]
|
|
97
|
-
}) : /* @__PURE__ */
|
|
403
|
+
}) : /* @__PURE__ */ y("div", {
|
|
98
404
|
className: "space-y-3",
|
|
99
|
-
children:
|
|
405
|
+
children: M.map((e) => /* @__PURE__ */ y(l, {
|
|
100
406
|
invite: e,
|
|
101
|
-
onAccept:
|
|
102
|
-
onReject:
|
|
103
|
-
accepting:
|
|
104
|
-
rejecting:
|
|
407
|
+
onAccept: ue,
|
|
408
|
+
onReject: de,
|
|
409
|
+
accepting: H,
|
|
410
|
+
rejecting: W
|
|
105
411
|
}, e.id))
|
|
106
412
|
})
|
|
107
413
|
]
|
|
@@ -109,6 +415,6 @@ function h() {
|
|
|
109
415
|
});
|
|
110
416
|
}
|
|
111
417
|
//#endregion
|
|
112
|
-
export {
|
|
418
|
+
export { D as MyInvitesPage };
|
|
113
419
|
|
|
114
420
|
//# sourceMappingURL=MyInvitesPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MyInvitesPage.js","names":[],"sources":["../../../../../src/organization-management/modules/members/pages/MyInvitesPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { Mail, Loader2, AlertCircle } from 'lucide-react';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useMyInvites, useAcceptInvite, useRejectInvite } from '../hooks/useInvites';\nimport { MyInviteCard } from '../components/MyInviteCard';\nimport { LoadingState } from '../../../shared/components/feedback/LoadingState';\nimport { InviteStatus } from '../../../../generated/global-types';\nimport { useTr } from '../../../shared/hooks/useTr';\nimport { useOrganizationPageView } from '../../../hooks/useOrganizationPageView';\n\n/**\n * My Invites Page\n * Shows pending invites for the current user with accept/reject actions\n */\nexport function MyInvitesPage() {\n useOrganizationPageView('organizations.my-invites');\n const tr = useTr();\n const { isLoading: permissionsLoading } = usePermissions();\n const { invites, loading, error, total } = useMyInvites(InviteStatus.Pending);\n const { acceptInvite, loading: accepting } = useAcceptInvite();\n const { rejectInvite, loading: rejecting } = useRejectInvite();\n const [actionError, setActionError] = useState<string | null>(null);\n\n const handleAccept = async (inviteId: string) => {\n try {\n setActionError(null);\n await acceptInvite(inviteId);\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr('members.myInvites.acceptFailed', 'Failed to accept invite')\n );\n }\n };\n\n const handleReject = async (inviteId: string) => {\n try {\n setActionError(null);\n await rejectInvite(inviteId);\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr('members.myInvites.rejectFailed', 'Failed to reject invite')\n );\n }\n };\n\n // Own invites are always accessible — no permission denial needed.\n // We still wait for permissions to load to ensure consistent UX.\n if (permissionsLoading) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] p-6\">\n <LoadingState message={tr('common.loadingPermissions', 'Loading permissions...')} />\n </div>\n );\n }\n\n if (loading && invites.length === 0) {\n return (\n <div className=\"flex items-center justify-center min-h-[300px]\">\n <Loader2 size={24} className=\"animate-spin text-[var(--color-text-muted)]\" />\n </div>\n );\n }\n\n if (error) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <div className=\"max-w-3xl mx-auto text-center py-12\">\n <p className=\"text-[var(--color-status-error-text)]\">\n {tr('members.myInvites.loadFailed', 'Failed to load invites')}: {error.message}\n </p>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <div className=\"max-w-3xl mx-auto\">\n {/* Header */}\n <div className=\"flex items-center gap-3 mb-6\">\n <Mail size={24} className=\"text-[var(--color-text-primary)]\" />\n <h1 className=\"text-2xl font-bold text-[var(--color-text-primary)]\">\n {tr('members.myInvites.title', 'My Invites')}\n </h1>\n {total > 0 && (\n <span className=\"px-2.5 py-0.5 rounded-full text-xs font-medium bg-[var(--color-action-primary-bg)] text-[var(--color-action-primary-text)]\">\n {total}\n </span>\n )}\n </div>\n\n {actionError && (\n <div className=\"mb-4 flex items-center gap-2 rounded-lg border border-[var(--color-status-error-border)] bg-[var(--color-status-error-bgSubtle)] p-3\">\n <AlertCircle size={16} className=\"shrink-0 text-[var(--color-status-error-text)]\" />\n <p className=\"text-sm text-[var(--color-status-error-text)]\">{actionError}</p>\n </div>\n )}\n\n {/* Invites list */}\n {invites.length === 0 ? (\n <div className=\"text-center py-12 bg-[var(--color-bg-surface)] rounded-xl border border-[var(--color-border-default)]\">\n <Mail size={48} className=\"mx-auto mb-4 text-[var(--color-text-muted)] opacity-50\" />\n <h3 className=\"text-lg font-medium text-[var(--color-text-primary)] mb-1\">\n {tr('members.myInvites.emptyTitle', 'No pending invites')}\n </h3>\n <p className=\"text-sm text-[var(--color-text-muted)]\">\n {tr(\n 'members.myInvites.emptyDescription',\n 'When someone invites you to an organization, it will appear here.'\n )}\n </p>\n </div>\n ) : (\n <div className=\"space-y-3\">\n {invites.map((invite) => (\n <MyInviteCard\n key={invite.id}\n invite={invite}\n onAccept={handleAccept}\n onReject={handleReject}\n accepting={accepting}\n rejecting={rejecting}\n />\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;AAcA,SAAgB,IAAgB;AAC9B,GAAwB,2BAA2B;CACnD,IAAM,IAAK,GAAO,EACZ,EAAE,WAAW,MAAuB,GAAgB,EACpD,EAAE,YAAS,YAAS,UAAO,aAAU,EAAa,EAAa,QAAQ,EACvE,EAAE,iBAAc,SAAS,MAAc,GAAiB,EACxD,EAAE,iBAAc,SAAS,MAAc,GAAiB,EACxD,CAAC,GAAa,KAAkB,EAAwB,KAAK,EAE7D,IAAe,OAAO,MAAqB;AAC/C,MAAI;AAEF,GADA,EAAe,KAAK,EACpB,MAAM,EAAa,EAAS;WACrB,GAAK;AACZ,KACE,aAAe,QACX,EAAI,UACJ,EAAG,kCAAkC,0BAA0B,CACpE;;IAIC,IAAe,OAAO,MAAqB;AAC/C,MAAI;AAEF,GADA,EAAe,KAAK,EACpB,MAAM,EAAa,EAAS;WACrB,GAAK;AACZ,KACE,aAAe,QACX,EAAI,UACJ,EAAG,kCAAkC,0BAA0B,CACpE;;;AAkCL,QA5BI,IAEA,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD,EAAc,SAAS,EAAG,6BAA6B,yBAAyB,EAAI,CAAA;EAChF,CAAA,GAIN,KAAW,EAAQ,WAAW,IAE9B,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GAAS,MAAM;GAAI,WAAU;GAAgD,CAAA;EACzE,CAAA,GAIN,IAEA,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,KAAD;IAAG,WAAU;cAAb;KACG,EAAG,gCAAgC,yBAAyB;KAAC;KAAG,EAAM;KACrE;;GACA,CAAA;EACF,CAAA,GAKR,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf;IAEE,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,GAAD;OAAM,MAAM;OAAI,WAAU;OAAqC,CAAA;MAC/D,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,2BAA2B,aAAa;OACzC,CAAA;MACJ,IAAQ,KACP,kBAAC,QAAD;OAAM,WAAU;iBACb;OACI,CAAA;MAEL;;IAEL,KACC,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MAAa,MAAM;MAAI,WAAU;MAAmD,CAAA,EACpF,kBAAC,KAAD;MAAG,WAAU;gBAAiD;MAAgB,CAAA,CAC1E;;IAIP,EAAQ,WAAW,IAClB,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,GAAD;OAAM,MAAM;OAAI,WAAU;OAA2D,CAAA;MACrF,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,gCAAgC,qBAAqB;OACtD,CAAA;MACL,kBAAC,KAAD;OAAG,WAAU;iBACV,EACC,sCACA,oEACD;OACC,CAAA;MACA;SAEN,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAQ,KAAK,MACZ,kBAAC,GAAD;MAEU;MACR,UAAU;MACV,UAAU;MACC;MACA;MACX,EANK,EAAO,GAMZ,CACF;KACE,CAAA;IAEJ;;EACF,CAAA"}
|
|
1
|
+
{"version":3,"file":"MyInvitesPage.js","names":[],"sources":["../../../../../src/organization-management/modules/members/pages/MyInvitesPage.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { NavLink } from 'react-router-dom';\nimport { Mail, Loader2, AlertCircle, BriefcaseBusiness, Building2 } from 'lucide-react';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport {\n ActorIdentity,\n useActorProfiles,\n type ActorInput,\n type ActorProfileMap,\n} from '@burdenoff/fe-libs/shared';\nimport { Badge } from '@burdenoff/fe-libs/ui';\nimport { useMyInvites, useAcceptInvite, useRejectInvite } from '../hooks/useInvites';\nimport {\n useAcceptWorkspaceInvite,\n useMyWorkspaceInvites,\n useRejectWorkspaceInvite,\n} from '../hooks/useWorkspaceInvites';\nimport { MyInviteCard } from '../components/MyInviteCard';\nimport { LoadingState } from '../../../shared/components/feedback/LoadingState';\nimport { InviteStatus as OrganizationInviteStatus } from '../../../../generated/global-types';\nimport { useTr } from '../../../shared/hooks/useTr';\nimport { useOrganizationPageView } from '../../../hooks/useOrganizationPageView';\nimport { useOrgConsole } from '../../../providers/OrgConsoleProvider';\nimport {\n getProjectDisplayNames,\n getRoleDisplayNames,\n getWorkspaceDisplayName,\n} from '../utils/workspaceInvitationDisplay';\n\n/**\n * My Invites Page\n * Shows pending invites for the current user with accept/reject actions\n */\ntype MyInvitesTab = 'workspace' | 'organization';\n\ninterface MyInvitesPageProps {\n activeTab?: MyInvitesTab;\n}\n\ninterface TabActionError {\n tab: MyInvitesTab;\n message: string;\n}\n\ninterface InvitesTabNavProps {\n activeTab: MyInvitesTab;\n basePath: string;\n tr: ReturnType<typeof useTr>;\n}\n\nfunction formatDate(value?: string | null) {\n if (!value) return null;\n\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) return null;\n\n return date.toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n });\n}\n\nfunction joinPath(base: string, path: string): string {\n const cleanBase = base.endsWith('/') ? base.slice(0, -1) : base;\n const cleanPath = path.startsWith('/') ? path : `/${path}`;\n return cleanBase + cleanPath;\n}\n\nfunction InvitesTabNav({ activeTab, basePath, tr }: InvitesTabNavProps) {\n const getTabClassName = (isActive: boolean) =>\n [\n 'border-b-2 px-4 py-2 text-sm font-medium transition-colors',\n isActive\n ? 'border-[var(--color-border-focus)] text-[var(--color-text-primary)]'\n : 'border-transparent text-[var(--color-text-muted)] hover:text-[var(--color-text-primary)]',\n ].join(' ');\n\n return (\n <div className=\"mb-6 flex gap-2 border-b border-[var(--color-border-default)]\">\n <NavLink\n to={joinPath(basePath, '/invites')}\n end\n className={getTabClassName(activeTab === 'workspace')}\n >\n {tr('members.myInvites.workspaceTab', 'Workspace Invites')}\n </NavLink>\n <NavLink\n to={joinPath(basePath, '/invites/organizations')}\n className={getTabClassName(activeTab === 'organization')}\n >\n {tr('members.myInvites.organizationTab', 'Organization Invites')}\n </NavLink>\n </div>\n );\n}\n\nexport function MyInvitesPage({ activeTab = 'workspace' }: MyInvitesPageProps) {\n useOrganizationPageView(\n activeTab === 'workspace'\n ? 'organizations.my-workspace-invites'\n : 'organizations.my-organization-invites'\n );\n const tr = useTr();\n const { isLoading: permissionsLoading } = usePermissions();\n const { basePath = '/organizations', currentUser, authToken, apiGatewayUrl } = useOrgConsole();\n const orgInvitesEnabled = activeTab === 'organization';\n const workspaceInvitesEnabled = activeTab === 'workspace';\n const { invites, loading, error, total } = useMyInvites(\n OrganizationInviteStatus.Pending,\n 20,\n 0,\n orgInvitesEnabled\n );\n const {\n invites: workspaceInvites,\n loading: workspaceLoading,\n error: workspaceError,\n total: workspaceTotal,\n refetch: refetchWorkspaceInvites,\n } = useMyWorkspaceInvites(currentUser?.email, workspaceInvitesEnabled);\n const { acceptInvite, loading: accepting } = useAcceptInvite();\n const { rejectInvite, loading: rejecting } = useRejectInvite();\n const { acceptInvite: acceptWorkspaceInvite, loading: acceptingWorkspace } =\n useAcceptWorkspaceInvite();\n const { rejectInvite: rejectWorkspaceInvite, loading: rejectingWorkspace } =\n useRejectWorkspaceInvite();\n const [actionError, setActionError] = useState<TabActionError | null>(null);\n\n const visibleActionError = actionError?.tab === activeTab ? actionError.message : null;\n const [processingWorkspaceAction, setProcessingWorkspaceAction] = useState<{\n inviteId: string;\n action: 'accept' | 'reject';\n } | null>(null);\n\n const workspaceInviteActors = useMemo<ActorInput[]>(\n () =>\n workspaceInvites.flatMap((invite) =>\n invite.invitedById ? [{ actorId: invite.invitedById, actorType: 'user' as const }] : []\n ),\n [workspaceInvites]\n );\n\n const inviterProfiles: ActorProfileMap = useActorProfiles(workspaceInviteActors, {\n apiGatewayUrl,\n authToken,\n });\n\n const sortedWorkspaceInvites = useMemo(\n () =>\n [...workspaceInvites].sort(\n (left: (typeof workspaceInvites)[number], right: (typeof workspaceInvites)[number]) =>\n new Date(right.createdAt).getTime() - new Date(left.createdAt).getTime()\n ),\n [workspaceInvites]\n );\n\n const totalCount = activeTab === 'workspace' ? workspaceTotal : total;\n\n const handleAccept = async (inviteId: string) => {\n try {\n setActionError(null);\n await acceptInvite(inviteId);\n } catch (err) {\n setActionError({\n tab: 'organization',\n message:\n err instanceof Error\n ? err.message\n : tr('members.myInvites.acceptFailed', 'Failed to accept invite'),\n });\n }\n };\n\n const handleReject = async (inviteId: string) => {\n try {\n setActionError(null);\n await rejectInvite(inviteId);\n } catch (err) {\n setActionError({\n tab: 'organization',\n message:\n err instanceof Error\n ? err.message\n : tr('members.myInvites.rejectFailed', 'Failed to reject invite'),\n });\n }\n };\n\n const handleAcceptWorkspace = async (inviteId: string) => {\n try {\n setProcessingWorkspaceAction({ inviteId, action: 'accept' });\n setActionError(null);\n await acceptWorkspaceInvite(inviteId);\n await refetchWorkspaceInvites().catch(() => undefined);\n } catch (err) {\n setActionError({\n tab: 'workspace',\n message:\n err instanceof Error\n ? err.message\n : tr('members.myInvites.workspaceAcceptFailed', 'Failed to accept workspace invite'),\n });\n } finally {\n setProcessingWorkspaceAction((current) =>\n current?.inviteId === inviteId && current.action === 'accept' ? null : current\n );\n }\n };\n\n const handleRejectWorkspace = async (inviteId: string) => {\n try {\n setProcessingWorkspaceAction({ inviteId, action: 'reject' });\n setActionError(null);\n await rejectWorkspaceInvite(inviteId);\n await refetchWorkspaceInvites().catch(() => undefined);\n } catch (err) {\n setActionError({\n tab: 'workspace',\n message:\n err instanceof Error\n ? err.message\n : tr('members.myInvites.workspaceRejectFailed', 'Failed to reject workspace invite'),\n });\n } finally {\n setProcessingWorkspaceAction((current) =>\n current?.inviteId === inviteId && current.action === 'reject' ? null : current\n );\n }\n };\n\n // Own invites are always accessible — no permission denial needed.\n // We still wait for permissions to load to ensure consistent UX.\n if (permissionsLoading) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] p-6\">\n <LoadingState message={tr('common.loadingPermissions', 'Loading permissions...')} />\n </div>\n );\n }\n\n if (workspaceInvitesEnabled && !currentUser?.email) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <div className=\"max-w-4xl mx-auto\">\n <div className=\"mb-6 flex items-center gap-3\">\n <Mail size={24} className=\"text-[var(--color-text-primary)]\" />\n <h1 className=\"text-2xl font-bold text-[var(--color-text-primary)]\">\n {tr('members.myInvites.title', 'My Invites')}\n </h1>\n </div>\n\n <InvitesTabNav activeTab={activeTab} basePath={basePath} tr={tr} />\n\n <div className=\"rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] p-6 text-center\">\n <p className=\"text-[var(--color-text-secondary)]\">\n {tr('members.myInvites.signInWorkspace', 'Sign in to view your workspace invites.')}\n </p>\n </div>\n </div>\n </div>\n );\n }\n\n if (orgInvitesEnabled && loading && invites.length === 0) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <div className=\"max-w-4xl mx-auto\">\n <div className=\"mb-6 flex items-center gap-3\">\n <Mail size={24} className=\"text-[var(--color-text-primary)]\" />\n <h1 className=\"text-2xl font-bold text-[var(--color-text-primary)]\">\n {tr('members.myInvites.title', 'My Invites')}\n </h1>\n </div>\n\n <InvitesTabNav activeTab={activeTab} basePath={basePath} tr={tr} />\n\n <div className=\"flex items-center justify-center min-h-[300px] rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)]\">\n <Loader2 size={24} className=\"animate-spin text-[var(--color-text-muted)]\" />\n </div>\n </div>\n </div>\n );\n }\n\n if (workspaceInvitesEnabled && workspaceLoading && workspaceInvites.length === 0) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <div className=\"max-w-4xl mx-auto\">\n <div className=\"mb-6 flex items-center gap-3\">\n <Mail size={24} className=\"text-[var(--color-text-primary)]\" />\n <h1 className=\"text-2xl font-bold text-[var(--color-text-primary)]\">\n {tr('members.myInvites.title', 'My Invites')}\n </h1>\n </div>\n\n <InvitesTabNav activeTab={activeTab} basePath={basePath} tr={tr} />\n\n <div className=\"flex items-center justify-center min-h-[300px] rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)]\">\n <Loader2 size={24} className=\"animate-spin text-[var(--color-text-muted)]\" />\n </div>\n </div>\n </div>\n );\n }\n\n if (orgInvitesEnabled && error) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <div className=\"max-w-4xl mx-auto\">\n <div className=\"mb-6 flex items-center gap-3\">\n <Mail size={24} className=\"text-[var(--color-text-primary)]\" />\n <h1 className=\"text-2xl font-bold text-[var(--color-text-primary)]\">\n {tr('members.myInvites.title', 'My Invites')}\n </h1>\n </div>\n\n <InvitesTabNav activeTab={activeTab} basePath={basePath} tr={tr} />\n\n <div className=\"rounded-xl border border-[var(--color-status-error-border)] bg-[var(--color-status-error-bgSubtle)] p-6 text-center\">\n <p className=\"text-[var(--color-status-error-text)]\">\n {tr('members.myInvites.loadFailed', 'Failed to load invites')}: {error.message}\n </p>\n </div>\n </div>\n </div>\n );\n }\n\n if (workspaceInvitesEnabled && workspaceError) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <div className=\"max-w-4xl mx-auto\">\n <div className=\"mb-6 flex items-center gap-3\">\n <Mail size={24} className=\"text-[var(--color-text-primary)]\" />\n <h1 className=\"text-2xl font-bold text-[var(--color-text-primary)]\">\n {tr('members.myInvites.title', 'My Invites')}\n </h1>\n </div>\n\n <InvitesTabNav activeTab={activeTab} basePath={basePath} tr={tr} />\n\n <div className=\"rounded-xl border border-[var(--color-status-error-border)] bg-[var(--color-status-error-bgSubtle)] p-6 text-center\">\n <p className=\"text-[var(--color-status-error-text)]\">\n {tr('members.myInvites.workspaceLoadFailed', 'Failed to load workspace invites')}:{' '}\n {workspaceError.message}\n </p>\n </div>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <div className=\"max-w-4xl mx-auto\">\n {/* Header */}\n <div className=\"flex items-center gap-3 mb-6\">\n <Mail size={24} className=\"text-[var(--color-text-primary)]\" />\n <h1 className=\"text-2xl font-bold text-[var(--color-text-primary)]\">\n {tr('members.myInvites.title', 'My Invites')}\n </h1>\n {totalCount > 0 && (\n <span className=\"px-2.5 py-0.5 rounded-full text-xs font-medium bg-[var(--color-action-primary-bg)] text-[var(--color-action-primary-text)]\">\n {totalCount}\n </span>\n )}\n </div>\n\n <InvitesTabNav activeTab={activeTab} basePath={basePath} tr={tr} />\n\n {visibleActionError && (\n <div className=\"mb-4 flex items-center gap-2 rounded-lg border border-[var(--color-status-error-border)] bg-[var(--color-status-error-bgSubtle)] p-3\">\n <AlertCircle size={16} className=\"shrink-0 text-[var(--color-status-error-text)]\" />\n <p className=\"text-sm text-[var(--color-status-error-text)]\">{visibleActionError}</p>\n </div>\n )}\n\n {workspaceInvitesEnabled ? (\n sortedWorkspaceInvites.length === 0 ? (\n <div className=\"text-center py-12 bg-[var(--color-bg-surface)] rounded-xl border border-[var(--color-border-default)]\">\n <BriefcaseBusiness\n size={48}\n className=\"mx-auto mb-4 text-[var(--color-text-muted)] opacity-50\"\n />\n <h3 className=\"text-lg font-medium text-[var(--color-text-primary)] mb-1\">\n {tr('members.myInvites.workspaceEmptyTitle', 'No pending workspace invites')}\n </h3>\n <p className=\"text-sm text-[var(--color-text-muted)]\">\n {tr(\n 'members.myInvites.workspaceEmptyDescription',\n 'When someone invites you to a workspace, it will appear here.'\n )}\n </p>\n </div>\n ) : (\n <div className=\"space-y-3\">\n {sortedWorkspaceInvites.map((invite) => {\n const workspaceName = getWorkspaceDisplayName(invite);\n const roleNames = getRoleDisplayNames(invite);\n const projectNames = getProjectDisplayNames(invite);\n const inviterProfile = invite.invitedById\n ? inviterProfiles[invite.invitedById]\n : undefined;\n const inviterLabel =\n inviterProfile?.displayName ||\n inviterProfile?.email ||\n tr('members.myInvites.invitedByFallback', 'Someone');\n const isProcessingWorkspaceAccept =\n processingWorkspaceAction?.inviteId === invite.id &&\n processingWorkspaceAction?.action === 'accept' &&\n acceptingWorkspace;\n const isProcessingWorkspaceReject =\n processingWorkspaceAction?.inviteId === invite.id &&\n processingWorkspaceAction?.action === 'reject' &&\n rejectingWorkspace;\n\n return (\n <div\n key={invite.id}\n className=\"rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] p-5\"\n >\n <div className=\"flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between\">\n <div className=\"min-w-0 space-y-3\">\n <div className=\"flex items-start gap-3\">\n <div className=\"rounded-lg bg-[var(--color-bg-subtle)] p-2\">\n <BriefcaseBusiness\n size={20}\n className=\"text-[var(--color-text-secondary)]\"\n />\n </div>\n <div className=\"min-w-0\">\n <h3 className=\"font-semibold text-[var(--color-text-primary)] break-words\">\n {workspaceName}\n </h3>\n <p className=\"mt-1 text-sm text-[var(--color-text-secondary)] break-all\">\n {invite.email}\n </p>\n </div>\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2\">\n <Badge variant=\"secondary\">{invite.status}</Badge>\n {roleNames.map((roleName) => (\n <Badge key={`${invite.id}-${roleName}`} variant=\"outline\">\n {roleName}\n </Badge>\n ))}\n </div>\n\n <dl className=\"grid gap-3 text-sm text-[var(--color-text-secondary)] sm:grid-cols-2\">\n <div>\n <dt className=\"font-medium text-[var(--color-text-primary)]\">\n {tr('members.myInvites.invitedByLabel', 'Invited by')}\n </dt>\n <dd className=\"break-all\">\n {inviterProfile ? (\n <ActorIdentity\n profile={inviterProfile}\n variant=\"inline\"\n hideIdDrilldown\n />\n ) : (\n inviterLabel\n )}\n </dd>\n </div>\n <div>\n <dt className=\"font-medium text-[var(--color-text-primary)]\">\n {tr('members.myInvites.receivedLabel', 'Received')}\n </dt>\n <dd>{formatDate(invite.createdAt) ?? '—'}</dd>\n </div>\n <div>\n <dt className=\"font-medium text-[var(--color-text-primary)]\">\n {tr('members.myInvites.expiresLabel', 'Expires')}\n </dt>\n <dd>{formatDate(invite.expiresAt) ?? '—'}</dd>\n </div>\n {projectNames.length > 0 ? (\n <div className=\"sm:col-span-2\">\n <dt className=\"font-medium text-[var(--color-text-primary)]\">\n {tr('members.myInvites.projectsLabel', 'Projects')}\n </dt>\n <dd className=\"mt-1 flex flex-wrap gap-2\">\n {projectNames.map((projectName) => (\n <Badge key={`${invite.id}-${projectName}`} variant=\"outline\">\n {projectName}\n </Badge>\n ))}\n </dd>\n </div>\n ) : null}\n </dl>\n </div>\n\n <div className=\"flex flex-wrap items-center gap-2 shrink-0\">\n <button\n type=\"button\"\n onClick={() => void handleAcceptWorkspace(invite.id)}\n disabled={isProcessingWorkspaceAccept || isProcessingWorkspaceReject}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-[var(--color-status-success-bg)] px-4 py-2 text-sm font-medium text-[var(--color-text-inverse)] transition-all duration-200 hover:opacity-90 active:scale-[0.98] disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {isProcessingWorkspaceAccept ? (\n <Loader2 size={14} className=\"animate-spin\" />\n ) : null}\n {tr('members.myInvites.accept', 'Accept')}\n </button>\n <button\n type=\"button\"\n onClick={() => void handleRejectWorkspace(invite.id)}\n disabled={isProcessingWorkspaceAccept || isProcessingWorkspaceReject}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-[var(--color-border-default)] bg-transparent px-4 py-2 text-sm font-medium text-[var(--color-text-primary)] transition-all duration-200 hover:border-[var(--color-status-error-border)] hover:bg-[var(--color-status-error-bgSubtle)] hover:text-[var(--color-status-error-text)] active:scale-[0.98] disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {isProcessingWorkspaceReject ? (\n <Loader2 size={14} className=\"animate-spin\" />\n ) : null}\n {tr('members.myInvites.decline', 'Decline')}\n </button>\n </div>\n </div>\n </div>\n );\n })}\n </div>\n )\n ) : invites.length === 0 ? (\n <div className=\"text-center py-12 bg-[var(--color-bg-surface)] rounded-xl border border-[var(--color-border-default)]\">\n <Building2\n size={48}\n className=\"mx-auto mb-4 text-[var(--color-text-muted)] opacity-50\"\n />\n <h3 className=\"text-lg font-medium text-[var(--color-text-primary)] mb-1\">\n {tr('members.myInvites.emptyTitle', 'No pending invites')}\n </h3>\n <p className=\"text-sm text-[var(--color-text-muted)]\">\n {tr(\n 'members.myInvites.emptyDescription',\n 'When someone invites you to an organization, it will appear here.'\n )}\n </p>\n </div>\n ) : (\n <div className=\"space-y-3\">\n {invites.map((invite) => (\n <MyInviteCard\n key={invite.id}\n invite={invite}\n onAccept={handleAccept}\n onReject={handleReject}\n accepting={accepting}\n rejecting={rejecting}\n />\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region src/organization-management/modules/members/utils/workspaceInvitationDisplay.ts
|
|
2
|
+
function e(e) {
|
|
3
|
+
let t = e.context?.metadata;
|
|
4
|
+
return t && typeof t == "object" && !Array.isArray(t) ? t : null;
|
|
5
|
+
}
|
|
6
|
+
function t(t) {
|
|
7
|
+
if (t.workspaceName) return t.workspaceName;
|
|
8
|
+
let n = e(t)?.workspaceName;
|
|
9
|
+
return typeof n == "string" && n.trim().length > 0 ? n : t.workspaceId || "—";
|
|
10
|
+
}
|
|
11
|
+
function n(t) {
|
|
12
|
+
if (Array.isArray(t.roleNames) && t.roleNames.length > 0) return t.roleNames;
|
|
13
|
+
let n = e(t)?.roleNames;
|
|
14
|
+
return Array.isArray(n) && n.every((e) => typeof e == "string") ? n : [];
|
|
15
|
+
}
|
|
16
|
+
function r(t) {
|
|
17
|
+
let n = e(t), r = n?.projectNames;
|
|
18
|
+
if (Array.isArray(r) && r.every((e) => typeof e == "string")) return r;
|
|
19
|
+
let i = n?.projectIds, a = [
|
|
20
|
+
...Array.isArray(t.projectIds) ? t.projectIds : [],
|
|
21
|
+
...t.projectId ? [t.projectId] : [],
|
|
22
|
+
...Array.isArray(i) ? i.filter((e) => typeof e == "string") : []
|
|
23
|
+
], o = new Set(a).size;
|
|
24
|
+
return o === 0 ? [] : [`${o} project${o === 1 ? "" : "s"} selected`];
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { r as getProjectDisplayNames, n as getRoleDisplayNames, t as getWorkspaceDisplayName };
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=workspaceInvitationDisplay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspaceInvitationDisplay.js","names":[],"sources":["../../../../../src/organization-management/modules/members/utils/workspaceInvitationDisplay.ts"],"sourcesContent":["import type { Invitation } from '../../../../generated/wspace-types';\n\ntype InvitationLike = Pick<Invitation, 'workspaceId' | 'roleIds' | 'projectId' | 'context'> & {\n workspaceName?: string;\n projectIds?: string[];\n roleNames?: string[];\n};\n\nfunction readMetadata(invitation: InvitationLike): Record<string, unknown> | null {\n const metadata = invitation.context?.metadata;\n if (metadata && typeof metadata === 'object' && !Array.isArray(metadata)) {\n return metadata as Record<string, unknown>;\n }\n\n return null;\n}\n\nexport function getWorkspaceDisplayName(invitation: InvitationLike): string {\n if (invitation.workspaceName) {\n return invitation.workspaceName;\n }\n\n const metadata = readMetadata(invitation);\n const workspaceName = metadata?.workspaceName;\n if (typeof workspaceName === 'string' && workspaceName.trim().length > 0) {\n return workspaceName;\n }\n\n return invitation.workspaceId || '—';\n}\n\nexport function getRoleDisplayNames(invitation: InvitationLike): string[] {\n if (Array.isArray(invitation.roleNames) && invitation.roleNames.length > 0) {\n return invitation.roleNames;\n }\n\n const metadata = readMetadata(invitation);\n const roleNames = metadata?.roleNames;\n if (Array.isArray(roleNames) && roleNames.every((value) => typeof value === 'string')) {\n return roleNames;\n }\n\n return [];\n}\n\nexport function getProjectDisplayNames(invitation: InvitationLike): string[] {\n const metadata = readMetadata(invitation);\n const projectNames = metadata?.projectNames;\n if (Array.isArray(projectNames) && projectNames.every((value) => typeof value === 'string')) {\n return projectNames;\n }\n\n const metadataProjectIds = metadata?.projectIds;\n const projectIds = [\n ...(Array.isArray(invitation.projectIds) ? invitation.projectIds : []),\n ...(invitation.projectId ? [invitation.projectId] : []),\n ...(Array.isArray(metadataProjectIds)\n ? metadataProjectIds.filter((value): value is string => typeof value === 'string')\n : []),\n ];\n const projectCount = new Set(projectIds).size;\n\n if (projectCount === 0) {\n return [];\n }\n\n return [`${projectCount} project${projectCount === 1 ? '' : 's'} selected`];\n}\n"],"mappings":";AAQA,SAAS,EAAa,GAA4D;CAChF,IAAM,IAAW,EAAW,SAAS;AAKrC,QAJI,KAAY,OAAO,KAAa,YAAY,CAAC,MAAM,QAAQ,EAAS,GAC/D,IAGF;;AAGT,SAAgB,EAAwB,GAAoC;AAC1E,KAAI,EAAW,cACb,QAAO,EAAW;CAIpB,IAAM,IADW,EAAa,EAAW,EACT;AAKhC,QAJI,OAAO,KAAkB,YAAY,EAAc,MAAM,CAAC,SAAS,IAC9D,IAGF,EAAW,eAAe;;AAGnC,SAAgB,EAAoB,GAAsC;AACxE,KAAI,MAAM,QAAQ,EAAW,UAAU,IAAI,EAAW,UAAU,SAAS,EACvE,QAAO,EAAW;CAIpB,IAAM,IADW,EAAa,EAAW,EACb;AAK5B,QAJI,MAAM,QAAQ,EAAU,IAAI,EAAU,OAAO,MAAU,OAAO,KAAU,SAAS,GAC5E,IAGF,EAAE;;AAGX,SAAgB,EAAuB,GAAsC;CAC3E,IAAM,IAAW,EAAa,EAAW,EACnC,IAAe,GAAU;AAC/B,KAAI,MAAM,QAAQ,EAAa,IAAI,EAAa,OAAO,MAAU,OAAO,KAAU,SAAS,CACzF,QAAO;CAGT,IAAM,IAAqB,GAAU,YAC/B,IAAa;EACjB,GAAI,MAAM,QAAQ,EAAW,WAAW,GAAG,EAAW,aAAa,EAAE;EACrE,GAAI,EAAW,YAAY,CAAC,EAAW,UAAU,GAAG,EAAE;EACtD,GAAI,MAAM,QAAQ,EAAmB,GACjC,EAAmB,QAAQ,MAA2B,OAAO,KAAU,SAAS,GAChF,EAAE;EACP,EACK,IAAe,IAAI,IAAI,EAAW,CAAC;AAMzC,QAJI,MAAiB,IACZ,EAAE,GAGJ,CAAC,GAAG,EAAa,UAAU,MAAiB,IAAI,KAAK,IAAI,WAAW"}
|