@cedros/login-react 0.0.13 → 0.0.14

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 (185) hide show
  1. package/dist/AdminDepositList-CyT4VBH8.js +311 -0
  2. package/dist/AdminDepositList-CyT4VBH8.js.map +1 -0
  3. package/dist/AdminDepositList-b2AXtLg0.cjs +1 -0
  4. package/dist/AdminDepositList-b2AXtLg0.cjs.map +1 -0
  5. package/dist/{AdminWithdrawalHistory-BGjfrIe3.js → AdminWithdrawalHistory-Cud-yuWy.js} +295 -283
  6. package/dist/AdminWithdrawalHistory-Cud-yuWy.js.map +1 -0
  7. package/dist/AdminWithdrawalHistory-DL9zbu2b.cjs +1 -0
  8. package/dist/AdminWithdrawalHistory-DL9zbu2b.cjs.map +1 -0
  9. package/dist/{AuthenticationSettings-5Vi7Ib_A.cjs → AuthenticationSettings-D739nNul.cjs} +1 -1
  10. package/dist/{AuthenticationSettings-5Vi7Ib_A.cjs.map → AuthenticationSettings-D739nNul.cjs.map} +1 -1
  11. package/dist/AuthenticationSettings-DtLoxQ2z.cjs +1 -0
  12. package/dist/{AuthenticationSettings-BPAh1my6.cjs.map → AuthenticationSettings-DtLoxQ2z.cjs.map} +1 -1
  13. package/dist/{AuthenticationSettings-CJg8CJY9.js → AuthenticationSettings-Dx3JCI3m.js} +1 -1
  14. package/dist/{AuthenticationSettings-CJg8CJY9.js.map → AuthenticationSettings-Dx3JCI3m.js.map} +1 -1
  15. package/dist/{AuthenticationSettings-CR_i6TTS.js → AuthenticationSettings-vowmQPXz.js} +170 -140
  16. package/dist/{AuthenticationSettings-CR_i6TTS.js.map → AuthenticationSettings-vowmQPXz.js.map} +1 -1
  17. package/dist/{AutosaveStatus-CYkC2aI_.cjs → AutosaveStatus-CCrZszKA.cjs} +1 -1
  18. package/dist/{AutosaveStatus-CYkC2aI_.cjs.map → AutosaveStatus-CCrZszKA.cjs.map} +1 -1
  19. package/dist/{AutosaveStatus-N4uNS6-2.js → AutosaveStatus-Ciyt350A.js} +1 -1
  20. package/dist/{AutosaveStatus-N4uNS6-2.js.map → AutosaveStatus-Ciyt350A.js.map} +1 -1
  21. package/dist/{CreditSystemSettings-CIf_SfJq.js → CreditSystemSettings-BQ3h4CyM.js} +1 -1
  22. package/dist/{CreditSystemSettings-CIf_SfJq.js.map → CreditSystemSettings-BQ3h4CyM.js.map} +1 -1
  23. package/dist/{CreditSystemSettings-BnAOK_tT.cjs → CreditSystemSettings-C6dUsu72.cjs} +1 -1
  24. package/dist/{CreditSystemSettings-BnAOK_tT.cjs.map → CreditSystemSettings-C6dUsu72.cjs.map} +1 -1
  25. package/dist/{CreditSystemSettings-Ck5WIMp3.cjs → CreditSystemSettings-CBot8EPW.cjs} +1 -1
  26. package/dist/{CreditSystemSettings-Ck5WIMp3.cjs.map → CreditSystemSettings-CBot8EPW.cjs.map} +1 -1
  27. package/dist/{CreditSystemSettings-CePYGgev.js → CreditSystemSettings-bVuNLsqp.js} +1 -1
  28. package/dist/{CreditSystemSettings-CePYGgev.js.map → CreditSystemSettings-bVuNLsqp.js.map} +1 -1
  29. package/dist/DepositsSection-BkKUS4vk.cjs +1 -0
  30. package/dist/DepositsSection-BkKUS4vk.cjs.map +1 -0
  31. package/dist/{DepositsSection-DA89uR9A.js → DepositsSection-DD9MKUFt.js} +20 -14
  32. package/dist/DepositsSection-DD9MKUFt.js.map +1 -0
  33. package/dist/EmailRegisterForm-Pvm3I8GP.cjs +1 -0
  34. package/dist/{EmailRegisterForm-CxktR-4J.cjs.map → EmailRegisterForm-Pvm3I8GP.cjs.map} +1 -1
  35. package/dist/{EmailRegisterForm-BrDL3BZy.js → EmailRegisterForm-nI0BOIxR.js} +2 -2
  36. package/dist/{EmailRegisterForm-BrDL3BZy.js.map → EmailRegisterForm-nI0BOIxR.js.map} +1 -1
  37. package/dist/{EmailSettings-DZywTTRq.cjs → EmailSettings-B9qwPSiM.cjs} +1 -1
  38. package/dist/{EmailSettings-DZywTTRq.cjs.map → EmailSettings-B9qwPSiM.cjs.map} +1 -1
  39. package/dist/{EmailSettings-DbMDfVaM.js → EmailSettings-CCA8dNCi.js} +1 -1
  40. package/dist/{EmailSettings-DbMDfVaM.js.map → EmailSettings-CCA8dNCi.js.map} +1 -1
  41. package/dist/{EmailSettings-B8xwgd6_.cjs → EmailSettings-RbgAq9FB.cjs} +1 -1
  42. package/dist/{EmailSettings-B8xwgd6_.cjs.map → EmailSettings-RbgAq9FB.cjs.map} +1 -1
  43. package/dist/{EmailSettings-Bna7Z53E.js → EmailSettings-mxlKNcPl.js} +1 -1
  44. package/dist/{EmailSettings-Bna7Z53E.js.map → EmailSettings-mxlKNcPl.js.map} +1 -1
  45. package/dist/{EmbeddedWalletSettings-DivEPn39.cjs → EmbeddedWalletSettings-B4h-8rxB.cjs} +1 -1
  46. package/dist/{EmbeddedWalletSettings-DivEPn39.cjs.map → EmbeddedWalletSettings-B4h-8rxB.cjs.map} +1 -1
  47. package/dist/{EmbeddedWalletSettings-BEztqO19.js → EmbeddedWalletSettings-BInZvFZf.js} +1 -1
  48. package/dist/{EmbeddedWalletSettings-BEztqO19.js.map → EmbeddedWalletSettings-BInZvFZf.js.map} +1 -1
  49. package/dist/{EmbeddedWalletSettings-ANbhj3Lt.js → EmbeddedWalletSettings-CXlZFFDw.js} +1 -1
  50. package/dist/{EmbeddedWalletSettings-ANbhj3Lt.js.map → EmbeddedWalletSettings-CXlZFFDw.js.map} +1 -1
  51. package/dist/{EmbeddedWalletSettings-D6M7pwgk.cjs → EmbeddedWalletSettings-D5JXae1L.cjs} +1 -1
  52. package/dist/{EmbeddedWalletSettings-D6M7pwgk.cjs.map → EmbeddedWalletSettings-D5JXae1L.cjs.map} +1 -1
  53. package/dist/{GoogleLoginButton-B3uRMJ_n.js → GoogleLoginButton-CXwp4LsQ.js} +1 -1
  54. package/dist/{GoogleLoginButton-B3uRMJ_n.js.map → GoogleLoginButton-CXwp4LsQ.js.map} +1 -1
  55. package/dist/GoogleLoginButton-zS_69-KV.cjs +1 -0
  56. package/dist/{GoogleLoginButton-BydKswn4.cjs.map → GoogleLoginButton-zS_69-KV.cjs.map} +1 -1
  57. package/dist/PermissionsSection-BPbE-hNx.cjs +1 -0
  58. package/dist/{PermissionsSection-CKXXDfqi.cjs.map → PermissionsSection-BPbE-hNx.cjs.map} +1 -1
  59. package/dist/{PermissionsSection-BGaj_sI7.js → PermissionsSection-CighC1p6.js} +3 -3
  60. package/dist/{PermissionsSection-BGaj_sI7.js.map → PermissionsSection-CighC1p6.js.map} +1 -1
  61. package/dist/{ServerSettings-B2RKhJtZ.js → ServerSettings-BE8fsE5k.js} +1 -1
  62. package/dist/{ServerSettings-B2RKhJtZ.js.map → ServerSettings-BE8fsE5k.js.map} +1 -1
  63. package/dist/{ServerSettings-BZXlm1BX.cjs → ServerSettings-CYTlQ2xy.cjs} +1 -1
  64. package/dist/{ServerSettings-BZXlm1BX.cjs.map → ServerSettings-CYTlQ2xy.cjs.map} +1 -1
  65. package/dist/{ServerSettings-DZUKo6By.cjs → ServerSettings-DFs9jQ3f.cjs} +1 -1
  66. package/dist/{ServerSettings-DZUKo6By.cjs.map → ServerSettings-DFs9jQ3f.cjs.map} +1 -1
  67. package/dist/{ServerSettings-Bqm4-bt2.js → ServerSettings-pSmWDC1d.js} +1 -1
  68. package/dist/{ServerSettings-Bqm4-bt2.js.map → ServerSettings-pSmWDC1d.js.map} +1 -1
  69. package/dist/{SettingsPageLayout-DpgNEkuu.js → SettingsPageLayout--GZ_iHLc.js} +1 -1
  70. package/dist/{SettingsPageLayout-DpgNEkuu.js.map → SettingsPageLayout--GZ_iHLc.js.map} +1 -1
  71. package/dist/{SettingsPageLayout-COSYLMu7.cjs → SettingsPageLayout-j5lMjEID.cjs} +1 -1
  72. package/dist/{SettingsPageLayout-COSYLMu7.cjs.map → SettingsPageLayout-j5lMjEID.cjs.map} +1 -1
  73. package/dist/SolanaLoginButton-BjOxpE1C.cjs +1 -0
  74. package/dist/{SolanaLoginButton-fAW7kRUu.cjs.map → SolanaLoginButton-BjOxpE1C.cjs.map} +1 -1
  75. package/dist/{SolanaLoginButton-C_u9OppS.js → SolanaLoginButton-P22QjBaO.js} +1 -1
  76. package/dist/{SolanaLoginButton-C_u9OppS.js.map → SolanaLoginButton-P22QjBaO.js.map} +1 -1
  77. package/dist/{TeamSection-CvrCoa9D.js → TeamSection-BIECkp7g.js} +2 -2
  78. package/dist/{TeamSection-CvrCoa9D.js.map → TeamSection-BIECkp7g.js.map} +1 -1
  79. package/dist/{TeamSection-DlUD5kp5.cjs → TeamSection-BOH9pv_E.cjs} +1 -1
  80. package/dist/{TeamSection-DlUD5kp5.cjs.map → TeamSection-BOH9pv_E.cjs.map} +1 -1
  81. package/dist/UsersSection-e6q7FHzx.cjs +1 -0
  82. package/dist/UsersSection-e6q7FHzx.cjs.map +1 -0
  83. package/dist/UsersSection-t-zm0jZW.js +33 -0
  84. package/dist/UsersSection-t-zm0jZW.js.map +1 -0
  85. package/dist/{WebhookSettings-bUg2u_p0.js → WebhookSettings-Bb70MbFj.js} +1 -1
  86. package/dist/{WebhookSettings-bUg2u_p0.js.map → WebhookSettings-Bb70MbFj.js.map} +1 -1
  87. package/dist/{WebhookSettings-BWl_wsvg.cjs → WebhookSettings-C-gvNAW1.cjs} +1 -1
  88. package/dist/{WebhookSettings-BWl_wsvg.cjs.map → WebhookSettings-C-gvNAW1.cjs.map} +1 -1
  89. package/dist/{WebhookSettings-DXNH5bal.cjs → WebhookSettings-CGyDKjrm.cjs} +1 -1
  90. package/dist/{WebhookSettings-DXNH5bal.cjs.map → WebhookSettings-CGyDKjrm.cjs.map} +1 -1
  91. package/dist/{WebhookSettings-BT5q6AZ8.js → WebhookSettings-kIstSjZi.js} +1 -1
  92. package/dist/{WebhookSettings-BT5q6AZ8.js.map → WebhookSettings-kIstSjZi.js.map} +1 -1
  93. package/dist/WithdrawalsSection-sljIyeaz.cjs +1 -0
  94. package/dist/WithdrawalsSection-sljIyeaz.cjs.map +1 -0
  95. package/dist/WithdrawalsSection-yRDTVFsb.js +27 -0
  96. package/dist/WithdrawalsSection-yRDTVFsb.js.map +1 -0
  97. package/dist/admin-only.cjs +1 -1
  98. package/dist/admin-only.js +1 -1
  99. package/dist/email-only.cjs +1 -1
  100. package/dist/email-only.d.ts +13 -2
  101. package/dist/email-only.js +3 -3
  102. package/dist/google-only.cjs +1 -1
  103. package/dist/google-only.d.ts +13 -2
  104. package/dist/google-only.js +3 -3
  105. package/dist/index.cjs +12 -12
  106. package/dist/index.cjs.map +1 -1
  107. package/dist/index.d.ts +31 -8
  108. package/dist/index.js +1066 -1092
  109. package/dist/index.js.map +1 -1
  110. package/dist/{plugin-BtYBW6JY.cjs → plugin-8_dpq7tC.cjs} +1 -1
  111. package/dist/{plugin-BtYBW6JY.cjs.map → plugin-8_dpq7tC.cjs.map} +1 -1
  112. package/dist/{plugin-5qRh-YhX.js → plugin-D1NdppqC.js} +1 -1
  113. package/dist/{plugin-5qRh-YhX.js.map → plugin-D1NdppqC.js.map} +1 -1
  114. package/dist/{shamir-AeLLfw0p.cjs → shamir-4DyQMJCk.cjs} +1 -1
  115. package/dist/{shamir-AeLLfw0p.cjs.map → shamir-4DyQMJCk.cjs.map} +1 -1
  116. package/dist/{shamir-B0wConeK.js → shamir-L-s-Tp1Z.js} +1 -1
  117. package/dist/{shamir-B0wConeK.js.map → shamir-L-s-Tp1Z.js.map} +1 -1
  118. package/dist/silentWalletEnroll-BgTb4H5I.cjs +1 -0
  119. package/dist/{silentWalletEnroll-B8pgdKZO.cjs.map → silentWalletEnroll-BgTb4H5I.cjs.map} +1 -1
  120. package/dist/{silentWalletEnroll-DR2kPw7W.js → silentWalletEnroll-DWt6Pr3B.js} +3 -3
  121. package/dist/{silentWalletEnroll-DR2kPw7W.js.map → silentWalletEnroll-DWt6Pr3B.js.map} +1 -1
  122. package/dist/solana-only.cjs +1 -1
  123. package/dist/solana-only.d.ts +13 -2
  124. package/dist/solana-only.js +3 -3
  125. package/dist/{useAdminDeposits-BDY5KJ0-.js → useAdminDeposits-BTSyeAfg.js} +1 -1
  126. package/dist/{useAdminDeposits-BDY5KJ0-.js.map → useAdminDeposits-BTSyeAfg.js.map} +1 -1
  127. package/dist/useAdminDeposits-BkkCwHWp.cjs +1 -0
  128. package/dist/{useAdminDeposits-Dvx3_UUE.cjs.map → useAdminDeposits-BkkCwHWp.cjs.map} +1 -1
  129. package/dist/{useAuth-Bge6KaWN.js → useAuth-C3dpk0po.js} +597 -561
  130. package/dist/useAuth-C3dpk0po.js.map +1 -0
  131. package/dist/useAuth-D3Pk_H3z.cjs +1 -0
  132. package/dist/useAuth-D3Pk_H3z.cjs.map +1 -0
  133. package/dist/useCedrosLogin-C9MrcZvh.cjs +1 -0
  134. package/dist/useCedrosLogin-C9MrcZvh.cjs.map +1 -0
  135. package/dist/{apiClient-B2JxVPlH.js → useCedrosLogin-_94MmGGq.js} +29 -29
  136. package/dist/useCedrosLogin-_94MmGGq.js.map +1 -0
  137. package/dist/{useOrgs-Be3KH4ib.js → useOrgs-C3pzMA9h.js} +1 -1
  138. package/dist/{useOrgs-Be3KH4ib.js.map → useOrgs-C3pzMA9h.js.map} +1 -1
  139. package/dist/useOrgs-DDVRCaVi.cjs +1 -0
  140. package/dist/{useOrgs-CVbacmaQ.cjs.map → useOrgs-DDVRCaVi.cjs.map} +1 -1
  141. package/dist/{useSystemSettings-DN5YqfNq.js → useSystemSettings-DBlAMjFi.js} +1 -1
  142. package/dist/{useSystemSettings-DN5YqfNq.js.map → useSystemSettings-DBlAMjFi.js.map} +1 -1
  143. package/dist/useSystemSettings-DRrreszl.cjs +1 -0
  144. package/dist/{useSystemSettings-D9Cr7ZTl.cjs.map → useSystemSettings-DRrreszl.cjs.map} +1 -1
  145. package/dist/useUsersStatsSummary-8qY7iP4G.cjs +1 -0
  146. package/dist/useUsersStatsSummary-8qY7iP4G.cjs.map +1 -0
  147. package/dist/{AdminUserDetail-DHFDzY8B.js → useUsersStatsSummary-NjEFvWuz.js} +431 -380
  148. package/dist/useUsersStatsSummary-NjEFvWuz.js.map +1 -0
  149. package/package.json +1 -1
  150. package/dist/AdminDepositList-Cx0xRwES.js +0 -305
  151. package/dist/AdminDepositList-Cx0xRwES.js.map +0 -1
  152. package/dist/AdminDepositList-UEcyRZkA.cjs +0 -1
  153. package/dist/AdminDepositList-UEcyRZkA.cjs.map +0 -1
  154. package/dist/AdminUserDetail-BzEIdNJh.cjs +0 -1
  155. package/dist/AdminUserDetail-BzEIdNJh.cjs.map +0 -1
  156. package/dist/AdminUserDetail-DHFDzY8B.js.map +0 -1
  157. package/dist/AdminWithdrawalHistory-0yxtMh6q.cjs +0 -1
  158. package/dist/AdminWithdrawalHistory-0yxtMh6q.cjs.map +0 -1
  159. package/dist/AdminWithdrawalHistory-BGjfrIe3.js.map +0 -1
  160. package/dist/AuthenticationSettings-BPAh1my6.cjs +0 -1
  161. package/dist/DepositsSection-DA89uR9A.js.map +0 -1
  162. package/dist/DepositsSection-i6XdhLNs.cjs +0 -1
  163. package/dist/DepositsSection-i6XdhLNs.cjs.map +0 -1
  164. package/dist/EmailRegisterForm-CxktR-4J.cjs +0 -1
  165. package/dist/GoogleLoginButton-BydKswn4.cjs +0 -1
  166. package/dist/PermissionsSection-CKXXDfqi.cjs +0 -1
  167. package/dist/SolanaLoginButton-fAW7kRUu.cjs +0 -1
  168. package/dist/UsersSection-C2U8Tb7V.cjs +0 -1
  169. package/dist/UsersSection-C2U8Tb7V.cjs.map +0 -1
  170. package/dist/UsersSection-Dbh9PTSA.js +0 -83
  171. package/dist/UsersSection-Dbh9PTSA.js.map +0 -1
  172. package/dist/WithdrawalsSection-BL_LOUq8.cjs +0 -1
  173. package/dist/WithdrawalsSection-BL_LOUq8.cjs.map +0 -1
  174. package/dist/WithdrawalsSection-CN-lLnqX.js +0 -20
  175. package/dist/WithdrawalsSection-CN-lLnqX.js.map +0 -1
  176. package/dist/apiClient-B2JxVPlH.js.map +0 -1
  177. package/dist/apiClient-CTTKhsYb.cjs +0 -1
  178. package/dist/apiClient-CTTKhsYb.cjs.map +0 -1
  179. package/dist/silentWalletEnroll-B8pgdKZO.cjs +0 -1
  180. package/dist/useAdminDeposits-Dvx3_UUE.cjs +0 -1
  181. package/dist/useAuth-Bge6KaWN.js.map +0 -1
  182. package/dist/useAuth-DhIDTLRd.cjs +0 -1
  183. package/dist/useAuth-DhIDTLRd.cjs.map +0 -1
  184. package/dist/useOrgs-CVbacmaQ.cjs +0 -1
  185. package/dist/useSystemSettings-D9Cr7ZTl.cjs +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"PermissionsSection-BGaj_sI7.js","sources":["../src/components/members/MemberList.tsx","../src/components/invites/InviteForm.tsx","../src/components/invites/InviteList.tsx","../src/utils/memberApi.ts","../src/hooks/useMembers.ts","../src/utils/inviteApi.ts","../src/hooks/useInvites.ts","../src/hooks/useServerFeatures.ts","../src/types/org.ts","../src/hooks/useDashboardPermissions.ts","../src/components/admin/PermissionsSection.tsx"],"sourcesContent":["import { useState, useCallback, useMemo } from 'react';\nimport type { Member, OrgRole, DisplayError } from '../../types';\nimport { LoadingSpinner } from '../shared/LoadingSpinner';\nimport { ErrorMessage } from '../shared/ErrorMessage';\nimport { sanitizeImageUrl } from '../../utils/sanitization';\n\ntype SortField = 'name' | 'role' | 'joinedAt';\ntype SortOrder = 'asc' | 'desc';\n\nexport interface MemberListProps {\n /** List of members to display */\n members: Member[];\n /** Current user's ID (to prevent self-actions) */\n currentUserId?: string;\n /** Loading state */\n isLoading?: boolean;\n /** Error message */\n error?: DisplayError;\n /** Whether the current user can manage members */\n canManage?: boolean;\n /** Whether the current user can change roles */\n canChangeRoles?: boolean;\n /** Callback when role is updated */\n onUpdateRole?: (userId: string, role: OrgRole) => Promise<void>;\n /** Callback when member is removed */\n onRemove?: (userId: string) => Promise<void>;\n /** Additional CSS class */\n className?: string;\n}\n\nconst ROLE_OPTIONS: OrgRole[] = ['owner', 'admin', 'member'];\n\n/**\n * Display and manage organization members.\n *\n * @example\n * ```tsx\n * function TeamMembers() {\n * const { activeOrg, hasPermission } = useOrgs();\n * const { members, isLoading, error, updateMemberRole, removeMember } = useMembers(activeOrg?.id);\n * const { user } = useAuth();\n *\n * return (\n * <MemberList\n * members={members}\n * currentUserId={user?.id}\n * isLoading={isLoading}\n * error={error?.message}\n * canManage={hasPermission('member:remove')}\n * canChangeRoles={hasPermission('member:role_change')}\n * onUpdateRole={updateMemberRole}\n * onRemove={removeMember}\n * />\n * );\n * }\n * ```\n */\nexport function MemberList({\n members,\n currentUserId,\n isLoading = false,\n error,\n canManage = false,\n canChangeRoles = false,\n onUpdateRole,\n onRemove,\n className = '',\n}: MemberListProps) {\n const [sortField, setSortField] = useState<SortField>('name');\n const [sortOrder, setSortOrder] = useState<SortOrder>('asc');\n\n const toggleSort = (field: SortField) => {\n if (sortField === field) {\n setSortOrder(sortOrder === 'asc' ? 'desc' : 'asc');\n } else {\n setSortField(field);\n setSortOrder('asc');\n }\n };\n\n const sortedMembers = useMemo(() => {\n const roleOrder: Record<OrgRole, number> = { owner: 0, admin: 1, member: 2 };\n return [...members].sort((a, b) => {\n let aVal: string | number;\n let bVal: string | number;\n\n switch (sortField) {\n case 'name':\n aVal = (a.user.name || a.user.email || '').toLowerCase();\n bVal = (b.user.name || b.user.email || '').toLowerCase();\n break;\n case 'role':\n aVal = roleOrder[a.role] ?? 99;\n bVal = roleOrder[b.role] ?? 99;\n break;\n case 'joinedAt':\n aVal = new Date(a.joinedAt).getTime();\n bVal = new Date(b.joinedAt).getTime();\n break;\n default:\n return 0;\n }\n\n if (aVal < bVal) return sortOrder === 'asc' ? -1 : 1;\n if (aVal > bVal) return sortOrder === 'asc' ? 1 : -1;\n return 0;\n });\n }, [members, sortField, sortOrder]);\n\n if (isLoading && members.length === 0) {\n return (\n <div className={`cedros-member-list cedros-member-list-loading ${className}`}>\n <LoadingSpinner />\n <span>Loading members...</span>\n </div>\n );\n }\n\n if (error) {\n return (\n <div className={`cedros-member-list ${className}`}>\n <ErrorMessage error={error} />\n </div>\n );\n }\n\n if (members.length === 0) {\n return (\n <div className={`cedros-member-list cedros-member-list-empty ${className}`}>\n <p>No members found.</p>\n </div>\n );\n }\n\n return (\n <div className={`cedros-member-list ${className}`}>\n <table className=\"cedros-member-table\">\n <thead>\n <tr>\n <th>\n <button\n type=\"button\"\n className={`cedros-admin-sort-button ${sortField === 'name' ? 'cedros-admin-sort-active' : ''}`}\n onClick={() => toggleSort('name')}\n >\n Member{' '}\n <span className=\"cedros-admin-sort-icon\">\n {sortField === 'name' ? (sortOrder === 'asc' ? '↑' : '↓') : '↕'}\n </span>\n </button>\n </th>\n <th>\n <button\n type=\"button\"\n className={`cedros-admin-sort-button ${sortField === 'role' ? 'cedros-admin-sort-active' : ''}`}\n onClick={() => toggleSort('role')}\n >\n Role{' '}\n <span className=\"cedros-admin-sort-icon\">\n {sortField === 'role' ? (sortOrder === 'asc' ? '↑' : '↓') : '↕'}\n </span>\n </button>\n </th>\n <th>\n <button\n type=\"button\"\n className={`cedros-admin-sort-button ${sortField === 'joinedAt' ? 'cedros-admin-sort-active' : ''}`}\n onClick={() => toggleSort('joinedAt')}\n >\n Joined{' '}\n <span className=\"cedros-admin-sort-icon\">\n {sortField === 'joinedAt' ? (sortOrder === 'asc' ? '↑' : '↓') : '↕'}\n </span>\n </button>\n </th>\n {(canManage || canChangeRoles) && <th>Actions</th>}\n </tr>\n </thead>\n <tbody>\n {sortedMembers.map((member) => (\n <MemberRow\n key={member.id}\n member={member}\n isCurrentUser={member.userId === currentUserId}\n canManage={canManage}\n canChangeRoles={canChangeRoles}\n onUpdateRole={onUpdateRole}\n onRemove={onRemove}\n />\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n\n// Member row component\ninterface MemberRowProps {\n member: Member;\n isCurrentUser: boolean;\n canManage: boolean;\n canChangeRoles: boolean;\n onUpdateRole?: (userId: string, role: OrgRole) => Promise<void>;\n onRemove?: (userId: string) => Promise<void>;\n}\n\nfunction MemberRow({\n member,\n isCurrentUser,\n canManage,\n canChangeRoles,\n onUpdateRole,\n onRemove,\n}: MemberRowProps) {\n const [isUpdating, setIsUpdating] = useState(false);\n const [selectedRole, setSelectedRole] = useState<OrgRole>(member.role);\n\n const handleRoleChange = useCallback(\n async (newRole: OrgRole) => {\n if (!onUpdateRole || newRole === member.role) return;\n\n setIsUpdating(true);\n try {\n await onUpdateRole(member.userId, newRole);\n setSelectedRole(newRole);\n } catch {\n // Revert on error\n setSelectedRole(member.role);\n } finally {\n setIsUpdating(false);\n }\n },\n [member.userId, member.role, onUpdateRole]\n );\n\n const handleRemove = useCallback(async () => {\n if (!onRemove) return;\n\n const confirmed = window.confirm(\n `Are you sure you want to remove ${member.user.name || member.user.email} from this organization?`\n );\n if (!confirmed) return;\n\n setIsUpdating(true);\n try {\n await onRemove(member.userId);\n } finally {\n setIsUpdating(false);\n }\n }, [member.userId, member.user.name, member.user.email, onRemove]);\n\n const isOwner = member.role === 'owner';\n const canModify = !isCurrentUser && !isOwner;\n\n return (\n <tr className={`cedros-member-row ${isCurrentUser ? 'cedros-member-row-current' : ''}`}>\n <td className=\"cedros-member-info\">\n <MemberAvatar user={member.user} />\n <div className=\"cedros-member-details\">\n <span className=\"cedros-member-name\">\n {member.user.name || 'Unknown'}\n {isCurrentUser && <span className=\"cedros-member-you\">(you)</span>}\n </span>\n <span className=\"cedros-member-email\">{member.user.email}</span>\n </div>\n </td>\n <td className=\"cedros-member-role\">\n {canChangeRoles && canModify && onUpdateRole ? (\n <select\n value={selectedRole}\n onChange={(e) => handleRoleChange(e.target.value as OrgRole)}\n disabled={isUpdating}\n className=\"cedros-role-select\"\n >\n {ROLE_OPTIONS.map((role) => (\n <option key={role} value={role}>\n {role.charAt(0).toUpperCase() + role.slice(1)}\n </option>\n ))}\n </select>\n ) : (\n <span className={`cedros-role-badge cedros-role-badge-${member.role}`}>\n {member.role.charAt(0).toUpperCase() + member.role.slice(1)}\n </span>\n )}\n </td>\n <td className=\"cedros-member-joined\">{formatDate(member.joinedAt)}</td>\n {(canManage || canChangeRoles) && (\n <td className=\"cedros-member-actions\">\n {canManage && canModify && onRemove && (\n <button\n type=\"button\"\n className=\"cedros-button cedros-button-danger cedros-button-sm\"\n onClick={handleRemove}\n disabled={isUpdating}\n aria-label={`Remove ${member.user.name || member.user.email}`}\n >\n {isUpdating ? <LoadingSpinner size=\"sm\" /> : 'Remove'}\n </button>\n )}\n </td>\n )}\n </tr>\n );\n}\n\n// Helper components\nfunction MemberAvatar({ user }: { user: Member['user'] }) {\n // COMP-06: Cache sanitized URL and verify before use (blocks dangerous protocols)\n const sanitizedPicture = sanitizeImageUrl(user.picture);\n if (sanitizedPicture) {\n return (\n <img\n src={sanitizedPicture}\n alt={user.name || user.email || 'Member'}\n className=\"cedros-member-avatar\"\n referrerPolicy=\"no-referrer\"\n />\n );\n }\n\n const initial = (user.name?.[0] || user.email?.[0] || '?').toUpperCase();\n return <div className=\"cedros-member-avatar-placeholder\">{initial}</div>;\n}\n\nfunction formatDate(dateString: string): string {\n const date = new Date(dateString);\n return date.toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n}\n","import { useState, useCallback, useEffect, useRef } from 'react';\nimport type { OrgRole, DisplayError } from '../../types';\nimport { LoadingSpinner } from '../shared/LoadingSpinner';\nimport { ErrorMessage } from '../shared/ErrorMessage';\nimport { validateEmail } from '../../utils/validation';\n\ntype InviteRole = Exclude<OrgRole, 'owner'>;\n\nexport interface InviteFormProps {\n /** Callback when invite is submitted */\n onSubmit: (email: string, role: InviteRole) => Promise<void>;\n /** Loading state */\n isLoading?: boolean;\n /** Error message */\n error?: DisplayError;\n /** Available roles for invite (default: admin, member) */\n availableRoles?: InviteRole[];\n /** Default role for new invites */\n defaultRole?: InviteRole;\n /** Additional CSS class */\n className?: string;\n}\n\nconst DEFAULT_ROLES: InviteRole[] = ['admin', 'member'];\n\n/**\n * Form for inviting new members to an organization.\n *\n * @example\n * ```tsx\n * function InviteManager() {\n * const { activeOrg } = useOrgs();\n * const { createInvite, isLoading, error } = useInvites(activeOrg?.id);\n *\n * return (\n * <InviteForm\n * onSubmit={createInvite}\n * isLoading={isLoading}\n * error={error?.message}\n * defaultRole=\"member\"\n * />\n * );\n * }\n * ```\n */\nexport function InviteForm({\n onSubmit,\n isLoading = false,\n error,\n availableRoles = DEFAULT_ROLES,\n defaultRole = 'member',\n className = '',\n}: InviteFormProps) {\n const [email, setEmail] = useState('');\n const [role, setRole] = useState<InviteRole>(defaultRole);\n const [formError, setFormError] = useState<string | null>(null);\n const [success, setSuccess] = useState(false);\n const successTimerRef = useRef<number | null>(null);\n // UI-03: Track mounted state to prevent state updates after unmount\n const isMountedRef = useRef(true);\n\n useEffect(() => {\n isMountedRef.current = true;\n return () => {\n isMountedRef.current = false;\n if (successTimerRef.current !== null) {\n window.clearTimeout(successTimerRef.current);\n successTimerRef.current = null;\n }\n };\n }, []);\n\n const handleSubmit = useCallback(\n async (e: React.FormEvent) => {\n e.preventDefault();\n setFormError(null);\n setSuccess(false);\n\n const trimmedEmail = email.trim();\n\n if (!trimmedEmail) {\n setFormError('Email is required');\n return;\n }\n\n if (!validateEmail(trimmedEmail)) {\n setFormError('Please enter a valid email address');\n return;\n }\n\n try {\n await onSubmit(trimmedEmail, role);\n setEmail('');\n setRole(defaultRole);\n setSuccess(true);\n // Clear success message after 3 seconds\n if (successTimerRef.current !== null) {\n window.clearTimeout(successTimerRef.current);\n }\n successTimerRef.current = window.setTimeout(() => {\n // UI-03: Check mounted before state update to prevent memory leak warnings\n if (isMountedRef.current) {\n setSuccess(false);\n }\n successTimerRef.current = null;\n }, 3000);\n } catch {\n // H-05: Error handling is delegated to parent component.\n // Parent's onSubmit throws -> parent catches -> sets error prop -> ErrorMessage displays it.\n // This pattern allows the parent to control error display and retry logic.\n }\n },\n [email, role, defaultRole, onSubmit]\n );\n\n return (\n <form className={`cedros-invite-form ${className}`} onSubmit={handleSubmit}>\n {(error || formError) && <ErrorMessage error={formError ?? error ?? null} />}\n\n {success && (\n <div className=\"cedros-invite-success\" role=\"status\">\n <CheckIcon />\n <span>Invitation sent successfully!</span>\n </div>\n )}\n\n <div className=\"cedros-invite-form-row\">\n <div className=\"cedros-form-group cedros-invite-email-group\">\n <label htmlFor=\"invite-email\" className=\"cedros-form-label\">\n Email Address\n </label>\n <input\n id=\"invite-email\"\n type=\"email\"\n className=\"cedros-form-input\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n placeholder=\"colleague@example.com\"\n disabled={isLoading}\n autoComplete=\"email\"\n />\n </div>\n\n <div className=\"cedros-form-group cedros-invite-role-group\">\n <label htmlFor=\"invite-role\" className=\"cedros-form-label\">\n Role\n </label>\n <select\n id=\"invite-role\"\n className=\"cedros-form-select\"\n value={role}\n onChange={(e) => setRole(e.target.value as InviteRole)}\n disabled={isLoading}\n >\n {availableRoles.map((r) => (\n <option key={r} value={r}>\n {r.charAt(0).toUpperCase() + r.slice(1)}\n </option>\n ))}\n </select>\n </div>\n\n <button\n type=\"submit\"\n className=\"cedros-button cedros-button-primary cedros-invite-submit\"\n disabled={isLoading || !email.trim()}\n >\n {isLoading ? <LoadingSpinner size=\"sm\" /> : 'Send Invite'}\n </button>\n </div>\n\n <p className=\"cedros-form-hint\">\n The invited user will receive an email with a link to join your organization.\n </p>\n </form>\n );\n}\n\nfunction CheckIcon() {\n return (\n <svg\n className=\"cedros-invite-check\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M3 8L6 11L13 5\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n","import { useState, useCallback, useEffect, useRef } from 'react';\nimport type { Invite, DisplayError } from '../../types';\nimport { LoadingSpinner } from '../shared/LoadingSpinner';\nimport { ErrorMessage } from '../shared/ErrorMessage';\n\nexport interface InviteListProps {\n /** List of pending invites */\n invites: Invite[];\n /** Loading state */\n isLoading?: boolean;\n /** Error message */\n error?: DisplayError;\n /** Whether the current user can manage invites */\n canManage?: boolean;\n /** Callback when invite is cancelled */\n onCancel?: (inviteId: string) => Promise<void>;\n /** Callback when invite is resent */\n onResend?: (inviteId: string) => Promise<void>;\n /** Additional CSS class */\n className?: string;\n}\n\n/**\n * Display and manage pending organization invites.\n *\n * @example\n * ```tsx\n * function PendingInvites() {\n * const { activeOrg, hasPermission } = useOrgs();\n * const { invites, isLoading, error, cancelInvite, resendInvite } = useInvites(activeOrg?.id);\n *\n * return (\n * <InviteList\n * invites={invites}\n * isLoading={isLoading}\n * error={error?.message}\n * canManage={hasPermission('invite:cancel')}\n * onCancel={cancelInvite}\n * onResend={resendInvite}\n * />\n * );\n * }\n * ```\n */\nexport function InviteList({\n invites,\n isLoading = false,\n error,\n canManage = false,\n onCancel,\n onResend,\n className = '',\n}: InviteListProps) {\n if (isLoading && invites.length === 0) {\n return (\n <div className={`cedros-invite-list cedros-invite-list-loading ${className}`}>\n <LoadingSpinner />\n <span>Loading invites...</span>\n </div>\n );\n }\n\n if (error) {\n return (\n <div className={`cedros-invite-list ${className}`}>\n <ErrorMessage error={error} />\n </div>\n );\n }\n\n if (invites.length === 0) {\n return (\n <div className={`cedros-invite-list cedros-invite-list-empty ${className}`}>\n <p>No pending invites.</p>\n </div>\n );\n }\n\n return (\n <div className={`cedros-invite-list ${className}`}>\n <ul className=\"cedros-invite-items\">\n {invites.map((invite) => (\n <InviteItem\n key={invite.id}\n invite={invite}\n canManage={canManage}\n onCancel={onCancel}\n onResend={onResend}\n />\n ))}\n </ul>\n </div>\n );\n}\n\n// Invite item component\ninterface InviteItemProps {\n invite: Invite;\n canManage: boolean;\n onCancel?: (inviteId: string) => Promise<void>;\n onResend?: (inviteId: string) => Promise<void>;\n}\n\nfunction InviteItem({ invite, canManage, onCancel, onResend }: InviteItemProps) {\n const [isUpdating, setIsUpdating] = useState(false);\n const [resendSuccess, setResendSuccess] = useState(false);\n const resendTimerRef = useRef<number | null>(null);\n\n const isExpired = new Date(invite.expiresAt) < new Date();\n\n const handleCancel = useCallback(async () => {\n if (!onCancel) return;\n\n const confirmed = window.confirm(\n `Are you sure you want to cancel the invite for ${invite.email}?`\n );\n if (!confirmed) return;\n\n setIsUpdating(true);\n try {\n await onCancel(invite.id);\n } finally {\n setIsUpdating(false);\n }\n }, [invite.id, invite.email, onCancel]);\n\n const handleResend = useCallback(async () => {\n if (!onResend) return;\n\n setIsUpdating(true);\n setResendSuccess(false);\n try {\n await onResend(invite.id);\n setResendSuccess(true);\n if (resendTimerRef.current !== null) {\n window.clearTimeout(resendTimerRef.current);\n }\n resendTimerRef.current = window.setTimeout(() => {\n setResendSuccess(false);\n resendTimerRef.current = null;\n }, 3000);\n } finally {\n setIsUpdating(false);\n }\n }, [invite.id, onResend]);\n\n useEffect(() => {\n return () => {\n if (resendTimerRef.current !== null) {\n window.clearTimeout(resendTimerRef.current);\n resendTimerRef.current = null;\n }\n };\n }, []);\n\n return (\n <li className={`cedros-invite-item ${isExpired ? 'cedros-invite-item-expired' : ''}`}>\n <div className=\"cedros-invite-item-info\">\n <div className=\"cedros-invite-item-main\">\n <span className=\"cedros-invite-item-email\">{invite.email}</span>\n <span className={`cedros-role-badge cedros-role-badge-${invite.role}`}>\n {invite.role.charAt(0).toUpperCase() + invite.role.slice(1)}\n </span>\n {isExpired && <span className=\"cedros-invite-expired-badge\">Expired</span>}\n </div>\n <div className=\"cedros-invite-item-meta\">\n <span className=\"cedros-invite-item-date\">\n {/* TYPE-05: invitedByName removed - backend doesn't populate it */}\n Invited {formatDate(invite.createdAt)}\n </span>\n {!isExpired && (\n <span className=\"cedros-invite-item-expires\">\n Expires {formatRelativeTime(invite.expiresAt)}\n </span>\n )}\n </div>\n </div>\n\n {canManage && (\n <div className=\"cedros-invite-item-actions\">\n {resendSuccess && <span className=\"cedros-invite-resend-success\">Sent!</span>}\n {onResend && !isExpired && (\n <button\n type=\"button\"\n className=\"cedros-button cedros-button-outline cedros-button-sm\"\n onClick={handleResend}\n disabled={isUpdating}\n aria-label={`Resend invite to ${invite.email}`}\n >\n {isUpdating ? <LoadingSpinner size=\"sm\" /> : 'Resend'}\n </button>\n )}\n {onCancel && (\n <button\n type=\"button\"\n className=\"cedros-button cedros-button-danger cedros-button-sm\"\n onClick={handleCancel}\n disabled={isUpdating}\n aria-label={`Cancel invite for ${invite.email}`}\n >\n Cancel\n </button>\n )}\n </div>\n )}\n </li>\n );\n}\n\n// Helper functions\nfunction formatDate(dateString: string): string {\n const date = new Date(dateString);\n return date.toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n}\n\nfunction formatRelativeTime(dateString: string): string {\n const date = new Date(dateString);\n const now = new Date();\n const diffMs = date.getTime() - now.getTime();\n const diffDays = Math.ceil(diffMs / (1000 * 60 * 60 * 24));\n\n if (diffDays < 0) {\n return 'expired';\n } else if (diffDays === 0) {\n return 'today';\n } else if (diffDays === 1) {\n return 'tomorrow';\n } else if (diffDays < 7) {\n return `in ${diffDays} days`;\n } else {\n return formatDate(dateString);\n }\n}\n","import type {\n Member,\n MemberApiResponse,\n UpdateMemberRoleRequest,\n ListMembersResponse,\n} from '../types';\nimport { ApiClient, handleApiError } from './apiClient';\n\n/**\n * API client for member operations within an organization\n */\nexport class MemberApiClient {\n private client: ApiClient;\n\n constructor(\n baseUrl: string,\n timeoutMs?: number,\n retryAttempts?: number,\n getAccessToken?: () => string | null\n ) {\n this.client = new ApiClient({ baseUrl, timeoutMs, retryAttempts, getAccessToken });\n }\n\n /**\n * List all members of an organization\n */\n async listMembers(\n orgId: string,\n limit: number = 50,\n offset: number = 0\n ): Promise<{ members: Member[]; total: number }> {\n try {\n const response = await this.client.get<ListMembersResponse>(\n `/orgs/${orgId}/members?limit=${limit}&offset=${offset}`\n );\n return {\n members: response.members.map((member: MemberApiResponse) => ({\n id: member.id,\n userId: member.userId,\n orgId,\n role: member.role,\n joinedAt: member.joinedAt,\n user: {\n id: member.userId,\n email: member.email,\n name: member.name,\n },\n })),\n total: response.total,\n };\n } catch (error) {\n throw handleApiError(error, 'Failed to list members');\n }\n }\n\n /**\n * Update a member's role\n */\n async updateMemberRole(\n orgId: string,\n userId: string,\n data: UpdateMemberRoleRequest\n ): Promise<Member> {\n try {\n return await this.client.patch<Member>(`/orgs/${orgId}/members/${userId}`, data);\n } catch (error) {\n throw handleApiError(error, 'Failed to update member role');\n }\n }\n\n /**\n * Remove a member from the organization\n */\n async removeMember(orgId: string, userId: string): Promise<void> {\n try {\n await this.client.delete<void>(`/orgs/${orgId}/members/${userId}`);\n } catch (error) {\n throw handleApiError(error, 'Failed to remove member');\n }\n }\n}\n","import { useState, useCallback, useMemo, useEffect, useRef } from 'react';\nimport type { Member, OrgRole, AuthError } from '../types';\nimport { useCedrosLogin } from '../context/useCedrosLogin';\nimport { MemberApiClient } from '../utils/memberApi';\n\nexport interface UseMembersReturn {\n /** List of members */\n members: Member[];\n /** Total members available on the server */\n total: number;\n /** Loading state */\n isLoading: boolean;\n /** Error state */\n error: AuthError | null;\n /** Fetch/refresh members list */\n fetchMembers: (options?: { limit?: number; offset?: number }) => Promise<void>;\n /** Update a member's role */\n updateMemberRole: (userId: string, role: OrgRole) => Promise<void>;\n /** Remove a member */\n removeMember: (userId: string) => Promise<void>;\n}\n\n/**\n * Hook for managing organization members.\n *\n * @param orgId - The organization ID to manage members for\n *\n * @example\n * ```tsx\n * function MembersList() {\n * const { activeOrg } = useOrgs();\n * const { members, isLoading, updateMemberRole, removeMember } = useMembers(activeOrg?.id);\n *\n * if (!activeOrg) return null;\n *\n * return (\n * <ul>\n * {members.map(member => (\n * <li key={member.id}>\n * {member.user.name} - {member.role}\n * <button onClick={() => updateMemberRole(member.userId, 'admin')}>\n * Make Admin\n * </button>\n * <button onClick={() => removeMember(member.userId)}>\n * Remove\n * </button>\n * </li>\n * ))}\n * </ul>\n * );\n * }\n * ```\n */\nexport function useMembers(orgId: string | undefined): UseMembersReturn {\n const { config, authState, _internal } = useCedrosLogin();\n\n const [members, setMembers] = useState<Member[]>([]);\n const [total, setTotal] = useState(0);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<AuthError | null>(null);\n // P-12: Track fetched orgId to prevent duplicate fetches on remount\n const fetchedOrgIdRef = useRef<string | undefined>(undefined);\n const requestIdRef = useRef(0);\n\n const apiClient = useMemo(\n () =>\n new MemberApiClient(\n config.serverUrl,\n config.requestTimeout,\n config.retryAttempts,\n _internal?.getAccessToken\n ),\n [config.serverUrl, config.requestTimeout, config.retryAttempts, _internal]\n );\n\n // C-02: Use ref to avoid apiClient in callback dependencies\n // Prevents infinite loop when apiClient identity changes\n const apiClientRef = useRef(apiClient);\n apiClientRef.current = apiClient;\n\n const fetchMembers = useCallback(\n async (options?: { limit?: number; offset?: number }) => {\n if (!orgId || authState !== 'authenticated') {\n setMembers([]);\n setTotal(0);\n return;\n }\n\n setIsLoading(true);\n setError(null);\n const requestId = ++requestIdRef.current;\n\n try {\n const { limit = 50, offset = 0 } = options ?? {};\n const response = await apiClientRef.current.listMembers(orgId, limit, offset);\n if (requestId !== requestIdRef.current) return;\n setMembers(response.members);\n setTotal(response.total);\n } catch (err) {\n if (requestId !== requestIdRef.current) return;\n setError(err as AuthError);\n } finally {\n if (requestId === requestIdRef.current) {\n setIsLoading(false);\n }\n }\n },\n [orgId, authState]\n );\n\n // P-12: Auto-fetch when orgId changes, but not on every remount\n useEffect(() => {\n if (authState !== 'authenticated') {\n fetchedOrgIdRef.current = undefined;\n return;\n }\n\n if (orgId !== fetchedOrgIdRef.current) {\n fetchedOrgIdRef.current = orgId;\n fetchMembers();\n }\n }, [orgId, authState, fetchMembers]);\n\n const updateMemberRole = useCallback(\n async (userId: string, role: OrgRole): Promise<void> => {\n if (!orgId) {\n throw new Error('No organization selected');\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n await apiClientRef.current.updateMemberRole(orgId, userId, { role });\n // Refresh members list\n await fetchMembers();\n } catch (err) {\n setError(err as AuthError);\n throw err;\n } finally {\n setIsLoading(false);\n }\n },\n [orgId, fetchMembers]\n );\n\n const removeMember = useCallback(\n async (userId: string): Promise<void> => {\n if (!orgId) {\n throw new Error('No organization selected');\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n await apiClientRef.current.removeMember(orgId, userId);\n // Refresh members list\n await fetchMembers();\n } catch (err) {\n setError(err as AuthError);\n throw err;\n } finally {\n setIsLoading(false);\n }\n },\n [orgId, fetchMembers]\n );\n\n return {\n members,\n total,\n isLoading,\n error,\n fetchMembers,\n updateMemberRole,\n removeMember,\n };\n}\n","import type {\n Invite,\n InviteApiResponse,\n CreateInviteRequest,\n AcceptInviteRequest,\n ListInvitesResponse,\n CreateInviteResponse,\n AcceptInviteResponse,\n} from '../types';\nimport { ApiClient, handleApiError } from './apiClient';\n\n/**\n * API client for invite operations\n */\nexport class InviteApiClient {\n private client: ApiClient;\n\n constructor(\n baseUrl: string,\n timeoutMs?: number,\n retryAttempts?: number,\n getAccessToken?: () => string | null\n ) {\n this.client = new ApiClient({ baseUrl, timeoutMs, retryAttempts, getAccessToken });\n }\n\n /**\n * List all pending invites for an organization\n */\n async listInvites(\n orgId: string,\n limit: number = 50,\n offset: number = 0\n ): Promise<{ invites: Invite[]; total: number }> {\n try {\n const response = await this.client.get<ListInvitesResponse>(\n `/orgs/${orgId}/invites?limit=${limit}&offset=${offset}`\n );\n return {\n invites: response.invites.map((invite: InviteApiResponse) => ({\n id: invite.id,\n orgId: invite.orgId,\n email: invite.email,\n role: invite.role,\n invitedBy: invite.invitedBy,\n createdAt: invite.createdAt,\n expiresAt: invite.expiresAt,\n })),\n total: response.total,\n };\n } catch (error) {\n throw handleApiError(error, 'Failed to list invites');\n }\n }\n\n /**\n * Create a new invite\n */\n async createInvite(orgId: string, data: CreateInviteRequest): Promise<CreateInviteResponse> {\n try {\n return await this.client.post<CreateInviteResponse>(`/orgs/${orgId}/invites`, data);\n } catch (error) {\n throw handleApiError(error, 'Failed to create invite');\n }\n }\n\n /**\n * Cancel a pending invite\n */\n async cancelInvite(orgId: string, inviteId: string): Promise<void> {\n try {\n await this.client.delete<void>(`/orgs/${orgId}/invites/${inviteId}`);\n } catch (error) {\n throw handleApiError(error, 'Failed to cancel invite');\n }\n }\n\n /**\n * Resend an invite email\n */\n async resendInvite(orgId: string, inviteId: string): Promise<void> {\n try {\n await this.client.post<void>(`/orgs/${orgId}/invites/${inviteId}/resend`, {});\n } catch (error) {\n throw handleApiError(error, 'Failed to resend invite');\n }\n }\n\n /**\n * Accept an invite (public endpoint)\n */\n async acceptInvite(data: AcceptInviteRequest): Promise<AcceptInviteResponse> {\n try {\n return await this.client.post<AcceptInviteResponse>('/invites/accept', data);\n } catch (error) {\n throw handleApiError(error, 'Failed to accept invite');\n }\n }\n}\n","import { useState, useCallback, useMemo, useEffect, useRef } from 'react';\nimport type { Invite, OrgRole, AuthError, AcceptInviteResponse } from '../types';\nimport { useCedrosLogin } from '../context/useCedrosLogin';\nimport { InviteApiClient } from '../utils/inviteApi';\n\nexport interface UseInvitesReturn {\n /** List of pending invites */\n invites: Invite[];\n /** Total pending invites available on the server */\n total: number;\n /** Loading state */\n isLoading: boolean;\n /** Error state */\n error: AuthError | null;\n /** Fetch/refresh invites list */\n fetchInvites: (options?: { limit?: number; offset?: number }) => Promise<void>;\n /** Create a new invite */\n createInvite: (email: string, role?: Exclude<OrgRole, 'owner'>) => Promise<void>;\n /** Cancel a pending invite */\n cancelInvite: (inviteId: string) => Promise<void>;\n /** Resend an invite email */\n resendInvite: (inviteId: string) => Promise<void>;\n /** Accept an invite (public) */\n acceptInvite: (token: string) => Promise<AcceptInviteResponse>;\n}\n\n/**\n * Hook for managing organization invites.\n *\n * @param orgId - The organization ID to manage invites for\n *\n * @example\n * ```tsx\n * function InviteManager() {\n * const { activeOrg } = useOrgs();\n * const { invites, createInvite, cancelInvite, resendInvite } = useInvites(activeOrg?.id);\n *\n * const handleInvite = async (email: string) => {\n * await createInvite(email, 'member');\n * };\n *\n * return (\n * <div>\n * <InviteForm onSubmit={handleInvite} />\n * <ul>\n * {invites.map(invite => (\n * <li key={invite.id}>\n * {invite.email} ({invite.role})\n * <button onClick={() => resendInvite(invite.id)}>Resend</button>\n * <button onClick={() => cancelInvite(invite.id)}>Cancel</button>\n * </li>\n * ))}\n * </ul>\n * </div>\n * );\n * }\n * ```\n */\nexport function useInvites(orgId: string | undefined): UseInvitesReturn {\n const { config, authState, _internal } = useCedrosLogin();\n\n const [invites, setInvites] = useState<Invite[]>([]);\n const [total, setTotal] = useState(0);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<AuthError | null>(null);\n // P-13: Track fetched orgId to prevent duplicate fetches on remount\n const fetchedOrgIdRef = useRef<string | undefined>(undefined);\n const requestIdRef = useRef(0);\n\n const apiClient = useMemo(\n () =>\n new InviteApiClient(\n config.serverUrl,\n config.requestTimeout,\n config.retryAttempts,\n _internal?.getAccessToken\n ),\n [config.serverUrl, config.requestTimeout, config.retryAttempts, _internal]\n );\n\n // H-02: Use ref to avoid apiClient in callback dependencies\n // Prevents infinite loop when apiClient identity changes\n const apiClientRef = useRef(apiClient);\n apiClientRef.current = apiClient;\n\n const fetchInvites = useCallback(\n async (options?: { limit?: number; offset?: number }) => {\n if (!orgId || authState !== 'authenticated') {\n setInvites([]);\n setTotal(0);\n return;\n }\n\n setIsLoading(true);\n setError(null);\n const requestId = ++requestIdRef.current;\n\n try {\n const { limit = 50, offset = 0 } = options ?? {};\n const response = await apiClientRef.current.listInvites(orgId, limit, offset);\n if (requestId !== requestIdRef.current) return;\n setInvites(response.invites);\n setTotal(response.total);\n } catch (err) {\n if (requestId !== requestIdRef.current) return;\n setError(err as AuthError);\n } finally {\n if (requestId === requestIdRef.current) {\n setIsLoading(false);\n }\n }\n },\n [orgId, authState]\n );\n\n // P-13: Auto-fetch when orgId changes, but not on every remount\n useEffect(() => {\n if (authState !== 'authenticated') {\n fetchedOrgIdRef.current = undefined;\n return;\n }\n\n if (orgId !== fetchedOrgIdRef.current) {\n fetchedOrgIdRef.current = orgId;\n fetchInvites();\n }\n }, [orgId, authState, fetchInvites]);\n\n const createInvite = useCallback(\n async (email: string, role: Exclude<OrgRole, 'owner'> = 'member'): Promise<void> => {\n if (!orgId) {\n throw new Error('No organization selected');\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n await apiClientRef.current.createInvite(orgId, { email, role });\n // Refresh invites list\n await fetchInvites();\n } catch (err) {\n setError(err as AuthError);\n throw err;\n } finally {\n setIsLoading(false);\n }\n },\n [orgId, fetchInvites]\n );\n\n const cancelInvite = useCallback(\n async (inviteId: string): Promise<void> => {\n if (!orgId) {\n throw new Error('No organization selected');\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n await apiClientRef.current.cancelInvite(orgId, inviteId);\n // Refresh invites list\n await fetchInvites();\n } catch (err) {\n setError(err as AuthError);\n throw err;\n } finally {\n setIsLoading(false);\n }\n },\n [orgId, fetchInvites]\n );\n\n const resendInvite = useCallback(\n async (inviteId: string): Promise<void> => {\n if (!orgId) {\n throw new Error('No organization selected');\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n await apiClientRef.current.resendInvite(orgId, inviteId);\n } catch (err) {\n setError(err as AuthError);\n throw err;\n } finally {\n setIsLoading(false);\n }\n },\n [orgId]\n );\n\n const acceptInvite = useCallback(async (token: string): Promise<AcceptInviteResponse> => {\n setIsLoading(true);\n setError(null);\n\n try {\n return await apiClientRef.current.acceptInvite({ token });\n } catch (err) {\n setError(err as AuthError);\n throw err;\n } finally {\n setIsLoading(false);\n }\n }, []);\n\n return {\n invites,\n total,\n isLoading,\n error,\n fetchInvites,\n createInvite,\n cancelInvite,\n resendInvite,\n acceptInvite,\n };\n}\n","import { useState, useEffect, useCallback, useMemo } from 'react';\nimport { useSystemSettings } from './useSystemSettings';\n\n/**\n * Server-side feature flags stored in system settings.\n *\n * These control which features are available in the application.\n * Unlike client-side FeatureFlags (passed to CedrosLoginProvider),\n * these can be toggled at runtime via the admin dashboard.\n */\nexport interface ServerFeatures {\n /** Enable multi-tenant organizations. Controls: Team, Invites sections */\n organizations: boolean;\n /** Enable Enterprise SSO for organizations */\n sso: boolean;\n /** Enable two-factor authentication (TOTP) */\n mfa: boolean;\n /** Enable embedded wallet for transaction signing */\n walletSigning: boolean;\n /** Enable deposits and credits system. Controls: Deposits, Withdrawals, Credit System sections */\n credits: boolean;\n /** Enable user withdrawals from embedded wallet to external addresses */\n userWithdrawals: boolean;\n /** Enable Cedros Pay integration. Controls: Products, Transactions, Refunds, etc. */\n cedrosPay: boolean;\n}\n\n/**\n * Default feature values when settings haven't loaded yet.\n * All features disabled by default for safety.\n */\nconst DEFAULT_FEATURES: ServerFeatures = {\n organizations: false,\n sso: false,\n mfa: false,\n walletSigning: false,\n credits: false,\n userWithdrawals: false,\n cedrosPay: false,\n};\n\nexport interface UseServerFeaturesReturn {\n /** Current feature flag states */\n features: ServerFeatures;\n /** Whether settings are still loading */\n isLoading: boolean;\n /** Error if settings failed to load */\n error: Error | null;\n /** Refresh feature flags from server */\n refetch: () => Promise<void>;\n /** Check if a specific feature is enabled */\n isEnabled: (feature: keyof ServerFeatures) => boolean;\n}\n\n/**\n * Hook for reading server-side feature flags from system settings.\n *\n * Use this to conditionally show/hide features based on admin settings.\n *\n * @example\n * ```tsx\n * function AdminDashboard() {\n * const { features, isLoading, isEnabled } = useServerFeatures();\n *\n * if (isLoading) return <LoadingSpinner />;\n *\n * return (\n * <nav>\n * {isEnabled('organizations') && <NavItem>Team</NavItem>}\n * {isEnabled('credits') && <NavItem>Deposits</NavItem>}\n * </nav>\n * );\n * }\n * ```\n */\nexport function useServerFeatures(): UseServerFeaturesReturn {\n const { settings, isLoading, error, fetchSettings, getValue } = useSystemSettings();\n const [hasFetched, setHasFetched] = useState(false);\n\n // Fetch settings on mount\n useEffect(() => {\n if (!hasFetched) {\n fetchSettings();\n setHasFetched(true);\n }\n }, [fetchSettings, hasFetched]);\n\n // Parse boolean value from string setting\n const parseBoolean = useCallback((value: string | undefined): boolean => {\n if (value === undefined) return false;\n return value === 'true' || value === '1';\n }, []);\n\n // Derive features from settings\n const features = useMemo<ServerFeatures>(() => {\n // If no settings loaded yet, return defaults\n if (Object.keys(settings).length === 0) {\n return DEFAULT_FEATURES;\n }\n\n return {\n organizations: parseBoolean(getValue('feature_organizations')),\n sso: parseBoolean(getValue('feature_sso')),\n mfa: parseBoolean(getValue('feature_mfa')),\n walletSigning: parseBoolean(getValue('feature_wallet_signing')),\n credits: parseBoolean(getValue('feature_credits')),\n userWithdrawals: parseBoolean(getValue('feature_user_withdrawals')),\n cedrosPay: parseBoolean(getValue('feature_cedros_pay')),\n };\n }, [settings, getValue, parseBoolean]);\n\n const refetch = useCallback(async () => {\n await fetchSettings();\n }, [fetchSettings]);\n\n const isEnabled = useCallback(\n (feature: keyof ServerFeatures): boolean => {\n return features[feature];\n },\n [features]\n );\n\n return {\n features,\n isLoading,\n error,\n refetch,\n isEnabled,\n };\n}\n","/**\n * Organization role in RBAC hierarchy\n * owner > admin > member\n */\nexport type OrgRole = 'owner' | 'admin' | 'member';\n\n/**\n * Organization entity\n */\nexport interface Organization {\n id: string;\n name: string;\n slug: string;\n logoUrl?: string;\n isPersonal: boolean;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Membership - user's relationship to an organization\n */\nexport interface Membership {\n id?: string;\n userId?: string;\n orgId?: string;\n role: OrgRole;\n joinedAt?: string;\n}\n\n/**\n * Organization with membership details for the current user\n */\nexport interface OrgWithMembership extends Organization {\n membership: Membership;\n}\n\n/**\n * Permission types for RBAC\n */\nexport type Permission =\n | 'org:delete'\n | 'org:update'\n | 'org:read'\n | 'member:invite'\n | 'member:remove'\n | 'member:role_change'\n | 'member:read'\n | 'invite:create'\n | 'invite:cancel'\n | 'invite:read'\n | 'audit:read';\n\n/**\n * Create organization request\n */\nexport interface CreateOrgRequest {\n name: string;\n slug?: string;\n}\n\n/**\n * Update organization request\n */\nexport interface UpdateOrgRequest {\n name?: string;\n slug?: string;\n logoUrl?: string;\n}\n\n/**\n * List organizations response\n */\nexport interface ListOrgsResponse {\n orgs: Array<Organization & { role: OrgRole }>;\n total?: number;\n limit?: number;\n offset?: number;\n}\n\n/**\n * Authorization check request\n */\nexport interface AuthorizeRequest {\n orgId: string;\n action: string;\n resource?: string;\n resourceId?: string;\n}\n\n/**\n * Authorization check response\n */\nexport interface AuthorizeResponse {\n allowed: boolean;\n reason?: string;\n}\n\n/**\n * Permissions response\n */\nexport interface PermissionsResponse {\n permissions: Permission[];\n role: OrgRole;\n}\n\n/**\n * Organization state for context\n */\nexport interface OrgState {\n /** Currently active organization */\n activeOrg: OrgWithMembership | null;\n /** All organizations the user belongs to */\n orgs: OrgWithMembership[];\n /** User's permissions in the active org */\n permissions: Permission[];\n /** User's role in the active org */\n role: OrgRole | null;\n /** Loading state for org operations */\n isLoading: boolean;\n}\n\n// =============================================================================\n// DASHBOARD PERMISSIONS\n// =============================================================================\n\n/**\n * Admin dashboard sections that can be permission-controlled\n */\nexport type DashboardSection =\n // Cedros Login sections\n | 'users'\n | 'team'\n | 'deposits'\n | 'withdrawals'\n | 'settings-wallet'\n | 'settings-auth'\n | 'settings-messaging'\n | 'settings-credits'\n | 'settings-server'\n // Cedros Pay sections\n | 'pay-products'\n | 'pay-subscriptions'\n | 'pay-transactions'\n | 'pay-coupons'\n | 'pay-refunds'\n | 'pay-storefront'\n | 'pay-ai'\n | 'pay-payment'\n | 'pay-messaging'\n | 'pay-settings';\n\n/**\n * Cedros Login dashboard sections\n */\nexport const LOGIN_DASHBOARD_SECTIONS: DashboardSection[] = [\n 'users',\n 'team',\n 'deposits',\n 'withdrawals',\n 'settings-wallet',\n 'settings-auth',\n 'settings-messaging',\n 'settings-credits',\n 'settings-server',\n];\n\n/**\n * Cedros Pay dashboard sections\n */\nexport const PAY_DASHBOARD_SECTIONS: DashboardSection[] = [\n 'pay-products',\n 'pay-subscriptions',\n 'pay-transactions',\n 'pay-coupons',\n 'pay-refunds',\n 'pay-storefront',\n 'pay-ai',\n 'pay-payment',\n 'pay-messaging',\n 'pay-settings',\n];\n\n/**\n * All available dashboard sections\n */\nexport const ALL_DASHBOARD_SECTIONS: DashboardSection[] = [\n ...LOGIN_DASHBOARD_SECTIONS,\n ...PAY_DASHBOARD_SECTIONS,\n];\n\n/**\n * Human-readable labels for dashboard sections\n */\nexport const DASHBOARD_SECTION_LABELS: Record<DashboardSection, string> = {\n // Cedros Login\n users: 'Users',\n team: 'Team',\n deposits: 'Deposits',\n withdrawals: 'Withdrawals',\n 'settings-wallet': 'Wallet Settings',\n 'settings-auth': 'Auth Settings',\n 'settings-messaging': 'Messages Settings',\n 'settings-credits': 'Credits Settings',\n 'settings-server': 'Server Settings',\n // Cedros Pay\n 'pay-products': 'Products',\n 'pay-subscriptions': 'Subscriptions',\n 'pay-transactions': 'Transactions',\n 'pay-coupons': 'Coupons',\n 'pay-refunds': 'Refunds',\n 'pay-storefront': 'Storefront',\n 'pay-ai': 'Store AI',\n 'pay-payment': 'Payment Options',\n 'pay-messaging': 'Store Messages',\n 'pay-settings': 'Store Server',\n};\n\n/**\n * Dashboard permissions per role\n * Only admin and member are configurable - owner always has full access\n */\nexport interface DashboardPermissions {\n admin: Record<DashboardSection, boolean>;\n member: Record<DashboardSection, boolean>;\n}\n\n/**\n * Default dashboard permissions for new orgs\n */\nexport const DEFAULT_DASHBOARD_PERMISSIONS: DashboardPermissions = {\n admin: {\n // Cedros Login\n users: true,\n team: true,\n deposits: true,\n withdrawals: true,\n 'settings-wallet': true,\n 'settings-auth': true,\n 'settings-messaging': true,\n 'settings-credits': true,\n 'settings-server': true,\n // Cedros Pay\n 'pay-products': true,\n 'pay-subscriptions': true,\n 'pay-transactions': true,\n 'pay-coupons': true,\n 'pay-refunds': true,\n 'pay-storefront': true,\n 'pay-ai': true,\n 'pay-payment': true,\n 'pay-messaging': true,\n 'pay-settings': true,\n },\n member: {\n // Cedros Login\n users: false,\n team: true,\n deposits: false,\n withdrawals: false,\n 'settings-wallet': false,\n 'settings-auth': false,\n 'settings-messaging': false,\n 'settings-credits': false,\n 'settings-server': false,\n // Cedros Pay\n 'pay-products': false,\n 'pay-subscriptions': false,\n 'pay-transactions': false,\n 'pay-coupons': false,\n 'pay-refunds': false,\n 'pay-storefront': false,\n 'pay-ai': false,\n 'pay-payment': false,\n 'pay-messaging': false,\n 'pay-settings': false,\n },\n};\n","import { useState, useCallback, useMemo, useRef, useEffect } from 'react';\nimport type { DashboardSection, DashboardPermissions, AuthError } from '../types';\nimport { DEFAULT_DASHBOARD_PERMISSIONS } from '../types/org';\nimport { useCedrosLogin } from '../context/useCedrosLogin';\nimport { useOrgs } from './useOrgs';\nimport { ApiClient } from '../utils/apiClient';\n\nexport interface UseDashboardPermissionsReturn {\n /** Current dashboard permissions config */\n permissions: DashboardPermissions;\n /** Whether the current user can access a specific section */\n canAccess: (section: DashboardSection) => boolean;\n /** Update permissions (owner only) */\n updatePermissions: (permissions: DashboardPermissions) => Promise<void>;\n /** Loading state */\n isLoading: boolean;\n /** Updating state */\n isUpdating: boolean;\n /** Error state */\n error: AuthError | null;\n /** Refresh permissions from server */\n fetchPermissions: () => Promise<void>;\n}\n\n/**\n * Hook for managing dashboard permissions per role.\n *\n * Allows org owners to configure which dashboard sections each role can access.\n * - Owner always has full access (not configurable)\n * - Admin and Member roles are configurable\n *\n * @example\n * ```tsx\n * function AdminDashboard() {\n * const { canAccess, permissions, updatePermissions } = useDashboardPermissions();\n *\n * // Check if current user can access a section\n * if (!canAccess('deposits')) {\n * return <div>You don't have access to deposits</div>;\n * }\n *\n * // Update permissions (owner only)\n * const toggleMemberDeposits = () => {\n * updatePermissions({\n * ...permissions,\n * member: { ...permissions.member, deposits: !permissions.member.deposits },\n * });\n * };\n * }\n * ```\n */\nexport function useDashboardPermissions(): UseDashboardPermissionsReturn {\n const { config, authState, _internal } = useCedrosLogin();\n const { activeOrg, role } = useOrgs();\n\n const [permissions, setPermissions] = useState<DashboardPermissions>(\n DEFAULT_DASHBOARD_PERMISSIONS\n );\n const [isLoading, setIsLoading] = useState(false);\n const [isUpdating, setIsUpdating] = useState(false);\n const [error, setError] = useState<AuthError | null>(null);\n const requestIdRef = useRef(0);\n\n const apiClient = useMemo(\n () =>\n new ApiClient({\n baseUrl: config.serverUrl,\n timeoutMs: config.requestTimeout,\n retryAttempts: config.retryAttempts,\n getAccessToken: _internal?.getAccessToken,\n }),\n [config.serverUrl, config.requestTimeout, config.retryAttempts, _internal]\n );\n\n // Use ref to avoid apiClient in callback dependencies\n const apiClientRef = useRef(apiClient);\n apiClientRef.current = apiClient;\n\n const fetchPermissions = useCallback(async () => {\n if (authState !== 'authenticated' || !activeOrg) {\n setPermissions(DEFAULT_DASHBOARD_PERMISSIONS);\n return;\n }\n\n setIsLoading(true);\n setError(null);\n const requestId = ++requestIdRef.current;\n\n try {\n const response = await apiClientRef.current.get<{ permissions: DashboardPermissions }>(\n '/admin/dashboard-permissions'\n );\n if (requestId !== requestIdRef.current) return;\n setPermissions(response.permissions);\n } catch (err) {\n if (requestId !== requestIdRef.current) return;\n // If 404, use defaults (permissions not configured yet)\n if (err instanceof Error && err.message.includes('404')) {\n setPermissions(DEFAULT_DASHBOARD_PERMISSIONS);\n } else {\n const message = err instanceof Error ? err.message : 'Failed to fetch permissions';\n setError({ code: 'NETWORK_ERROR', message } as AuthError);\n // Fall back to defaults on error\n setPermissions(DEFAULT_DASHBOARD_PERMISSIONS);\n }\n } finally {\n if (requestId === requestIdRef.current) {\n setIsLoading(false);\n }\n }\n }, [authState, activeOrg]);\n\n const updatePermissions = useCallback(\n async (newPermissions: DashboardPermissions): Promise<void> => {\n if (authState !== 'authenticated' || !activeOrg) {\n throw new Error('Not authenticated');\n }\n\n if (role !== 'owner') {\n throw new Error('Only owners can modify dashboard permissions');\n }\n\n setIsUpdating(true);\n setError(null);\n\n try {\n await apiClientRef.current.request<{ permissions: DashboardPermissions }>({\n method: 'PUT',\n path: '/admin/dashboard-permissions',\n body: newPermissions,\n });\n setPermissions(newPermissions);\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Failed to update permissions';\n const authError = { code: 'NETWORK_ERROR', message } as AuthError;\n setError(authError);\n throw new Error(message);\n } finally {\n setIsUpdating(false);\n }\n },\n [authState, activeOrg, role]\n );\n\n /**\n * Check if the current user can access a dashboard section\n * - No org context (system admin): full access (permissions are org-scoped)\n * - Owner: always has full access\n * - Admin: check permissions.admin[section]\n * - Member: check permissions.member[section]\n */\n const canAccess = useCallback(\n (section: DashboardSection): boolean => {\n // No org context = system admin level, allow all\n // (dashboard permissions are org-scoped, not system-scoped)\n if (!activeOrg || !role) {\n return true;\n }\n\n // Owner always has full access\n if (role === 'owner') {\n return true;\n }\n\n // Admin and member: check configured permissions\n const rolePermissions = permissions[role as 'admin' | 'member'];\n return rolePermissions?.[section] ?? false;\n },\n [activeOrg, role, permissions]\n );\n\n // Fetch permissions when org changes\n useEffect(() => {\n if (activeOrg?.id) {\n fetchPermissions();\n }\n }, [activeOrg?.id, fetchPermissions]);\n\n return {\n permissions,\n canAccess,\n updatePermissions,\n isLoading,\n isUpdating,\n error,\n fetchPermissions,\n };\n}\n","/**\n * PermissionsSection - Dashboard permissions matrix for role configuration\n *\n * Allows org owners to configure which dashboard sections each role can access.\n */\n\nimport React, { useCallback, useRef, useEffect } from 'react';\nimport { useDashboardPermissions } from '../../hooks/useDashboardPermissions';\nimport { useServerFeatures } from '../../hooks/useServerFeatures';\nimport {\n LOGIN_DASHBOARD_SECTIONS,\n PAY_DASHBOARD_SECTIONS,\n DASHBOARD_SECTION_LABELS,\n type DashboardSection,\n type DashboardPermissions,\n type OrgRole,\n} from '../../types/org';\n\ninterface PermissionToggleProps {\n checked: boolean;\n onChange: (checked: boolean) => void;\n disabled?: boolean;\n label: string;\n}\n\nfunction PermissionToggle({ checked, onChange, disabled, label }: PermissionToggleProps) {\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={checked}\n aria-label={label}\n disabled={disabled}\n className={`cedros-toggle cedros-toggle-sm ${checked ? 'cedros-toggle-on' : 'cedros-toggle-off'} ${disabled ? 'cedros-toggle-disabled' : ''}`}\n onClick={() => !disabled && onChange(!checked)}\n >\n <span className=\"cedros-toggle-track\">\n <span className=\"cedros-toggle-thumb\" />\n </span>\n </button>\n );\n}\n\nexport interface PermissionsSectionProps {\n /** Current user's role in the org */\n userRole?: OrgRole | null;\n}\n\nexport function PermissionsSection({ userRole }: PermissionsSectionProps): React.JSX.Element {\n const { permissions, updatePermissions, isLoading, isUpdating, error } =\n useDashboardPermissions();\n const { features, isLoading: featuresLoading } = useServerFeatures();\n const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const pendingPermissions = useRef<DashboardPermissions | null>(null);\n\n const isOwner = userRole === 'owner';\n const cedrosPayEnabled = features.cedrosPay;\n\n // Debounced save - batch rapid changes\n const debouncedSave = useCallback(\n (newPermissions: DashboardPermissions) => {\n pendingPermissions.current = newPermissions;\n if (debounceRef.current) {\n clearTimeout(debounceRef.current);\n }\n debounceRef.current = setTimeout(() => {\n if (pendingPermissions.current) {\n updatePermissions(pendingPermissions.current).catch(() => {\n // Error is already set in state by the hook\n });\n pendingPermissions.current = null;\n }\n }, 500);\n },\n [updatePermissions]\n );\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (debounceRef.current) {\n clearTimeout(debounceRef.current);\n }\n };\n }, []);\n\n const handleToggle = useCallback(\n (role: 'admin' | 'member', section: DashboardSection, enabled: boolean) => {\n const newPermissions: DashboardPermissions = {\n ...permissions,\n [role]: {\n ...permissions[role],\n [section]: enabled,\n },\n };\n debouncedSave(newPermissions);\n },\n [permissions, debouncedSave]\n );\n\n if (isLoading || featuresLoading) {\n return (\n <div className=\"cedros-dashboard__section\">\n <div className=\"cedros-dashboard__loading\">Loading permissions...</div>\n </div>\n );\n }\n\n if (!isOwner) {\n return (\n <div className=\"cedros-dashboard__section\">\n <div className=\"cedros-dashboard__empty\">\n Only organization owners can configure dashboard permissions.\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"cedros-dashboard__section cedros-permissions-section\">\n <div className=\"cedros-permissions-header\">\n <p className=\"cedros-permissions-description\">\n Configure which dashboard sections each role can access. Owners always have full access.\n </p>\n {error && <div className=\"cedros-permissions-error\">{error.message}</div>}\n {isUpdating && <span className=\"cedros-permissions-saving\">Saving...</span>}\n </div>\n\n <div className=\"cedros-permissions-matrix\">\n <table className=\"cedros-permissions-table\">\n <tbody>\n {/* Cedros Login Sections */}\n <tr className=\"cedros-permissions-group-header\">\n <th className=\"cedros-permissions-section-header\">Cedros Login</th>\n <th className=\"cedros-permissions-role-header\">Admin</th>\n <th className=\"cedros-permissions-role-header\">Member</th>\n </tr>\n {LOGIN_DASHBOARD_SECTIONS.map((section) => (\n <tr key={section} className=\"cedros-permissions-row\">\n <td className=\"cedros-permissions-section-label\">\n {DASHBOARD_SECTION_LABELS[section]}\n </td>\n <td className=\"cedros-permissions-toggle-cell\">\n <PermissionToggle\n checked={permissions.admin[section] ?? false}\n onChange={(enabled) => handleToggle('admin', section, enabled)}\n disabled={isUpdating}\n label={`Admin access to ${DASHBOARD_SECTION_LABELS[section]}`}\n />\n </td>\n <td className=\"cedros-permissions-toggle-cell\">\n <PermissionToggle\n checked={permissions.member[section] ?? false}\n onChange={(enabled) => handleToggle('member', section, enabled)}\n disabled={isUpdating}\n label={`Member access to ${DASHBOARD_SECTION_LABELS[section]}`}\n />\n </td>\n </tr>\n ))}\n\n {/* Cedros Pay Sections (only when cedrosPay feature is enabled) */}\n {cedrosPayEnabled && (\n <>\n <tr className=\"cedros-permissions-group-header\">\n <th className=\"cedros-permissions-section-header\">Cedros Pay</th>\n <th className=\"cedros-permissions-role-header\">Admin</th>\n <th className=\"cedros-permissions-role-header\">Member</th>\n </tr>\n {PAY_DASHBOARD_SECTIONS.map((section) => (\n <tr key={section} className=\"cedros-permissions-row\">\n <td className=\"cedros-permissions-section-label\">\n {DASHBOARD_SECTION_LABELS[section]}\n </td>\n <td className=\"cedros-permissions-toggle-cell\">\n <PermissionToggle\n checked={permissions.admin[section] ?? false}\n onChange={(enabled) => handleToggle('admin', section, enabled)}\n disabled={isUpdating}\n label={`Admin access to ${DASHBOARD_SECTION_LABELS[section]}`}\n />\n </td>\n <td className=\"cedros-permissions-toggle-cell\">\n <PermissionToggle\n checked={permissions.member[section] ?? false}\n onChange={(enabled) => handleToggle('member', section, enabled)}\n disabled={isUpdating}\n label={`Member access to ${DASHBOARD_SECTION_LABELS[section]}`}\n />\n </td>\n </tr>\n ))}\n </>\n )}\n </tbody>\n </table>\n </div>\n </div>\n );\n}\n"],"names":["ROLE_OPTIONS","MemberList","members","currentUserId","isLoading","error","canManage","canChangeRoles","onUpdateRole","onRemove","className","sortField","setSortField","useState","sortOrder","setSortOrder","toggleSort","field","sortedMembers","useMemo","roleOrder","a","b","aVal","bVal","jsxs","jsx","LoadingSpinner","ErrorMessage","member","MemberRow","isCurrentUser","isUpdating","setIsUpdating","selectedRole","setSelectedRole","handleRoleChange","useCallback","newRole","handleRemove","isOwner","canModify","MemberAvatar","e","role","formatDate","user","sanitizedPicture","sanitizeImageUrl","initial","dateString","DEFAULT_ROLES","InviteForm","onSubmit","availableRoles","defaultRole","email","setEmail","setRole","formError","setFormError","success","setSuccess","successTimerRef","useRef","isMountedRef","useEffect","handleSubmit","trimmedEmail","validateEmail","CheckIcon","r","InviteList","invites","onCancel","onResend","invite","InviteItem","resendSuccess","setResendSuccess","resendTimerRef","isExpired","handleCancel","handleResend","formatRelativeTime","date","now","diffMs","diffDays","MemberApiClient","baseUrl","timeoutMs","retryAttempts","getAccessToken","ApiClient","orgId","limit","offset","response","handleApiError","userId","data","useMembers","config","authState","_internal","useCedrosLogin","setMembers","total","setTotal","setIsLoading","setError","fetchedOrgIdRef","requestIdRef","apiClient","apiClientRef","fetchMembers","options","requestId","err","updateMemberRole","removeMember","InviteApiClient","inviteId","useInvites","setInvites","fetchInvites","createInvite","cancelInvite","resendInvite","acceptInvite","token","DEFAULT_FEATURES","useServerFeatures","settings","fetchSettings","getValue","useSystemSettings","hasFetched","setHasFetched","parseBoolean","value","features","refetch","isEnabled","feature","LOGIN_DASHBOARD_SECTIONS","PAY_DASHBOARD_SECTIONS","DASHBOARD_SECTION_LABELS","DEFAULT_DASHBOARD_PERMISSIONS","useDashboardPermissions","activeOrg","useOrgs","permissions","setPermissions","fetchPermissions","message","updatePermissions","newPermissions","canAccess","section","PermissionToggle","checked","onChange","disabled","label","PermissionsSection","userRole","featuresLoading","debounceRef","pendingPermissions","cedrosPayEnabled","debouncedSave","handleToggle","enabled","Fragment"],"mappings":"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"}
