@burdenoff/microfe-organization 2026.601.3 → 2026.601.5
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/AdminOrganizationRoot.js +24 -29
- package/dist/organization-management/AdminOrganizationRoot.js.map +1 -1
- package/dist/organization-management/AdminOrganizationRoutes.js +9 -9
- package/dist/organization-management/AdminOrganizationRoutes.js.map +1 -1
- package/dist/organization-management/modules/members/hooks/useWorkspaceInvites.js +34 -28
- package/dist/organization-management/modules/members/hooks/useWorkspaceInvites.js.map +1 -1
- package/package.json +1 -1
|
@@ -3,66 +3,61 @@ import { AdminOrganizationRoutes as t } from "./AdminOrganizationRoutes.js";
|
|
|
3
3
|
import { useEffect as n } from "react";
|
|
4
4
|
import { Briefcase as r, Building as i, Mail as a, Users as o } from "lucide-react";
|
|
5
5
|
import { Toaster as s } from "@burdenoff/fe-libs/ui";
|
|
6
|
-
import { FeatureFlagProvider as c
|
|
7
|
-
import { jsx as
|
|
6
|
+
import { FeatureFlagProvider as c } from "@burdenoff/fe-libs/shared/feature-flags";
|
|
7
|
+
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
8
8
|
//#region src/organization-management/AdminOrganizationRoot.tsx
|
|
9
|
-
var
|
|
10
|
-
let { registerNavItems:
|
|
9
|
+
var d = (d) => {
|
|
10
|
+
let { registerNavItems: f, registerFooterItems: p, basePath: m = "/organizations" } = d, h = (e, t) => (e.endsWith("/") ? e.slice(0, -1) : e) + (t.startsWith("/") ? t : `/${t}`);
|
|
11
11
|
return n(() => {
|
|
12
|
-
if (
|
|
12
|
+
if (f) return f([
|
|
13
13
|
{
|
|
14
14
|
id: "admin-org-organizations",
|
|
15
15
|
label: "Organizations",
|
|
16
|
-
path:
|
|
17
|
-
icon: /* @__PURE__ */
|
|
16
|
+
path: m,
|
|
17
|
+
icon: /* @__PURE__ */ l(i, { size: 20 }),
|
|
18
18
|
order: 30,
|
|
19
19
|
group: "globalconsole"
|
|
20
20
|
},
|
|
21
|
-
|
|
21
|
+
{
|
|
22
22
|
id: "admin-org-workspaces",
|
|
23
23
|
label: "Workspaces",
|
|
24
|
-
path:
|
|
25
|
-
icon: /* @__PURE__ */
|
|
24
|
+
path: h(m, "/workspaces"),
|
|
25
|
+
icon: /* @__PURE__ */ l(r, { size: 20 }),
|
|
26
26
|
order: 40,
|
|
27
27
|
group: "globalconsole"
|
|
28
|
-
}
|
|
29
|
-
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
30
|
id: "admin-org-members",
|
|
31
31
|
label: "Members",
|
|
32
|
-
path:
|
|
33
|
-
icon: /* @__PURE__ */
|
|
32
|
+
path: m,
|
|
33
|
+
icon: /* @__PURE__ */ l(o, { size: 20 }),
|
|
34
34
|
order: 50,
|
|
35
35
|
group: "globalconsole"
|
|
36
|
-
}
|
|
36
|
+
},
|
|
37
37
|
{
|
|
38
38
|
id: "admin-org-invites",
|
|
39
39
|
label: "My Invites",
|
|
40
|
-
path:
|
|
41
|
-
icon: /* @__PURE__ */
|
|
40
|
+
path: h(m, "/invites"),
|
|
41
|
+
icon: /* @__PURE__ */ l(a, { size: 20 }),
|
|
42
42
|
order: 60,
|
|
43
43
|
group: "globalconsole"
|
|
44
44
|
}
|
|
45
45
|
]);
|
|
46
|
-
}, [
|
|
47
|
-
p
|
|
48
|
-
h,
|
|
49
|
-
v,
|
|
50
|
-
y
|
|
51
|
-
]), n(() => {
|
|
52
|
-
if (m) return m([{
|
|
46
|
+
}, [f, m]), n(() => {
|
|
47
|
+
if (p) return p([{
|
|
53
48
|
id: "organization-management-version",
|
|
54
49
|
label: "Organization Management v0.1.0",
|
|
55
50
|
type: "status",
|
|
56
51
|
order: 30,
|
|
57
52
|
section: "left"
|
|
58
53
|
}]);
|
|
59
|
-
}, [
|
|
54
|
+
}, [p]), /* @__PURE__ */ l(c, {
|
|
60
55
|
workspaceId: null,
|
|
61
56
|
gateway: "global",
|
|
62
57
|
defaultEnabled: !0,
|
|
63
|
-
children: /* @__PURE__ */
|
|
64
|
-
...
|
|
65
|
-
children: [/* @__PURE__ */
|
|
58
|
+
children: /* @__PURE__ */ u(e, {
|
|
59
|
+
...d,
|
|
60
|
+
children: [/* @__PURE__ */ l(t, {}), /* @__PURE__ */ l(s, {
|
|
66
61
|
position: "top-right",
|
|
67
62
|
richColors: !0,
|
|
68
63
|
closeButton: !0
|
|
@@ -71,6 +66,6 @@ var f = (f) => {
|
|
|
71
66
|
});
|
|
72
67
|
};
|
|
73
68
|
//#endregion
|
|
74
|
-
export {
|
|
69
|
+
export { d as AdminOrganizationRoot };
|
|
75
70
|
|
|
76
71
|
//# sourceMappingURL=AdminOrganizationRoot.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminOrganizationRoot.js","names":[],"sources":["../../src/organization-management/AdminOrganizationRoot.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useEffect } from 'react';\nimport { Building, Briefcase, Mail, Users } from 'lucide-react';\nimport { Toaster } from '@burdenoff/fe-libs/ui';\nimport {
|
|
1
|
+
{"version":3,"file":"AdminOrganizationRoot.js","names":[],"sources":["../../src/organization-management/AdminOrganizationRoot.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useEffect } from 'react';\nimport { Building, Briefcase, Mail, Users } from 'lucide-react';\nimport { Toaster } from '@burdenoff/fe-libs/ui';\nimport { FeatureFlagProvider } from '@burdenoff/fe-libs/shared/feature-flags';\nimport { OrgConsoleProvider } from './providers/OrgConsoleProvider';\nimport type { NavItem, OrganizationRootProps } from './types';\nimport { AdminOrganizationRoutes } from './AdminOrganizationRoutes';\n\n/**\n * AdminOrganizationRoot\n *\n * Full-capability root for the organization management MFE, intended to\n * be mounted inside the admin application. Exposes organizations,\n * workspaces, members, and invites management — registering nav items\n * for each top-level surface with IDs prefixed `admin-org-*`.\n *\n * Takes the same props as `OrganizationRootProps` so hosts can\n * swap between the user and admin roots without adapter code.\n */\nexport const AdminOrganizationRoot: FC<OrganizationRootProps> = (props) => {\n const { registerNavItems, registerFooterItems, basePath = '/organizations' } = props;\n\n const 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\n useEffect(() => {\n if (!registerNavItems) return;\n\n const navItems: NavItem[] = [\n {\n id: 'admin-org-organizations',\n label: 'Organizations',\n path: basePath,\n icon: <Building size={20} />,\n order: 30,\n group: 'globalconsole',\n },\n {\n id: 'admin-org-workspaces',\n label: 'Workspaces',\n path: joinPath(basePath, '/workspaces'),\n icon: <Briefcase size={20} />,\n order: 40,\n group: 'globalconsole',\n },\n {\n id: 'admin-org-members',\n label: 'Members',\n // Members are accessed through org detail pages; point at orgs\n // list so admins have a discoverable entry point in the\n // top-level nav.\n path: basePath,\n icon: <Users size={20} />,\n order: 50,\n group: 'globalconsole',\n },\n {\n id: 'admin-org-invites',\n label: 'My Invites',\n path: joinPath(basePath, '/invites'),\n icon: <Mail size={20} />,\n order: 60,\n group: 'globalconsole',\n },\n ];\n\n const cleanup = registerNavItems(navItems);\n return cleanup;\n }, [registerNavItems, basePath]);\n\n useEffect(() => {\n if (!registerFooterItems) return;\n\n const footerItems = [\n {\n id: 'organization-management-version',\n label: 'Organization Management v0.1.0',\n type: 'status' as const,\n order: 30,\n section: 'left' as const,\n },\n ];\n\n const cleanup = registerFooterItems(footerItems);\n return cleanup;\n }, [registerFooterItems]);\n\n return (\n <FeatureFlagProvider workspaceId={null} gateway=\"global\" defaultEnabled={true}>\n <OrgConsoleProvider {...props}>\n <AdminOrganizationRoutes />\n <Toaster position=\"top-right\" richColors closeButton />\n </OrgConsoleProvider>\n </FeatureFlagProvider>\n );\n};\n"],"mappings":";;;;;;;;AAoBA,IAAa,KAAoD,MAAU;CACzE,IAAM,EAAE,qBAAkB,wBAAqB,cAAW,qBAAqB,GAEzE,KAAY,GAAc,OACZ,EAAK,SAAS,IAAI,GAAG,EAAK,MAAM,GAAG,GAAG,GAAG,MACzC,EAAK,WAAW,IAAI,GAAG,IAAO,IAAI;AAkEtD,QA9DA,QAAgB;AACT,QAyCL,QADgB,EAtCY;GAC1B;IACE,IAAI;IACJ,OAAO;IACP,MAAM;IACN,MAAM,kBAAC,GAAD,EAAU,MAAM,IAAM,CAAA;IAC5B,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO;IACP,MAAM,EAAS,GAAU,cAAc;IACvC,MAAM,kBAAC,GAAD,EAAW,MAAM,IAAM,CAAA;IAC7B,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO;IAIP,MAAM;IACN,MAAM,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA;IACzB,OAAO;IACP,OAAO;IACR;GACD;IACE,IAAI;IACJ,OAAO;IACP,MAAM,EAAS,GAAU,WAAW;IACpC,MAAM,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA;IACxB,OAAO;IACP,OAAO;IACR;GACF,CAEyC;IAEzC,CAAC,GAAkB,EAAS,CAAC,EAEhC,QAAgB;AACT,QAaL,QADgB,EAVI,CAClB;GACE,IAAI;GACJ,OAAO;GACP,MAAM;GACN,OAAO;GACP,SAAS;GACV,CACF,CAE+C;IAE/C,CAAC,EAAoB,CAAC,EAGvB,kBAAC,GAAD;EAAqB,aAAa;EAAM,SAAQ;EAAS,gBAAgB;YACvE,kBAAC,GAAD;GAAoB,GAAI;aAAxB,CACE,kBAAC,GAAD,EAA2B,CAAA,EAC3B,kBAAC,GAAD;IAAS,UAAS;IAAY,YAAA;IAAW,aAAA;IAAc,CAAA,CACpC;;EACD,CAAA"}
|
|
@@ -20,7 +20,7 @@ function C() {
|
|
|
20
20
|
});
|
|
21
21
|
}
|
|
22
22
|
function w() {
|
|
23
|
-
let t = i("organization.create"), r = i("organization.
|
|
23
|
+
let t = i("organization.create"), r = i("organization.invite"), s = t ? !!t.value : !0, u = r ? !!r.value : !0;
|
|
24
24
|
return /* @__PURE__ */ a(n, {
|
|
25
25
|
fallback: /* @__PURE__ */ a(C, {}),
|
|
26
26
|
children: /* @__PURE__ */ o(l, { children: [
|
|
@@ -28,7 +28,7 @@ function w() {
|
|
|
28
28
|
index: !0,
|
|
29
29
|
element: /* @__PURE__ */ a(e, { mode: "admin" })
|
|
30
30
|
}),
|
|
31
|
-
|
|
31
|
+
s && /* @__PURE__ */ a(c, {
|
|
32
32
|
path: "new",
|
|
33
33
|
element: /* @__PURE__ */ a(d, {})
|
|
34
34
|
}),
|
|
@@ -43,19 +43,19 @@ function w() {
|
|
|
43
43
|
element: /* @__PURE__ */ a(p, {})
|
|
44
44
|
})]
|
|
45
45
|
}),
|
|
46
|
-
|
|
46
|
+
/* @__PURE__ */ a(c, {
|
|
47
47
|
path: "workspaces",
|
|
48
48
|
element: /* @__PURE__ */ a(m, { mode: "admin" })
|
|
49
49
|
}),
|
|
50
|
-
|
|
50
|
+
/* @__PURE__ */ a(c, {
|
|
51
51
|
path: "workspaces/new",
|
|
52
52
|
element: /* @__PURE__ */ a(h, {})
|
|
53
53
|
}),
|
|
54
|
-
|
|
54
|
+
/* @__PURE__ */ a(c, {
|
|
55
55
|
path: "workspaces/:id",
|
|
56
56
|
element: /* @__PURE__ */ a(g, {})
|
|
57
57
|
}),
|
|
58
|
-
|
|
58
|
+
/* @__PURE__ */ a(c, {
|
|
59
59
|
path: "workspaces/:id/edit",
|
|
60
60
|
element: /* @__PURE__ */ a(_, {})
|
|
61
61
|
}),
|
|
@@ -71,15 +71,15 @@ function w() {
|
|
|
71
71
|
path: ":organizationId",
|
|
72
72
|
element: /* @__PURE__ */ a(S, { paramName: "organizationId" }),
|
|
73
73
|
children: [
|
|
74
|
-
|
|
74
|
+
u && /* @__PURE__ */ a(c, {
|
|
75
75
|
path: "members/invite",
|
|
76
76
|
element: /* @__PURE__ */ a(b, {})
|
|
77
77
|
}),
|
|
78
|
-
|
|
78
|
+
/* @__PURE__ */ a(c, {
|
|
79
79
|
path: "members",
|
|
80
80
|
element: /* @__PURE__ */ a(v, {})
|
|
81
81
|
}),
|
|
82
|
-
|
|
82
|
+
/* @__PURE__ */ a(c, {
|
|
83
83
|
path: "members/:userId",
|
|
84
84
|
element: /* @__PURE__ */ a(y, {})
|
|
85
85
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminOrganizationRoutes.js","names":[],"sources":["../../src/organization-management/AdminOrganizationRoutes.tsx"],"sourcesContent":["import { lazy, Suspense } from 'react';\nimport { Outlet, Route, Routes, useParams } from 'react-router-dom';\nimport { useFeatureFlagDetails } from '@burdenoff/fe-libs/shared/feature-flags';\nimport { OrgScopedPermissions } from './providers/OrgScopedPermissions';\n\n// Eager load - main entry point page\nimport { OrganizationsListPage } from './modules/organizations/pages/OrganizationsListPage';\n\n// Lazy load - secondary pages\nconst OrganizationCreatePage = lazy(() =>\n import('./modules/organizations/pages/OrganizationCreatePage').then((m) => ({\n default: m.OrganizationCreatePage,\n }))\n);\nconst OrganizationDetailPage = lazy(() =>\n import('./modules/organizations/pages/OrganizationDetailPage').then((m) => ({\n default: m.OrganizationDetailPage,\n }))\n);\nconst OrganizationEditPage = lazy(() =>\n import('./modules/organizations/pages/OrganizationEditPage').then((m) => ({\n default: m.OrganizationEditPage,\n }))\n);\n\n// Workspaces - lazy load all\nconst WorkspacesListPage = lazy(() =>\n import('./modules/workspaces/pages/WorkspacesListPage').then((m) => ({\n default: m.WorkspacesListPage,\n }))\n);\nconst WorkspaceCreatePage = lazy(() =>\n import('./modules/workspaces/pages/WorkspaceCreatePage').then((m) => ({\n default: m.WorkspaceCreatePage,\n }))\n);\nconst WorkspaceDetailPage = lazy(() =>\n import('./modules/workspaces/pages/WorkspaceDetailPage').then((m) => ({\n default: m.WorkspaceDetailPage,\n }))\n);\nconst WorkspaceEditPage = lazy(() =>\n import('./modules/workspaces/pages/WorkspaceEditPage').then((m) => ({\n default: m.WorkspaceEditPage,\n }))\n);\n\n// Members - lazy load all\nconst MembersListPage = lazy(() =>\n import('./modules/members/pages/MembersListPage').then((m) => ({ default: m.MembersListPage }))\n);\nconst MemberDetailPage = lazy(() =>\n import('./modules/members/pages/MemberDetailPage').then((m) => ({ default: m.MemberDetailPage }))\n);\nconst InviteMemberPage = lazy(() =>\n import('./modules/members/pages/InviteMemberPage').then((m) => ({ default: m.InviteMemberPage }))\n);\nconst MyInvitesPage = lazy(() =>\n import('./modules/members/pages/MyInvitesPage').then((m) => ({ default: m.MyInvitesPage }))\n);\n\n/**\n * Layout wrapper that scopes the PermissionProvider to the current\n * organization's id. This layout owns the `:id` or `:organizationId` URL\n * segment directly (see route declarations below) so\n * `useParams()[paramName]` is guaranteed to be populated and the\n * `OrgScopedPermissions` provider always wraps its descendants. Mirrors\n * the helper in UserOrganizationRoutes — keep them aligned.\n */\nfunction OrgScopedRouteLayout({ paramName }: { paramName: 'id' | 'organizationId' }) {\n const params = useParams<Record<string, string | undefined>>();\n const orgId = params[paramName];\n if (!orgId) return <Outlet />;\n return (\n <OrgScopedPermissions organizationId={orgId}>\n <Outlet />\n </OrgScopedPermissions>\n );\n}\n\n/**\n * Loading fallback for lazy-loaded pages\n */\nfunction PageLoadingFallback() {\n return (\n <div className=\"flex items-center justify-center min-h-[200px]\">\n <div className=\"size-8 animate-spin rounded-full border-2 border-[var(--color-border-default)] border-t-[var(--color-action-primary-bg)]\" />\n </div>\n );\n}\n\n/**\n * AdminOrganizationRoutes\n *\n * Full admin routing surface for the organization management MFE,\n * mounted by the admin application. Exposes all pages:\n * organizations CRUD, workspaces CRUD, members management, and\n * user-level invites.\n *\n * Routes start from root (/) since parent route is /organizations/*\n *\n * Lazy loading strategy:\n * - OrganizationsListPage: Eager loaded (main entry point)\n * - All other pages: Lazy loaded for better initial bundle size\n */\nexport function AdminOrganizationRoutes() {\n // Keep aligned with the platform feature-flag default-allow policy: an\n // unseeded flag must not disable shipped CRUDL. Explicit false still gates a\n // surface off when admins configure the flag.\n const createDetails = useFeatureFlagDetails('organization.create');\n const
|
|
1
|
+
{"version":3,"file":"AdminOrganizationRoutes.js","names":[],"sources":["../../src/organization-management/AdminOrganizationRoutes.tsx"],"sourcesContent":["import { lazy, Suspense } from 'react';\nimport { Outlet, Route, Routes, useParams } from 'react-router-dom';\nimport { useFeatureFlagDetails } from '@burdenoff/fe-libs/shared/feature-flags';\nimport { OrgScopedPermissions } from './providers/OrgScopedPermissions';\n\n// Eager load - main entry point page\nimport { OrganizationsListPage } from './modules/organizations/pages/OrganizationsListPage';\n\n// Lazy load - secondary pages\nconst OrganizationCreatePage = lazy(() =>\n import('./modules/organizations/pages/OrganizationCreatePage').then((m) => ({\n default: m.OrganizationCreatePage,\n }))\n);\nconst OrganizationDetailPage = lazy(() =>\n import('./modules/organizations/pages/OrganizationDetailPage').then((m) => ({\n default: m.OrganizationDetailPage,\n }))\n);\nconst OrganizationEditPage = lazy(() =>\n import('./modules/organizations/pages/OrganizationEditPage').then((m) => ({\n default: m.OrganizationEditPage,\n }))\n);\n\n// Workspaces - lazy load all\nconst WorkspacesListPage = lazy(() =>\n import('./modules/workspaces/pages/WorkspacesListPage').then((m) => ({\n default: m.WorkspacesListPage,\n }))\n);\nconst WorkspaceCreatePage = lazy(() =>\n import('./modules/workspaces/pages/WorkspaceCreatePage').then((m) => ({\n default: m.WorkspaceCreatePage,\n }))\n);\nconst WorkspaceDetailPage = lazy(() =>\n import('./modules/workspaces/pages/WorkspaceDetailPage').then((m) => ({\n default: m.WorkspaceDetailPage,\n }))\n);\nconst WorkspaceEditPage = lazy(() =>\n import('./modules/workspaces/pages/WorkspaceEditPage').then((m) => ({\n default: m.WorkspaceEditPage,\n }))\n);\n\n// Members - lazy load all\nconst MembersListPage = lazy(() =>\n import('./modules/members/pages/MembersListPage').then((m) => ({ default: m.MembersListPage }))\n);\nconst MemberDetailPage = lazy(() =>\n import('./modules/members/pages/MemberDetailPage').then((m) => ({ default: m.MemberDetailPage }))\n);\nconst InviteMemberPage = lazy(() =>\n import('./modules/members/pages/InviteMemberPage').then((m) => ({ default: m.InviteMemberPage }))\n);\nconst MyInvitesPage = lazy(() =>\n import('./modules/members/pages/MyInvitesPage').then((m) => ({ default: m.MyInvitesPage }))\n);\n\n/**\n * Layout wrapper that scopes the PermissionProvider to the current\n * organization's id. This layout owns the `:id` or `:organizationId` URL\n * segment directly (see route declarations below) so\n * `useParams()[paramName]` is guaranteed to be populated and the\n * `OrgScopedPermissions` provider always wraps its descendants. Mirrors\n * the helper in UserOrganizationRoutes — keep them aligned.\n */\nfunction OrgScopedRouteLayout({ paramName }: { paramName: 'id' | 'organizationId' }) {\n const params = useParams<Record<string, string | undefined>>();\n const orgId = params[paramName];\n if (!orgId) return <Outlet />;\n return (\n <OrgScopedPermissions organizationId={orgId}>\n <Outlet />\n </OrgScopedPermissions>\n );\n}\n\n/**\n * Loading fallback for lazy-loaded pages\n */\nfunction PageLoadingFallback() {\n return (\n <div className=\"flex items-center justify-center min-h-[200px]\">\n <div className=\"size-8 animate-spin rounded-full border-2 border-[var(--color-border-default)] border-t-[var(--color-action-primary-bg)]\" />\n </div>\n );\n}\n\n/**\n * AdminOrganizationRoutes\n *\n * Full admin routing surface for the organization management MFE,\n * mounted by the admin application. Exposes all pages:\n * organizations CRUD, workspaces CRUD, members management, and\n * user-level invites.\n *\n * Routes start from root (/) since parent route is /organizations/*\n *\n * Lazy loading strategy:\n * - OrganizationsListPage: Eager loaded (main entry point)\n * - All other pages: Lazy loaded for better initial bundle size\n */\nexport function AdminOrganizationRoutes() {\n // Keep aligned with the platform feature-flag default-allow policy: an\n // unseeded flag must not disable shipped CRUDL. Explicit false still gates a\n // surface off when admins configure the flag.\n const createDetails = useFeatureFlagDetails('organization.create');\n const inviteDetails = useFeatureFlagDetails('organization.invite');\n const createEnabled = createDetails ? Boolean(createDetails.value) : true;\n const inviteEnabled = inviteDetails ? Boolean(inviteDetails.value) : true;\n\n return (\n <Suspense fallback={<PageLoadingFallback />}>\n <Routes>\n {/* Organizations - index is the list (eager loaded). Admin app\n renders the platform-wide list (organizations query); product-app\n shells mounting this page should leave the default `mode=\"my\"`. */}\n <Route index element={<OrganizationsListPage mode=\"admin\" />} />\n {createEnabled && <Route path=\"new\" element={<OrganizationCreatePage />} />}\n\n {/* Per-org routes — the layout OWNS the `:id` segment so\n useParams().id is guaranteed to be set inside\n OrgScopedPermissions. */}\n <Route path=\":id\" element={<OrgScopedRouteLayout paramName=\"id\" />}>\n <Route index element={<OrganizationDetailPage />} />\n <Route path=\"edit\" element={<OrganizationEditPage />} />\n </Route>\n\n {/* Workspaces — literal \"workspaces\" prefix ranks above the bare\n dynamic `:id` / `:organizationId` segments. */}\n <Route path=\"workspaces\" element={<WorkspacesListPage mode=\"admin\" />} />\n <Route path=\"workspaces/new\" element={<WorkspaceCreatePage />} />\n <Route path=\"workspaces/:id\" element={<WorkspaceDetailPage />} />\n <Route path=\"workspaces/:id/edit\" element={<WorkspaceEditPage />} />\n\n {/* My Invites - user-level, not org-scoped. Declared before the\n `:organizationId` block so the literal \"invites\" wins the rank\n match. */}\n <Route path=\"invites\" element={<MyInvitesPage activeTab=\"workspace\" />} />\n <Route path=\"invites/organizations\" element={<MyInvitesPage activeTab=\"organization\" />} />\n\n {/* Member routes — layout OWNS the `:organizationId` segment for\n the same reason as the detail block above. */}\n <Route path=\":organizationId\" element={<OrgScopedRouteLayout paramName=\"organizationId\" />}>\n {inviteEnabled && <Route path=\"members/invite\" element={<InviteMemberPage />} />}\n <Route path=\"members\" element={<MembersListPage />} />\n <Route path=\"members/:userId\" element={<MemberDetailPage />} />\n </Route>\n </Routes>\n </Suspense>\n );\n}\n"],"mappings":"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"}
|
|
@@ -6,56 +6,62 @@ var s = "\n query GetMyPendingWorkspaceInvites($email: String!) {\n myPendin
|
|
|
6
6
|
function u(e, t) {
|
|
7
7
|
return e instanceof Error ? e : Error(t);
|
|
8
8
|
}
|
|
9
|
-
function d(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
function d(e) {
|
|
10
|
+
return e instanceof Error ? e.name === "AbortError" || e.message.toLowerCase().includes("signal is aborted") : !1;
|
|
11
|
+
}
|
|
12
|
+
function f(c, l = !0) {
|
|
13
|
+
let { authToken: f } = e(), p = l && !!c, [m, h] = a([]), [g, _] = a(p), [v, y] = a(null), b = i(0), x = i(null), S = t(async (e) => {
|
|
14
|
+
if (!l || !c) return h([]), y(null), _(!1), [];
|
|
15
|
+
let t = ++b.current;
|
|
16
|
+
_(!0), y(null);
|
|
14
17
|
try {
|
|
15
18
|
let n = await o({
|
|
16
19
|
gateway: "workspace",
|
|
17
|
-
authToken:
|
|
20
|
+
authToken: f || void 0,
|
|
18
21
|
query: s,
|
|
19
22
|
variables: { email: c },
|
|
20
23
|
signal: e,
|
|
21
24
|
workspaceToken: !1
|
|
22
25
|
});
|
|
23
|
-
if (n.errors?.length)
|
|
26
|
+
if (n.errors?.length) {
|
|
27
|
+
if (e?.aborted) return [];
|
|
28
|
+
throw Error(n.errors[0]?.message || "Failed to fetch workspace invites");
|
|
29
|
+
}
|
|
24
30
|
let r = n.data?.myPendingInvitations ?? [];
|
|
25
|
-
return
|
|
31
|
+
return b.current === t && h(r), r;
|
|
26
32
|
} catch (n) {
|
|
27
|
-
if (e?.aborted) return [];
|
|
33
|
+
if (e?.aborted || d(n)) return [];
|
|
28
34
|
let r = u(n, "Failed to fetch workspace invites");
|
|
29
|
-
throw
|
|
35
|
+
throw b.current === t && (y(r), h([])), r;
|
|
30
36
|
} finally {
|
|
31
|
-
|
|
37
|
+
b.current === t && _(!1);
|
|
32
38
|
}
|
|
33
39
|
}, [
|
|
34
|
-
|
|
40
|
+
f,
|
|
35
41
|
c,
|
|
36
42
|
l
|
|
37
43
|
]);
|
|
38
44
|
n(() => {
|
|
39
45
|
let e = new AbortController();
|
|
40
|
-
return
|
|
41
|
-
|
|
46
|
+
return x.current?.abort(), x.current = e, S(e.signal).catch(() => void 0), () => {
|
|
47
|
+
x.current === e && (x.current = null), e.abort();
|
|
42
48
|
};
|
|
43
|
-
}, [
|
|
44
|
-
let
|
|
49
|
+
}, [S]);
|
|
50
|
+
let C = g || p && m.length === 0 && v === null && b.current === 0;
|
|
45
51
|
return r(() => ({
|
|
46
|
-
invites:
|
|
47
|
-
total:
|
|
48
|
-
loading:
|
|
49
|
-
error:
|
|
50
|
-
refetch:
|
|
52
|
+
invites: m,
|
|
53
|
+
total: m.length,
|
|
54
|
+
loading: C,
|
|
55
|
+
error: v,
|
|
56
|
+
refetch: S
|
|
51
57
|
}), [
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
58
|
+
v,
|
|
59
|
+
m,
|
|
60
|
+
C,
|
|
61
|
+
S
|
|
56
62
|
]);
|
|
57
63
|
}
|
|
58
|
-
function
|
|
64
|
+
function p() {
|
|
59
65
|
let { authToken: n } = e(), [r, i] = a(!1), [s, l] = a(null);
|
|
60
66
|
return {
|
|
61
67
|
acceptInvite: t(async (e) => {
|
|
@@ -81,7 +87,7 @@ function f() {
|
|
|
81
87
|
error: s
|
|
82
88
|
};
|
|
83
89
|
}
|
|
84
|
-
function
|
|
90
|
+
function m() {
|
|
85
91
|
let { authToken: n } = e(), [r, i] = a(!1), [s, c] = a(null);
|
|
86
92
|
return {
|
|
87
93
|
rejectInvite: t(async (e) => {
|
|
@@ -108,6 +114,6 @@ function p() {
|
|
|
108
114
|
};
|
|
109
115
|
}
|
|
110
116
|
//#endregion
|
|
111
|
-
export {
|
|
117
|
+
export { p as useAcceptWorkspaceInvite, f as useMyWorkspaceInvites, m as useRejectWorkspaceInvite };
|
|
112
118
|
|
|
113
119
|
//# sourceMappingURL=useWorkspaceInvites.js.map
|
|
@@ -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($email: String!) {\n myPendingInvitations(email: $email) {\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\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 variables: { email },\n signal,\n workspaceToken: false,\n });\n\n if (result.errors?.length) {\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) {\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":";;;;AAKA,IAAM,IAAmC,oXAuBnC,IAA0B,6JAW1B,IAA0B;AAoBhC,SAAS,EAAQ,GAAgB,GAAkB;AACjD,QAAO,aAAiB,QAAQ,IAAY,MAAM,EAAS;;AAG7D,SAAgB,EAAsB,GAAgB,IAAmB,IAAM;CAC7E,IAAM,EAAE,iBAAc,GAAe,EAC/B,IAAc,KAAW,EAAQ,GACjC,CAAC,GAAS,KAAc,EAAuB,EAAE,CAAC,EAClD,CAAC,GAAS,KAAc,EAAS,EAAY,EAC7C,CAAC,GAAO,KAAY,EAAuB,KAAK,EAChD,IAAe,EAAO,EAAE,EACxB,IAAqB,EAA+B,KAAK,EAEzD,IAAc,EAClB,OAAO,MAAyB;AAC9B,MAAI,CAAC,KAAW,CAAC,EAIf,QAHA,EAAW,EAAE,CAAC,EACd,EAAS,KAAK,EACd,EAAW,GAAM,EACV,EAAE;EAGX,IAAM,IAAY,EAAE,EAAa;AAEjC,EADA,EAAW,GAAK,EAChB,EAAS,KAAK;AAEd,MAAI;GACF,IAAM,IAAS,MAAM,EAAuC;IAC1D,SAAS;IACT,WAAW,KAAa,KAAA;IACxB,OAAO;IACP,WAAW,EAAE,UAAO;IACpB;IACA,gBAAgB;IACjB,CAAC;AAEF,OAAI,EAAO,QAAQ,
|
|
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($email: String!) {\n myPendingInvitations(email: $email) {\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 variables: { email },\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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"}
|