@burdenoff/microfe-organization 2026.601.6 → 2026.601.8
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/organization-management/modules/members/hooks/useWorkspaceInvites.js +1 -2
- package/dist/organization-management/modules/members/hooks/useWorkspaceInvites.js.map +1 -1
- package/dist/organization-management/modules/members/pages/MemberDetailPage.js +74 -58
- package/dist/organization-management/modules/members/pages/MemberDetailPage.js.map +1 -1
- package/dist/organization-management/modules/members/pages/MembersListPage.js +202 -199
- package/dist/organization-management/modules/members/pages/MembersListPage.js.map +1 -1
- package/dist/organization-management/modules/workspaces/components/AddWorkspaceMemberDialog.js +92 -82
- package/dist/organization-management/modules/workspaces/components/AddWorkspaceMemberDialog.js.map +1 -1
- package/dist/organization-management/modules/workspaces/pages/WorkspaceDetailPage.js +180 -162
- package/dist/organization-management/modules/workspaces/pages/WorkspaceDetailPage.js.map +1 -1
- package/package.json +2 -2
|
@@ -2,7 +2,7 @@ import { useOrgConsole as e } from "../../../providers/OrgConsoleProvider.js";
|
|
|
2
2
|
import { useCallback as t, useEffect as n, useMemo as r, useRef as i, useState as a } from "react";
|
|
3
3
|
import { graphqlFetch as o } from "@burdenoff/fe-libs/shared/graphql";
|
|
4
4
|
//#region src/organization-management/modules/members/hooks/useWorkspaceInvites.ts
|
|
5
|
-
var s = "\n query GetMyPendingWorkspaceInvites
|
|
5
|
+
var s = "\n query GetMyPendingWorkspaceInvites {\n myPendingInvitations {\n id\n email\n status\n roleIds\n workspaceId\n invitedById\n expiresAt\n createdAt\n projectId\n invitedUserId\n updatedAt\n deletedAt\n context {\n type\n metadata\n }\n }\n }\n", c = "\n mutation AcceptWorkspaceInvite($id: ID!) {\n acceptInvitation(id: $id) {\n id\n status\n workspaceId\n updatedAt\n }\n }\n", l = "\n mutation RejectWorkspaceInvite($id: ID!) {\n rejectInvitation(id: $id) {\n id\n status\n workspaceId\n updatedAt\n }\n }\n";
|
|
6
6
|
function u(e, t) {
|
|
7
7
|
return e instanceof Error ? e : Error(t);
|
|
8
8
|
}
|
|
@@ -19,7 +19,6 @@ function f(c, l = !0) {
|
|
|
19
19
|
gateway: "workspace",
|
|
20
20
|
authToken: f || void 0,
|
|
21
21
|
query: s,
|
|
22
|
-
variables: { email: c },
|
|
23
22
|
signal: e,
|
|
24
23
|
workspaceToken: !1
|
|
25
24
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useWorkspaceInvites.js","names":[],"sources":["../../../../../src/organization-management/modules/members/hooks/useWorkspaceInvites.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\nimport type { Invitation } from '../../../../generated/wspace-types';\nimport { useOrgConsole } from '../../../providers/OrgConsoleProvider';\n\nconst GET_MY_PENDING_WORKSPACE_INVITES = `\n query GetMyPendingWorkspaceInvites
|
|
1
|
+
{"version":3,"file":"useWorkspaceInvites.js","names":[],"sources":["../../../../../src/organization-management/modules/members/hooks/useWorkspaceInvites.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\nimport type { Invitation } from '../../../../generated/wspace-types';\nimport { useOrgConsole } from '../../../providers/OrgConsoleProvider';\n\nconst GET_MY_PENDING_WORKSPACE_INVITES = `\n query GetMyPendingWorkspaceInvites {\n myPendingInvitations {\n id\n email\n status\n roleIds\n workspaceId\n invitedById\n expiresAt\n createdAt\n projectId\n invitedUserId\n updatedAt\n deletedAt\n context {\n type\n metadata\n }\n }\n }\n`;\n\nconst ACCEPT_WORKSPACE_INVITE = `\n mutation AcceptWorkspaceInvite($id: ID!) {\n acceptInvitation(id: $id) {\n id\n status\n workspaceId\n updatedAt\n }\n }\n`;\n\nconst REJECT_WORKSPACE_INVITE = `\n mutation RejectWorkspaceInvite($id: ID!) {\n rejectInvitation(id: $id) {\n id\n status\n workspaceId\n updatedAt\n }\n }\n`;\n\ninterface WorkspaceInvitesResponse {\n myPendingInvitations: Invitation[];\n}\n\ninterface WorkspaceInviteMutationResponse {\n acceptInvitation?: Pick<Invitation, 'id' | 'status' | 'workspaceId' | 'updatedAt'>;\n rejectInvitation?: Pick<Invitation, 'id' | 'status' | 'workspaceId' | 'updatedAt'>;\n}\n\nfunction toError(error: unknown, fallback: string) {\n return error instanceof Error ? error : new Error(fallback);\n}\n\nfunction isAbortLikeError(error: unknown) {\n if (!(error instanceof Error)) {\n return false;\n }\n\n return error.name === 'AbortError' || error.message.toLowerCase().includes('signal is aborted');\n}\n\nexport function useMyWorkspaceInvites(email?: string, enabled: boolean = true) {\n const { authToken } = useOrgConsole();\n const shouldFetch = enabled && Boolean(email);\n const [invites, setInvites] = useState<Invitation[]>([]);\n const [loading, setLoading] = useState(shouldFetch);\n const [error, setError] = useState<Error | null>(null);\n const requestIdRef = useRef(0);\n const abortControllerRef = useRef<AbortController | null>(null);\n\n const loadInvites = useCallback(\n async (signal?: AbortSignal) => {\n if (!enabled || !email) {\n setInvites([]);\n setError(null);\n setLoading(false);\n return [] as Invitation[];\n }\n\n const requestId = ++requestIdRef.current;\n setLoading(true);\n setError(null);\n\n try {\n const result = await graphqlFetch<WorkspaceInvitesResponse>({\n gateway: 'workspace',\n authToken: authToken || undefined,\n query: GET_MY_PENDING_WORKSPACE_INVITES,\n signal,\n workspaceToken: false,\n });\n\n if (result.errors?.length) {\n if (signal?.aborted) {\n return [] as Invitation[];\n }\n\n throw new Error(result.errors[0]?.message || 'Failed to fetch workspace invites');\n }\n\n const nextInvites = result.data?.myPendingInvitations ?? [];\n if (requestIdRef.current === requestId) {\n setInvites(nextInvites);\n }\n return nextInvites;\n } catch (fetchError) {\n if (signal?.aborted || isAbortLikeError(fetchError)) {\n return [] as Invitation[];\n }\n\n const normalizedError = toError(fetchError, 'Failed to fetch workspace invites');\n if (requestIdRef.current === requestId) {\n setError(normalizedError);\n setInvites([]);\n }\n throw normalizedError;\n } finally {\n if (requestIdRef.current === requestId) {\n setLoading(false);\n }\n }\n },\n [authToken, email, enabled]\n );\n\n useEffect(() => {\n const abortController = new AbortController();\n abortControllerRef.current?.abort();\n abortControllerRef.current = abortController;\n\n void loadInvites(abortController.signal).catch(() => undefined);\n\n return () => {\n if (abortControllerRef.current === abortController) {\n abortControllerRef.current = null;\n }\n abortController.abort();\n };\n }, [loadInvites]);\n\n const isLoading =\n loading ||\n (shouldFetch && invites.length === 0 && error === null && requestIdRef.current === 0);\n\n return useMemo(\n () => ({\n invites,\n total: invites.length,\n loading: isLoading,\n error,\n refetch: loadInvites,\n }),\n [error, invites, isLoading, loadInvites]\n );\n}\n\nexport function useAcceptWorkspaceInvite() {\n const { authToken } = useOrgConsole();\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const acceptInvite = useCallback(\n async (inviteId: string) => {\n setLoading(true);\n setError(null);\n\n try {\n const result = await graphqlFetch<WorkspaceInviteMutationResponse>({\n gateway: 'workspace',\n authToken: authToken || undefined,\n query: ACCEPT_WORKSPACE_INVITE,\n variables: { id: inviteId },\n workspaceToken: false,\n });\n\n if (result.errors?.length) {\n throw new Error(result.errors[0]?.message || 'Failed to accept workspace invite');\n }\n\n return result.data?.acceptInvitation ?? null;\n } catch (mutationError) {\n const normalizedError = toError(mutationError, 'Failed to accept workspace invite');\n setError(normalizedError);\n throw normalizedError;\n } finally {\n setLoading(false);\n }\n },\n [authToken]\n );\n\n return { acceptInvite, loading, error };\n}\n\nexport function useRejectWorkspaceInvite() {\n const { authToken } = useOrgConsole();\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const rejectInvite = useCallback(\n async (inviteId: string) => {\n setLoading(true);\n setError(null);\n\n try {\n const result = await graphqlFetch<WorkspaceInviteMutationResponse>({\n gateway: 'workspace',\n authToken: authToken || undefined,\n query: REJECT_WORKSPACE_INVITE,\n variables: { id: inviteId },\n workspaceToken: false,\n });\n\n if (result.errors?.length) {\n throw new Error(result.errors[0]?.message || 'Failed to reject workspace invite');\n }\n\n return result.data?.rejectInvitation ?? null;\n } catch (mutationError) {\n const normalizedError = toError(mutationError, 'Failed to reject workspace invite');\n setError(normalizedError);\n throw normalizedError;\n } finally {\n setLoading(false);\n }\n },\n [authToken]\n );\n\n return { rejectInvite, loading, error };\n}\n"],"mappings":"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"}
|
|
@@ -5,118 +5,134 @@ import { ErrorState as r } from "../../../shared/components/feedback/ErrorState.
|
|
|
5
5
|
import { PERMISSIONS as i } from "../../../constants/permissions.js";
|
|
6
6
|
import { MemberRoleBadge as a } from "../components/MemberRoleBadge.js";
|
|
7
7
|
import { useMember as o } from "../hooks/useMembers.js";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
8
|
+
import { useMemo as s } from "react";
|
|
9
|
+
import { ArrowLeft as c, Shield as l } from "lucide-react";
|
|
10
|
+
import { usePermissions as u } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
11
|
+
import { jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
12
|
+
import { useParams as p } from "react-router-dom";
|
|
13
|
+
import { buildActorFallback as m, useActorProfiles as h } from "@burdenoff/fe-libs/shared";
|
|
12
14
|
//#region src/organization-management/modules/members/pages/MemberDetailPage.tsx
|
|
13
|
-
function
|
|
14
|
-
let
|
|
15
|
-
|
|
15
|
+
function g() {
|
|
16
|
+
let g = t(), { organizationId: _, userId: v } = p(), { navigate: y, basePath: b = "/organizations", apiGatewayUrl: x, authToken: S } = e(), { hasPermission: C, isLoading: w } = u(), { member: T, loading: E, error: D } = o(_, v), O = h(s(() => v ? [{
|
|
17
|
+
actorId: v,
|
|
18
|
+
actorType: "user"
|
|
19
|
+
}] : [], [v]), {
|
|
20
|
+
apiGatewayUrl: x,
|
|
21
|
+
authToken: S,
|
|
22
|
+
orgId: _
|
|
23
|
+
}), k = v && T ? O[T.userId] ?? m({
|
|
24
|
+
actorId: T.userId,
|
|
25
|
+
actorType: "user"
|
|
26
|
+
}) : null;
|
|
27
|
+
return w ? /* @__PURE__ */ d("div", {
|
|
16
28
|
className: "min-h-full bg-[var(--color-bg-canvas)] p-6",
|
|
17
|
-
children: /* @__PURE__ */
|
|
18
|
-
}) :
|
|
29
|
+
children: /* @__PURE__ */ d(n, { message: g("common.loadingPermissions", "Loading permissions...") })
|
|
30
|
+
}) : C(i.MEMBER_READ) ? E ? /* @__PURE__ */ d("div", {
|
|
19
31
|
className: "min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6",
|
|
20
|
-
children: /* @__PURE__ */
|
|
21
|
-
}) :
|
|
32
|
+
children: /* @__PURE__ */ d(n, { message: g("members.detail.loading", "Loading member...") })
|
|
33
|
+
}) : D || !T ? /* @__PURE__ */ d("div", {
|
|
22
34
|
className: "min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6",
|
|
23
|
-
children: /* @__PURE__ */
|
|
24
|
-
message:
|
|
35
|
+
children: /* @__PURE__ */ d(r, {
|
|
36
|
+
message: D?.message || g("members.detail.notFound", "Member not found"),
|
|
25
37
|
action: {
|
|
26
|
-
label:
|
|
27
|
-
onClick: () =>
|
|
38
|
+
label: g("common.goBack", "Go Back"),
|
|
39
|
+
onClick: () => y(`${b}/${_}/members`)
|
|
28
40
|
}
|
|
29
41
|
})
|
|
30
|
-
}) : /* @__PURE__ */
|
|
42
|
+
}) : /* @__PURE__ */ f("div", {
|
|
31
43
|
className: "min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6 animate-in fade-in duration-300",
|
|
32
|
-
children: [/* @__PURE__ */
|
|
44
|
+
children: [/* @__PURE__ */ f("div", {
|
|
33
45
|
className: "mb-6",
|
|
34
|
-
children: [/* @__PURE__ */
|
|
46
|
+
children: [/* @__PURE__ */ f("button", {
|
|
35
47
|
type: "button",
|
|
36
|
-
onClick: () =>
|
|
48
|
+
onClick: () => y(`${b}/${_}/members`),
|
|
37
49
|
className: "inline-flex items-center gap-2 text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] active:scale-[0.98] transition-all duration-200 mb-4",
|
|
38
|
-
children: [/* @__PURE__ */
|
|
39
|
-
}), /* @__PURE__ */
|
|
50
|
+
children: [/* @__PURE__ */ d(c, { size: 20 }), g("members.detail.backToMembers", "Back to Members")]
|
|
51
|
+
}), /* @__PURE__ */ f("div", {
|
|
40
52
|
className: "flex items-start gap-4",
|
|
41
|
-
children: [/* @__PURE__ */
|
|
53
|
+
children: [/* @__PURE__ */ d("div", {
|
|
42
54
|
className: "size-16 rounded-full bg-[var(--color-status-info-muted)] flex items-center justify-center",
|
|
43
|
-
children: /* @__PURE__ */
|
|
55
|
+
children: /* @__PURE__ */ d(l, {
|
|
44
56
|
size: 32,
|
|
45
57
|
className: "text-[var(--color-status-info)]"
|
|
46
58
|
})
|
|
47
|
-
}), /* @__PURE__ */
|
|
48
|
-
/* @__PURE__ */
|
|
59
|
+
}), /* @__PURE__ */ f("div", { children: [
|
|
60
|
+
/* @__PURE__ */ d("h1", {
|
|
49
61
|
className: "text-3xl font-bold text-[var(--color-text-primary)]",
|
|
50
|
-
children:
|
|
62
|
+
children: k?.displayName ?? g("members.detail.titlePrefix", "Member")
|
|
51
63
|
}),
|
|
52
|
-
/* @__PURE__ */
|
|
64
|
+
k?.email ? /* @__PURE__ */ d("p", {
|
|
65
|
+
className: "text-[var(--color-text-secondary)] mt-1 break-all",
|
|
66
|
+
children: k.email
|
|
67
|
+
}) : null,
|
|
68
|
+
/* @__PURE__ */ d("p", {
|
|
53
69
|
className: "text-[var(--color-text-secondary)] mt-1",
|
|
54
|
-
children:
|
|
70
|
+
children: T.role
|
|
55
71
|
}),
|
|
56
|
-
/* @__PURE__ */
|
|
72
|
+
/* @__PURE__ */ f("details", {
|
|
57
73
|
className: "mt-2 text-xs text-[var(--color-text-secondary)]",
|
|
58
|
-
children: [/* @__PURE__ */
|
|
74
|
+
children: [/* @__PURE__ */ d("summary", {
|
|
59
75
|
className: "cursor-pointer",
|
|
60
|
-
children:
|
|
61
|
-
}), /* @__PURE__ */
|
|
76
|
+
children: g("members.detail.showIds", "Show technical IDs")
|
|
77
|
+
}), /* @__PURE__ */ f("dl", {
|
|
62
78
|
className: "mt-1 grid grid-cols-[auto_1fr] gap-x-3 gap-y-1",
|
|
63
79
|
children: [
|
|
64
|
-
/* @__PURE__ */
|
|
65
|
-
/* @__PURE__ */
|
|
80
|
+
/* @__PURE__ */ d("dt", { children: g("members.detail.userId", "User ID") }),
|
|
81
|
+
/* @__PURE__ */ d("dd", {
|
|
66
82
|
className: "break-all font-mono",
|
|
67
|
-
children:
|
|
83
|
+
children: T.userId
|
|
68
84
|
}),
|
|
69
|
-
/* @__PURE__ */
|
|
70
|
-
/* @__PURE__ */
|
|
85
|
+
/* @__PURE__ */ d("dt", { children: g("members.list.memberId", "Member ID") }),
|
|
86
|
+
/* @__PURE__ */ d("dd", {
|
|
71
87
|
className: "break-all font-mono",
|
|
72
|
-
children:
|
|
88
|
+
children: T.id
|
|
73
89
|
})
|
|
74
90
|
]
|
|
75
91
|
})]
|
|
76
92
|
})
|
|
77
93
|
] })]
|
|
78
94
|
})]
|
|
79
|
-
}), /* @__PURE__ */
|
|
95
|
+
}), /* @__PURE__ */ f("div", {
|
|
80
96
|
className: "bg-[var(--color-bg-surface)] border border-[var(--color-border-default)] rounded-lg p-6",
|
|
81
|
-
children: [/* @__PURE__ */
|
|
97
|
+
children: [/* @__PURE__ */ d("h2", {
|
|
82
98
|
className: "text-lg font-semibold text-[var(--color-text-primary)] mb-4",
|
|
83
|
-
children:
|
|
84
|
-
}), /* @__PURE__ */
|
|
99
|
+
children: g("members.detail.info", "Member Information")
|
|
100
|
+
}), /* @__PURE__ */ f("div", {
|
|
85
101
|
className: "space-y-4",
|
|
86
102
|
children: [
|
|
87
|
-
/* @__PURE__ */
|
|
103
|
+
/* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("p", {
|
|
88
104
|
className: "text-sm text-[var(--color-text-secondary)]",
|
|
89
|
-
children:
|
|
90
|
-
}), /* @__PURE__ */
|
|
105
|
+
children: g("members.list.column.role", "Role")
|
|
106
|
+
}), /* @__PURE__ */ d("div", {
|
|
91
107
|
className: "mt-1",
|
|
92
|
-
children: /* @__PURE__ */
|
|
108
|
+
children: /* @__PURE__ */ d(a, { role: T.role })
|
|
93
109
|
})] }),
|
|
94
|
-
|
|
110
|
+
T.invitedBy && /* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("p", {
|
|
95
111
|
className: "text-sm text-[var(--color-text-secondary)]",
|
|
96
|
-
children:
|
|
97
|
-
}), /* @__PURE__ */
|
|
112
|
+
children: g("members.detail.invitedBy", "Invited By")
|
|
113
|
+
}), /* @__PURE__ */ d("p", {
|
|
98
114
|
className: "text-[var(--color-text-primary)] font-medium",
|
|
99
|
-
children:
|
|
115
|
+
children: T.invitedBy
|
|
100
116
|
})] }),
|
|
101
|
-
|
|
117
|
+
T.joinedAt && /* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("p", {
|
|
102
118
|
className: "text-sm text-[var(--color-text-secondary)]",
|
|
103
|
-
children:
|
|
104
|
-
}), /* @__PURE__ */
|
|
119
|
+
children: g("members.detail.joinedAt", "Joined At")
|
|
120
|
+
}), /* @__PURE__ */ d("p", {
|
|
105
121
|
className: "text-[var(--color-text-primary)] font-medium",
|
|
106
|
-
children: new Date(
|
|
122
|
+
children: new Date(T.joinedAt).toLocaleString()
|
|
107
123
|
})] })
|
|
108
124
|
]
|
|
109
125
|
})]
|
|
110
126
|
})]
|
|
111
|
-
}) : /* @__PURE__ */
|
|
127
|
+
}) : /* @__PURE__ */ d("div", {
|
|
112
128
|
className: "min-h-full bg-[var(--color-bg-canvas)] p-6",
|
|
113
|
-
children: /* @__PURE__ */
|
|
129
|
+
children: /* @__PURE__ */ d("div", {
|
|
114
130
|
className: "p-8 text-center text-[var(--color-text-secondary)]",
|
|
115
|
-
children:
|
|
131
|
+
children: g("members.detail.noPermission", "You don't have permission to view member details.")
|
|
116
132
|
})
|
|
117
133
|
});
|
|
118
134
|
}
|
|
119
135
|
//#endregion
|
|
120
|
-
export {
|
|
136
|
+
export { g as MemberDetailPage };
|
|
121
137
|
|
|
122
138
|
//# sourceMappingURL=MemberDetailPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MemberDetailPage.js","names":[],"sources":["../../../../../src/organization-management/modules/members/pages/MemberDetailPage.tsx"],"sourcesContent":["import { useParams } from 'react-router-dom';\nimport { ArrowLeft, Shield } from 'lucide-react';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useOrgConsole } from '../../../providers/OrgConsoleProvider';\nimport { useMember } from '../hooks/useMembers';\nimport { MemberRoleBadge } from '../components/MemberRoleBadge';\nimport { LoadingState } from '../../../shared/components/feedback/LoadingState';\nimport { ErrorState } from '../../../shared/components/feedback/ErrorState';\nimport { PERMISSIONS } from '../../../constants/permissions';\nimport { useTr } from '../../../shared/hooks/useTr';\n\n/**\n * Member Detail Page\n * Simplified version showing available member fields\n */\nexport function MemberDetailPage() {\n const tr = useTr();\n const { organizationId, userId } = useParams<{ organizationId: string; userId: string }>();\n const { navigate, basePath = '/organizations' } = useOrgConsole();\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n const { member, loading, error } = useMember(organizationId!, userId!);\n\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 (!hasPermission(PERMISSIONS.MEMBER_READ)) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] p-6\">\n <div className=\"p-8 text-center text-[var(--color-text-secondary)]\">\n {tr('members.detail.noPermission', \"You don't have permission to view member details.\")}\n </div>\n </div>\n );\n }\n\n if (loading) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <LoadingState message={tr('members.detail.loading', 'Loading member...')} />\n </div>\n );\n }\n\n if (error || !member) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <ErrorState\n message={error?.message || tr('members.detail.notFound', 'Member not found')}\n action={{\n label: tr('common.goBack', 'Go Back'),\n onClick: () => navigate(`${basePath}/${organizationId}/members`),\n }}\n />\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 animate-in fade-in duration-300\">\n {/* Header */}\n <div className=\"mb-6\">\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${organizationId}/members`)}\n className=\"inline-flex items-center gap-2 text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] active:scale-[0.98] transition-all duration-200 mb-4\"\n >\n <ArrowLeft size={20} />\n {tr('members.detail.backToMembers', 'Back to Members')}\n </button>\n\n <div className=\"flex items-start gap-4\">\n <div className=\"size-16 rounded-full bg-[var(--color-status-info-muted)] flex items-center justify-center\">\n <Shield size={32} className=\"text-[var(--color-status-info)]\" />\n </div>\n <div>\n <h1 className=\"text-3xl font-bold text-[var(--color-text-primary)]\">\n {tr('members.detail.titlePrefix', 'Member')}\n </h1>\n <p className=\"text-[var(--color-text-secondary)] mt-1\">{member.role}</p>\n <details className=\"mt-2 text-xs text-[var(--color-text-secondary)]\">\n <summary className=\"cursor-pointer\">\n {tr('members.detail.showIds', 'Show technical IDs')}\n </summary>\n <dl className=\"mt-1 grid grid-cols-[auto_1fr] gap-x-3 gap-y-1\">\n <dt>{tr('members.detail.userId', 'User ID')}</dt>\n <dd className=\"break-all font-mono\">{member.userId}</dd>\n <dt>{tr('members.list.memberId', 'Member ID')}</dt>\n <dd className=\"break-all font-mono\">{member.id}</dd>\n </dl>\n </details>\n </div>\n </div>\n </div>\n\n {/* Details */}\n <div className=\"bg-[var(--color-bg-surface)] border border-[var(--color-border-default)] rounded-lg p-6\">\n <h2 className=\"text-lg font-semibold text-[var(--color-text-primary)] mb-4\">\n {tr('members.detail.info', 'Member Information')}\n </h2>\n\n <div className=\"space-y-4\">\n <div>\n <p className=\"text-sm text-[var(--color-text-secondary)]\">\n {tr('members.list.column.role', 'Role')}\n </p>\n <div className=\"mt-1\">\n <MemberRoleBadge role={member.role} />\n </div>\n </div>\n\n {member.invitedBy && (\n <div>\n <p className=\"text-sm text-[var(--color-text-secondary)]\">\n {tr('members.detail.invitedBy', 'Invited By')}\n </p>\n <p className=\"text-[var(--color-text-primary)] font-medium\">{member.invitedBy}</p>\n </div>\n )}\n\n {member.joinedAt && (\n <div>\n <p className=\"text-sm text-[var(--color-text-secondary)]\">\n {tr('members.detail.joinedAt', 'Joined At')}\n </p>\n <p className=\"text-[var(--color-text-primary)] font-medium\">\n {new Date(member.joinedAt).toLocaleString()}\n </p>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"MemberDetailPage.js","names":[],"sources":["../../../../../src/organization-management/modules/members/pages/MemberDetailPage.tsx"],"sourcesContent":["import { useMemo } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { ArrowLeft, Shield } from 'lucide-react';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { buildActorFallback, useActorProfiles, type ActorInput } from '@burdenoff/fe-libs/shared';\nimport { useOrgConsole } from '../../../providers/OrgConsoleProvider';\nimport { useMember } from '../hooks/useMembers';\nimport { MemberRoleBadge } from '../components/MemberRoleBadge';\nimport { LoadingState } from '../../../shared/components/feedback/LoadingState';\nimport { ErrorState } from '../../../shared/components/feedback/ErrorState';\nimport { PERMISSIONS } from '../../../constants/permissions';\nimport { useTr } from '../../../shared/hooks/useTr';\n\n/**\n * Member Detail Page\n * Simplified version showing available member fields\n */\nexport function MemberDetailPage() {\n const tr = useTr();\n const { organizationId, userId } = useParams<{ organizationId: string; userId: string }>();\n const { navigate, basePath = '/organizations', apiGatewayUrl, authToken } = useOrgConsole();\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n const { member, loading, error } = useMember(organizationId!, userId!);\n\n const memberActors = useMemo<ActorInput[]>(\n () => (userId ? [{ actorId: userId, actorType: 'user' }] : []),\n [userId]\n );\n const profileMap = useActorProfiles(memberActors, {\n apiGatewayUrl,\n authToken,\n orgId: organizationId,\n });\n const memberProfile =\n userId && member\n ? (profileMap[member.userId] ??\n buildActorFallback({ actorId: member.userId, actorType: 'user' }))\n : null;\n\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 (!hasPermission(PERMISSIONS.MEMBER_READ)) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] p-6\">\n <div className=\"p-8 text-center text-[var(--color-text-secondary)]\">\n {tr('members.detail.noPermission', \"You don't have permission to view member details.\")}\n </div>\n </div>\n );\n }\n\n if (loading) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <LoadingState message={tr('members.detail.loading', 'Loading member...')} />\n </div>\n );\n }\n\n if (error || !member) {\n return (\n <div className=\"min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6\">\n <ErrorState\n message={error?.message || tr('members.detail.notFound', 'Member not found')}\n action={{\n label: tr('common.goBack', 'Go Back'),\n onClick: () => navigate(`${basePath}/${organizationId}/members`),\n }}\n />\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 animate-in fade-in duration-300\">\n {/* Header */}\n <div className=\"mb-6\">\n <button\n type=\"button\"\n onClick={() => navigate(`${basePath}/${organizationId}/members`)}\n className=\"inline-flex items-center gap-2 text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] active:scale-[0.98] transition-all duration-200 mb-4\"\n >\n <ArrowLeft size={20} />\n {tr('members.detail.backToMembers', 'Back to Members')}\n </button>\n\n <div className=\"flex items-start gap-4\">\n <div className=\"size-16 rounded-full bg-[var(--color-status-info-muted)] flex items-center justify-center\">\n <Shield size={32} className=\"text-[var(--color-status-info)]\" />\n </div>\n <div>\n <h1 className=\"text-3xl font-bold text-[var(--color-text-primary)]\">\n {memberProfile?.displayName ?? tr('members.detail.titlePrefix', 'Member')}\n </h1>\n {memberProfile?.email ? (\n <p className=\"text-[var(--color-text-secondary)] mt-1 break-all\">\n {memberProfile.email}\n </p>\n ) : null}\n <p className=\"text-[var(--color-text-secondary)] mt-1\">{member.role}</p>\n <details className=\"mt-2 text-xs text-[var(--color-text-secondary)]\">\n <summary className=\"cursor-pointer\">\n {tr('members.detail.showIds', 'Show technical IDs')}\n </summary>\n <dl className=\"mt-1 grid grid-cols-[auto_1fr] gap-x-3 gap-y-1\">\n <dt>{tr('members.detail.userId', 'User ID')}</dt>\n <dd className=\"break-all font-mono\">{member.userId}</dd>\n <dt>{tr('members.list.memberId', 'Member ID')}</dt>\n <dd className=\"break-all font-mono\">{member.id}</dd>\n </dl>\n </details>\n </div>\n </div>\n </div>\n\n {/* Details */}\n <div className=\"bg-[var(--color-bg-surface)] border border-[var(--color-border-default)] rounded-lg p-6\">\n <h2 className=\"text-lg font-semibold text-[var(--color-text-primary)] mb-4\">\n {tr('members.detail.info', 'Member Information')}\n </h2>\n\n <div className=\"space-y-4\">\n <div>\n <p className=\"text-sm text-[var(--color-text-secondary)]\">\n {tr('members.list.column.role', 'Role')}\n </p>\n <div className=\"mt-1\">\n <MemberRoleBadge role={member.role} />\n </div>\n </div>\n\n {member.invitedBy && (\n <div>\n <p className=\"text-sm text-[var(--color-text-secondary)]\">\n {tr('members.detail.invitedBy', 'Invited By')}\n </p>\n <p className=\"text-[var(--color-text-primary)] font-medium\">{member.invitedBy}</p>\n </div>\n )}\n\n {member.joinedAt && (\n <div>\n <p className=\"text-sm text-[var(--color-text-secondary)]\">\n {tr('members.detail.joinedAt', 'Joined At')}\n </p>\n <p className=\"text-[var(--color-text-primary)] font-medium\">\n {new Date(member.joinedAt).toLocaleString()}\n </p>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|