1
+ {"version":3,"file":"PermissionsSection-CighC1p6.js","sources":["../src/components/members/MemberList.tsx","../src/components/invites/InviteForm.tsx","../src/components/invites/InviteList.tsx","../src/utils/memberApi.ts","../src/hooks/useMembers.ts","../src/utils/inviteApi.ts","../src/hooks/useInvites.ts","../src/hooks/useServerFeatures.ts","../src/types/org.ts","../src/hooks/useDashboardPermissions.ts","../src/components/admin/PermissionsSection.tsx"],"sourcesContent":["import { useState, useCallback, useMemo } from 'react';\nimport type { Member, OrgRole, DisplayError } from '../../types';\nimport { LoadingSpinner } from '../shared/LoadingSpinner';\nimport { ErrorMessage } from '../shared/ErrorMessage';\nimport { sanitizeImageUrl } from '../../utils/sanitization';\n\ntype SortField = 'name' | 'role' | 'joinedAt';\ntype SortOrder = 'asc' | 'desc';\n\nexport interface MemberListProps {\n /** List of members to display */\n members: Member[];\n /** Current user's ID (to prevent self-actions) */\n currentUserId?: string;\n /** Loading state */\n isLoading?: boolean;\n /** Error message */\n error?: DisplayError;\n /** Whether the current user can manage members */\n canManage?: boolean;\n /** Whether the current user can change roles */\n canChangeRoles?: boolean;\n /** Callback when role is updated */\n onUpdateRole?: (userId: string, role: OrgRole) => Promise<void>;\n /** Callback when member is removed */\n onRemove?: (userId: string) => Promise<void>;\n /** Additional CSS class */\n className?: string;\n}\n\nconst ROLE_OPTIONS: OrgRole[] = ['owner', 'admin', 'member'];\n\n/**\n * Display and manage organization members.\n *\n * @example\n * ```tsx\n * function TeamMembers() {\n * const { activeOrg, hasPermission } = useOrgs();\n * const { members, isLoading, error, updateMemberRole, removeMember } = useMembers(activeOrg?.id);\n * const { user } = useAuth();\n *\n * return (\n * <MemberList\n * members={members}\n * currentUserId={user?.id}\n * isLoading={isLoading}\n * error={error?.message}\n * canManage={hasPermission('member:remove')}\n * canChangeRoles={hasPermission('member:role_change')}\n * onUpdateRole={updateMemberRole}\n * onRemove={removeMember}\n * />\n * );\n * }\n * ```\n */\nexport function MemberList({\n members,\n currentUserId,\n isLoading = false,\n error,\n canManage = false,\n canChangeRoles = false,\n onUpdateRole,\n onRemove,\n className = '',\n}: MemberListProps) {\n const [sortField, setSortField] = useState<SortField>('name');\n const [sortOrder, setSortOrder] = useState<SortOrder>('asc');\n\n const toggleSort = (field: SortField) => {\n if (sortField === field) {\n setSortOrder(sortOrder === 'asc' ? 'desc' : 'asc');\n } else {\n setSortField(field);\n setSortOrder('asc');\n }\n };\n\n const sortedMembers = useMemo(() => {\n const roleOrder: Record<OrgRole, number> = { owner: 0, admin: 1, member: 2 };\n return [...members].sort((a, b) => {\n let aVal: string | number;\n let bVal: string | number;\n\n switch (sortField) {\n case 'name':\n aVal = (a.user.name || a.user.email || '').toLowerCase();\n bVal = (b.user.name || b.user.email || '').toLowerCase();\n break;\n case 'role':\n aVal = roleOrder[a.role] ?? 99;\n bVal = roleOrder[b.role] ?? 99;\n break;\n case 'joinedAt':\n aVal = new Date(a.joinedAt).getTime();\n bVal = new Date(b.joinedAt).getTime();\n break;\n default:\n return 0;\n }\n\n if (aVal < bVal) return sortOrder === 'asc' ? -1 : 1;\n if (aVal > bVal) return sortOrder === 'asc' ? 1 : -1;\n return 0;\n });\n }, [members, sortField, sortOrder]);\n\n if (isLoading && members.length === 0) {\n return (\n <div className={`cedros-member-list cedros-member-list-loading ${className}`}>\n <LoadingSpinner />\n <span>Loading members...</span>\n </div>\n );\n }\n\n if (error) {\n return (\n <div className={`cedros-member-list ${className}`}>\n <ErrorMessage error={error} />\n </div>\n );\n }\n\n if (members.length === 0) {\n return (\n <div className={`cedros-member-list cedros-member-list-empty ${className}`}>\n <p>No members found.</p>\n </div>\n );\n }\n\n return (\n <div className={`cedros-member-list ${className}`}>\n <table className=\"cedros-member-table\">\n <thead>\n <tr>\n <th>\n <button\n type=\"button\"\n className={`cedros-admin-sort-button ${sortField === 'name' ? 'cedros-admin-sort-active' : ''}`}\n onClick={() => toggleSort('name')}\n >\n Member{' '}\n <span className=\"cedros-admin-sort-icon\">\n {sortField === 'name' ? (sortOrder === 'asc' ? '↑' : '↓') : '↕'}\n </span>\n </button>\n </th>\n <th>\n <button\n type=\"button\"\n className={`cedros-admin-sort-button ${sortField === 'role' ? 'cedros-admin-sort-active' : ''}`}\n onClick={() => toggleSort('role')}\n >\n Role{' '}\n <span className=\"cedros-admin-sort-icon\">\n {sortField === 'role' ? (sortOrder === 'asc' ? '↑' : '↓') : '↕'}\n </span>\n </button>\n </th>\n <th>\n <button\n type=\"button\"\n className={`cedros-admin-sort-button ${sortField === 'joinedAt' ? 'cedros-admin-sort-active' : ''}`}\n onClick={() => toggleSort('joinedAt')}\n >\n Joined{' '}\n <span className=\"cedros-admin-sort-icon\">\n {sortField === 'joinedAt' ? (sortOrder === 'asc' ? '↑' : '↓') : '↕'}\n </span>\n </button>\n </th>\n {(canManage || canChangeRoles) && <th>Actions</th>}\n </tr>\n </thead>\n <tbody>\n {sortedMembers.map((member) => (\n <MemberRow\n key={member.id}\n member={member}\n isCurrentUser={member.userId === currentUserId}\n canManage={canManage}\n canChangeRoles={canChangeRoles}\n onUpdateRole={onUpdateRole}\n onRemove={onRemove}\n />\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n\n// Member row component\ninterface MemberRowProps {\n member: Member;\n isCurrentUser: boolean;\n canManage: boolean;\n canChangeRoles: boolean;\n onUpdateRole?: (userId: string, role: OrgRole) => Promise<void>;\n onRemove?: (userId: string) => Promise<void>;\n}\n\nfunction MemberRow({\n member,\n isCurrentUser,\n canManage,\n canChangeRoles,\n onUpdateRole,\n onRemove,\n}: MemberRowProps) {\n const [isUpdating, setIsUpdating] = useState(false);\n const [selectedRole, setSelectedRole] = useState<OrgRole>(member.role);\n\n const handleRoleChange = useCallback(\n async (newRole: OrgRole) => {\n if (!onUpdateRole || newRole === member.role) return;\n\n setIsUpdating(true);\n try {\n await onUpdateRole(member.userId, newRole);\n setSelectedRole(newRole);\n } catch {\n // Revert on error\n setSelectedRole(member.role);\n } finally {\n setIsUpdating(false);\n }\n },\n [member.userId, member.role, onUpdateRole]\n );\n\n const handleRemove = useCallback(async () => {\n if (!onRemove) return;\n\n const confirmed = window.confirm(\n `Are you sure you want to remove ${member.user.name || member.user.email} from this organization?`\n );\n if (!confirmed) return;\n\n setIsUpdating(true);\n try {\n await onRemove(member.userId);\n } finally {\n setIsUpdating(false);\n }\n }, [member.userId, member.user.name, member.user.email, onRemove]);\n\n const isOwner = member.role === 'owner';\n const canModify = !isCurrentUser && !isOwner;\n\n return (\n <tr className={`cedros-member-row ${isCurrentUser ? 'cedros-member-row-current' : ''}`}>\n <td className=\"cedros-member-info\">\n <MemberAvatar user={member.user} />\n <div className=\"cedros-member-details\">\n <span className=\"cedros-member-name\">\n {member.user.name || 'Unknown'}\n {isCurrentUser && <span className=\"cedros-member-you\">(you)</span>}\n </span>\n <span className=\"cedros-member-email\">{member.user.email}</span>\n </div>\n </td>\n <td className=\"cedros-member-role\">\n {canChangeRoles && canModify && onUpdateRole ? (\n <select\n value={selectedRole}\n onChange={(e) => handleRoleChange(e.target.value as OrgRole)}\n disabled={isUpdating}\n className=\"cedros-role-select\"\n >\n {ROLE_OPTIONS.map((role) => (\n <option key={role} value={role}>\n {role.charAt(0).toUpperCase() + role.slice(1)}\n </option>\n ))}\n </select>\n ) : (\n <span className={`cedros-role-badge cedros-role-badge-${member.role}`}>\n {member.role.charAt(0).toUpperCase() + member.role.slice(1)}\n </span>\n )}\n </td>\n <td className=\"cedros-member-joined\">{formatDate(member.joinedAt)}</td>\n {(canManage || canChangeRoles) && (\n <td className=\"cedros-member-actions\">\n {canManage && canModify && onRemove && (\n <button\n type=\"button\"\n className=\"cedros-button cedros-button-danger cedros-button-sm\"\n onClick={handleRemove}\n disabled={isUpdating}\n aria-label={`Remove ${member.user.name || member.user.email}`}\n >\n {isUpdating ? <LoadingSpinner size=\"sm\" /> : 'Remove'}\n </button>\n )}\n </td>\n )}\n </tr>\n );\n}\n\n// Helper components\nfunction MemberAvatar({ user }: { user: Member['user'] }) {\n // COMP-06: Cache sanitized URL and verify before use (blocks dangerous protocols)\n const sanitizedPicture = sanitizeImageUrl(user.picture);\n if (sanitizedPicture) {\n return (\n <img\n src={sanitizedPicture}\n alt={user.name || user.email || 'Member'}\n className=\"cedros-member-avatar\"\n referrerPolicy=\"no-referrer\"\n />\n );\n }\n\n const initial = (user.name?.[0] || user.email?.[0] || '?').toUpperCase();\n return <div className=\"cedros-member-avatar-placeholder\">{initial}</div>;\n}\n\nfunction formatDate(dateString: string): string {\n const date = new Date(dateString);\n return date.toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n}\n","import { useState, useCallback, useEffect, useRef } from 'react';\nimport type { OrgRole, DisplayError } from '../../types';\nimport { LoadingSpinner } from '../shared/LoadingSpinner';\nimport { ErrorMessage } from '../shared/ErrorMessage';\nimport { validateEmail } from '../../utils/validation';\n\ntype InviteRole = Exclude<OrgRole, 'owner'>;\n\nexport interface InviteFormProps {\n /** Callback when invite is submitted */\n onSubmit: (email: string, role: InviteRole) => Promise<void>;\n /** Loading state */\n isLoading?: boolean;\n /** Error message */\n error?: DisplayError;\n /** Available roles for invite (default: admin, member) */\n availableRoles?: InviteRole[];\n /** Default role for new invites */\n defaultRole?: InviteRole;\n /** Additional CSS class */\n className?: string;\n}\n\nconst DEFAULT_ROLES: InviteRole[] = ['admin', 'member'];\n\n/**\n * Form for inviting new members to an organization.\n *\n * @example\n * ```tsx\n * function InviteManager() {\n * const { activeOrg } = useOrgs();\n * const { createInvite, isLoading, error } = useInvites(activeOrg?.id);\n *\n * return (\n * <InviteForm\n * onSubmit={createInvite}\n * isLoading={isLoading}\n * error={error?.message}\n * defaultRole=\"member\"\n * />\n * );\n * }\n * ```\n */\nexport function InviteForm({\n onSubmit,\n isLoading = false,\n error,\n availableRoles = DEFAULT_ROLES,\n defaultRole = 'member',\n className = '',\n}: InviteFormProps) {\n const [email, setEmail] = useState('');\n const [role, setRole] = useState<InviteRole>(defaultRole);\n const [formError, setFormError] = useState<string | null>(null);\n const [success, setSuccess] = useState(false);\n const successTimerRef = useRef<number | null>(null);\n // UI-03: Track mounted state to prevent state updates after unmount\n const isMountedRef = useRef(true);\n\n useEffect(() => {\n isMountedRef.current = true;\n return () => {\n isMountedRef.current = false;\n if (successTimerRef.current !== null) {\n window.clearTimeout(successTimerRef.current);\n successTimerRef.current = null;\n }\n };\n }, []);\n\n const handleSubmit = useCallback(\n async (e: React.FormEvent) => {\n e.preventDefault();\n setFormError(null);\n setSuccess(false);\n\n const trimmedEmail = email.trim();\n\n if (!trimmedEmail) {\n setFormError('Email is required');\n return;\n }\n\n if (!validateEmail(trimmedEmail)) {\n setFormError('Please enter a valid email address');\n return;\n }\n\n try {\n await onSubmit(trimmedEmail, role);\n setEmail('');\n setRole(defaultRole);\n setSuccess(true);\n // Clear success message after 3 seconds\n if (successTimerRef.current !== null) {\n window.clearTimeout(successTimerRef.current);\n }\n successTimerRef.current = window.setTimeout(() => {\n // UI-03: Check mounted before state update to prevent memory leak warnings\n if (isMountedRef.current) {\n setSuccess(false);\n }\n successTimerRef.current = null;\n }, 3000);\n } catch {\n // H-05: Error handling is delegated to parent component.\n // Parent's onSubmit throws -> parent catches -> sets error prop -> ErrorMessage displays it.\n // This pattern allows the parent to control error display and retry logic.\n }\n },\n [email, role, defaultRole, onSubmit]\n );\n\n return (\n <form className={`cedros-invite-form ${className}`} onSubmit={handleSubmit}>\n {(error || formError) && <ErrorMessage error={formError ?? error ?? null} />}\n\n {success && (\n <div className=\"cedros-invite-success\" role=\"status\">\n <CheckIcon />\n <span>Invitation sent successfully!</span>\n </div>\n )}\n\n <div className=\"cedros-invite-form-row\">\n <div className=\"cedros-form-group cedros-invite-email-group\">\n <label htmlFor=\"invite-email\" className=\"cedros-form-label\">\n Email Address\n </label>\n <input\n id=\"invite-email\"\n type=\"email\"\n className=\"cedros-form-input\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n placeholder=\"colleague@example.com\"\n disabled={isLoading}\n autoComplete=\"email\"\n />\n </div>\n\n <div className=\"cedros-form-group cedros-invite-role-group\">\n <label htmlFor=\"invite-role\" className=\"cedros-form-label\">\n Role\n </label>\n <select\n id=\"invite-role\"\n className=\"cedros-form-select\"\n value={role}\n onChange={(e) => setRole(e.target.value as InviteRole)}\n disabled={isLoading}\n >\n {availableRoles.map((r) => (\n <option key={r} value={r}>\n {r.charAt(0).toUpperCase() + r.slice(1)}\n </option>\n ))}\n </select>\n </div>\n\n <button\n type=\"submit\"\n className=\"cedros-button cedros-button-primary cedros-invite-submit\"\n disabled={isLoading || !email.trim()}\n >\n {isLoading ? <LoadingSpinner size=\"sm\" /> : 'Send Invite'}\n </button>\n </div>\n\n <p className=\"cedros-form-hint\">\n The invited user will receive an email with a link to join your organization.\n </p>\n </form>\n );\n}\n\nfunction CheckIcon() {\n return (\n <svg\n className=\"cedros-invite-check\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M3 8L6 11L13 5\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n","import { useState, useCallback, useEffect, useRef } from 'react';\nimport type { Invite, DisplayError } from '../../types';\nimport { LoadingSpinner } from '../shared/LoadingSpinner';\nimport { ErrorMessage } from '../shared/ErrorMessage';\n\nexport interface InviteListProps {\n /** List of pending invites */\n invites: Invite[];\n /** Loading state */\n isLoading?: boolean;\n /** Error message */\n error?: DisplayError;\n /** Whether the current user can manage invites */\n canManage?: boolean;\n /** Callback when invite is cancelled */\n onCancel?: (inviteId: string) => Promise<void>;\n /** Callback when invite is resent */\n onResend?: (inviteId: string) => Promise<void>;\n /** Additional CSS class */\n className?: string;\n}\n\n/**\n * Display and manage pending organization invites.\n *\n * @example\n * ```tsx\n * function PendingInvites() {\n * const { activeOrg, hasPermission } = useOrgs();\n * const { invites, isLoading, error, cancelInvite, resendInvite } = useInvites(activeOrg?.id);\n *\n * return (\n * <InviteList\n * invites={invites}\n * isLoading={isLoading}\n * error={error?.message}\n * canManage={hasPermission('invite:cancel')}\n * onCancel={cancelInvite}\n * onResend={resendInvite}\n * />\n * );\n * }\n * ```\n */\nexport function InviteList({\n invites,\n isLoading = false,\n error,\n canManage = false,\n onCancel,\n onResend,\n className = '',\n}: InviteListProps) {\n if (isLoading && invites.length === 0) {\n return (\n <div className={`cedros-invite-list cedros-invite-list-loading ${className}`}>\n <LoadingSpinner />\n <span>Loading invites...</span>\n </div>\n );\n }\n\n if (error) {\n return (\n <div className={`cedros-invite-list ${className}`}>\n <ErrorMessage error={error} />\n </div>\n );\n }\n\n if (invites.length === 0) {\n return (\n <div className={`cedros-invite-list cedros-invite-list-empty ${className}`}>\n <p>No pending invites.</p>\n </div>\n );\n }\n\n return (\n <div className={`cedros-invite-list ${className}`}>\n <ul className=\"cedros-invite-items\">\n {invites.map((invite) => (\n <InviteItem\n key={invite.id}\n invite={invite}\n canManage={canManage}\n onCancel={onCancel}\n onResend={onResend}\n />\n ))}\n </ul>\n </div>\n );\n}\n\n// Invite item component\ninterface InviteItemProps {\n invite: Invite;\n canManage: boolean;\n onCancel?: (inviteId: string) => Promise<void>;\n onResend?: (inviteId: string) => Promise<void>;\n}\n\nfunction InviteItem({ invite, canManage, onCancel, onResend }: InviteItemProps) {\n const [isUpdating, setIsUpdating] = useState(false);\n const [resendSuccess, setResendSuccess] = useState(false);\n const resendTimerRef = useRef<number | null>(null);\n\n const isExpired = new Date(invite.expiresAt) < new Date();\n\n const handleCancel = useCallback(async () => {\n if (!onCancel) return;\n\n const confirmed = window.confirm(\n `Are you sure you want to cancel the invite for ${invite.email}?`\n );\n if (!confirmed) return;\n\n setIsUpdating(true);\n try {\n await onCancel(invite.id);\n } finally {\n setIsUpdating(false);\n }\n }, [invite.id, invite.email, onCancel]);\n\n const handleResend = useCallback(async () => {\n if (!onResend) return;\n\n setIsUpdating(true);\n setResendSuccess(false);\n try {\n await onResend(invite.id);\n setResendSuccess(true);\n if (resendTimerRef.current !== null) {\n window.clearTimeout(resendTimerRef.current);\n }\n resendTimerRef.current = window.setTimeout(() => {\n setResendSuccess(false);\n resendTimerRef.current = null;\n }, 3000);\n } finally {\n setIsUpdating(false);\n }\n }, [invite.id, onResend]);\n\n useEffect(() => {\n return () => {\n if (resendTimerRef.current !== null) {\n window.clearTimeout(resendTimerRef.current);\n resendTimerRef.current = null;\n }\n };\n }, []);\n\n return (\n <li className={`cedros-invite-item ${isExpired ? 'cedros-invite-item-expired' : ''}`}>\n <div className=\"cedros-invite-item-info\">\n <div className=\"cedros-invite-item-main\">\n <span className=\"cedros-invite-item-email\">{invite.email}</span>\n <span className={`cedros-role-badge cedros-role-badge-${invite.role}`}>\n {invite.role.charAt(0).toUpperCase() + invite.role.slice(1)}\n </span>\n {isExpired && <span className=\"cedros-invite-expired-badge\">Expired</span>}\n </div>\n <div className=\"cedros-invite-item-meta\">\n <span className=\"cedros-invite-item-date\">\n {/* TYPE-05: invitedByName removed - backend doesn't populate it */}\n Invited {formatDate(invite.createdAt)}\n </span>\n {!isExpired && (\n <span className=\"cedros-invite-item-expires\">\n Expires {formatRelativeTime(invite.expiresAt)}\n </span>\n )}\n </div>\n </div>\n\n {canManage && (\n <div className=\"cedros-invite-item-actions\">\n {resendSuccess && <span className=\"cedros-invite-resend-success\">Sent!</span>}\n {onResend && !isExpired && (\n <button\n type=\"button\"\n className=\"cedros-button cedros-button-outline cedros-button-sm\"\n onClick={handleResend}\n disabled={isUpdating}\n aria-label={`Resend invite to ${invite.email}`}\n >\n {isUpdating ? <LoadingSpinner size=\"sm\" /> : 'Resend'}\n </button>\n )}\n {onCancel && (\n <button\n type=\"button\"\n className=\"cedros-button cedros-button-danger cedros-button-sm\"\n onClick={handleCancel}\n disabled={isUpdating}\n aria-label={`Cancel invite for ${invite.email}`}\n >\n Cancel\n </button>\n )}\n </div>\n )}\n </li>\n );\n}\n\n// Helper functions\nfunction formatDate(dateString: string): string {\n const date = new Date(dateString);\n return date.toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n}\n\nfunction formatRelativeTime(dateString: string): string {\n const date = new Date(dateString);\n const now = new Date();\n const diffMs = date.getTime() - now.getTime();\n const diffDays = Math.ceil(diffMs / (1000 * 60 * 60 * 24));\n\n if (diffDays < 0) {\n return 'expired';\n } else if (diffDays === 0) {\n return 'today';\n } else if (diffDays === 1) {\n return 'tomorrow';\n } else if (diffDays < 7) {\n return `in ${diffDays} days`;\n } else {\n return formatDate(dateString);\n }\n}\n","import type {\n Member,\n MemberApiResponse,\n UpdateMemberRoleRequest,\n ListMembersResponse,\n} from '../types';\nimport { ApiClient, handleApiError } from './apiClient';\n\n/**\n * API client for member operations within an organization\n */\nexport class MemberApiClient {\n private client: ApiClient;\n\n constructor(\n baseUrl: string,\n timeoutMs?: number,\n retryAttempts?: number,\n getAccessToken?: () => string | null\n ) {\n this.client = new ApiClient({ baseUrl, timeoutMs, retryAttempts, getAccessToken });\n }\n\n /**\n * List all members of an organization\n */\n async listMembers(\n orgId: string,\n limit: number = 50,\n offset: number = 0\n ): Promise<{ members: Member[]; total: number }> {\n try {\n const response = await this.client.get<ListMembersResponse>(\n `/orgs/${orgId}/members?limit=${limit}&offset=${offset}`\n );\n return {\n members: response.members.map((member: MemberApiResponse) => ({\n id: member.id,\n userId: member.userId,\n orgId,\n role: member.role,\n joinedAt: member.joinedAt,\n user: {\n id: member.userId,\n email: member.email,\n name: member.name,\n },\n })),\n total: response.total,\n };\n } catch (error) {\n throw handleApiError(error, 'Failed to list members');\n }\n }\n\n /**\n * Update a member's role\n */\n async updateMemberRole(\n orgId: string,\n userId: string,\n data: UpdateMemberRoleRequest\n ): Promise<Member> {\n try {\n return await this.client.patch<Member>(`/orgs/${orgId}/members/${userId}`, data);\n } catch (error) {\n throw handleApiError(error, 'Failed to update member role');\n }\n }\n\n /**\n * Remove a member from the organization\n */\n async removeMember(orgId: string, userId: string): Promise<void> {\n try {\n await this.client.delete<void>(`/orgs/${orgId}/members/${userId}`);\n } catch (error) {\n throw handleApiError(error, 'Failed to remove member');\n }\n }\n}\n","import { useState, useCallback, useMemo, useEffect, useRef } from 'react';\nimport type { Member, OrgRole, AuthError } from '../types';\nimport { useCedrosLogin } from '../context/useCedrosLogin';\nimport { MemberApiClient } from '../utils/memberApi';\n\nexport interface UseMembersReturn {\n /** List of members */\n members: Member[];\n /** Total members available on the server */\n total: number;\n /** Loading state */\n isLoading: boolean;\n /** Error state */\n error: AuthError | null;\n /** Fetch/refresh members list */\n fetchMembers: (options?: { limit?: number; offset?: number }) => Promise<void>;\n /** Update a member's role */\n updateMemberRole: (userId: string, role: OrgRole) => Promise<void>;\n /** Remove a member */\n removeMember: (userId: string) => Promise<void>;\n}\n\n/**\n * Hook for managing organization members.\n *\n * @param orgId - The organization ID to manage members for\n *\n * @example\n * ```tsx\n * function MembersList() {\n * const { activeOrg } = useOrgs();\n * const { members, isLoading, updateMemberRole, removeMember } = useMembers(activeOrg?.id);\n *\n * if (!activeOrg) return null;\n *\n * return (\n * <ul>\n * {members.map(member => (\n * <li key={member.id}>\n * {member.user.name} - {member.role}\n * <button onClick={() => updateMemberRole(member.userId, 'admin')}>\n * Make Admin\n * </button>\n * <button onClick={() => removeMember(member.userId)}>\n * Remove\n * </button>\n * </li>\n * ))}\n * </ul>\n * );\n * }\n * ```\n */\nexport function useMembers(orgId: string | undefined): UseMembersReturn {\n const { config, authState, _internal } = useCedrosLogin();\n\n const [members, setMembers] = useState<Member[]>([]);\n const [total, setTotal] = useState(0);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<AuthError | null>(null);\n // P-12: Track fetched orgId to prevent duplicate fetches on remount\n const fetchedOrgIdRef = useRef<string | undefined>(undefined);\n const requestIdRef = useRef(0);\n\n const apiClient = useMemo(\n () =>\n new MemberApiClient(\n config.serverUrl,\n config.requestTimeout,\n config.retryAttempts,\n _internal?.getAccessToken\n ),\n [config.serverUrl, config.requestTimeout, config.retryAttempts, _internal]\n );\n\n // C-02: Use ref to avoid apiClient in callback dependencies\n // Prevents infinite loop when apiClient identity changes\n const apiClientRef = useRef(apiClient);\n apiClientRef.current = apiClient;\n\n const fetchMembers = useCallback(\n async (options?: { limit?: number; offset?: number }) => {\n if (!orgId || authState !== 'authenticated') {\n setMembers([]);\n setTotal(0);\n return;\n }\n\n setIsLoading(true);\n setError(null);\n const requestId = ++requestIdRef.current;\n\n try {\n const { limit = 50, offset = 0 } = options ?? {};\n const response = await apiClientRef.current.listMembers(orgId, limit, offset);\n if (requestId !== requestIdRef.current) return;\n setMembers(response.members);\n setTotal(response.total);\n } catch (err) {\n if (requestId !== requestIdRef.current) return;\n setError(err as AuthError);\n } finally {\n if (requestId === requestIdRef.current) {\n setIsLoading(false);\n }\n }\n },\n [orgId, authState]\n );\n\n // P-12: Auto-fetch when orgId changes, but not on every remount\n useEffect(() => {\n if (authState !== 'authenticated') {\n fetchedOrgIdRef.current = undefined;\n return;\n }\n\n if (orgId !== fetchedOrgIdRef.current) {\n fetchedOrgIdRef.current = orgId;\n fetchMembers();\n }\n }, [orgId, authState, fetchMembers]);\n\n const updateMemberRole = useCallback(\n async (userId: string, role: OrgRole): Promise<void> => {\n if (!orgId) {\n throw new Error('No organization selected');\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n await apiClientRef.current.updateMemberRole(orgId, userId, { role });\n // Refresh members list\n await fetchMembers();\n } catch (err) {\n setError(err as AuthError);\n throw err;\n } finally {\n setIsLoading(false);\n }\n },\n [orgId, fetchMembers]\n );\n\n const removeMember = useCallback(\n async (userId: string): Promise<void> => {\n if (!orgId) {\n throw new Error('No organization selected');\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n await apiClientRef.current.removeMember(orgId, userId);\n // Refresh members list\n await fetchMembers();\n } catch (err) {\n setError(err as AuthError);\n throw err;\n } finally {\n setIsLoading(false);\n }\n },\n [orgId, fetchMembers]\n );\n\n return {\n members,\n total,\n isLoading,\n error,\n fetchMembers,\n updateMemberRole,\n removeMember,\n };\n}\n","import type {\n Invite,\n InviteApiResponse,\n CreateInviteRequest,\n AcceptInviteRequest,\n ListInvitesResponse,\n CreateInviteResponse,\n AcceptInviteResponse,\n} from '../types';\nimport { ApiClient, handleApiError } from './apiClient';\n\n/**\n * API client for invite operations\n */\nexport class InviteApiClient {\n private client: ApiClient;\n\n constructor(\n baseUrl: string,\n timeoutMs?: number,\n retryAttempts?: number,\n getAccessToken?: () => string | null\n ) {\n this.client = new ApiClient({ baseUrl, timeoutMs, retryAttempts, getAccessToken });\n }\n\n /**\n * List all pending invites for an organization\n */\n async listInvites(\n orgId: string,\n limit: number = 50,\n offset: number = 0\n ): Promise<{ invites: Invite[]; total: number }> {\n try {\n const response = await this.client.get<ListInvitesResponse>(\n `/orgs/${orgId}/invites?limit=${limit}&offset=${offset}`\n );\n return {\n invites: response.invites.map((invite: InviteApiResponse) => ({\n id: invite.id,\n orgId: invite.orgId,\n email: invite.email,\n role: invite.role,\n invitedBy: invite.invitedBy,\n createdAt: invite.createdAt,\n expiresAt: invite.expiresAt,\n })),\n total: response.total,\n };\n } catch (error) {\n throw handleApiError(error, 'Failed to list invites');\n }\n }\n\n /**\n * Create a new invite\n */\n async createInvite(orgId: string, data: CreateInviteRequest): Promise<CreateInviteResponse> {\n try {\n return await this.client.post<CreateInviteResponse>(`/orgs/${orgId}/invites`, data);\n } catch (error) {\n throw handleApiError(error, 'Failed to create invite');\n }\n }\n\n /**\n * Cancel a pending invite\n */\n async cancelInvite(orgId: string, inviteId: string): Promise<void> {\n try {\n await this.client.delete<void>(`/orgs/${orgId}/invites/${inviteId}`);\n } catch (error) {\n throw handleApiError(error, 'Failed to cancel invite');\n }\n }\n\n /**\n * Resend an invite email\n */\n async resendInvite(orgId: string, inviteId: string): Promise<void> {\n try {\n await this.client.post<void>(`/orgs/${orgId}/invites/${inviteId}/resend`, {});\n } catch (error) {\n throw handleApiError(error, 'Failed to resend invite');\n }\n }\n\n /**\n * Accept an invite (public endpoint)\n */\n async acceptInvite(data: AcceptInviteRequest): Promise<AcceptInviteResponse> {\n try {\n return await this.client.post<AcceptInviteResponse>('/invites/accept', data);\n } catch (error) {\n throw handleApiError(error, 'Failed to accept invite');\n }\n }\n}\n","import { useState, useCallback, useMemo, useEffect, useRef } from 'react';\nimport type { Invite, OrgRole, AuthError, AcceptInviteResponse } from '../types';\nimport { useCedrosLogin } from '../context/useCedrosLogin';\nimport { InviteApiClient } from '../utils/inviteApi';\n\nexport interface UseInvitesReturn {\n /** List of pending invites */\n invites: Invite[];\n /** Total pending invites available on the server */\n total: number;\n /** Loading state */\n isLoading: boolean;\n /** Error state */\n error: AuthError | null;\n /** Fetch/refresh invites list */\n fetchInvites: (options?: { limit?: number; offset?: number }) => Promise<void>;\n /** Create a new invite */\n createInvite: (email: string, role?: Exclude<OrgRole, 'owner'>) => Promise<void>;\n /** Cancel a pending invite */\n cancelInvite: (inviteId: string) => Promise<void>;\n /** Resend an invite email */\n resendInvite: (inviteId: string) => Promise<void>;\n /** Accept an invite (public) */\n acceptInvite: (token: string) => Promise<AcceptInviteResponse>;\n}\n\n/**\n * Hook for managing organization invites.\n *\n * @param orgId - The organization ID to manage invites for\n *\n * @example\n * ```tsx\n * function InviteManager() {\n * const { activeOrg } = useOrgs();\n * const { invites, createInvite, cancelInvite, resendInvite } = useInvites(activeOrg?.id);\n *\n * const handleInvite = async (email: string) => {\n * await createInvite(email, 'member');\n * };\n *\n * return (\n * <div>\n * <InviteForm onSubmit={handleInvite} />\n * <ul>\n * {invites.map(invite => (\n * <li key={invite.id}>\n * {invite.email} ({invite.role})\n * <button onClick={() => resendInvite(invite.id)}>Resend</button>\n * <button onClick={() => cancelInvite(invite.id)}>Cancel</button>\n * </li>\n * ))}\n * </ul>\n * </div>\n * );\n * }\n * ```\n */\nexport function useInvites(orgId: string | undefined): UseInvitesReturn {\n const { config, authState, _internal } = useCedrosLogin();\n\n const [invites, setInvites] = useState<Invite[]>([]);\n const [total, setTotal] = useState(0);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<AuthError | null>(null);\n // P-13: Track fetched orgId to prevent duplicate fetches on remount\n const fetchedOrgIdRef = useRef<string | undefined>(undefined);\n const requestIdRef = useRef(0);\n\n const apiClient = useMemo(\n () =>\n new InviteApiClient(\n config.serverUrl,\n config.requestTimeout,\n config.retryAttempts,\n _internal?.getAccessToken\n ),\n [config.serverUrl, config.requestTimeout, config.retryAttempts, _internal]\n );\n\n // H-02: Use ref to avoid apiClient in callback dependencies\n // Prevents infinite loop when apiClient identity changes\n const apiClientRef = useRef(apiClient);\n apiClientRef.current = apiClient;\n\n const fetchInvites = useCallback(\n async (options?: { limit?: number; offset?: number }) => {\n if (!orgId || authState !== 'authenticated') {\n setInvites([]);\n setTotal(0);\n return;\n }\n\n setIsLoading(true);\n setError(null);\n const requestId = ++requestIdRef.current;\n\n try {\n const { limit = 50, offset = 0 } = options ?? {};\n const response = await apiClientRef.current.listInvites(orgId, limit, offset);\n if (requestId !== requestIdRef.current) return;\n setInvites(response.invites);\n setTotal(response.total);\n } catch (err) {\n if (requestId !== requestIdRef.current) return;\n setError(err as AuthError);\n } finally {\n if (requestId === requestIdRef.current) {\n setIsLoading(false);\n }\n }\n },\n [orgId, authState]\n );\n\n // P-13: Auto-fetch when orgId changes, but not on every remount\n useEffect(() => {\n if (authState !== 'authenticated') {\n fetchedOrgIdRef.current = undefined;\n return;\n }\n\n if (orgId !== fetchedOrgIdRef.current) {\n fetchedOrgIdRef.current = orgId;\n fetchInvites();\n }\n }, [orgId, authState, fetchInvites]);\n\n const createInvite = useCallback(\n async (email: string, role: Exclude<OrgRole, 'owner'> = 'member'): Promise<void> => {\n if (!orgId) {\n throw new Error('No organization selected');\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n await apiClientRef.current.createInvite(orgId, { email, role });\n // Refresh invites list\n await fetchInvites();\n } catch (err) {\n setError(err as AuthError);\n throw err;\n } finally {\n setIsLoading(false);\n }\n },\n [orgId, fetchInvites]\n );\n\n const cancelInvite = useCallback(\n async (inviteId: string): Promise<void> => {\n if (!orgId) {\n throw new Error('No organization selected');\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n await apiClientRef.current.cancelInvite(orgId, inviteId);\n // Refresh invites list\n await fetchInvites();\n } catch (err) {\n setError(err as AuthError);\n throw err;\n } finally {\n setIsLoading(false);\n }\n },\n [orgId, fetchInvites]\n );\n\n const resendInvite = useCallback(\n async (inviteId: string): Promise<void> => {\n if (!orgId) {\n throw new Error('No organization selected');\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n await apiClientRef.current.resendInvite(orgId, inviteId);\n } catch (err) {\n setError(err as AuthError);\n throw err;\n } finally {\n setIsLoading(false);\n }\n },\n [orgId]\n );\n\n const acceptInvite = useCallback(async (token: string): Promise<AcceptInviteResponse> => {\n setIsLoading(true);\n setError(null);\n\n try {\n return await apiClientRef.current.acceptInvite({ token });\n } catch (err) {\n setError(err as AuthError);\n throw err;\n } finally {\n setIsLoading(false);\n }\n }, []);\n\n return {\n invites,\n total,\n isLoading,\n error,\n fetchInvites,\n createInvite,\n cancelInvite,\n resendInvite,\n acceptInvite,\n };\n}\n","import { useState, useEffect, useCallback, useMemo } from 'react';\nimport { useSystemSettings } from './useSystemSettings';\n\n/**\n * Server-side feature flags stored in system settings.\n *\n * These control which features are available in the application.\n * Unlike client-side FeatureFlags (passed to CedrosLoginProvider),\n * these can be toggled at runtime via the admin dashboard.\n */\nexport interface ServerFeatures {\n /** Enable multi-tenant organizations. Controls: Team, Invites sections */\n organizations: boolean;\n /** Enable Enterprise SSO for organizations */\n sso: boolean;\n /** Enable two-factor authentication (TOTP) */\n mfa: boolean;\n /** Enable embedded wallet for transaction signing */\n walletSigning: boolean;\n /** Enable deposits and credits system. Controls: Deposits, Withdrawals, Credit System sections */\n credits: boolean;\n /** Enable user withdrawals from embedded wallet to external addresses */\n userWithdrawals: boolean;\n /** Enable Cedros Pay integration. Controls: Products, Transactions, Refunds, etc. */\n cedrosPay: boolean;\n}\n\n/**\n * Default feature values when settings haven't loaded yet.\n * All features disabled by default for safety.\n */\nconst DEFAULT_FEATURES: ServerFeatures = {\n organizations: false,\n sso: false,\n mfa: false,\n walletSigning: false,\n credits: false,\n userWithdrawals: false,\n cedrosPay: false,\n};\n\nexport interface UseServerFeaturesReturn {\n /** Current feature flag states */\n features: ServerFeatures;\n /** Whether settings are still loading */\n isLoading: boolean;\n /** Error if settings failed to load */\n error: Error | null;\n /** Refresh feature flags from server */\n refetch: () => Promise<void>;\n /** Check if a specific feature is enabled */\n isEnabled: (feature: keyof ServerFeatures) => boolean;\n}\n\n/**\n * Hook for reading server-side feature flags from system settings.\n *\n * Use this to conditionally show/hide features based on admin settings.\n *\n * @example\n * ```tsx\n * function AdminDashboard() {\n * const { features, isLoading, isEnabled } = useServerFeatures();\n *\n * if (isLoading) return <LoadingSpinner />;\n *\n * return (\n * <nav>\n * {isEnabled('organizations') && <NavItem>Team</NavItem>}\n * {isEnabled('credits') && <NavItem>Deposits</NavItem>}\n * </nav>\n * );\n * }\n * ```\n */\nexport function useServerFeatures(): UseServerFeaturesReturn {\n const { settings, isLoading, error, fetchSettings, getValue } = useSystemSettings();\n const [hasFetched, setHasFetched] = useState(false);\n\n // Fetch settings on mount\n useEffect(() => {\n if (!hasFetched) {\n fetchSettings();\n setHasFetched(true);\n }\n }, [fetchSettings, hasFetched]);\n\n // Parse boolean value from string setting\n const parseBoolean = useCallback((value: string | undefined): boolean => {\n if (value === undefined) return false;\n return value === 'true' || value === '1';\n }, []);\n\n // Derive features from settings\n const features = useMemo<ServerFeatures>(() => {\n // If no settings loaded yet, return defaults\n if (Object.keys(settings).length === 0) {\n return DEFAULT_FEATURES;\n }\n\n return {\n organizations: parseBoolean(getValue('feature_organizations')),\n sso: parseBoolean(getValue('feature_sso')),\n mfa: parseBoolean(getValue('feature_mfa')),\n walletSigning: parseBoolean(getValue('feature_wallet_signing')),\n credits: parseBoolean(getValue('feature_credits')),\n userWithdrawals: parseBoolean(getValue('feature_user_withdrawals')),\n cedrosPay: parseBoolean(getValue('feature_cedros_pay')),\n };\n }, [settings, getValue, parseBoolean]);\n\n const refetch = useCallback(async () => {\n await fetchSettings();\n }, [fetchSettings]);\n\n const isEnabled = useCallback(\n (feature: keyof ServerFeatures): boolean => {\n return features[feature];\n },\n [features]\n );\n\n return {\n features,\n isLoading,\n error,\n refetch,\n isEnabled,\n };\n}\n","/**\n * Organization role in RBAC hierarchy\n * owner > admin > member\n */\nexport type OrgRole = 'owner' | 'admin' | 'member';\n\n/**\n * Organization entity\n */\nexport interface Organization {\n id: string;\n name: string;\n slug: string;\n logoUrl?: string;\n isPersonal: boolean;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Membership - user's relationship to an organization\n */\nexport interface Membership {\n id?: string;\n userId?: string;\n orgId?: string;\n role: OrgRole;\n joinedAt?: string;\n}\n\n/**\n * Organization with membership details for the current user\n */\nexport interface OrgWithMembership extends Organization {\n membership: Membership;\n}\n\n/**\n * Permission types for RBAC\n */\nexport type Permission =\n | 'org:delete'\n | 'org:update'\n | 'org:read'\n | 'member:invite'\n | 'member:remove'\n | 'member:role_change'\n | 'member:read'\n | 'invite:create'\n | 'invite:cancel'\n | 'invite:read'\n | 'audit:read';\n\n/**\n * Create organization request\n */\nexport interface CreateOrgRequest {\n name: string;\n slug?: string;\n}\n\n/**\n * Update organization request\n */\nexport interface UpdateOrgRequest {\n name?: string;\n slug?: string;\n logoUrl?: string;\n}\n\n/**\n * List organizations response\n */\nexport interface ListOrgsResponse {\n orgs: Array<Organization & { role: OrgRole }>;\n total?: number;\n limit?: number;\n offset?: number;\n}\n\n/**\n * Authorization check request\n */\nexport interface AuthorizeRequest {\n orgId: string;\n action: string;\n resource?: string;\n resourceId?: string;\n}\n\n/**\n * Authorization check response\n */\nexport interface AuthorizeResponse {\n allowed: boolean;\n reason?: string;\n}\n\n/**\n * Permissions response\n */\nexport interface PermissionsResponse {\n permissions: Permission[];\n role: OrgRole;\n}\n\n/**\n * Organization state for context\n */\nexport interface OrgState {\n /** Currently active organization */\n activeOrg: OrgWithMembership | null;\n /** All organizations the user belongs to */\n orgs: OrgWithMembership[];\n /** User's permissions in the active org */\n permissions: Permission[];\n /** User's role in the active org */\n role: OrgRole | null;\n /** Loading state for org operations */\n isLoading: boolean;\n}\n\n// =============================================================================\n// DASHBOARD PERMISSIONS\n// =============================================================================\n\n/**\n * Admin dashboard sections that can be permission-controlled\n */\nexport type DashboardSection =\n // Cedros Login sections\n | 'users'\n | 'team'\n | 'deposits'\n | 'withdrawals'\n | 'settings-wallet'\n | 'settings-auth'\n | 'settings-messaging'\n | 'settings-credits'\n | 'settings-server'\n // Cedros Pay sections\n | 'pay-products'\n | 'pay-subscriptions'\n | 'pay-transactions'\n | 'pay-coupons'\n | 'pay-refunds'\n | 'pay-storefront'\n | 'pay-ai'\n | 'pay-payment'\n | 'pay-messaging'\n | 'pay-settings';\n\n/**\n * Cedros Login dashboard sections\n */\nexport const LOGIN_DASHBOARD_SECTIONS: DashboardSection[] = [\n 'users',\n 'team',\n 'deposits',\n 'withdrawals',\n 'settings-wallet',\n 'settings-auth',\n 'settings-messaging',\n 'settings-credits',\n 'settings-server',\n];\n\n/**\n * Cedros Pay dashboard sections\n */\nexport const PAY_DASHBOARD_SECTIONS: DashboardSection[] = [\n 'pay-products',\n 'pay-subscriptions',\n 'pay-transactions',\n 'pay-coupons',\n 'pay-refunds',\n 'pay-storefront',\n 'pay-ai',\n 'pay-payment',\n 'pay-messaging',\n 'pay-settings',\n];\n\n/**\n * All available dashboard sections\n */\nexport const ALL_DASHBOARD_SECTIONS: DashboardSection[] = [\n ...LOGIN_DASHBOARD_SECTIONS,\n ...PAY_DASHBOARD_SECTIONS,\n];\n\n/**\n * Human-readable labels for dashboard sections\n */\nexport const DASHBOARD_SECTION_LABELS: Record<DashboardSection, string> = {\n // Cedros Login\n users: 'Users',\n team: 'Team',\n deposits: 'Deposits',\n withdrawals: 'Withdrawals',\n 'settings-wallet': 'Wallet Settings',\n 'settings-auth': 'Auth Settings',\n 'settings-messaging': 'Messages Settings',\n 'settings-credits': 'Credits Settings',\n 'settings-server': 'Server Settings',\n // Cedros Pay\n 'pay-products': 'Products',\n 'pay-subscriptions': 'Subscriptions',\n 'pay-transactions': 'Transactions',\n 'pay-coupons': 'Coupons',\n 'pay-refunds': 'Refunds',\n 'pay-storefront': 'Storefront',\n 'pay-ai': 'Store AI',\n 'pay-payment': 'Payment Options',\n 'pay-messaging': 'Store Messages',\n 'pay-settings': 'Store Server',\n};\n\n/**\n * Dashboard permissions per role\n * Only admin and member are configurable - owner always has full access\n */\nexport interface DashboardPermissions {\n admin: Record<DashboardSection, boolean>;\n member: Record<DashboardSection, boolean>;\n}\n\n/**\n * Default dashboard permissions for new orgs\n */\nexport const DEFAULT_DASHBOARD_PERMISSIONS: DashboardPermissions = {\n admin: {\n // Cedros Login\n users: true,\n team: true,\n deposits: true,\n withdrawals: true,\n 'settings-wallet': true,\n 'settings-auth': true,\n 'settings-messaging': true,\n 'settings-credits': true,\n 'settings-server': true,\n // Cedros Pay\n 'pay-products': true,\n 'pay-subscriptions': true,\n 'pay-transactions': true,\n 'pay-coupons': true,\n 'pay-refunds': true,\n 'pay-storefront': true,\n 'pay-ai': true,\n 'pay-payment': true,\n 'pay-messaging': true,\n 'pay-settings': true,\n },\n member: {\n // Cedros Login\n users: false,\n team: true,\n deposits: false,\n withdrawals: false,\n 'settings-wallet': false,\n 'settings-auth': false,\n 'settings-messaging': false,\n 'settings-credits': false,\n 'settings-server': false,\n // Cedros Pay\n 'pay-products': false,\n 'pay-subscriptions': false,\n 'pay-transactions': false,\n 'pay-coupons': false,\n 'pay-refunds': false,\n 'pay-storefront': false,\n 'pay-ai': false,\n 'pay-payment': false,\n 'pay-messaging': false,\n 'pay-settings': false,\n },\n};\n","import { useState, useCallback, useMemo, useRef, useEffect } from 'react';\nimport type { DashboardSection, DashboardPermissions, AuthError } from '../types';\nimport { DEFAULT_DASHBOARD_PERMISSIONS } from '../types/org';\nimport { useCedrosLogin } from '../context/useCedrosLogin';\nimport { useOrgs } from './useOrgs';\nimport { ApiClient } from '../utils/apiClient';\n\nexport interface UseDashboardPermissionsReturn {\n /** Current dashboard permissions config */\n permissions: DashboardPermissions;\n /** Whether the current user can access a specific section */\n canAccess: (section: DashboardSection) => boolean;\n /** Update permissions (owner only) */\n updatePermissions: (permissions: DashboardPermissions) => Promise<void>;\n /** Loading state */\n isLoading: boolean;\n /** Updating state */\n isUpdating: boolean;\n /** Error state */\n error: AuthError | null;\n /** Refresh permissions from server */\n fetchPermissions: () => Promise<void>;\n}\n\n/**\n * Hook for managing dashboard permissions per role.\n *\n * Allows org owners to configure which dashboard sections each role can access.\n * - Owner always has full access (not configurable)\n * - Admin and Member roles are configurable\n *\n * @example\n * ```tsx\n * function AdminDashboard() {\n * const { canAccess, permissions, updatePermissions } = useDashboardPermissions();\n *\n * // Check if current user can access a section\n * if (!canAccess('deposits')) {\n * return <div>You don't have access to deposits</div>;\n * }\n *\n * // Update permissions (owner only)\n * const toggleMemberDeposits = () => {\n * updatePermissions({\n * ...permissions,\n * member: { ...permissions.member, deposits: !permissions.member.deposits },\n * });\n * };\n * }\n * ```\n */\nexport function useDashboardPermissions(): UseDashboardPermissionsReturn {\n const { config, authState, _internal } = useCedrosLogin();\n const { activeOrg, role } = useOrgs();\n\n const [permissions, setPermissions] = useState<DashboardPermissions>(\n DEFAULT_DASHBOARD_PERMISSIONS\n );\n const [isLoading, setIsLoading] = useState(false);\n const [isUpdating, setIsUpdating] = useState(false);\n const [error, setError] = useState<AuthError | null>(null);\n const requestIdRef = useRef(0);\n\n const apiClient = useMemo(\n () =>\n new ApiClient({\n baseUrl: config.serverUrl,\n timeoutMs: config.requestTimeout,\n retryAttempts: config.retryAttempts,\n getAccessToken: _internal?.getAccessToken,\n }),\n [config.serverUrl, config.requestTimeout, config.retryAttempts, _internal]\n );\n\n // Use ref to avoid apiClient in callback dependencies\n const apiClientRef = useRef(apiClient);\n apiClientRef.current = apiClient;\n\n const fetchPermissions = useCallback(async () => {\n if (authState !== 'authenticated' || !activeOrg) {\n setPermissions(DEFAULT_DASHBOARD_PERMISSIONS);\n return;\n }\n\n setIsLoading(true);\n setError(null);\n const requestId = ++requestIdRef.current;\n\n try {\n const response = await apiClientRef.current.get<{ permissions: DashboardPermissions }>(\n '/admin/dashboard-permissions'\n );\n if (requestId !== requestIdRef.current) return;\n setPermissions(response.permissions);\n } catch (err) {\n if (requestId !== requestIdRef.current) return;\n // If 404, use defaults (permissions not configured yet)\n if (err instanceof Error && err.message.includes('404')) {\n setPermissions(DEFAULT_DASHBOARD_PERMISSIONS);\n } else {\n const message = err instanceof Error ? err.message : 'Failed to fetch permissions';\n setError({ code: 'NETWORK_ERROR', message } as AuthError);\n // Fall back to defaults on error\n setPermissions(DEFAULT_DASHBOARD_PERMISSIONS);\n }\n } finally {\n if (requestId === requestIdRef.current) {\n setIsLoading(false);\n }\n }\n }, [authState, activeOrg]);\n\n const updatePermissions = useCallback(\n async (newPermissions: DashboardPermissions): Promise<void> => {\n if (authState !== 'authenticated' || !activeOrg) {\n throw new Error('Not authenticated');\n }\n\n if (role !== 'owner') {\n throw new Error('Only owners can modify dashboard permissions');\n }\n\n setIsUpdating(true);\n setError(null);\n\n try {\n await apiClientRef.current.request<{ permissions: DashboardPermissions }>({\n method: 'PUT',\n path: '/admin/dashboard-permissions',\n body: newPermissions,\n });\n setPermissions(newPermissions);\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Failed to update permissions';\n const authError = { code: 'NETWORK_ERROR', message } as AuthError;\n setError(authError);\n throw new Error(message);\n } finally {\n setIsUpdating(false);\n }\n },\n [authState, activeOrg, role]\n );\n\n /**\n * Check if the current user can access a dashboard section\n * - No org context (system admin): full access (permissions are org-scoped)\n * - Owner: always has full access\n * - Admin: check permissions.admin[section]\n * - Member: check permissions.member[section]\n */\n const canAccess = useCallback(\n (section: DashboardSection): boolean => {\n // No org context = system admin level, allow all\n // (dashboard permissions are org-scoped, not system-scoped)\n if (!activeOrg || !role) {\n return true;\n }\n\n // Owner always has full access\n if (role === 'owner') {\n return true;\n }\n\n // Admin and member: check configured permissions\n const rolePermissions = permissions[role as 'admin' | 'member'];\n return rolePermissions?.[section] ?? false;\n },\n [activeOrg, role, permissions]\n );\n\n // Fetch permissions when org changes\n useEffect(() => {\n if (activeOrg?.id) {\n fetchPermissions();\n }\n }, [activeOrg?.id, fetchPermissions]);\n\n return {\n permissions,\n canAccess,\n updatePermissions,\n isLoading,\n isUpdating,\n error,\n fetchPermissions,\n };\n}\n","/**\n * PermissionsSection - Dashboard permissions matrix for role configuration\n *\n * Allows org owners to configure which dashboard sections each role can access.\n */\n\nimport React, { useCallback, useRef, useEffect } from 'react';\nimport { useDashboardPermissions } from '../../hooks/useDashboardPermissions';\nimport { useServerFeatures } from '../../hooks/useServerFeatures';\nimport {\n LOGIN_DASHBOARD_SECTIONS,\n PAY_DASHBOARD_SECTIONS,\n DASHBOARD_SECTION_LABELS,\n type DashboardSection,\n type DashboardPermissions,\n type OrgRole,\n} from '../../types/org';\n\ninterface PermissionToggleProps {\n checked: boolean;\n onChange: (checked: boolean) => void;\n disabled?: boolean;\n label: string;\n}\n\nfunction PermissionToggle({ checked, onChange, disabled, label }: PermissionToggleProps) {\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={checked}\n aria-label={label}\n disabled={disabled}\n className={`cedros-toggle cedros-toggle-sm ${checked ? 'cedros-toggle-on' : 'cedros-toggle-off'} ${disabled ? 'cedros-toggle-disabled' : ''}`}\n onClick={() => !disabled && onChange(!checked)}\n >\n <span className=\"cedros-toggle-track\">\n <span className=\"cedros-toggle-thumb\" />\n </span>\n </button>\n );\n}\n\nexport interface PermissionsSectionProps {\n /** Current user's role in the org */\n userRole?: OrgRole | null;\n}\n\nexport function PermissionsSection({ userRole }: PermissionsSectionProps): React.JSX.Element {\n const { permissions, updatePermissions, isLoading, isUpdating, error } =\n useDashboardPermissions();\n const { features, isLoading: featuresLoading } = useServerFeatures();\n const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const pendingPermissions = useRef<DashboardPermissions | null>(null);\n\n const isOwner = userRole === 'owner';\n const cedrosPayEnabled = features.cedrosPay;\n\n // Debounced save - batch rapid changes\n const debouncedSave = useCallback(\n (newPermissions: DashboardPermissions) => {\n pendingPermissions.current = newPermissions;\n if (debounceRef.current) {\n clearTimeout(debounceRef.current);\n }\n debounceRef.current = setTimeout(() => {\n if (pendingPermissions.current) {\n updatePermissions(pendingPermissions.current).catch(() => {\n // Error is already set in state by the hook\n });\n pendingPermissions.current = null;\n }\n }, 500);\n },\n [updatePermissions]\n );\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (debounceRef.current) {\n clearTimeout(debounceRef.current);\n }\n };\n }, []);\n\n const handleToggle = useCallback(\n (role: 'admin' | 'member', section: DashboardSection, enabled: boolean) => {\n const newPermissions: DashboardPermissions = {\n ...permissions,\n [role]: {\n ...permissions[role],\n [section]: enabled,\n },\n };\n debouncedSave(newPermissions);\n },\n [permissions, debouncedSave]\n );\n\n if (isLoading || featuresLoading) {\n return (\n <div className=\"cedros-dashboard__section\">\n <div className=\"cedros-dashboard__loading\">Loading permissions...</div>\n </div>\n );\n }\n\n if (!isOwner) {\n return (\n <div className=\"cedros-dashboard__section\">\n <div className=\"cedros-dashboard__empty\">\n Only organization owners can configure dashboard permissions.\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"cedros-dashboard__section cedros-permissions-section\">\n <div className=\"cedros-permissions-header\">\n <p className=\"cedros-permissions-description\">\n Configure which dashboard sections each role can access. Owners always have full access.\n </p>\n {error && <div className=\"cedros-permissions-error\">{error.message}</div>}\n {isUpdating && <span className=\"cedros-permissions-saving\">Saving...</span>}\n </div>\n\n <div className=\"cedros-permissions-matrix\">\n <table className=\"cedros-permissions-table\">\n <tbody>\n {/* Cedros Login Sections */}\n <tr className=\"cedros-permissions-group-header\">\n <th className=\"cedros-permissions-section-header\">Cedros Login</th>\n <th className=\"cedros-permissions-role-header\">Admin</th>\n <th className=\"cedros-permissions-role-header\">Member</th>\n </tr>\n {LOGIN_DASHBOARD_SECTIONS.map((section) => (\n <tr key={section} className=\"cedros-permissions-row\">\n <td className=\"cedros-permissions-section-label\">\n {DASHBOARD_SECTION_LABELS[section]}\n </td>\n <td className=\"cedros-permissions-toggle-cell\">\n <PermissionToggle\n checked={permissions.admin[section] ?? false}\n onChange={(enabled) => handleToggle('admin', section, enabled)}\n disabled={isUpdating}\n label={`Admin access to ${DASHBOARD_SECTION_LABELS[section]}`}\n />\n </td>\n <td className=\"cedros-permissions-toggle-cell\">\n <PermissionToggle\n checked={permissions.member[section] ?? false}\n onChange={(enabled) => handleToggle('member', section, enabled)}\n disabled={isUpdating}\n label={`Member access to ${DASHBOARD_SECTION_LABELS[section]}`}\n />\n </td>\n </tr>\n ))}\n\n {/* Cedros Pay Sections (only when cedrosPay feature is enabled) */}\n {cedrosPayEnabled && (\n <>\n <tr className=\"cedros-permissions-group-header\">\n <th className=\"cedros-permissions-section-header\">Cedros Pay</th>\n <th className=\"cedros-permissions-role-header\">Admin</th>\n <th className=\"cedros-permissions-role-header\">Member</th>\n </tr>\n {PAY_DASHBOARD_SECTIONS.map((section) => (\n <tr key={section} className=\"cedros-permissions-row\">\n <td className=\"cedros-permissions-section-label\">\n {DASHBOARD_SECTION_LABELS[section]}\n </td>\n <td className=\"cedros-permissions-toggle-cell\">\n <PermissionToggle\n checked={permissions.admin[section] ?? false}\n onChange={(enabled) => handleToggle('admin', section, enabled)}\n disabled={isUpdating}\n label={`Admin access to ${DASHBOARD_SECTION_LABELS[section]}`}\n />\n </td>\n <td className=\"cedros-permissions-toggle-cell\">\n <PermissionToggle\n checked={permissions.member[section] ?? false}\n onChange={(enabled) => handleToggle('member', section, enabled)}\n disabled={isUpdating}\n label={`Member access to ${DASHBOARD_SECTION_LABELS[section]}`}\n />\n </td>\n </tr>\n ))}\n </>\n )}\n </tbody>\n </table>\n </div>\n </div>\n );\n}\n"],"names":["ROLE_OPTIONS","MemberList","members","currentUserId","isLoading","error","canManage","canChangeRoles","onUpdateRole","onRemove","className","sortField","setSortField","useState","sortOrder","setSortOrder","toggleSort","field","sortedMembers","useMemo","roleOrder","a","b","aVal","bVal","jsxs","jsx","LoadingSpinner","ErrorMessage","member","MemberRow","isCurrentUser","isUpdating","setIsUpdating","selectedRole","setSelectedRole","handleRoleChange","useCallback","newRole","handleRemove","isOwner","canModify","MemberAvatar","e","role","formatDate","user","sanitizedPicture","sanitizeImageUrl","initial","dateString","DEFAULT_ROLES","InviteForm","onSubmit","availableRoles","defaultRole","email","setEmail","setRole","formError","setFormError","success","setSuccess","successTimerRef","useRef","isMountedRef","useEffect","handleSubmit","trimmedEmail","validateEmail","CheckIcon","r","InviteList","invites","onCancel","onResend","invite","InviteItem","resendSuccess","setResendSuccess","resendTimerRef","isExpired","handleCancel","handleResend","formatRelativeTime","date","now","diffMs","diffDays","MemberApiClient","baseUrl","timeoutMs","retryAttempts","getAccessToken","ApiClient","orgId","limit","offset","response","handleApiError","userId","data","useMembers","config","authState","_internal","useCedrosLogin","setMembers","total","setTotal","setIsLoading","setError","fetchedOrgIdRef","requestIdRef","apiClient","apiClientRef","fetchMembers","options","requestId","err","updateMemberRole","removeMember","InviteApiClient","inviteId","useInvites","setInvites","fetchInvites","createInvite","cancelInvite","resendInvite","acceptInvite","token","DEFAULT_FEATURES","useServerFeatures","settings","fetchSettings","getValue","useSystemSettings","hasFetched","setHasFetched","parseBoolean","value","features","refetch","isEnabled","feature","LOGIN_DASHBOARD_SECTIONS","PAY_DASHBOARD_SECTIONS","DASHBOARD_SECTION_LABELS","DEFAULT_DASHBOARD_PERMISSIONS","useDashboardPermissions","activeOrg","useOrgs","permissions","setPermissions","fetchPermissions","message","updatePermissions","newPermissions","canAccess","section","PermissionToggle","checked","onChange","disabled","label","PermissionsSection","userRole","featuresLoading","debounceRef","pendingPermissions","cedrosPayEnabled","debouncedSave","handleToggle","enabled","Fragment"],"mappings":"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"}
@@ -2,7 +2,7 @@ import { jsxs as i, jsx as e } from "react/jsx-runtime";
2
2
  import { useState as b, useEffect as k, useMemo as _ } from "react";
