@burdenoff/microfe-organization 2026.519.1 → 2026.520.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/generated/global-operations.d.ts +41 -0
  2. package/dist/generated/global-operations.d.ts.map +1 -1
  3. package/dist/generated/global-operations.js +39 -30
  4. package/dist/generated/global-operations.js.map +1 -1
  5. package/dist/generated/global-types.js +3 -1
  6. package/dist/generated/global-types.js.map +1 -1
  7. package/dist/organization-management/AdminOrganizationRoutes.d.ts.map +1 -1
  8. package/dist/organization-management/AdminOrganizationRoutes.js +62 -45
  9. package/dist/organization-management/AdminOrganizationRoutes.js.map +1 -1
  10. package/dist/organization-management/UserOrganizationRoutes.d.ts.map +1 -1
  11. package/dist/organization-management/UserOrganizationRoutes.js +60 -43
  12. package/dist/organization-management/UserOrganizationRoutes.js.map +1 -1
  13. package/dist/organization-management/modules/members/components/PendingInvitesList.d.ts.map +1 -1
  14. package/dist/organization-management/modules/members/components/PendingInvitesList.js +70 -67
  15. package/dist/organization-management/modules/members/components/PendingInvitesList.js.map +1 -1
  16. package/dist/organization-management/modules/members/hooks/useInvites.d.ts +7 -2
  17. package/dist/organization-management/modules/members/hooks/useInvites.d.ts.map +1 -1
  18. package/dist/organization-management/modules/members/hooks/useInvites.js +9 -8
  19. package/dist/organization-management/modules/members/hooks/useInvites.js.map +1 -1
  20. package/dist/organization-management/modules/members/pages/InviteMemberPage.d.ts.map +1 -1
  21. package/dist/organization-management/modules/members/pages/InviteMemberPage.js +48 -47
  22. package/dist/organization-management/modules/members/pages/InviteMemberPage.js.map +1 -1
  23. package/dist/organization-management/modules/members/pages/MyInvitesPage.js +8 -8
  24. package/dist/organization-management/modules/organizations/hooks/useOrgsWithPermission.d.ts +26 -0
  25. package/dist/organization-management/modules/organizations/hooks/useOrgsWithPermission.d.ts.map +1 -0
  26. package/dist/organization-management/modules/organizations/hooks/useOrgsWithPermission.js +63 -0
  27. package/dist/organization-management/modules/organizations/hooks/useOrgsWithPermission.js.map +1 -0
  28. package/dist/organization-management/modules/organizations/pages/OrganizationDetailPage.d.ts.map +1 -1
  29. package/dist/organization-management/modules/organizations/pages/OrganizationDetailPage.js +5 -5
  30. package/dist/organization-management/modules/organizations/pages/OrganizationDetailPage.js.map +1 -1
  31. package/dist/organization-management/modules/organizations/pages/OrganizationsListPage.d.ts.map +1 -1
  32. package/dist/organization-management/modules/organizations/pages/OrganizationsListPage.js +226 -202
  33. package/dist/organization-management/modules/organizations/pages/OrganizationsListPage.js.map +1 -1
  34. package/dist/organization-management/modules/workspaces/components/WorkspaceForm.d.ts.map +1 -1
  35. package/dist/organization-management/modules/workspaces/components/WorkspaceForm.js +152 -147
  36. package/dist/organization-management/modules/workspaces/components/WorkspaceForm.js.map +1 -1
  37. package/dist/organization-management/modules/workspaces/pages/WorkspaceCreatePage.d.ts.map +1 -1
  38. package/dist/organization-management/modules/workspaces/pages/WorkspaceCreatePage.js +39 -46
  39. package/dist/organization-management/modules/workspaces/pages/WorkspaceCreatePage.js.map +1 -1
  40. package/dist/organization-management/modules/workspaces/pages/WorkspacesListPage.d.ts.map +1 -1
  41. package/dist/organization-management/modules/workspaces/pages/WorkspacesListPage.js +3 -3
  42. package/dist/organization-management/modules/workspaces/pages/WorkspacesListPage.js.map +1 -1
  43. package/dist/organization-management/providers/OrgScopedPermissions.d.ts +22 -0
  44. package/dist/organization-management/providers/OrgScopedPermissions.d.ts.map +1 -0
  45. package/dist/organization-management/providers/OrgScopedPermissions.js +14 -0
  46. package/dist/organization-management/providers/OrgScopedPermissions.js.map +1 -0
  47. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"PendingInvitesList.js","names":[],"sources":["../../../../../src/organization-management/modules/members/components/PendingInvitesList.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { RotateCw, X, Loader2, AlertCircle } from 'lucide-react';\nimport { useOrganizationInvites, useCancelInvite, useResendInvite } from '../hooks/useInvites';\nimport { InviteStatusBadge } from './InviteStatusBadge';\nimport { MemberRoleBadge } from './MemberRoleBadge';\nimport { InviteStatus } from '../../../../generated/global-types';\nimport { useTr } from '../../../shared/hooks/useTr';\n\ninterface PendingInvitesListProps {\n organizationId: string;\n}\n\nexport function PendingInvitesList({ organizationId }: PendingInvitesListProps) {\n const tr = useTr();\n const { invites, loading, error, total } = useOrganizationInvites(\n organizationId,\n { status: InviteStatus.Pending },\n 50\n );\n const { cancelInvite, loading: cancelling } = useCancelInvite();\n const { resendInvite, loading: resending } = useResendInvite();\n const [actionError, setActionError] = useState<string | null>(null);\n\n if (loading && invites.length === 0) {\n return (\n <div className=\"flex items-center justify-center py-8\">\n <Loader2 size={20} className=\"animate-spin text-[var(--color-text-muted)]\" />\n </div>\n );\n }\n\n if (error) {\n return (\n <p className=\"py-6 text-center text-sm text-[var(--color-status-error-text)]\">\n {tr('members.myInvites.loadFailed', 'Failed to load invites')}: {error.message}\n </p>\n );\n }\n\n if (invites.length === 0) {\n return (\n <p className=\"text-sm text-[var(--color-text-muted)] text-center py-6\">\n {tr('members.myInvites.emptyTitle', 'No pending invites')}\n </p>\n );\n }\n\n const handleCancel = async (inviteId: string) => {\n try {\n setActionError(null);\n await cancelInvite(inviteId);\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr('members.invite.cancelFailed', 'Failed to cancel invite')\n );\n }\n };\n\n const handleResend = async (inviteId: string) => {\n try {\n setActionError(null);\n await resendInvite(inviteId);\n } catch (err) {\n setActionError(\n err instanceof Error\n ? err.message\n : tr('members.invite.resendFailed', 'Failed to resend invite')\n );\n }\n };\n\n return (\n <div>\n <h3 className=\"text-sm font-semibold text-[var(--color-text-secondary)] uppercase tracking-wider mb-3\">\n {tr('members.invite.pendingTitle', 'Pending Invites')} ({total})\n </h3>\n\n {actionError && (\n <div className=\"mb-3 flex items-center gap-2 rounded-lg border border-[var(--color-status-error-border)] bg-[var(--color-status-error-bgSubtle)] p-2.5\">\n <AlertCircle size={14} 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 <div className=\"overflow-x-auto rounded-lg border border-[var(--color-border-default)]\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"bg-[var(--color-bg-subtle)] border-b border-[var(--color-border-default)]\">\n <th className=\"text-left px-4 py-2.5 font-medium text-[var(--color-text-secondary)]\">\n {tr('members.invite.emailLabel', 'Email Address')}\n </th>\n <th className=\"text-left px-4 py-2.5 font-medium text-[var(--color-text-secondary)]\">\n {tr('members.list.column.role', 'Role')}\n </th>\n <th className=\"text-left px-4 py-2.5 font-medium text-[var(--color-text-secondary)]\">\n {tr('common.status', 'Status')}\n </th>\n <th className=\"text-left px-4 py-2.5 font-medium text-[var(--color-text-secondary)]\">\n {tr('members.invite.expires', 'Expires')}\n </th>\n <th className=\"text-right px-4 py-2.5 font-medium text-[var(--color-text-secondary)]\">\n {tr('common.actions', 'Actions')}\n </th>\n </tr>\n </thead>\n <tbody>\n {invites.map((invite) => (\n <tr\n key={invite.id}\n className=\"border-b border-[var(--color-border-default)] last:border-b-0 hover:bg-[var(--color-bg-subtle)] transition-colors\"\n >\n <td className=\"px-4 py-3 text-[var(--color-text-primary)]\">{invite.email}</td>\n <td className=\"px-4 py-3\">\n <MemberRoleBadge role={invite.role} />\n </td>\n <td className=\"px-4 py-3\">\n <InviteStatusBadge status={invite.status} />\n </td>\n <td className=\"px-4 py-3 text-[var(--color-text-muted)]\">\n {new Date(invite.expiresAt).toLocaleDateString()}\n </td>\n <td className=\"px-4 py-3 text-right\">\n <div className=\"flex items-center justify-end gap-1\">\n <button\n onClick={() => handleResend(invite.id)}\n disabled={resending}\n className=\"p-1.5 rounded-md hover:bg-[var(--color-bg-subtle)] text-[var(--color-text-muted)] hover:text-[var(--color-text-primary)] transition-colors\"\n title={tr('members.invite.resend', 'Resend invite')}\n aria-label={`${tr('members.invite.resendFor', 'Resend invite for')} ${invite.email}`}\n >\n <RotateCw size={14} />\n </button>\n <button\n onClick={() => handleCancel(invite.id)}\n disabled={cancelling}\n className=\"p-1.5 rounded-md text-[var(--color-text-muted)] transition-colors hover:bg-[var(--color-status-error-bgSubtle)] hover:text-[var(--color-status-error-text)]\"\n title={tr('members.invite.cancel', 'Cancel invite')}\n aria-label={`${tr('members.invite.cancelFor', 'Cancel invite for')} ${invite.email}`}\n >\n <X size={14} />\n </button>\n </div>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"PendingInvitesList.js","names":[],"sources":["../../../../../src/organization-management/modules/members/components/PendingInvitesList.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { RotateCw, X, Loader2, AlertCircle } from 'lucide-react';\nimport { toast } from 'sonner';\nimport { useOrganizationInvites, useCancelInvite, useResendInvite } from '../hooks/useInvites';\nimport { InviteStatusBadge } from './InviteStatusBadge';\nimport { MemberRoleBadge } from './MemberRoleBadge';\nimport { InviteStatus } from '../../../../generated/global-types';\nimport { useTr } from '../../../shared/hooks/useTr';\n\ninterface PendingInvitesListProps {\n organizationId: string;\n}\n\nexport function PendingInvitesList({ organizationId }: PendingInvitesListProps) {\n const tr = useTr();\n const { invites, loading, error, total } = useOrganizationInvites(\n organizationId,\n { status: InviteStatus.Pending },\n 50\n );\n const { cancelInvite, loading: cancelling } = useCancelInvite();\n const { resendInvite, loading: resending } = useResendInvite();\n const [actionError, setActionError] = useState<string | null>(null);\n\n if (loading && invites.length === 0) {\n return (\n <div className=\"flex items-center justify-center py-8\">\n <Loader2 size={20} className=\"animate-spin text-[var(--color-text-muted)]\" />\n </div>\n );\n }\n\n if (error) {\n return (\n <p className=\"py-6 text-center text-sm text-[var(--color-status-error-text)]\">\n {tr('members.myInvites.loadFailed', 'Failed to load invites')}: {error.message}\n </p>\n );\n }\n\n if (invites.length === 0) {\n return (\n <p className=\"text-sm text-[var(--color-text-muted)] text-center py-6\">\n {tr('members.myInvites.emptyTitle', 'No pending invites')}\n </p>\n );\n }\n\n const handleCancel = async (inviteId: string, email: string) => {\n try {\n setActionError(null);\n await cancelInvite(inviteId);\n toast.success(`${tr('members.invite.cancelSuccess', 'Invite cancelled for')} ${email}`);\n } catch (err) {\n const msg =\n err instanceof Error\n ? err.message\n : tr('members.invite.cancelFailed', 'Failed to cancel invite');\n setActionError(msg);\n toast.error(msg);\n }\n };\n\n const handleResend = async (inviteId: string, email: string) => {\n try {\n setActionError(null);\n await resendInvite(inviteId);\n toast.success(`${tr('members.invite.resendSuccess', 'Invite re-sent to')} ${email}`);\n } catch (err) {\n const msg =\n err instanceof Error\n ? err.message\n : tr('members.invite.resendFailed', 'Failed to resend invite');\n setActionError(msg);\n toast.error(msg);\n }\n };\n\n return (\n <div>\n <h3 className=\"text-sm font-semibold text-[var(--color-text-secondary)] uppercase tracking-wider mb-3\">\n {tr('members.invite.pendingTitle', 'Pending Invites')} ({total})\n </h3>\n\n {actionError && (\n <div className=\"mb-3 flex items-center gap-2 rounded-lg border border-[var(--color-status-error-border)] bg-[var(--color-status-error-bgSubtle)] p-2.5\">\n <AlertCircle size={14} 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 <div className=\"overflow-x-auto rounded-lg border border-[var(--color-border-default)]\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"bg-[var(--color-bg-subtle)] border-b border-[var(--color-border-default)]\">\n <th className=\"text-left px-4 py-2.5 font-medium text-[var(--color-text-secondary)]\">\n {tr('members.invite.emailLabel', 'Email Address')}\n </th>\n <th className=\"text-left px-4 py-2.5 font-medium text-[var(--color-text-secondary)]\">\n {tr('members.list.column.role', 'Role')}\n </th>\n <th className=\"text-left px-4 py-2.5 font-medium text-[var(--color-text-secondary)]\">\n {tr('common.status', 'Status')}\n </th>\n <th className=\"text-left px-4 py-2.5 font-medium text-[var(--color-text-secondary)]\">\n {tr('members.invite.expires', 'Expires')}\n </th>\n <th className=\"text-right px-4 py-2.5 font-medium text-[var(--color-text-secondary)]\">\n {tr('common.actions', 'Actions')}\n </th>\n </tr>\n </thead>\n <tbody>\n {invites.map((invite) => (\n <tr\n key={invite.id}\n className=\"border-b border-[var(--color-border-default)] last:border-b-0 hover:bg-[var(--color-bg-subtle)] transition-colors\"\n >\n <td className=\"px-4 py-3 text-[var(--color-text-primary)]\">{invite.email}</td>\n <td className=\"px-4 py-3\">\n <MemberRoleBadge role={invite.role} />\n </td>\n <td className=\"px-4 py-3\">\n <InviteStatusBadge status={invite.status} />\n </td>\n <td className=\"px-4 py-3 text-[var(--color-text-muted)]\">\n {new Date(invite.expiresAt).toLocaleDateString()}\n </td>\n <td className=\"px-4 py-3 text-right\">\n <div className=\"flex items-center justify-end gap-1\">\n <button\n onClick={() => handleResend(invite.id, invite.email)}\n disabled={resending}\n className=\"p-1.5 rounded-md hover:bg-[var(--color-bg-subtle)] text-[var(--color-text-muted)] hover:text-[var(--color-text-primary)] transition-colors\"\n title={tr('members.invite.resend', 'Resend invite')}\n aria-label={`${tr('members.invite.resendFor', 'Resend invite for')} ${invite.email}`}\n >\n <RotateCw size={14} />\n </button>\n <button\n onClick={() => handleCancel(invite.id, invite.email)}\n disabled={cancelling}\n className=\"p-1.5 rounded-md text-[var(--color-text-muted)] transition-colors hover:bg-[var(--color-status-error-bgSubtle)] hover:text-[var(--color-status-error-text)]\"\n title={tr('members.invite.cancel', 'Cancel invite')}\n aria-label={`${tr('members.invite.cancelFor', 'Cancel invite for')} ${invite.email}`}\n >\n <X size={14} />\n </button>\n </div>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;AAaA,SAAgB,EAAmB,EAAE,qBAA2C;CAC9E,IAAM,IAAK,GAAO,EACZ,EAAE,YAAS,YAAS,UAAO,aAAU,EACzC,GACA,EAAE,QAAQ,EAAa,SAAS,EAChC,GACD,EACK,EAAE,iBAAc,SAAS,MAAe,GAAiB,EACzD,EAAE,iBAAc,SAAS,MAAc,GAAiB,EACxD,CAAC,GAAa,KAAkB,EAAwB,KAAK;AAEnE,KAAI,KAAW,EAAQ,WAAW,EAChC,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GAAS,MAAM;GAAI,WAAU;GAAgD,CAAA;EACzE,CAAA;AAIV,KAAI,EACF,QACE,kBAAC,KAAD;EAAG,WAAU;YAAb;GACG,EAAG,gCAAgC,yBAAyB;GAAC;GAAG,EAAM;GACrE;;AAIR,KAAI,EAAQ,WAAW,EACrB,QACE,kBAAC,KAAD;EAAG,WAAU;YACV,EAAG,gCAAgC,qBAAqB;EACvD,CAAA;CAIR,IAAM,IAAe,OAAO,GAAkB,MAAkB;AAC9D,MAAI;AAGF,GAFA,EAAe,KAAK,EACpB,MAAM,EAAa,EAAS,EAC5B,EAAM,QAAQ,GAAG,EAAG,gCAAgC,uBAAuB,CAAC,GAAG,IAAQ;WAChF,GAAK;GACZ,IAAM,IACJ,aAAe,QACX,EAAI,UACJ,EAAG,+BAA+B,0BAA0B;AAElE,GADA,EAAe,EAAI,EACnB,EAAM,MAAM,EAAI;;IAId,IAAe,OAAO,GAAkB,MAAkB;AAC9D,MAAI;AAGF,GAFA,EAAe,KAAK,EACpB,MAAM,EAAa,EAAS,EAC5B,EAAM,QAAQ,GAAG,EAAG,gCAAgC,oBAAoB,CAAC,GAAG,IAAQ;WAC7E,GAAK;GACZ,IAAM,IACJ,aAAe,QACX,EAAI,UACJ,EAAG,+BAA+B,0BAA0B;AAElE,GADA,EAAe,EAAI,EACnB,EAAM,MAAM,EAAI;;;AAIpB,QACE,kBAAC,OAAD,EAAA,UAAA;EACE,kBAAC,MAAD;GAAI,WAAU;aAAd;IACG,EAAG,+BAA+B,kBAAkB;IAAC;IAAG;IAAM;IAC5D;;EAEJ,KACC,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,GAAD;IAAa,MAAM;IAAI,WAAU;IAAmD,CAAA,EACpF,kBAAC,KAAD;IAAG,WAAU;cAAiD;IAAgB,CAAA,CAC1E;;EAGR,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,SAAD;IAAO,WAAU;cAAjB,CACE,kBAAC,SAAD,EAAA,UACE,kBAAC,MAAD;KAAI,WAAU;eAAd;MACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,6BAA6B,gBAAgB;OAC9C,CAAA;MACL,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,4BAA4B,OAAO;OACpC,CAAA;MACL,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,iBAAiB,SAAS;OAC3B,CAAA;MACL,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,0BAA0B,UAAU;OACrC,CAAA;MACL,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,kBAAkB,UAAU;OAC7B,CAAA;MACF;QACC,CAAA,EACR,kBAAC,SAAD,EAAA,UACG,EAAQ,KAAK,MACZ,kBAAC,MAAD;KAEE,WAAU;eAFZ;MAIE,kBAAC,MAAD;OAAI,WAAU;iBAA8C,EAAO;OAAW,CAAA;MAC9E,kBAAC,MAAD;OAAI,WAAU;iBACZ,kBAAC,GAAD,EAAiB,MAAM,EAAO,MAAQ,CAAA;OACnC,CAAA;MACL,kBAAC,MAAD;OAAI,WAAU;iBACZ,kBAAC,GAAD,EAAmB,QAAQ,EAAO,QAAU,CAAA;OACzC,CAAA;MACL,kBAAC,MAAD;OAAI,WAAU;iBACX,IAAI,KAAK,EAAO,UAAU,CAAC,oBAAoB;OAC7C,CAAA;MACL,kBAAC,MAAD;OAAI,WAAU;iBACZ,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,UAAD;SACE,eAAe,EAAa,EAAO,IAAI,EAAO,MAAM;SACpD,UAAU;SACV,WAAU;SACV,OAAO,EAAG,yBAAyB,gBAAgB;SACnD,cAAY,GAAG,EAAG,4BAA4B,oBAAoB,CAAC,GAAG,EAAO;mBAE7E,kBAAC,GAAD,EAAU,MAAM,IAAM,CAAA;SACf,CAAA,EACT,kBAAC,UAAD;SACE,eAAe,EAAa,EAAO,IAAI,EAAO,MAAM;SACpD,UAAU;SACV,WAAU;SACV,OAAO,EAAG,yBAAyB,gBAAgB;SACnD,cAAY,GAAG,EAAG,4BAA4B,oBAAoB,CAAC,GAAG,EAAO;mBAE7E,kBAAC,GAAD,EAAG,MAAM,IAAM,CAAA;SACR,CAAA,CACL;;OACH,CAAA;MACF;OAnCE,EAAO,GAmCT,CACL,EACI,CAAA,CACF;;GACJ,CAAA;EACF,EAAA,CAAA"}
@@ -17,9 +17,14 @@ export declare function useOrganizationInvites(organizationId: string, filter?:
17
17
  refetch: (variables?: any) => Promise<import('@apollo/client').ApolloQueryResult<Types.GetOrganizationInvitesQuery>>;
18
18
  };
19
19
  /**
20
- * Hook to fetch invites for the current user (invitee view)
20
+ * Hook to fetch invites for the current user (invitee view).
21
+ *
22
+ * `enabled` defaults to `true` for backward compat. Callers in admin /
23
+ * service contexts (e.g. OrganizationsListPage in `mode="admin"`) should
24
+ * pass `false` to skip the network round-trip and avoid surfacing
25
+ * authorization errors for actors that don't hold the self-scope.
21
26
  */
22
- export declare function useMyInvites(status?: InviteStatus, limit?: number, offset?: number): {
27
+ export declare function useMyInvites(status?: InviteStatus, limit?: number, offset?: number, enabled?: boolean): {
23
28
  invites: OrganizationInvite[];
24
29
  total: any;
25
30
  hasMore: any;
@@ -1 +1 @@
1
- {"version":3,"file":"useInvites.d.ts","sourceRoot":"","sources":["../../../../../src/organization-management/modules/members/hooks/useInvites.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACV,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EACnB,MAAM,oCAAoC,CAAC;AAiB5C,UAAU,4BAA4B;IACpC,wBAAwB,EAAE,kBAAkB,CAAC;CAC9C;AAgCD;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,cAAc,EAAE,MAAM,EACtB,MAAM,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,YAAY,CAAA;CAAE,EAClC,KAAK,GAAE,MAAW,EAClB,MAAM,GAAE,MAAU;aAUqC,kBAAkB,EAAE;;;;;;EAO5E;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,CAAC,EAAE,YAAY,EAAE,KAAK,GAAE,MAAW,EAAE,MAAM,GAAE,MAAU;aAQ/B,kBAAkB,EAAE;;;;;;EAO9E;AAED;;GAEG;AACH,wBAAgB,eAAe;0BAOC;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE;;;EA4C1F;AAED;;GAEG;AACH,wBAAgB,eAAe;6BAUI,MAAM;;;EAyCxC;AAED;;GAEG;AACH,wBAAgB,eAAe;6BAOI,MAAM;;;EAsCxC;AAED;;GAEG;AACH,wBAAgB,eAAe;6BAOI,MAAM;;;EAsCxC;AAED;;GAEG;AACH,wBAAgB,eAAe;6BAOI,MAAM;;;EAsCxC"}
1
+ {"version":3,"file":"useInvites.d.ts","sourceRoot":"","sources":["../../../../../src/organization-management/modules/members/hooks/useInvites.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACV,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EACnB,MAAM,oCAAoC,CAAC;AAiB5C,UAAU,4BAA4B;IACpC,wBAAwB,EAAE,kBAAkB,CAAC;CAC9C;AAgCD;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,cAAc,EAAE,MAAM,EACtB,MAAM,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,YAAY,CAAA;CAAE,EAClC,KAAK,GAAE,MAAW,EAClB,MAAM,GAAE,MAAU;aAUqC,kBAAkB,EAAE;;;;;;EAO5E;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,MAAM,CAAC,EAAE,YAAY,EACrB,KAAK,GAAE,MAAW,EAClB,MAAM,GAAE,MAAU,EAClB,OAAO,GAAE,OAAc;aAUkC,kBAAkB,EAAE;;;;;;EAO9E;AAED;;GAEG;AACH,wBAAgB,eAAe;0BAOC;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE;;;EA4C1F;AAED;;GAEG;AACH,wBAAgB,eAAe;6BAUI,MAAM;;;EAyCxC;AAED;;GAEG;AACH,wBAAgB,eAAe;6BAOI,MAAM;;;EAsCxC;AAED;;GAEG;AACH,wBAAgB,eAAe;6BAOI,MAAM;;;EAsCxC;AAED;;GAEG;AACH,wBAAgB,eAAe;6BAOI,MAAM;;;EAsCxC"}
@@ -43,23 +43,24 @@ function v(e, t, n = 20, r = 0) {
43
43
  refetch: c
44
44
  };
45
45
  }
46
- function y(e, t = 20, n = 0) {
47
- let { data: r, loading: a, error: o, refetch: s } = i({
46
+ function y(e, t = 20, n = 0, r = !0) {
47
+ let { data: a, loading: o, error: s, refetch: c } = i({
48
48
  variables: {
49
49
  status: e,
50
50
  limit: t,
51
51
  offset: n
52
52
  },
53
+ skip: !r,
53
54
  fetchPolicy: "cache-first",
54
55
  nextFetchPolicy: "cache-first"
55
56
  });
56
57
  return {
57
- invites: r?.myOrganizationInvites?.items ?? [],
58
- total: r?.myOrganizationInvites?.total ?? 0,
59
- hasMore: r?.myOrganizationInvites?.hasMore ?? !1,
60
- loading: a,
61
- error: o,
62
- refetch: s
58
+ invites: a?.myOrganizationInvites?.items ?? [],
59
+ total: a?.myOrganizationInvites?.total ?? 0,
60
+ hasMore: a?.myOrganizationInvites?.hasMore ?? !1,
61
+ loading: o,
62
+ error: s,
63
+ refetch: c
63
64
  };
64
65
  }
65
66
  function b() {
@@ -1 +1 @@
1
- {"version":3,"file":"useInvites.js","names":[],"sources":["../../../../../src/organization-management/modules/members/hooks/useInvites.ts"],"sourcesContent":["import { gql } from '@apollo/client';\nimport { useMutation } from '@apollo/client/react';\nimport {\n useInviteOrganizationMemberMutation,\n useRejectOrganizationInviteMutation,\n useCancelOrganizationInviteMutation,\n useResendOrganizationInviteMutation,\n useGetOrganizationInvitesQuery,\n useGetMyOrganizationInvitesQuery,\n GetOrganizationInvitesDocument,\n GetMyOrganizationInvitesDocument,\n GetMembersDocument,\n} from '../../../../generated/global-operations';\nimport type {\n InviteStatus,\n OrganizationInvite,\n OrganizationMember,\n} from '../../../../generated/global-types';\nimport { useOrganizationEventEmitter } from '../../../hooks/useOrganizationEventEmitter';\nimport { logger, redactId } from '../../../shared/logger';\nimport { executeRecaptcha } from '../../../shared/recaptcha';\n\nconst ACCEPT_ORGANIZATION_INVITE_WITH_CAPTCHA = gql`\n mutation AcceptOrganizationInviteWithCaptcha($inviteId: ID!, $recaptchaToken: String) {\n acceptOrganizationInvite(inviteId: $inviteId, recaptchaToken: $recaptchaToken) {\n id\n userId\n organizationId\n role\n joinedAt\n }\n }\n`;\n\ninterface AcceptOrganizationInviteData {\n acceptOrganizationInvite: OrganizationMember;\n}\n\ninterface AcceptOrganizationInviteVariables {\n inviteId: string;\n recaptchaToken?: string;\n}\n\ninterface GraphqlExtensions {\n code?: string;\n}\n\ninterface GraphqlError {\n message?: string;\n extensions?: GraphqlExtensions;\n}\n\ninterface ApolloLikeError {\n message?: string;\n graphQLErrors?: ReadonlyArray<GraphqlError>;\n}\n\nfunction extractErrorCode(error: unknown): string | undefined {\n const apolloError = error as ApolloLikeError | undefined;\n return apolloError?.graphQLErrors?.[0]?.extensions?.code;\n}\n\nfunction extractErrorMessage(error: unknown): string {\n if (error instanceof Error) return error.message;\n const apolloError = error as ApolloLikeError | undefined;\n return apolloError?.message ?? 'Unknown error';\n}\n\n/**\n * Hook to fetch organization invites (admin view)\n */\nexport function useOrganizationInvites(\n organizationId: string,\n filter?: { status?: InviteStatus },\n limit: number = 20,\n offset: number = 0\n) {\n const { data, loading, error, refetch } = useGetOrganizationInvitesQuery({\n variables: { organizationId, filter, limit, offset },\n skip: !organizationId,\n fetchPolicy: 'cache-first',\n nextFetchPolicy: 'cache-first',\n });\n\n return {\n invites: (data?.organizationInvites?.items ?? []) as OrganizationInvite[],\n total: data?.organizationInvites?.total ?? 0,\n hasMore: data?.organizationInvites?.hasMore ?? false,\n loading,\n error,\n refetch,\n };\n}\n\n/**\n * Hook to fetch invites for the current user (invitee view)\n */\nexport function useMyInvites(status?: InviteStatus, limit: number = 20, offset: number = 0) {\n const { data, loading, error, refetch } = useGetMyOrganizationInvitesQuery({\n variables: { status, limit, offset },\n fetchPolicy: 'cache-first',\n nextFetchPolicy: 'cache-first',\n });\n\n return {\n invites: (data?.myOrganizationInvites?.items ?? []) as OrganizationInvite[],\n total: data?.myOrganizationInvites?.total ?? 0,\n hasMore: data?.myOrganizationInvites?.hasMore ?? false,\n loading,\n error,\n refetch,\n };\n}\n\n/**\n * Hook to invite a member by email\n */\nexport function useInviteMember() {\n const { emit } = useOrganizationEventEmitter();\n const [inviteMember, { loading, error }] = useInviteOrganizationMemberMutation({\n refetchQueries: [GetOrganizationInvitesDocument],\n });\n\n return {\n inviteMember: async (input: { organizationId: string; email: string; message?: string }) => {\n logger.info('mutation.start', {\n name: 'inviteMember',\n organizationId: redactId(input.organizationId),\n });\n try {\n const result = await inviteMember({ variables: { input } });\n const inviteId = result.data?.inviteOrganizationMember?.id;\n emit('organization.invite.created', {\n organizationId: input.organizationId,\n inviteId,\n source: 'microfe-organization',\n });\n logger.info('mutation.success', {\n name: 'inviteMember',\n organizationId: redactId(input.organizationId),\n inviteId: redactId(inviteId),\n });\n return result;\n } catch (mutationError) {\n const errorCode = extractErrorCode(mutationError);\n const errorMessage = extractErrorMessage(mutationError);\n emit('organization.invite.create_failed', {\n organizationId: input.organizationId,\n source: 'microfe-organization',\n errorCode,\n errorMessage,\n });\n logger.error(\n 'mutation.failed',\n {\n name: 'inviteMember',\n organizationId: redactId(input.organizationId),\n errorCode,\n errorMessage,\n },\n mutationError\n );\n throw mutationError;\n }\n },\n loading,\n error,\n };\n}\n\n/**\n * Hook to accept an organization invite\n */\nexport function useAcceptInvite() {\n const { emit } = useOrganizationEventEmitter();\n const [acceptInvite, { loading, error }] = useMutation<\n AcceptOrganizationInviteData,\n AcceptOrganizationInviteVariables\n >(ACCEPT_ORGANIZATION_INVITE_WITH_CAPTCHA, {\n refetchQueries: [GetMyOrganizationInvitesDocument, GetMembersDocument],\n });\n\n return {\n acceptInvite: async (inviteId: string) => {\n logger.info('mutation.start', {\n name: 'acceptInvite',\n inviteId: redactId(inviteId),\n });\n try {\n const recaptchaToken = await executeRecaptcha('invite_accept');\n const result = await acceptInvite({\n variables: { inviteId, ...(recaptchaToken ? { recaptchaToken } : {}) },\n });\n emit('organization.invite.accepted', { inviteId, source: 'microfe-organization' });\n logger.info('mutation.success', {\n name: 'acceptInvite',\n inviteId: redactId(inviteId),\n });\n return result;\n } catch (mutationError) {\n const errorCode = extractErrorCode(mutationError);\n const errorMessage = extractErrorMessage(mutationError);\n emit('organization.invite.accept_failed', {\n inviteId,\n source: 'microfe-organization',\n errorCode,\n errorMessage,\n });\n logger.error(\n 'mutation.failed',\n {\n name: 'acceptInvite',\n inviteId: redactId(inviteId),\n errorCode,\n errorMessage,\n },\n mutationError\n );\n throw mutationError;\n }\n },\n loading,\n error,\n };\n}\n\n/**\n * Hook to reject an organization invite\n */\nexport function useRejectInvite() {\n const { emit } = useOrganizationEventEmitter();\n const [rejectInvite, { loading, error }] = useRejectOrganizationInviteMutation({\n refetchQueries: [GetMyOrganizationInvitesDocument],\n });\n\n return {\n rejectInvite: async (inviteId: string) => {\n logger.info('mutation.start', {\n name: 'rejectInvite',\n inviteId: redactId(inviteId),\n });\n try {\n const result = await rejectInvite({ variables: { inviteId } });\n emit('organization.invite.rejected', { inviteId, source: 'microfe-organization' });\n logger.info('mutation.success', {\n name: 'rejectInvite',\n inviteId: redactId(inviteId),\n });\n return result;\n } catch (mutationError) {\n const errorCode = extractErrorCode(mutationError);\n const errorMessage = extractErrorMessage(mutationError);\n emit('organization.invite.reject_failed', {\n inviteId,\n source: 'microfe-organization',\n errorCode,\n errorMessage,\n });\n logger.error(\n 'mutation.failed',\n {\n name: 'rejectInvite',\n inviteId: redactId(inviteId),\n errorCode,\n errorMessage,\n },\n mutationError\n );\n throw mutationError;\n }\n },\n loading,\n error,\n };\n}\n\n/**\n * Hook to cancel an organization invite\n */\nexport function useCancelInvite() {\n const { emit } = useOrganizationEventEmitter();\n const [cancelInvite, { loading, error }] = useCancelOrganizationInviteMutation({\n refetchQueries: [GetOrganizationInvitesDocument],\n });\n\n return {\n cancelInvite: async (inviteId: string) => {\n logger.info('mutation.start', {\n name: 'cancelInvite',\n inviteId: redactId(inviteId),\n });\n try {\n const result = await cancelInvite({ variables: { inviteId } });\n emit('organization.invite.cancelled', { inviteId, source: 'microfe-organization' });\n logger.info('mutation.success', {\n name: 'cancelInvite',\n inviteId: redactId(inviteId),\n });\n return result;\n } catch (mutationError) {\n const errorCode = extractErrorCode(mutationError);\n const errorMessage = extractErrorMessage(mutationError);\n emit('organization.invite.cancel_failed', {\n inviteId,\n source: 'microfe-organization',\n errorCode,\n errorMessage,\n });\n logger.error(\n 'mutation.failed',\n {\n name: 'cancelInvite',\n inviteId: redactId(inviteId),\n errorCode,\n errorMessage,\n },\n mutationError\n );\n throw mutationError;\n }\n },\n loading,\n error,\n };\n}\n\n/**\n * Hook to resend an organization invite\n */\nexport function useResendInvite() {\n const { emit } = useOrganizationEventEmitter();\n const [resendInvite, { loading, error }] = useResendOrganizationInviteMutation({\n refetchQueries: [GetOrganizationInvitesDocument],\n });\n\n return {\n resendInvite: async (inviteId: string) => {\n logger.info('mutation.start', {\n name: 'resendInvite',\n inviteId: redactId(inviteId),\n });\n try {\n const result = await resendInvite({ variables: { inviteId } });\n emit('organization.invite.resent', { inviteId, source: 'microfe-organization' });\n logger.info('mutation.success', {\n name: 'resendInvite',\n inviteId: redactId(inviteId),\n });\n return result;\n } catch (mutationError) {\n const errorCode = extractErrorCode(mutationError);\n const errorMessage = extractErrorMessage(mutationError);\n emit('organization.invite.resend_failed', {\n inviteId,\n source: 'microfe-organization',\n errorCode,\n errorMessage,\n });\n logger.error(\n 'mutation.failed',\n {\n name: 'resendInvite',\n inviteId: redactId(inviteId),\n errorCode,\n errorMessage,\n },\n mutationError\n );\n throw mutationError;\n }\n },\n loading,\n error,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"useInvites.js","names":[],"sources":["../../../../../src/organization-management/modules/members/hooks/useInvites.ts"],"sourcesContent":["import { gql } from '@apollo/client';\nimport { useMutation } from '@apollo/client/react';\nimport {\n useInviteOrganizationMemberMutation,\n useRejectOrganizationInviteMutation,\n useCancelOrganizationInviteMutation,\n useResendOrganizationInviteMutation,\n useGetOrganizationInvitesQuery,\n useGetMyOrganizationInvitesQuery,\n GetOrganizationInvitesDocument,\n GetMyOrganizationInvitesDocument,\n GetMembersDocument,\n} from '../../../../generated/global-operations';\nimport type {\n InviteStatus,\n OrganizationInvite,\n OrganizationMember,\n} from '../../../../generated/global-types';\nimport { useOrganizationEventEmitter } from '../../../hooks/useOrganizationEventEmitter';\nimport { logger, redactId } from '../../../shared/logger';\nimport { executeRecaptcha } from '../../../shared/recaptcha';\n\nconst ACCEPT_ORGANIZATION_INVITE_WITH_CAPTCHA = gql`\n mutation AcceptOrganizationInviteWithCaptcha($inviteId: ID!, $recaptchaToken: String) {\n acceptOrganizationInvite(inviteId: $inviteId, recaptchaToken: $recaptchaToken) {\n id\n userId\n organizationId\n role\n joinedAt\n }\n }\n`;\n\ninterface AcceptOrganizationInviteData {\n acceptOrganizationInvite: OrganizationMember;\n}\n\ninterface AcceptOrganizationInviteVariables {\n inviteId: string;\n recaptchaToken?: string;\n}\n\ninterface GraphqlExtensions {\n code?: string;\n}\n\ninterface GraphqlError {\n message?: string;\n extensions?: GraphqlExtensions;\n}\n\ninterface ApolloLikeError {\n message?: string;\n graphQLErrors?: ReadonlyArray<GraphqlError>;\n}\n\nfunction extractErrorCode(error: unknown): string | undefined {\n const apolloError = error as ApolloLikeError | undefined;\n return apolloError?.graphQLErrors?.[0]?.extensions?.code;\n}\n\nfunction extractErrorMessage(error: unknown): string {\n if (error instanceof Error) return error.message;\n const apolloError = error as ApolloLikeError | undefined;\n return apolloError?.message ?? 'Unknown error';\n}\n\n/**\n * Hook to fetch organization invites (admin view)\n */\nexport function useOrganizationInvites(\n organizationId: string,\n filter?: { status?: InviteStatus },\n limit: number = 20,\n offset: number = 0\n) {\n const { data, loading, error, refetch } = useGetOrganizationInvitesQuery({\n variables: { organizationId, filter, limit, offset },\n skip: !organizationId,\n fetchPolicy: 'cache-first',\n nextFetchPolicy: 'cache-first',\n });\n\n return {\n invites: (data?.organizationInvites?.items ?? []) as OrganizationInvite[],\n total: data?.organizationInvites?.total ?? 0,\n hasMore: data?.organizationInvites?.hasMore ?? false,\n loading,\n error,\n refetch,\n };\n}\n\n/**\n * Hook to fetch invites for the current user (invitee view).\n *\n * `enabled` defaults to `true` for backward compat. Callers in admin /\n * service contexts (e.g. OrganizationsListPage in `mode=\"admin\"`) should\n * pass `false` to skip the network round-trip and avoid surfacing\n * authorization errors for actors that don't hold the self-scope.\n */\nexport function useMyInvites(\n status?: InviteStatus,\n limit: number = 20,\n offset: number = 0,\n enabled: boolean = true\n) {\n const { data, loading, error, refetch } = useGetMyOrganizationInvitesQuery({\n variables: { status, limit, offset },\n skip: !enabled,\n fetchPolicy: 'cache-first',\n nextFetchPolicy: 'cache-first',\n });\n\n return {\n invites: (data?.myOrganizationInvites?.items ?? []) as OrganizationInvite[],\n total: data?.myOrganizationInvites?.total ?? 0,\n hasMore: data?.myOrganizationInvites?.hasMore ?? false,\n loading,\n error,\n refetch,\n };\n}\n\n/**\n * Hook to invite a member by email\n */\nexport function useInviteMember() {\n const { emit } = useOrganizationEventEmitter();\n const [inviteMember, { loading, error }] = useInviteOrganizationMemberMutation({\n refetchQueries: [GetOrganizationInvitesDocument],\n });\n\n return {\n inviteMember: async (input: { organizationId: string; email: string; message?: string }) => {\n logger.info('mutation.start', {\n name: 'inviteMember',\n organizationId: redactId(input.organizationId),\n });\n try {\n const result = await inviteMember({ variables: { input } });\n const inviteId = result.data?.inviteOrganizationMember?.id;\n emit('organization.invite.created', {\n organizationId: input.organizationId,\n inviteId,\n source: 'microfe-organization',\n });\n logger.info('mutation.success', {\n name: 'inviteMember',\n organizationId: redactId(input.organizationId),\n inviteId: redactId(inviteId),\n });\n return result;\n } catch (mutationError) {\n const errorCode = extractErrorCode(mutationError);\n const errorMessage = extractErrorMessage(mutationError);\n emit('organization.invite.create_failed', {\n organizationId: input.organizationId,\n source: 'microfe-organization',\n errorCode,\n errorMessage,\n });\n logger.error(\n 'mutation.failed',\n {\n name: 'inviteMember',\n organizationId: redactId(input.organizationId),\n errorCode,\n errorMessage,\n },\n mutationError\n );\n throw mutationError;\n }\n },\n loading,\n error,\n };\n}\n\n/**\n * Hook to accept an organization invite\n */\nexport function useAcceptInvite() {\n const { emit } = useOrganizationEventEmitter();\n const [acceptInvite, { loading, error }] = useMutation<\n AcceptOrganizationInviteData,\n AcceptOrganizationInviteVariables\n >(ACCEPT_ORGANIZATION_INVITE_WITH_CAPTCHA, {\n refetchQueries: [GetMyOrganizationInvitesDocument, GetMembersDocument],\n });\n\n return {\n acceptInvite: async (inviteId: string) => {\n logger.info('mutation.start', {\n name: 'acceptInvite',\n inviteId: redactId(inviteId),\n });\n try {\n const recaptchaToken = await executeRecaptcha('invite_accept');\n const result = await acceptInvite({\n variables: { inviteId, ...(recaptchaToken ? { recaptchaToken } : {}) },\n });\n emit('organization.invite.accepted', { inviteId, source: 'microfe-organization' });\n logger.info('mutation.success', {\n name: 'acceptInvite',\n inviteId: redactId(inviteId),\n });\n return result;\n } catch (mutationError) {\n const errorCode = extractErrorCode(mutationError);\n const errorMessage = extractErrorMessage(mutationError);\n emit('organization.invite.accept_failed', {\n inviteId,\n source: 'microfe-organization',\n errorCode,\n errorMessage,\n });\n logger.error(\n 'mutation.failed',\n {\n name: 'acceptInvite',\n inviteId: redactId(inviteId),\n errorCode,\n errorMessage,\n },\n mutationError\n );\n throw mutationError;\n }\n },\n loading,\n error,\n };\n}\n\n/**\n * Hook to reject an organization invite\n */\nexport function useRejectInvite() {\n const { emit } = useOrganizationEventEmitter();\n const [rejectInvite, { loading, error }] = useRejectOrganizationInviteMutation({\n refetchQueries: [GetMyOrganizationInvitesDocument],\n });\n\n return {\n rejectInvite: async (inviteId: string) => {\n logger.info('mutation.start', {\n name: 'rejectInvite',\n inviteId: redactId(inviteId),\n });\n try {\n const result = await rejectInvite({ variables: { inviteId } });\n emit('organization.invite.rejected', { inviteId, source: 'microfe-organization' });\n logger.info('mutation.success', {\n name: 'rejectInvite',\n inviteId: redactId(inviteId),\n });\n return result;\n } catch (mutationError) {\n const errorCode = extractErrorCode(mutationError);\n const errorMessage = extractErrorMessage(mutationError);\n emit('organization.invite.reject_failed', {\n inviteId,\n source: 'microfe-organization',\n errorCode,\n errorMessage,\n });\n logger.error(\n 'mutation.failed',\n {\n name: 'rejectInvite',\n inviteId: redactId(inviteId),\n errorCode,\n errorMessage,\n },\n mutationError\n );\n throw mutationError;\n }\n },\n loading,\n error,\n };\n}\n\n/**\n * Hook to cancel an organization invite\n */\nexport function useCancelInvite() {\n const { emit } = useOrganizationEventEmitter();\n const [cancelInvite, { loading, error }] = useCancelOrganizationInviteMutation({\n refetchQueries: [GetOrganizationInvitesDocument],\n });\n\n return {\n cancelInvite: async (inviteId: string) => {\n logger.info('mutation.start', {\n name: 'cancelInvite',\n inviteId: redactId(inviteId),\n });\n try {\n const result = await cancelInvite({ variables: { inviteId } });\n emit('organization.invite.cancelled', { inviteId, source: 'microfe-organization' });\n logger.info('mutation.success', {\n name: 'cancelInvite',\n inviteId: redactId(inviteId),\n });\n return result;\n } catch (mutationError) {\n const errorCode = extractErrorCode(mutationError);\n const errorMessage = extractErrorMessage(mutationError);\n emit('organization.invite.cancel_failed', {\n inviteId,\n source: 'microfe-organization',\n errorCode,\n errorMessage,\n });\n logger.error(\n 'mutation.failed',\n {\n name: 'cancelInvite',\n inviteId: redactId(inviteId),\n errorCode,\n errorMessage,\n },\n mutationError\n );\n throw mutationError;\n }\n },\n loading,\n error,\n };\n}\n\n/**\n * Hook to resend an organization invite\n */\nexport function useResendInvite() {\n const { emit } = useOrganizationEventEmitter();\n const [resendInvite, { loading, error }] = useResendOrganizationInviteMutation({\n refetchQueries: [GetOrganizationInvitesDocument],\n });\n\n return {\n resendInvite: async (inviteId: string) => {\n logger.info('mutation.start', {\n name: 'resendInvite',\n inviteId: redactId(inviteId),\n });\n try {\n const result = await resendInvite({ variables: { inviteId } });\n emit('organization.invite.resent', { inviteId, source: 'microfe-organization' });\n logger.info('mutation.success', {\n name: 'resendInvite',\n inviteId: redactId(inviteId),\n });\n return result;\n } catch (mutationError) {\n const errorCode = extractErrorCode(mutationError);\n const errorMessage = extractErrorMessage(mutationError);\n emit('organization.invite.resend_failed', {\n inviteId,\n source: 'microfe-organization',\n errorCode,\n errorMessage,\n });\n logger.error(\n 'mutation.failed',\n {\n name: 'resendInvite',\n inviteId: redactId(inviteId),\n errorCode,\n errorMessage,\n },\n mutationError\n );\n throw mutationError;\n }\n },\n loading,\n error,\n };\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"InviteMemberPage.d.ts","sourceRoot":"","sources":["../../../../../src/organization-management/modules/members/pages/InviteMemberPage.tsx"],"names":[],"mappings":"AAWA;;;GAGG;AACH,wBAAgB,gBAAgB,4CAsG/B"}
1
+ {"version":3,"file":"InviteMemberPage.d.ts","sourceRoot":"","sources":["../../../../../src/organization-management/modules/members/pages/InviteMemberPage.tsx"],"names":[],"mappings":"AAYA;;;GAGG;AACH,wBAAgB,gBAAgB,4CAuG/B"}
@@ -1,91 +1,92 @@
1
1
  import { useOrgConsole as e } from "../../../providers/OrgConsoleProvider.js";
2
- import { useTr as t } from "../../../shared/hooks/useTr.js";
3
- import { LoadingState as n } from "../../../shared/components/feedback/LoadingState.js";
4
- import { PERMISSIONS as r } from "../../../constants/permissions.js";
5
- import { useInviteMember as i } from "../hooks/useInvites.js";
6
- import { InviteMemberForm as a } from "../components/InviteMemberForm.js";
7
- import { PendingInvitesList as o } from "../components/PendingInvitesList.js";
8
- import { ArrowLeft as s, UserPlus as c } from "lucide-react";
9
- import { usePermissions as l } from "@burdenoff/fe-libs/shared/providers/shell";
10
- import { jsx as u, jsxs as d } from "react/jsx-runtime";
11
- import { useParams as f } from "react-router-dom";
2
+ import { toast as t } from "../../../../node_modules/sonner/dist/index.js";
3
+ import { useInviteMember as n } from "../hooks/useInvites.js";
4
+ import { useTr as r } from "../../../shared/hooks/useTr.js";
5
+ import { LoadingState as i } from "../../../shared/components/feedback/LoadingState.js";
6
+ import { PERMISSIONS as a } from "../../../constants/permissions.js";
7
+ import { InviteMemberForm as o } from "../components/InviteMemberForm.js";
8
+ import { PendingInvitesList as s } from "../components/PendingInvitesList.js";
9
+ import { ArrowLeft as c, UserPlus 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";
12
13
  //#region src/organization-management/modules/members/pages/InviteMemberPage.tsx
13
- function p() {
14
- let p = t(), { organizationId: m } = f(), { navigate: h, basePath: g = "/organizations" } = e(), { hasPermission: _, isLoading: v } = l(), { inviteMember: y, loading: b, error: x } = i(), S = async (e) => {
15
- await y(e);
16
- }, C = () => {
17
- h(`${g}/${m}/members`);
14
+ function m() {
15
+ let m = r(), { organizationId: h } = p(), { navigate: g, basePath: _ = "/organizations" } = e(), { hasPermission: v, isLoading: y } = u(), { inviteMember: b, loading: x, error: S } = n(), C = async (e) => {
16
+ await b(e), t.success(`${m("members.invite.success", "Invitation sent to")} ${e.email}`);
17
+ }, w = () => {
18
+ g(`${_}/${h}/members`);
18
19
  };
19
- return v ? /* @__PURE__ */ u("div", {
20
+ return y ? /* @__PURE__ */ d("div", {
20
21
  className: "min-h-full bg-[var(--color-bg-canvas)] p-6",
21
- children: /* @__PURE__ */ u(n, { message: p("common.loadingPermissions", "Loading permissions...") })
22
- }) : _(r.MEMBER_INVITE) ? /* @__PURE__ */ u("div", {
22
+ children: /* @__PURE__ */ d(i, { message: m("common.loadingPermissions", "Loading permissions...") })
23
+ }) : v(a.MEMBER_INVITE) ? /* @__PURE__ */ d("div", {
23
24
  className: "min-h-full bg-[var(--color-bg-canvas)] px-4 py-6 sm:px-6",
24
- children: /* @__PURE__ */ d("div", {
25
+ children: /* @__PURE__ */ f("div", {
25
26
  className: "mx-auto max-w-3xl space-y-8",
26
27
  children: [
27
- /* @__PURE__ */ d("div", {
28
+ /* @__PURE__ */ f("div", {
28
29
  className: "flex items-center gap-3",
29
- children: [/* @__PURE__ */ u("button", {
30
- onClick: C,
30
+ children: [/* @__PURE__ */ d("button", {
31
+ onClick: w,
31
32
  className: "rounded-lg p-2 transition-colors hover:bg-[var(--color-bg-subtle)]",
32
- "aria-label": p("members.invite.backToMembers", "Back to members"),
33
- children: /* @__PURE__ */ u(s, {
33
+ "aria-label": m("members.invite.backToMembers", "Back to members"),
34
+ children: /* @__PURE__ */ d(c, {
34
35
  size: 20,
35
36
  className: "text-[var(--color-text-secondary)]"
36
37
  })
37
- }), /* @__PURE__ */ d("div", {
38
+ }), /* @__PURE__ */ f("div", {
38
39
  className: "flex items-center gap-2",
39
- children: [/* @__PURE__ */ u(c, {
40
+ children: [/* @__PURE__ */ d(l, {
40
41
  size: 24,
41
42
  className: "text-[var(--color-text-primary)]"
42
- }), /* @__PURE__ */ u("h1", {
43
+ }), /* @__PURE__ */ d("h1", {
43
44
  className: "text-2xl font-bold text-[var(--color-text-primary)]",
44
- children: p("members.invite.title", "Invite Member")
45
+ children: m("members.invite.title", "Invite Member")
45
46
  })]
46
47
  })]
47
48
  }),
48
- /* @__PURE__ */ d("div", {
49
+ /* @__PURE__ */ f("div", {
49
50
  className: "bg-[var(--color-bg-surface)] rounded-xl border border-[var(--color-border-default)] p-6",
50
51
  children: [
51
- /* @__PURE__ */ u("h2", {
52
+ /* @__PURE__ */ d("h2", {
52
53
  className: "text-lg font-semibold text-[var(--color-text-primary)] mb-4",
53
- children: p("members.invite.send", "Send Invite")
54
+ children: m("members.invite.send", "Send Invite")
54
55
  }),
55
- /* @__PURE__ */ u("p", {
56
+ /* @__PURE__ */ d("p", {
56
57
  className: "text-sm text-[var(--color-text-muted)] mb-6",
57
- children: p("members.invite.description", "Enter the email address of the person you want to invite. They will receive an email notification and can accept or decline from their account.")
58
+ children: m("members.invite.description", "Enter the email address of the person you want to invite. They will receive an email notification and can accept or decline from their account.")
58
59
  }),
59
- x && /* @__PURE__ */ u("div", {
60
+ S && /* @__PURE__ */ d("div", {
60
61
  className: "mb-4 rounded-lg border border-[var(--color-status-error-border)] bg-[var(--color-status-error-bgSubtle)] p-3",
61
- children: /* @__PURE__ */ u("p", {
62
+ children: /* @__PURE__ */ d("p", {
62
63
  className: "text-sm text-[var(--color-status-error-text)]",
63
- children: x.message.includes("CONFLICT") ? p("members.invite.error.conflict", "An invite already exists for this email address.") : x.message.includes("already a member") ? p("members.invite.error.alreadyMember", "This user is already a member of the organization.") : x.message
64
+ children: S.message.includes("CONFLICT") ? m("members.invite.error.conflict", "An invite already exists for this email address.") : S.message.includes("already a member") ? m("members.invite.error.alreadyMember", "This user is already a member of the organization.") : S.message
64
65
  })
65
66
  }),
66
- /* @__PURE__ */ u(a, {
67
- organizationId: m,
68
- onSubmit: S,
69
- onCancel: C,
70
- loading: b
67
+ /* @__PURE__ */ d(o, {
68
+ organizationId: h,
69
+ onSubmit: C,
70
+ onCancel: w,
71
+ loading: x
71
72
  })
72
73
  ]
73
74
  }),
74
- /* @__PURE__ */ u("div", {
75
+ /* @__PURE__ */ d("div", {
75
76
  className: "bg-[var(--color-bg-surface)] rounded-xl border border-[var(--color-border-default)] p-6",
76
- children: /* @__PURE__ */ u(o, { organizationId: m })
77
+ children: /* @__PURE__ */ d(s, { organizationId: h })
77
78
  })
78
79
  ]
79
80
  })
80
- }) : /* @__PURE__ */ u("div", {
81
+ }) : /* @__PURE__ */ d("div", {
81
82
  className: "min-h-full bg-[var(--color-bg-canvas)] p-6",
82
- children: /* @__PURE__ */ u("div", {
83
+ children: /* @__PURE__ */ d("div", {
83
84
  className: "p-8 text-center text-[var(--color-text-secondary)]",
84
- children: p("members.invite.noPermission", "You don't have permission to invite members.")
85
+ children: m("members.invite.noPermission", "You don't have permission to invite members.")
85
86
  })
86
87
  });
87
88
  }
88
89
  //#endregion
89
- export { p as InviteMemberPage };
90
+ export { m as InviteMemberPage };
90
91
 
91
92
  //# sourceMappingURL=InviteMemberPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"InviteMemberPage.js","names":[],"sources":["../../../../../src/organization-management/modules/members/pages/InviteMemberPage.tsx"],"sourcesContent":["import { useParams } from 'react-router-dom';\nimport { ArrowLeft, UserPlus } from 'lucide-react';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useOrgConsole } from '../../../providers/OrgConsoleProvider';\nimport { useInviteMember } from '../hooks/useInvites';\nimport { InviteMemberForm } from '../components/InviteMemberForm';\nimport { PendingInvitesList } from '../components/PendingInvitesList';\nimport { LoadingState } from '../../../shared/components/feedback/LoadingState';\nimport { PERMISSIONS } from '../../../constants/permissions';\nimport { useTr } from '../../../shared/hooks/useTr';\n\n/**\n * Invite Member Page\n * Email-based invite form with pending invites list below\n */\nexport function InviteMemberPage() {\n const tr = useTr();\n const { organizationId } = useParams<{ organizationId: string }>();\n const { navigate, basePath = '/organizations' } = useOrgConsole();\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n const { inviteMember, loading, error } = useInviteMember();\n\n const handleSubmit = async (data: {\n organizationId: string;\n email: string;\n message?: string;\n }) => {\n await inviteMember(data);\n };\n\n const handleCancel = () => {\n navigate(`${basePath}/${organizationId}/members`);\n };\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_INVITE)) {\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.invite.noPermission', \"You don't have permission to invite members.\")}\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=\"mx-auto max-w-3xl space-y-8\">\n {/* Header */}\n <div className=\"flex items-center gap-3\">\n <button\n onClick={handleCancel}\n className=\"rounded-lg p-2 transition-colors hover:bg-[var(--color-bg-subtle)]\"\n aria-label={tr('members.invite.backToMembers', 'Back to members')}\n >\n <ArrowLeft size={20} className=\"text-[var(--color-text-secondary)]\" />\n </button>\n <div className=\"flex items-center gap-2\">\n <UserPlus size={24} className=\"text-[var(--color-text-primary)]\" />\n <h1 className=\"text-2xl font-bold text-[var(--color-text-primary)]\">\n {tr('members.invite.title', 'Invite Member')}\n </h1>\n </div>\n </div>\n\n {/* Invite Form Card */}\n <div className=\"bg-[var(--color-bg-surface)] rounded-xl border border-[var(--color-border-default)] p-6\">\n <h2 className=\"text-lg font-semibold text-[var(--color-text-primary)] mb-4\">\n {tr('members.invite.send', 'Send Invite')}\n </h2>\n <p className=\"text-sm text-[var(--color-text-muted)] mb-6\">\n {tr(\n 'members.invite.description',\n 'Enter the email address of the person you want to invite. They will receive an email notification and can accept or decline from their account.'\n )}\n </p>\n\n {error && (\n <div className=\"mb-4 rounded-lg border border-[var(--color-status-error-border)] bg-[var(--color-status-error-bgSubtle)] p-3\">\n <p className=\"text-sm text-[var(--color-status-error-text)]\">\n {error.message.includes('CONFLICT')\n ? tr(\n 'members.invite.error.conflict',\n 'An invite already exists for this email address.'\n )\n : error.message.includes('already a member')\n ? tr(\n 'members.invite.error.alreadyMember',\n 'This user is already a member of the organization.'\n )\n : error.message}\n </p>\n </div>\n )}\n\n <InviteMemberForm\n organizationId={organizationId!}\n onSubmit={handleSubmit}\n onCancel={handleCancel}\n loading={loading}\n />\n </div>\n\n {/* Pending Invites */}\n <div className=\"bg-[var(--color-bg-surface)] rounded-xl border border-[var(--color-border-default)] p-6\">\n <PendingInvitesList organizationId={organizationId!} />\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;AAeA,SAAgB,IAAmB;CACjC,IAAM,IAAK,GAAO,EACZ,EAAE,sBAAmB,GAAuC,EAC5D,EAAE,aAAU,cAAW,qBAAqB,GAAe,EAC3D,EAAE,kBAAe,WAAW,MAAuB,GAAgB,EACnE,EAAE,iBAAc,YAAS,aAAU,GAAiB,EAEpD,IAAe,OAAO,MAItB;AACJ,QAAM,EAAa,EAAK;IAGpB,UAAqB;AACzB,IAAS,GAAG,EAAS,GAAG,EAAe,UAAU;;AAqBnD,QAlBI,IAEA,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD,EAAc,SAAS,EAAG,6BAA6B,yBAAyB,EAAI,CAAA;EAChF,CAAA,GAIL,EAAc,EAAY,cAAc,GAW3C,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf;IAEE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,UAAD;MACE,SAAS;MACT,WAAU;MACV,cAAY,EAAG,gCAAgC,kBAAkB;gBAEjE,kBAAC,GAAD;OAAW,MAAM;OAAI,WAAU;OAAuC,CAAA;MAC/D,CAAA,EACT,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD;OAAU,MAAM;OAAI,WAAU;OAAqC,CAAA,EACnE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,wBAAwB,gBAAgB;OACzC,CAAA,CACD;QACF;;IAGN,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,uBAAuB,cAAc;OACtC,CAAA;MACL,kBAAC,KAAD;OAAG,WAAU;iBACV,EACC,8BACA,kJACD;OACC,CAAA;MAEH,KACC,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAM,QAAQ,SAAS,WAAW,GAC/B,EACE,iCACA,mDACD,GACD,EAAM,QAAQ,SAAS,mBAAmB,GACxC,EACE,sCACA,qDACD,GACD,EAAM;QACV,CAAA;OACA,CAAA;MAGR,kBAAC,GAAD;OACkB;OAChB,UAAU;OACV,UAAU;OACD;OACT,CAAA;MACE;;IAGN,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD,EAAoC,mBAAmB,CAAA;KACnD,CAAA;IACF;;EACF,CAAA,GAvEJ,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAG,+BAA+B,+CAA+C;GAC9E,CAAA;EACF,CAAA"}
1
+ {"version":3,"file":"InviteMemberPage.js","names":[],"sources":["../../../../../src/organization-management/modules/members/pages/InviteMemberPage.tsx"],"sourcesContent":["import { useParams } from 'react-router-dom';\nimport { ArrowLeft, UserPlus } from 'lucide-react';\nimport { toast } from 'sonner';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { useOrgConsole } from '../../../providers/OrgConsoleProvider';\nimport { useInviteMember } from '../hooks/useInvites';\nimport { InviteMemberForm } from '../components/InviteMemberForm';\nimport { PendingInvitesList } from '../components/PendingInvitesList';\nimport { LoadingState } from '../../../shared/components/feedback/LoadingState';\nimport { PERMISSIONS } from '../../../constants/permissions';\nimport { useTr } from '../../../shared/hooks/useTr';\n\n/**\n * Invite Member Page\n * Email-based invite form with pending invites list below\n */\nexport function InviteMemberPage() {\n const tr = useTr();\n const { organizationId } = useParams<{ organizationId: string }>();\n const { navigate, basePath = '/organizations' } = useOrgConsole();\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n const { inviteMember, loading, error } = useInviteMember();\n\n const handleSubmit = async (data: {\n organizationId: string;\n email: string;\n message?: string;\n }) => {\n await inviteMember(data);\n toast.success(`${tr('members.invite.success', 'Invitation sent to')} ${data.email}`);\n };\n\n const handleCancel = () => {\n navigate(`${basePath}/${organizationId}/members`);\n };\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_INVITE)) {\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.invite.noPermission', \"You don't have permission to invite members.\")}\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=\"mx-auto max-w-3xl space-y-8\">\n {/* Header */}\n <div className=\"flex items-center gap-3\">\n <button\n onClick={handleCancel}\n className=\"rounded-lg p-2 transition-colors hover:bg-[var(--color-bg-subtle)]\"\n aria-label={tr('members.invite.backToMembers', 'Back to members')}\n >\n <ArrowLeft size={20} className=\"text-[var(--color-text-secondary)]\" />\n </button>\n <div className=\"flex items-center gap-2\">\n <UserPlus size={24} className=\"text-[var(--color-text-primary)]\" />\n <h1 className=\"text-2xl font-bold text-[var(--color-text-primary)]\">\n {tr('members.invite.title', 'Invite Member')}\n </h1>\n </div>\n </div>\n\n {/* Invite Form Card */}\n <div className=\"bg-[var(--color-bg-surface)] rounded-xl border border-[var(--color-border-default)] p-6\">\n <h2 className=\"text-lg font-semibold text-[var(--color-text-primary)] mb-4\">\n {tr('members.invite.send', 'Send Invite')}\n </h2>\n <p className=\"text-sm text-[var(--color-text-muted)] mb-6\">\n {tr(\n 'members.invite.description',\n 'Enter the email address of the person you want to invite. They will receive an email notification and can accept or decline from their account.'\n )}\n </p>\n\n {error && (\n <div className=\"mb-4 rounded-lg border border-[var(--color-status-error-border)] bg-[var(--color-status-error-bgSubtle)] p-3\">\n <p className=\"text-sm text-[var(--color-status-error-text)]\">\n {error.message.includes('CONFLICT')\n ? tr(\n 'members.invite.error.conflict',\n 'An invite already exists for this email address.'\n )\n : error.message.includes('already a member')\n ? tr(\n 'members.invite.error.alreadyMember',\n 'This user is already a member of the organization.'\n )\n : error.message}\n </p>\n </div>\n )}\n\n <InviteMemberForm\n organizationId={organizationId!}\n onSubmit={handleSubmit}\n onCancel={handleCancel}\n loading={loading}\n />\n </div>\n\n {/* Pending Invites */}\n <div className=\"bg-[var(--color-bg-surface)] rounded-xl border border-[var(--color-border-default)] p-6\">\n <PendingInvitesList organizationId={organizationId!} />\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAgBA,SAAgB,IAAmB;CACjC,IAAM,IAAK,GAAO,EACZ,EAAE,sBAAmB,GAAuC,EAC5D,EAAE,aAAU,cAAW,qBAAqB,GAAe,EAC3D,EAAE,kBAAe,WAAW,MAAuB,GAAgB,EACnE,EAAE,iBAAc,YAAS,aAAU,GAAiB,EAEpD,IAAe,OAAO,MAItB;AAEJ,EADA,MAAM,EAAa,EAAK,EACxB,EAAM,QAAQ,GAAG,EAAG,0BAA0B,qBAAqB,CAAC,GAAG,EAAK,QAAQ;IAGhF,UAAqB;AACzB,IAAS,GAAG,EAAS,GAAG,EAAe,UAAU;;AAqBnD,QAlBI,IAEA,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD,EAAc,SAAS,EAAG,6BAA6B,yBAAyB,EAAI,CAAA;EAChF,CAAA,GAIL,EAAc,EAAY,cAAc,GAW3C,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf;IAEE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,UAAD;MACE,SAAS;MACT,WAAU;MACV,cAAY,EAAG,gCAAgC,kBAAkB;gBAEjE,kBAAC,GAAD;OAAW,MAAM;OAAI,WAAU;OAAuC,CAAA;MAC/D,CAAA,EACT,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD;OAAU,MAAM;OAAI,WAAU;OAAqC,CAAA,EACnE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,wBAAwB,gBAAgB;OACzC,CAAA,CACD;QACF;;IAGN,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAG,uBAAuB,cAAc;OACtC,CAAA;MACL,kBAAC,KAAD;OAAG,WAAU;iBACV,EACC,8BACA,kJACD;OACC,CAAA;MAEH,KACC,kBAAC,OAAD;OAAK,WAAU;iBACb,kBAAC,KAAD;QAAG,WAAU;kBACV,EAAM,QAAQ,SAAS,WAAW,GAC/B,EACE,iCACA,mDACD,GACD,EAAM,QAAQ,SAAS,mBAAmB,GACxC,EACE,sCACA,qDACD,GACD,EAAM;QACV,CAAA;OACA,CAAA;MAGR,kBAAC,GAAD;OACkB;OAChB,UAAU;OACV,UAAU;OACD;OACT,CAAA;MACE;;IAGN,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD,EAAoC,mBAAmB,CAAA;KACnD,CAAA;IACF;;EACF,CAAA,GAvEJ,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAG,+BAA+B,+CAA+C;GAC9E,CAAA;EACF,CAAA"}
@@ -1,8 +1,8 @@
1
- import { useTr as e } from "../../../shared/hooks/useTr.js";
2
- import { LoadingState as t } from "../../../shared/components/feedback/LoadingState.js";
3
- import { useOrganizationPageView as n } from "../../../hooks/useOrganizationPageView.js";
4
- import { useAcceptInvite as r, useMyInvites as i, useRejectInvite as a } from "../hooks/useInvites.js";
5
- import { InviteStatus as o } from "../../../../generated/global-types.js";
1
+ import { useAcceptInvite as e, useMyInvites as t, useRejectInvite as n } from "../hooks/useInvites.js";
2
+ import { InviteStatus as r } from "../../../../generated/global-types.js";
3
+ import { useTr as i } from "../../../shared/hooks/useTr.js";
4
+ import { LoadingState as a } from "../../../shared/components/feedback/LoadingState.js";
5
+ import { useOrganizationPageView as o } from "../../../hooks/useOrganizationPageView.js";
6
6
  import { MyInviteCard as s } from "../components/MyInviteCard.js";
7
7
  import { useState as c } from "react";
8
8
  import { AlertCircle as l, Loader2 as u, Mail as d } from "lucide-react";
@@ -10,8 +10,8 @@ import { usePermissions as f } from "@burdenoff/fe-libs/shared/providers/shell";
10
10
  import { jsx as p, jsxs as m } from "react/jsx-runtime";
11
11
  //#region src/organization-management/modules/members/pages/MyInvitesPage.tsx
12
12
  function h() {
13
- n("organizations.my-invites");
14
- let h = e(), { isLoading: g } = f(), { invites: _, loading: v, error: y, total: b } = i(o.Pending), { acceptInvite: x, loading: S } = r(), { rejectInvite: C, loading: w } = a(), [T, E] = c(null), D = async (e) => {
13
+ o("organizations.my-invites");
14
+ let h = i(), { isLoading: g } = f(), { invites: _, loading: v, error: y, total: b } = t(r.Pending), { acceptInvite: x, loading: S } = e(), { rejectInvite: C, loading: w } = n(), [T, E] = c(null), D = async (e) => {
15
15
  try {
16
16
  E(null), await x(e);
17
17
  } catch (e) {
@@ -26,7 +26,7 @@ function h() {
26
26
  };
27
27
  return g ? /* @__PURE__ */ p("div", {
28
28
  className: "min-h-full bg-[var(--color-bg-canvas)] p-6",
29
- children: /* @__PURE__ */ p(t, { message: h("common.loadingPermissions", "Loading permissions...") })
29
+ children: /* @__PURE__ */ p(a, { message: h("common.loadingPermissions", "Loading permissions...") })
30
30
  }) : v && _.length === 0 ? /* @__PURE__ */ p("div", {
31
31
  className: "flex items-center justify-center min-h-[300px]",
32
32
  children: /* @__PURE__ */ p(u, {
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Filter a set of organization ids down to those where the current user has
3
+ * a specific RBAC permission. Bulk-checks against the rbac service so the
4
+ * result tracks the authoritative evaluator — including overrides and any
5
+ * future OPA policies — instead of client-side-duplicating the
6
+ * role→permission mapping.
7
+ *
8
+ * The server caps a single bulk call at `CHECK_PERMISSIONS_BATCH_LIMIT`
9
+ * inputs, so when a user has more orgs than that we chunk into multiple
10
+ * parallel queries via `client.query()` and merge results positionally.
11
+ * Most users will fit in one batch; the chunking is defensive for power
12
+ * users / service accounts with many memberships (the WorkspaceForm
13
+ * caller fetches up to 100 orgs, so two batches is realistic).
14
+ *
15
+ * Use this whenever a control surface needs to constrain itself to "orgs
16
+ * where I can do X" rather than "orgs I'm a member of" — e.g. the org
17
+ * picker on Create Workspace, Invite Member targets, role-assignment
18
+ * dropdowns. The backend `@rbac` directives still enforce on submission;
19
+ * this is purely UX (don't show options that will 403).
20
+ */
21
+ export declare function useOrgsWithPermission(orgIds: readonly string[], resourceType: string, action: string): {
22
+ allowedIds: Set<string>;
23
+ loading: boolean;
24
+ isError: boolean;
25
+ };
26
+ //# sourceMappingURL=useOrgsWithPermission.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useOrgsWithPermission.d.ts","sourceRoot":"","sources":["../../../../../src/organization-management/modules/organizations/hooks/useOrgsWithPermission.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,GACb;IAAE,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAgGjE"}
@@ -0,0 +1,63 @@
1
+ import { CheckRbacPermissionsDocument as e } from "../../../../generated/global-operations.js";
2
+ import { ActorType as t } from "../../../../generated/global-types.js";
3
+ import { useEffect as n, useMemo as r, useState as i } from "react";
4
+ import { useAuth as a } from "@burdenoff/fe-libs/shared/providers/shell";
5
+ import { useApolloClient as o } from "@apollo/client/react";
6
+ //#region src/organization-management/modules/organizations/hooks/useOrgsWithPermission.ts
7
+ var s = 50;
8
+ function c(c, l, u) {
9
+ let { user: d } = a(), f = d?.id ?? "", p = o(), m = r(() => [...c], [r(() => c.join(""), [c])]), h = r(() => m.map((e) => ({
10
+ actorId: f,
11
+ actorType: t.User,
12
+ scopeId: e,
13
+ resourceType: l,
14
+ action: u
15
+ })), [
16
+ m,
17
+ f,
18
+ l,
19
+ u
20
+ ]), g = !f || m.length === 0, [_, v] = i([]), [y, b] = i(!1), [x, S] = i(!1);
21
+ return n(() => {
22
+ if (g) {
23
+ v([]), b(!1), S(!1);
24
+ return;
25
+ }
26
+ let t = !1;
27
+ b(!0), S(!1);
28
+ let n = [];
29
+ for (let e = 0; e < h.length; e += s) n.push(h.slice(e, e + s));
30
+ return Promise.all(n.map((t) => p.query({
31
+ query: e,
32
+ variables: { inputs: t },
33
+ fetchPolicy: "cache-first"
34
+ }))).then((e) => {
35
+ t || (v(e.flatMap((e) => e.data?.checkPermissions ?? [])), b(!1));
36
+ }).catch(() => {
37
+ t || (v([]), S(!0), b(!1));
38
+ }), () => {
39
+ t = !0;
40
+ };
41
+ }, [
42
+ p,
43
+ h,
44
+ g
45
+ ]), {
46
+ allowedIds: r(() => {
47
+ if (g) return /* @__PURE__ */ new Set();
48
+ let e = /* @__PURE__ */ new Set(), t = Math.min(_.length, m.length);
49
+ for (let n = 0; n < t; n += 1) _[n].allowed && m[n] && e.add(m[n]);
50
+ return e;
51
+ }, [
52
+ _,
53
+ m,
54
+ g
55
+ ]),
56
+ loading: !g && y,
57
+ isError: !g && x
58
+ };
59
+ }
60
+ //#endregion
61
+ export { c as useOrgsWithPermission };
62
+
63
+ //# sourceMappingURL=useOrgsWithPermission.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useOrgsWithPermission.js","names":[],"sources":["../../../../../src/organization-management/modules/organizations/hooks/useOrgsWithPermission.ts"],"sourcesContent":["import { useEffect, useMemo, useState } from 'react';\nimport { useApolloClient } from '@apollo/client/react';\nimport { useAuth } from '@burdenoff/fe-libs/shared/providers/shell';\nimport {\n CheckRbacPermissionsDocument,\n type CheckRbacPermissionsQuery,\n type CheckRbacPermissionsQueryVariables,\n} from '../../../../generated/global-operations';\nimport { ActorType } from '../../../../generated/global-types';\n\ntype PermissionCheckResult = CheckRbacPermissionsQuery['checkPermissions'][number];\n\n// Matches the server-side `MAX_BULK_CHECK_SIZE` on `checkPermissions`.\n// Kept as a constant so the chunking intent is explicit at the call site.\nconst CHECK_PERMISSIONS_BATCH_LIMIT = 50;\n\n/**\n * Filter a set of organization ids down to those where the current user has\n * a specific RBAC permission. Bulk-checks against the rbac service so the\n * result tracks the authoritative evaluator — including overrides and any\n * future OPA policies — instead of client-side-duplicating the\n * role→permission mapping.\n *\n * The server caps a single bulk call at `CHECK_PERMISSIONS_BATCH_LIMIT`\n * inputs, so when a user has more orgs than that we chunk into multiple\n * parallel queries via `client.query()` and merge results positionally.\n * Most users will fit in one batch; the chunking is defensive for power\n * users / service accounts with many memberships (the WorkspaceForm\n * caller fetches up to 100 orgs, so two batches is realistic).\n *\n * Use this whenever a control surface needs to constrain itself to \"orgs\n * where I can do X\" rather than \"orgs I'm a member of\" — e.g. the org\n * picker on Create Workspace, Invite Member targets, role-assignment\n * dropdowns. The backend `@rbac` directives still enforce on submission;\n * this is purely UX (don't show options that will 403).\n */\nexport function useOrgsWithPermission(\n orgIds: readonly string[],\n resourceType: string,\n action: string\n): { allowedIds: Set<string>; loading: boolean; isError: boolean } {\n const { user } = useAuth();\n const actorId = user?.id ?? '';\n const client = useApolloClient();\n\n // `stableKey` lets memos depend on the *values* of orgIds, not the array\n // reference — callers passing a fresh array with the same ids won't bust\n // the query cache or trigger refetch loops.\n const stableKey = useMemo(() => orgIds.join(''), [orgIds]);\n const stableIds = useMemo(() => [...orgIds], [stableKey]); // eslint-disable-line react-hooks/exhaustive-deps\n\n const inputs = useMemo(\n () =>\n stableIds.map((scopeId) => ({\n actorId,\n actorType: ActorType.User,\n scopeId,\n resourceType,\n action,\n })),\n [stableIds, actorId, resourceType, action]\n );\n\n const skip = !actorId || stableIds.length === 0;\n\n // Fan out the bulk check into <=BATCH_LIMIT-sized chunks, run them in\n // parallel via the Apollo client (so per-chunk caching still works), and\n // concat results in input order to preserve the positional contract.\n // We can't use multiple useQuery hooks here because the chunk count is\n // dynamic, hence the client.query + Promise.all pattern in an effect.\n const [results, setResults] = useState<PermissionCheckResult[]>([]);\n const [loading, setLoading] = useState(false);\n const [hadError, setHadError] = useState(false);\n\n useEffect(() => {\n if (skip) {\n setResults([]);\n setLoading(false);\n setHadError(false);\n return;\n }\n\n let cancelled = false;\n setLoading(true);\n setHadError(false);\n\n const chunks: (typeof inputs)[] = [];\n for (let i = 0; i < inputs.length; i += CHECK_PERMISSIONS_BATCH_LIMIT) {\n chunks.push(inputs.slice(i, i + CHECK_PERMISSIONS_BATCH_LIMIT));\n }\n\n Promise.all(\n chunks.map((chunk) =>\n client.query<CheckRbacPermissionsQuery, CheckRbacPermissionsQueryVariables>({\n query: CheckRbacPermissionsDocument,\n variables: { inputs: chunk },\n fetchPolicy: 'cache-first',\n })\n )\n )\n .then((responses) => {\n if (cancelled) return;\n const merged = responses.flatMap((r) => r.data?.checkPermissions ?? []);\n setResults(merged);\n setLoading(false);\n })\n .catch(() => {\n if (cancelled) return;\n setResults([]);\n setHadError(true);\n setLoading(false);\n });\n\n return () => {\n cancelled = true;\n };\n }, [client, inputs, skip]);\n\n const allowedIds = useMemo(() => {\n if (skip) return new Set<string>();\n const out = new Set<string>();\n // Length-guard the positional mapping so we never silently\n // mis-attribute a permission to the wrong org if the backend ever\n // truncates, reorders, or filters the response.\n const bounded = Math.min(results.length, stableIds.length);\n for (let i = 0; i < bounded; i += 1) {\n if (results[i].allowed && stableIds[i]) out.add(stableIds[i]);\n }\n return out;\n }, [results, stableIds, skip]);\n\n return {\n allowedIds,\n loading: !skip && loading,\n isError: !skip && hadError,\n };\n}\n"],"mappings":";;;;;;AAcA,IAAM,IAAgC;AAsBtC,SAAgB,EACd,GACA,GACA,GACiE;CACjE,IAAM,EAAE,YAAS,GAAS,EACpB,IAAU,GAAM,MAAM,IACtB,IAAS,GAAiB,EAM1B,IAAY,QAAc,CAAC,GAAG,EAAO,EAAE,CAD3B,QAAc,EAAO,KAAK,GAAG,EAAE,CAAC,EAAO,CAAC,CACF,CAAC,EAEnD,IAAS,QAEX,EAAU,KAAK,OAAa;EAC1B;EACA,WAAW,EAAU;EACrB;EACA;EACA;EACD,EAAE,EACL;EAAC;EAAW;EAAS;EAAc;EAAO,CAC3C,EAEK,IAAO,CAAC,KAAW,EAAU,WAAW,GAOxC,CAAC,GAAS,KAAc,EAAkC,EAAE,CAAC,EAC7D,CAAC,GAAS,KAAc,EAAS,GAAM,EACvC,CAAC,GAAU,KAAe,EAAS,GAAM;AA2D/C,QAzDA,QAAgB;AACd,MAAI,GAAM;AAGR,GAFA,EAAW,EAAE,CAAC,EACd,EAAW,GAAM,EACjB,EAAY,GAAM;AAClB;;EAGF,IAAI,IAAY;AAEhB,EADA,EAAW,GAAK,EAChB,EAAY,GAAM;EAElB,IAAM,IAA4B,EAAE;AACpC,OAAK,IAAI,IAAI,GAAG,IAAI,EAAO,QAAQ,KAAK,EACtC,GAAO,KAAK,EAAO,MAAM,GAAG,IAAI,EAA8B,CAAC;AAyBjE,SAtBA,QAAQ,IACN,EAAO,KAAK,MACV,EAAO,MAAqE;GAC1E,OAAO;GACP,WAAW,EAAE,QAAQ,GAAO;GAC5B,aAAa;GACd,CAAC,CACH,CACF,CACE,MAAM,MAAc;AACf,SAEJ,EADe,EAAU,SAAS,MAAM,EAAE,MAAM,oBAAoB,EAAE,CAAC,CACrD,EAClB,EAAW,GAAM;IACjB,CACD,YAAY;AACP,SACJ,EAAW,EAAE,CAAC,EACd,EAAY,GAAK,EACjB,EAAW,GAAM;IACjB,QAES;AACX,OAAY;;IAEb;EAAC;EAAQ;EAAQ;EAAK,CAAC,EAenB;EACL,YAdiB,QAAc;AAC/B,OAAI,EAAM,wBAAO,IAAI,KAAa;GAClC,IAAM,oBAAM,IAAI,KAAa,EAIvB,IAAU,KAAK,IAAI,EAAQ,QAAQ,EAAU,OAAO;AAC1D,QAAK,IAAI,IAAI,GAAG,IAAI,GAAS,KAAK,EAChC,CAAI,EAAQ,GAAG,WAAW,EAAU,MAAI,EAAI,IAAI,EAAU,GAAG;AAE/D,UAAO;KACN;GAAC;GAAS;GAAW;GAAK,CAAC;EAI5B,SAAS,CAAC,KAAQ;EAClB,SAAS,CAAC,KAAQ;EACnB"}
@@ -1 +1 @@
1
- {"version":3,"file":"OrganizationDetailPage.d.ts","sourceRoot":"","sources":["../../../../../src/organization-management/modules/organizations/pages/OrganizationDetailPage.tsx"],"names":[],"mappings":"AA4BA,wBAAgB,sBAAsB,4CAiVrC"}
1
+ {"version":3,"file":"OrganizationDetailPage.d.ts","sourceRoot":"","sources":["../../../../../src/organization-management/modules/organizations/pages/OrganizationDetailPage.tsx"],"names":[],"mappings":"AA4BA,wBAAgB,sBAAsB,4CAmWrC"}
@@ -102,13 +102,13 @@ function C() {
102
102
  })]
103
103
  }), /* @__PURE__ */ b("div", {
104
104
  className: "flex flex-col gap-3 sm:flex-row",
105
- children: [/* @__PURE__ */ b("button", {
105
+ children: [D(s.MEMBER_LIST) && /* @__PURE__ */ b("button", {
106
106
  onClick: () => T(`${E}/${w}/members`),
107
107
  className: "inline-flex min-h-11 items-center justify-center gap-2 rounded-lg border border-[var(--color-border-default)] px-4 py-2.5 text-[var(--color-text-primary)] transition-all duration-200 hover:bg-[var(--color-bg-subtle)]",
108
108
  children: [/* @__PURE__ */ y(_, {
109
109
  size: 16,
110
110
  "aria-hidden": "true"
111
- }), /* @__PURE__ */ y("span", { children: C("organizations.detail.manageMembers", "Manage Members") })]
111
+ }), /* @__PURE__ */ y("span", { children: D(s.MEMBER_INVITE) ? C("organizations.detail.manageMembers", "Manage Members") : C("organizations.detail.viewMembers", "View Members") })]
112
112
  }), D(s.ORG_UPDATE) && /* @__PURE__ */ b("button", {
113
113
  onClick: () => T(`${E}/${w}/edit`),
114
114
  className: "inline-flex min-h-11 items-center justify-center gap-2 rounded-lg bg-[var(--color-action-primary-bg)] px-4 py-2.5 text-[var(--color-action-primary-text)] transition-all duration-200 hover:opacity-90 active:scale-[0.98]",
@@ -281,11 +281,11 @@ function C() {
281
281
  "aria-hidden": "true"
282
282
  }),
283
283
  title: C("workspaces.list.emptyTitle", "No workspaces yet"),
284
- description: C("workspaces.list.emptyDescription", "Create a workspace when this organization is ready to collaborate with teams or projects."),
285
- action: {
284
+ description: D(s.WORKSPACE_CREATE) ? C("workspaces.list.emptyDescription", "Create a workspace when this organization is ready to collaborate with teams or projects.") : C("workspaces.list.emptyDescriptionViewer", "No workspaces have been created in this organization yet."),
285
+ action: D(s.WORKSPACE_CREATE) ? {
286
286
  label: C("workspaces.create.button", "Create Workspace"),
287
287
  onClick: () => T(`${E}/workspaces/new?organizationId=${w}`)
288
- }
288
+ } : void 0
289
289
  })
290
290
  })]
291
291
  })