3
3
  import { L as N } from "./LoadingSpinner-6vml-zwr.js";
4
4
  import { E as A } from "./ErrorMessage-CcEK0pYO.js";
5
- import { u as x, A as L, S as E } from "./AutosaveStatus-N4uNS6-2.js";
5
+ import { u as x, A as L, S as E } from "./AutosaveStatus-Ciyt350A.js";
6
6
  const u = [
7
7
  {
8
8
  id: "general",
@@ -1 +1 @@
1
- {"version":3,"file":"ServerSettings-B2RKhJtZ.js","sources":["../src/components/admin/settings/ServerSettings.tsx"],"sourcesContent":["/**\n * Server settings page - infrastructure configuration with tabs\n */\nimport { useState, useEffect, useMemo } from 'react';\nimport { LoadingSpinner } from '../../shared/LoadingSpinner';\nimport { ErrorMessage } from '../../shared/ErrorMessage';\nimport { useSettingsAutosave } from '../../../hooks/useSettingsAutosave';\nimport { SettingsSection } from './settingsInputs';\nimport { AutosaveStatus } from './AutosaveStatus';\n\ntype ServerTab = 'general' | 'logging' | 'metrics' | 'security';\n\ninterface TabConfig {\n id: ServerTab;\n label: string;\n /** Categories to pull settings from (defaults to ['server']) */\n categories?: string[];\n keys: string[];\n}\n\nconst TABS: TabConfig[] = [\n {\n id: 'general',\n label: 'Integrations',\n keys: ['server_cedros_pay_api_key'],\n },\n {\n id: 'logging',\n label: 'Logging',\n keys: ['server_log_level'],\n },\n {\n id: 'metrics',\n label: 'Metrics',\n keys: ['server_metrics_api_key'],\n },\n {\n id: 'security',\n label: 'Security',\n categories: ['security', 'features'],\n keys: ['feature_mfa', 'security_cors_origins', 'security_session_timeout'],\n },\n];\n\nexport interface ServerSettingsProps {\n className?: string;\n}\n\nexport function ServerSettings({ className }: ServerSettingsProps) {\n const {\n settings,\n edits,\n isLoading,\n autosaveStatus,\n autosaveError,\n error,\n fetchSettings,\n handleChange,\n } = useSettingsAutosave();\n\n const [activeTab, setActiveTab] = useState<ServerTab>('general');\n\n useEffect(() => {\n fetchSettings();\n }, [fetchSettings]);\n\n // Get current tab config\n const currentTab = TABS.find((t) => t.id === activeTab);\n\n // Collect settings from all categories for the current tab\n const currentSettings = useMemo(() => {\n if (!currentTab) return [];\n const categories = currentTab.categories ?? ['server'];\n const allSettings: (typeof settings)[string] = [];\n for (const category of categories) {\n const categorySettings = settings[category] ?? [];\n allSettings.push(...categorySettings);\n }\n // Filter by keys and sort by keys order\n return allSettings\n .filter((s) => currentTab.keys.includes(s.key))\n .sort((a, b) => currentTab.keys.indexOf(a.key) - currentTab.keys.indexOf(b.key));\n }, [settings, currentTab]);\n\n if (isLoading && Object.keys(settings).length === 0) {\n return (\n <div className={`cedros-system-settings cedros-system-settings-loading ${className ?? ''}`}>\n <LoadingSpinner />\n <span>Loading settings...</span>\n </div>\n );\n }\n\n if (error) {\n return (\n <div className={`cedros-system-settings ${className ?? ''}`}>\n <ErrorMessage error={error.message} />\n </div>\n );\n }\n\n return (\n <div className={`cedros-system-settings ${className ?? ''}`}>\n <div className=\"cedros-settings-page-header\">\n <div className=\"cedros-settings-page-header-content\">\n <h2 className=\"cedros-settings-page-title\">Auth Server</h2>\n <p className=\"cedros-settings-page-description\">\n Server infrastructure settings. Some may be overridden by environment variables.\n </p>\n </div>\n <AutosaveStatus status={autosaveStatus} error={autosaveError} />\n </div>\n\n {/* Tabs */}\n <div className=\"cedros-admin-tabs cedros-admin-tabs--line\">\n {TABS.map((tab) => (\n <button\n key={tab.id}\n type=\"button\"\n className={`cedros-admin-tab ${activeTab === tab.id ? 'cedros-admin-tab-active' : ''}`}\n onClick={() => setActiveTab(tab.id)}\n aria-selected={activeTab === tab.id}\n role=\"tab\"\n >\n {tab.label}\n </button>\n ))}\n </div>\n\n {/* Tab content */}\n <div className=\"cedros-admin-tab-content\" role=\"tabpanel\">\n {currentSettings.length === 0 ? (\n <div className=\"cedros-system-settings-empty\">\n <p>No settings found for {currentTab?.label ?? 'this section'}.</p>\n </div>\n ) : (\n <SettingsSection settings={currentSettings} edits={edits} onChange={handleChange} />\n )}\n </div>\n </div>\n );\n}\n"],"names":["TABS","ServerSettings","className","settings","edits","isLoading","autosaveStatus","autosaveError","error","fetchSettings","handleChange","useSettingsAutosave","activeTab","setActiveTab","useState","useEffect","currentTab","t","currentSettings","useMemo","categories","allSettings","category","categorySettings","s","a","b","jsx","LoadingSpinner","ErrorMessage","jsxs","AutosaveStatus","tab","SettingsSection"],"mappings":"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"}
1
+ {"version":3,"file":"ServerSettings-BE8fsE5k.js","sources":["../src/components/admin/settings/ServerSettings.tsx"],"sourcesContent":["/**\n * Server settings page - infrastructure configuration with tabs\n */\nimport { useState, useEffect, useMemo } from 'react';\nimport { LoadingSpinner } from '../../shared/LoadingSpinner';\nimport { ErrorMessage } from '../../shared/ErrorMessage';\nimport { useSettingsAutosave } from '../../../hooks/useSettingsAutosave';\nimport { SettingsSection } from './settingsInputs';\nimport { AutosaveStatus } from './AutosaveStatus';\n\ntype ServerTab = 'general' | 'logging' | 'metrics' | 'security';\n\ninterface TabConfig {\n id: ServerTab;\n label: string;\n /** Categories to pull settings from (defaults to ['server']) */\n categories?: string[];\n keys: string[];\n}\n\nconst TABS: TabConfig[] = [\n {\n id: 'general',\n label: 'Integrations',\n keys: ['server_cedros_pay_api_key'],\n },\n {\n id: 'logging',\n label: 'Logging',\n keys: ['server_log_level'],\n },\n {\n id: 'metrics',\n label: 'Metrics',\n keys: ['server_metrics_api_key'],\n },\n {\n id: 'security',\n label: 'Security',\n categories: ['security', 'features'],\n keys: ['feature_mfa', 'security_cors_origins', 'security_session_timeout'],\n },\n];\n\nexport interface ServerSettingsProps {\n className?: string;\n}\n\nexport function ServerSettings({ className }: ServerSettingsProps) {\n const {\n settings,\n edits,\n isLoading,\n autosaveStatus,\n autosaveError,\n error,\n fetchSettings,\n handleChange,\n } = useSettingsAutosave();\n\n const [activeTab, setActiveTab] = useState<ServerTab>('general');\n\n useEffect(() => {\n fetchSettings();\n }, [fetchSettings]);\n\n // Get current tab config\n const currentTab = TABS.find((t) => t.id === activeTab);\n\n // Collect settings from all categories for the current tab\n const currentSettings = useMemo(() => {\n if (!currentTab) return [];\n const categories = currentTab.categories ?? ['server'];\n const allSettings: (typeof settings)[string] = [];\n for (const category of categories) {\n const categorySettings = settings[category] ?? [];\n allSettings.push(...categorySettings);\n }\n // Filter by keys and sort by keys order\n return allSettings\n .filter((s) => currentTab.keys.includes(s.key))\n .sort((a, b) => currentTab.keys.indexOf(a.key) - currentTab.keys.indexOf(b.key));\n }, [settings, currentTab]);\n\n if (isLoading && Object.keys(settings).length === 0) {\n return (\n <div className={`cedros-system-settings cedros-system-settings-loading ${className ?? ''}`}>\n <LoadingSpinner />\n <span>Loading settings...</span>\n </div>\n );\n }\n\n if (error) {\n return (\n <div className={`cedros-system-settings ${className ?? ''}`}>\n <ErrorMessage error={error.message} />\n </div>\n );\n }\n\n return (\n <div className={`cedros-system-settings ${className ?? ''}`}>\n <div className=\"cedros-settings-page-header\">\n <div className=\"cedros-settings-page-header-content\">\n <h2 className=\"cedros-settings-page-title\">Auth Server</h2>\n <p className=\"cedros-settings-page-description\">\n Server infrastructure settings. Some may be overridden by environment variables.\n </p>\n </div>\n <AutosaveStatus status={autosaveStatus} error={autosaveError} />\n </div>\n\n {/* Tabs */}\n <div className=\"cedros-admin-tabs cedros-admin-tabs--line\">\n {TABS.map((tab) => (\n <button\n key={tab.id}\n type=\"button\"\n className={`cedros-admin-tab ${activeTab === tab.id ? 'cedros-admin-tab-active' : ''}`}\n onClick={() => setActiveTab(tab.id)}\n aria-selected={activeTab === tab.id}\n role=\"tab\"\n >\n {tab.label}\n </button>\n ))}\n </div>\n\n {/* Tab content */}\n <div className=\"cedros-admin-tab-content\" role=\"tabpanel\">\n {currentSettings.length === 0 ? (\n <div className=\"cedros-system-settings-empty\">\n <p>No settings found for {currentTab?.label ?? 'this section'}.</p>\n </div>\n ) : (\n <SettingsSection settings={currentSettings} edits={edits} onChange={handleChange} />\n )}\n </div>\n </div>\n );\n}\n"],"names":["TABS","ServerSettings","className","settings","edits","isLoading","autosaveStatus","autosaveError","error","fetchSettings","handleChange","useSettingsAutosave","activeTab","setActiveTab","useState","useEffect","currentTab","t","currentSettings","useMemo","categories","allSettings","category","categorySettings","s","a","b","jsx","LoadingSpinner","ErrorMessage","jsxs","AutosaveStatus","tab","SettingsSection"],"mappings":"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"}
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime");require("react");const r=require("./ServerSettings-DZUKo6By.cjs");function t(){return e.jsx("div",{className:"cedros-dashboard__section",children:e.jsx(r.ServerSettings,{})})}exports.default=t;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime");require("react");const r=require("./ServerSettings-DFs9jQ3f.cjs");function t(){return e.jsx("div",{className:"cedros-dashboard__section",children:e.jsx(r.ServerSettings,{})})}exports.default=t;
@@ -1 +1 @@
1
- {"version":3,"file":"ServerSettings-BZXlm1BX.cjs","sources":["../src/admin/sections/ServerSettings.tsx"],"sourcesContent":["/**\n * Server Settings Section - Plugin wrapper\n */\n\nimport React from 'react';\nimport { ServerSettings as Settings } from '../../components/admin/settings';\n\nexport default function ServerSettings(): React.JSX.Element {\n return (\n <div className=\"cedros-dashboard__section\">\n <Settings />\n </div>\n );\n}\n"],"names":["ServerSettings","jsx","Settings"],"mappings":"uLAOA,SAAwBA,GAAoC,CAC1D,aACG,MAAA,CAAI,UAAU,4BACb,SAAAC,MAACC,EAAAA,iBAAS,EACZ,CAEJ"}
1
+ {"version":3,"file":"ServerSettings-CYTlQ2xy.cjs","sources":["../src/admin/sections/ServerSettings.tsx"],"sourcesContent":["/**\n * Server Settings Section - Plugin wrapper\n */\n\nimport React from 'react';\nimport { ServerSettings as Settings } from '../../components/admin/settings';\n\nexport default function ServerSettings(): React.JSX.Element {\n return (\n <div className=\"cedros-dashboard__section\">\n <Settings />\n </div>\n );\n}\n"],"names":["ServerSettings","jsx","Settings"],"mappings":"uLAOA,SAAwBA,GAAoC,CAC1D,aACG,MAAA,CAAI,UAAU,4BACb,SAAAC,MAACC,EAAAA,iBAAS,EACZ,CAEJ"}
@@ -1 +1 @@
1
- "use strict";const e=require("react/jsx-runtime"),o=require("react"),b=require("./LoadingSpinner-d6sSxgQN.cjs"),p=require("./ErrorMessage-CHbYbVi2.cjs"),d=require("./AutosaveStatus-CYkC2aI_.cjs"),y=[{id:"general",label:"Integrations",keys:["server_cedros_pay_api_key"]},{id:"logging",label:"Logging",keys:["server_log_level"]},{id:"metrics",label:"Metrics",keys:["server_metrics_api_key"]},{id:"security",label:"Security",categories:["security","features"],keys:["feature_mfa","security_cors_origins","security_session_timeout"]}];function k({className:i}){const{settings:n,edits:v,isLoading:h,autosaveStatus:S,autosaveError:x,error:l,fetchSettings:g,handleChange:f}=d.useSettingsAutosave(),[a,j]=o.useState("general");o.useEffect(()=>{g()},[g]);const t=y.find(s=>s.id===a),u=o.useMemo(()=>{if(!t)return[];const s=t.categories??["server"],m=[];for(const r of s){const c=n[r]??[];m.push(...c)}return m.filter(r=>t.keys.includes(r.key)).sort((r,c)=>t.keys.indexOf(r.key)-t.keys.indexOf(c.key))},[n,t]);return h&&Object.keys(n).length===0?e.jsxs("div",{className:`cedros-system-settings cedros-system-settings-loading ${i??""}`,children:[e.jsx(b.LoadingSpinner,{}),e.jsx("span",{children:"Loading settings..."})]}):l?e.jsx("div",{className:`cedros-system-settings ${i??""}`,children:e.jsx(p.ErrorMessage,{error:l.message})}):e.jsxs("div",{className:`cedros-system-settings ${i??""}`,children:[e.jsxs("div",{className:"cedros-settings-page-header",children:[e.jsxs("div",{className:"cedros-settings-page-header-content",children:[e.jsx("h2",{className:"cedros-settings-page-title",children:"Auth Server"}),e.jsx("p",{className:"cedros-settings-page-description",children:"Server infrastructure settings. Some may be overridden by environment variables."})]}),e.jsx(d.AutosaveStatus,{status:S,error:x})]}),e.jsx("div",{className:"cedros-admin-tabs cedros-admin-tabs--line",children:y.map(s=>e.jsx("button",{type:"button",className:`cedros-admin-tab ${a===s.id?"cedros-admin-tab-active":""}`,onClick:()=>j(s.id),"aria-selected":a===s.id,role:"tab",children:s.label},s.id))}),e.jsx("div",{className:"cedros-admin-tab-content",role:"tabpanel",children:u.length===0?e.jsx("div",{className:"cedros-system-settings-empty",children:e.jsxs("p",{children:["No settings found for ",t?.label??"this section","."]})}):e.jsx(d.SettingsSection,{settings:u,edits:v,onChange:f})})]})}exports.ServerSettings=k;
1
+ "use strict";const e=require("react/jsx-runtime"),o=require("react"),b=require("./LoadingSpinner-d6sSxgQN.cjs"),p=require("./ErrorMessage-CHbYbVi2.cjs"),d=require("./AutosaveStatus-CCrZszKA.cjs"),y=[{id:"general",label:"Integrations",keys:["server_cedros_pay_api_key"]},{id:"logging",label:"Logging",keys:["server_log_level"]},{id:"metrics",label:"Metrics",keys:["server_metrics_api_key"]},{id:"security",label:"Security",categories:["security","features"],keys:["feature_mfa","security_cors_origins","security_session_timeout"]}];function k({className:i}){const{settings:n,edits:v,isLoading:h,autosaveStatus:S,autosaveError:x,error:l,fetchSettings:g,handleChange:f}=d.useSettingsAutosave(),[a,j]=o.useState("general");o.useEffect(()=>{g()},[g]);const t=y.find(s=>s.id===a),u=o.useMemo(()=>{if(!t)return[];const s=t.categories??["server"],m=[];for(const r of s){const c=n[r]??[];m.push(...c)}return m.filter(r=>t.keys.includes(r.key)).sort((r,c)=>t.keys.indexOf(r.key)-t.keys.indexOf(c.key))},[n,t]);return h&&Object.keys(n).length===0?e.jsxs("div",{className:`cedros-system-settings cedros-system-settings-loading ${i??""}`,children:[e.jsx(b.LoadingSpinner,{}),e.jsx("span",{children:"Loading settings..."})]}):l?e.jsx("div",{className:`cedros-system-settings ${i??""}`,children:e.jsx(p.ErrorMessage,{error:l.message})}):e.jsxs("div",{className:`cedros-system-settings ${i??""}`,children:[e.jsxs("div",{className:"cedros-settings-page-header",children:[e.jsxs("div",{className:"cedros-settings-page-header-content",children:[e.jsx("h2",{className:"cedros-settings-page-title",children:"Auth Server"}),e.jsx("p",{className:"cedros-settings-page-description",children:"Server infrastructure settings. Some may be overridden by environment variables."})]}),e.jsx(d.AutosaveStatus,{status:S,error:x})]}),e.jsx("div",{className:"cedros-admin-tabs cedros-admin-tabs--line",children:y.map(s=>e.jsx("button",{type:"button",className:`cedros-admin-tab ${a===s.id?"cedros-admin-tab-active":""}`,onClick:()=>j(s.id),"aria-selected":a===s.id,role:"tab",children:s.label},s.id))}),e.jsx("div",{className:"cedros-admin-tab-content",role:"tabpanel",children:u.length===0?e.jsx("div",{className:"cedros-system-settings-empty",children:e.jsxs("p",{children:["No settings found for ",t?.label??"this section","."]})}):e.jsx(d.SettingsSection,{settings:u,edits:v,onChange:f})})]})}exports.ServerSettings=k;