@better-auth-ui/heroui 1.6.8 → 1.6.9

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 (270) hide show
  1. package/dist/components/auth/additional-field.d.ts +2 -2
  2. package/dist/components/auth/additional-field.js +133 -266
  3. package/dist/components/auth/api-key/api-key-skeleton.js +4 -20
  4. package/dist/components/auth/api-key/api-key.d.ts +6 -2
  5. package/dist/components/auth/api-key/api-key.js +16 -54
  6. package/dist/components/auth/api-key/api-keys-empty.d.ts +3 -1
  7. package/dist/components/auth/api-key/api-keys-empty.js +8 -34
  8. package/dist/components/auth/api-key/api-keys.d.ts +10 -2
  9. package/dist/components/auth/api-key/api-keys.js +21 -40
  10. package/dist/components/auth/api-key/create-api-key-dialog.d.ts +3 -1
  11. package/dist/components/auth/api-key/create-api-key-dialog.js +43 -73
  12. package/dist/components/auth/api-key/delete-api-key-dialog.d.ts +4 -2
  13. package/dist/components/auth/api-key/delete-api-key-dialog.js +16 -50
  14. package/dist/components/auth/api-key/new-api-key-dialog.js +23 -59
  15. package/dist/components/auth/api-key/organization-api-keys.d.ts +14 -0
  16. package/dist/components/auth/api-key/organization-api-keys.js +22 -0
  17. package/dist/components/auth/auth-provider.d.ts +1 -1
  18. package/dist/components/auth/auth-provider.js +10 -16
  19. package/dist/components/auth/auth.d.ts +3 -3
  20. package/dist/components/auth/auth.js +86 -61
  21. package/dist/components/auth/delete-user/danger-zone.d.ts +3 -3
  22. package/dist/components/auth/delete-user/danger-zone.js +11 -17
  23. package/dist/components/auth/delete-user/delete-account.d.ts +9 -0
  24. package/dist/components/auth/delete-user/delete-account.js +50 -0
  25. package/dist/components/auth/email/email-changed-email.d.ts +2 -2
  26. package/dist/components/auth/email/email-changed-email.js +22 -29
  27. package/dist/components/auth/email/email-verification-email.d.ts +2 -2
  28. package/dist/components/auth/email/email-verification-email.js +22 -29
  29. package/dist/components/auth/email/magic-link-email.d.ts +2 -2
  30. package/dist/components/auth/email/magic-link-email.js +22 -29
  31. package/dist/components/auth/email/new-device-email.d.ts +2 -2
  32. package/dist/components/auth/email/new-device-email.js +22 -29
  33. package/dist/components/auth/email/organization-invitation-email.d.ts +3 -0
  34. package/dist/components/auth/email/organization-invitation-email.js +23 -0
  35. package/dist/components/auth/email/otp-email.d.ts +2 -2
  36. package/dist/components/auth/email/otp-email.js +21 -28
  37. package/dist/components/auth/email/password-changed-email.d.ts +2 -2
  38. package/dist/components/auth/email/password-changed-email.js +22 -29
  39. package/dist/components/auth/email/reset-password-email.d.ts +2 -2
  40. package/dist/components/auth/email/reset-password-email.js +22 -29
  41. package/dist/components/auth/error-toaster.js +32 -16
  42. package/dist/components/auth/field-separator.d.ts +1 -1
  43. package/dist/components/auth/field-separator.js +4 -17
  44. package/dist/components/auth/forgot-password.d.ts +1 -1
  45. package/dist/components/auth/forgot-password.js +36 -88
  46. package/dist/components/auth/magic-link/magic-link-button.d.ts +1 -1
  47. package/dist/components/auth/magic-link/magic-link-button.js +33 -19
  48. package/dist/components/auth/magic-link/magic-link.d.ts +2 -2
  49. package/dist/components/auth/magic-link/magic-link.js +39 -86
  50. package/dist/components/auth/multi-session/manage-account.d.ts +1 -1
  51. package/dist/components/auth/multi-session/manage-account.js +32 -48
  52. package/dist/components/auth/multi-session/manage-accounts.d.ts +1 -1
  53. package/dist/components/auth/multi-session/manage-accounts.js +32 -33
  54. package/dist/components/auth/multi-session/switch-account-submenu-content.d.ts +3 -1
  55. package/dist/components/auth/multi-session/switch-account-submenu-content.js +24 -27
  56. package/dist/components/auth/multi-session/switch-account-submenu-item.d.ts +3 -2
  57. package/dist/components/auth/multi-session/switch-account-submenu-item.js +16 -19
  58. package/dist/components/auth/multi-session/switch-account-submenu.d.ts +2 -1
  59. package/dist/components/auth/multi-session/switch-account-submenu.js +23 -23
  60. package/dist/components/auth/organization/change-organization-logo.d.ts +4 -0
  61. package/dist/components/auth/organization/change-organization-logo.js +69 -0
  62. package/dist/components/auth/organization/create-organization-dialog.d.ts +13 -0
  63. package/dist/components/auth/organization/create-organization-dialog.js +37 -0
  64. package/dist/components/auth/organization/delete-organization-dialog.d.ts +7 -0
  65. package/dist/components/auth/organization/delete-organization-dialog.js +25 -0
  66. package/dist/components/auth/organization/delete-organization-skeleton.d.ts +4 -0
  67. package/dist/components/auth/organization/delete-organization-skeleton.js +8 -0
  68. package/dist/components/auth/organization/delete-organization.d.ts +5 -0
  69. package/dist/components/auth/organization/delete-organization.js +27 -0
  70. package/dist/components/auth/organization/invite-member-dialog.d.ts +13 -0
  71. package/dist/components/auth/organization/invite-member-dialog.js +47 -0
  72. package/dist/components/auth/organization/leave-organization-dialog.d.ts +7 -0
  73. package/dist/components/auth/organization/leave-organization-dialog.js +21 -0
  74. package/dist/components/auth/organization/leave-organization.d.ts +4 -0
  75. package/dist/components/auth/organization/leave-organization.js +16 -0
  76. package/dist/components/auth/organization/organization-danger-zone.d.ts +16 -0
  77. package/dist/components/auth/organization/organization-danger-zone.js +23 -0
  78. package/dist/components/auth/organization/organization-invitation-row-skeleton.d.ts +5 -0
  79. package/dist/components/auth/organization/organization-invitation-row-skeleton.js +9 -0
  80. package/dist/components/auth/organization/organization-invitation-row.d.ts +5 -0
  81. package/dist/components/auth/organization/organization-invitation-row.js +31 -0
  82. package/dist/components/auth/organization/organization-invitations-empty.d.ts +8 -0
  83. package/dist/components/auth/organization/organization-invitations-empty.js +13 -0
  84. package/dist/components/auth/organization/organization-invitations.d.ts +9 -0
  85. package/dist/components/auth/organization/organization-invitations.js +66 -0
  86. package/dist/components/auth/organization/organization-logo.d.ts +15 -0
  87. package/dist/components/auth/organization/organization-logo.js +14 -0
  88. package/dist/components/auth/organization/organization-member-row-skeleton.d.ts +4 -0
  89. package/dist/components/auth/organization/organization-member-row-skeleton.js +9 -0
  90. package/dist/components/auth/organization/organization-member-row.d.ts +9 -0
  91. package/dist/components/auth/organization/organization-member-row.js +34 -0
  92. package/dist/components/auth/organization/organization-members.d.ts +9 -0
  93. package/dist/components/auth/organization/organization-members.js +67 -0
  94. package/dist/components/auth/organization/organization-people.d.ts +10 -0
  95. package/dist/components/auth/organization/organization-people.js +11 -0
  96. package/dist/components/auth/organization/organization-profile.d.ts +9 -0
  97. package/dist/components/auth/organization/organization-profile.js +34 -0
  98. package/dist/components/auth/organization/organization-row.d.ts +8 -0
  99. package/dist/components/auth/organization/organization-row.js +31 -0
  100. package/dist/components/auth/organization/organization-settings.d.ts +12 -0
  101. package/dist/components/auth/organization/organization-settings.js +13 -0
  102. package/dist/components/auth/organization/organization-switcher.d.ts +20 -0
  103. package/dist/components/auth/organization/organization-switcher.js +48 -0
  104. package/dist/components/auth/organization/organization-view-skeleton.d.ts +6 -0
  105. package/dist/components/auth/organization/organization-view-skeleton.js +9 -0
  106. package/dist/components/auth/organization/organization-view.d.ts +15 -0
  107. package/dist/components/auth/organization/organization-view.js +31 -0
  108. package/dist/components/auth/organization/organization.d.ts +17 -0
  109. package/dist/components/auth/organization/organization.js +60 -0
  110. package/dist/components/auth/organization/organizations-empty.d.ts +4 -0
  111. package/dist/components/auth/organization/organizations-empty.js +9 -0
  112. package/dist/components/auth/organization/organizations-settings.d.ts +17 -0
  113. package/dist/components/auth/organization/organizations-settings.js +17 -0
  114. package/dist/components/auth/organization/organizations.d.ts +10 -0
  115. package/dist/components/auth/organization/organizations.js +21 -0
  116. package/dist/components/auth/organization/remove-member-dialog.d.ts +9 -0
  117. package/dist/components/auth/organization/remove-member-dialog.js +20 -0
  118. package/dist/components/auth/organization/slug-field.d.ts +19 -0
  119. package/dist/components/auth/organization/slug-field.js +38 -0
  120. package/dist/components/auth/organization/user-invitation-row-skeleton.d.ts +4 -0
  121. package/dist/components/auth/organization/user-invitation-row-skeleton.js +8 -0
  122. package/dist/components/auth/organization/user-invitation-row.d.ts +10 -0
  123. package/dist/components/auth/organization/user-invitation-row.js +22 -0
  124. package/dist/components/auth/organization/user-invitations-empty.d.ts +4 -0
  125. package/dist/components/auth/organization/user-invitations-empty.js +12 -0
  126. package/dist/components/auth/organization/user-invitations.d.ts +10 -0
  127. package/dist/components/auth/organization/user-invitations.js +18 -0
  128. package/dist/components/auth/passkey/add-passkey-dialog.js +21 -64
  129. package/dist/components/auth/passkey/delete-passkey-dialog.js +13 -46
  130. package/dist/components/auth/passkey/passkey-button.d.ts +1 -1
  131. package/dist/components/auth/passkey/passkey-button.js +24 -23
  132. package/dist/components/auth/passkey/passkey-skeleton.js +4 -16
  133. package/dist/components/auth/passkey/passkey.d.ts +1 -1
  134. package/dist/components/auth/passkey/passkey.js +16 -47
  135. package/dist/components/auth/passkey/passkeys-empty.js +8 -34
  136. package/dist/components/auth/passkey/passkeys.d.ts +1 -1
  137. package/dist/components/auth/passkey/passkeys.js +15 -41
  138. package/dist/components/auth/provider-button.d.ts +2 -2
  139. package/dist/components/auth/provider-button.js +28 -24
  140. package/dist/components/auth/provider-buttons.js +28 -18
  141. package/dist/components/auth/reset-password.d.ts +1 -1
  142. package/dist/components/auth/reset-password.js +56 -146
  143. package/dist/components/auth/settings/account/account-settings.d.ts +2 -2
  144. package/dist/components/auth/settings/account/account-settings.js +21 -19
  145. package/dist/components/auth/settings/account/change-avatar.js +53 -88
  146. package/dist/components/auth/settings/account/change-email.d.ts +1 -1
  147. package/dist/components/auth/settings/account/change-email.js +27 -53
  148. package/dist/components/auth/settings/account/user-profile.d.ts +1 -1
  149. package/dist/components/auth/settings/account/user-profile.js +64 -85
  150. package/dist/components/auth/settings/security/active-session.d.ts +1 -1
  151. package/dist/components/auth/settings/security/active-session.js +50 -57
  152. package/dist/components/auth/settings/security/active-sessions.d.ts +1 -1
  153. package/dist/components/auth/settings/security/active-sessions.js +21 -32
  154. package/dist/components/auth/settings/security/change-password.d.ts +1 -1
  155. package/dist/components/auth/settings/security/change-password.js +76 -186
  156. package/dist/components/auth/settings/security/linked-account.d.ts +1 -1
  157. package/dist/components/auth/settings/security/linked-account.js +37 -55
  158. package/dist/components/auth/settings/security/linked-accounts.d.ts +1 -1
  159. package/dist/components/auth/settings/security/linked-accounts.js +34 -43
  160. package/dist/components/auth/settings/security/security-settings.d.ts +2 -2
  161. package/dist/components/auth/settings/security/security-settings.js +19 -21
  162. package/dist/components/auth/settings/settings.d.ts +4 -4
  163. package/dist/components/auth/settings/settings.js +52 -44
  164. package/dist/components/auth/sign-in.d.ts +2 -2
  165. package/dist/components/auth/sign-in.js +63 -132
  166. package/dist/components/auth/sign-out.js +32 -26
  167. package/dist/components/auth/sign-up.d.ts +2 -2
  168. package/dist/components/auth/sign-up.js +97 -211
  169. package/dist/components/auth/theme/appearance.d.ts +1 -1
  170. package/dist/components/auth/theme/appearance.js +23 -71
  171. package/dist/components/auth/theme/theme-toggle-item.js +56 -61
  172. package/dist/components/auth/user/user-avatar.d.ts +4 -4
  173. package/dist/components/auth/user/user-avatar.js +31 -28
  174. package/dist/components/auth/user/user-button.d.ts +6 -7
  175. package/dist/components/auth/user/user-button.js +38 -72
  176. package/dist/components/auth/user/user-view.d.ts +13 -7
  177. package/dist/components/auth/user/user-view.js +26 -36
  178. package/dist/components/auth/username/sign-in-username.d.ts +2 -2
  179. package/dist/components/auth/username/sign-in-username.js +87 -147
  180. package/dist/components/auth/username/username-field.d.ts +1 -1
  181. package/dist/components/auth/username/username-field.js +44 -52
  182. package/dist/email.d.ts +8 -7
  183. package/dist/email.js +8 -8
  184. package/dist/index.d.ts +21 -21
  185. package/dist/index.js +21 -22
  186. package/dist/lib/auth/api-key-plugin.d.ts +7 -4
  187. package/dist/lib/auth/api-key-plugin.js +12 -10
  188. package/dist/lib/auth/auth-plugin.d.ts +10 -6
  189. package/dist/lib/auth/auth-plugin.js +1 -0
  190. package/dist/lib/auth/delete-user-plugin.d.ts +6 -6
  191. package/dist/lib/auth/delete-user-plugin.js +6 -9
  192. package/dist/lib/auth/magic-link-plugin.d.ts +5 -5
  193. package/dist/lib/auth/magic-link-plugin.js +17 -12
  194. package/dist/lib/auth/multi-session-plugin.d.ts +5 -5
  195. package/dist/lib/auth/multi-session-plugin.js +8 -11
  196. package/dist/lib/auth/organization-plugin.d.ts +37 -0
  197. package/dist/lib/auth/organization-plugin.js +19 -0
  198. package/dist/lib/auth/passkey-plugin.d.ts +5 -5
  199. package/dist/lib/auth/passkey-plugin.js +8 -11
  200. package/dist/lib/auth/theme-plugin.d.ts +6 -6
  201. package/dist/lib/auth/theme-plugin.js +25 -22
  202. package/dist/lib/auth/username-plugin.d.ts +11 -11
  203. package/dist/lib/auth/username-plugin.js +18 -17
  204. package/dist/plugins.d.ts +46 -22
  205. package/dist/plugins.js +47 -22
  206. package/package.json +25 -19
  207. package/src/components/auth/api-key/api-key.tsx +25 -16
  208. package/src/components/auth/api-key/api-keys-empty.tsx +8 -4
  209. package/src/components/auth/api-key/api-keys.tsx +52 -14
  210. package/src/components/auth/api-key/create-api-key-dialog.tsx +15 -2
  211. package/src/components/auth/api-key/delete-api-key-dialog.tsx +10 -2
  212. package/src/components/auth/api-key/organization-api-keys.tsx +55 -0
  213. package/src/components/auth/delete-user/danger-zone.tsx +3 -3
  214. package/src/components/auth/delete-user/{delete-user.tsx → delete-account.tsx} +9 -9
  215. package/src/components/auth/email/organization-invitation-email.tsx +38 -0
  216. package/src/components/auth/error-toaster.tsx +28 -10
  217. package/src/components/auth/forgot-password.tsx +10 -2
  218. package/src/components/auth/multi-session/manage-accounts.tsx +1 -1
  219. package/src/components/auth/multi-session/switch-account-submenu-content.tsx +7 -2
  220. package/src/components/auth/multi-session/switch-account-submenu-item.tsx +4 -2
  221. package/src/components/auth/multi-session/switch-account-submenu.tsx +8 -4
  222. package/src/components/auth/organization/change-organization-logo.tsx +171 -0
  223. package/src/components/auth/organization/create-organization-dialog.tsx +133 -0
  224. package/src/components/auth/organization/delete-organization-dialog.tsx +97 -0
  225. package/src/components/auth/organization/delete-organization-skeleton.tsx +17 -0
  226. package/src/components/auth/organization/delete-organization.tsx +77 -0
  227. package/src/components/auth/organization/invite-member-dialog.tsx +177 -0
  228. package/src/components/auth/organization/leave-organization-dialog.tsx +95 -0
  229. package/src/components/auth/organization/leave-organization.tsx +59 -0
  230. package/src/components/auth/organization/organization-danger-zone.tsx +68 -0
  231. package/src/components/auth/organization/organization-invitation-row-skeleton.tsx +29 -0
  232. package/src/components/auth/organization/organization-invitation-row.tsx +97 -0
  233. package/src/components/auth/organization/organization-invitations-empty.tsx +39 -0
  234. package/src/components/auth/organization/organization-invitations.tsx +351 -0
  235. package/src/components/auth/organization/organization-logo.tsx +64 -0
  236. package/src/components/auth/organization/organization-member-row-skeleton.tsx +24 -0
  237. package/src/components/auth/organization/organization-member-row.tsx +157 -0
  238. package/src/components/auth/organization/organization-members.tsx +284 -0
  239. package/src/components/auth/organization/organization-people.tsx +26 -0
  240. package/src/components/auth/organization/organization-profile.tsx +141 -0
  241. package/src/components/auth/organization/organization-row.tsx +66 -0
  242. package/src/components/auth/organization/organization-settings.tsx +38 -0
  243. package/src/components/auth/organization/organization-switcher.tsx +233 -0
  244. package/src/components/auth/organization/organization-view-skeleton.tsx +36 -0
  245. package/src/components/auth/organization/organization-view.tsx +109 -0
  246. package/src/components/auth/organization/organization.tsx +162 -0
  247. package/src/components/auth/organization/organizations-empty.tsx +35 -0
  248. package/src/components/auth/organization/organizations-settings.tsx +36 -0
  249. package/src/components/auth/organization/organizations.tsx +80 -0
  250. package/src/components/auth/organization/remove-member-dialog.tsx +95 -0
  251. package/src/components/auth/organization/slug-field.tsx +111 -0
  252. package/src/components/auth/organization/user-invitation-row-skeleton.tsx +17 -0
  253. package/src/components/auth/organization/user-invitation-row.tsx +90 -0
  254. package/src/components/auth/organization/user-invitations-empty.tsx +30 -0
  255. package/src/components/auth/organization/user-invitations.tsx +59 -0
  256. package/src/components/auth/settings/account/change-email.tsx +1 -1
  257. package/src/components/auth/settings/account/user-profile.tsx +5 -5
  258. package/src/components/auth/settings/security/active-sessions.tsx +6 -4
  259. package/src/components/auth/settings/security/linked-accounts.tsx +2 -2
  260. package/src/components/auth/settings/settings.tsx +77 -14
  261. package/src/components/auth/user/user-avatar.tsx +4 -1
  262. package/src/components/auth/user/user-button.tsx +14 -11
  263. package/src/components/auth/user/user-view.tsx +32 -12
  264. package/src/email.ts +1 -0
  265. package/src/lib/auth/api-key-plugin.ts +10 -4
  266. package/src/lib/auth/auth-plugin.ts +6 -1
  267. package/src/lib/auth/organization-plugin.tsx +32 -0
  268. package/src/plugins.ts +25 -1
  269. package/dist/components/auth/delete-user/delete-user.d.ts +0 -9
  270. package/dist/components/auth/delete-user/delete-user.js +0 -95
@@ -0,0 +1,97 @@
1
+ import {
2
+ type OrganizationAuthClient,
3
+ useAuth,
4
+ useAuthPlugin,
5
+ useDeleteOrganization
6
+ } from "@better-auth-ui/react"
7
+ import { TriangleExclamation } from "@gravity-ui/icons"
8
+ import { AlertDialog, Button, Card, Form, Spinner, toast } from "@heroui/react"
9
+ import type { Organization } from "better-auth/client"
10
+ import type { SyntheticEvent } from "react"
11
+
12
+ import { organizationPlugin } from "../../../lib/auth/organization-plugin"
13
+ import { OrganizationView } from "./organization-view"
14
+
15
+ export type DeleteOrganizationDialogProps = {
16
+ isOpen: boolean
17
+ onOpenChange: (open: boolean) => void
18
+ organization: Organization
19
+ }
20
+
21
+ export function DeleteOrganizationDialog({
22
+ isOpen,
23
+ onOpenChange,
24
+ organization
25
+ }: DeleteOrganizationDialogProps) {
26
+ const { authClient, basePaths, localization, navigate } = useAuth()
27
+ const {
28
+ localization: organizationLocalization,
29
+ viewPaths: organizationPluginViewPaths
30
+ } = useAuthPlugin(organizationPlugin)
31
+
32
+ const { mutate: deleteOrganization, isPending } = useDeleteOrganization(
33
+ authClient as OrganizationAuthClient,
34
+ {
35
+ onSuccess: () => {
36
+ onOpenChange(false)
37
+ toast.success(organizationLocalization.organizationDeleted)
38
+
39
+ navigate({
40
+ to: `${basePaths.settings}/${organizationPluginViewPaths.settings.organizations}`,
41
+ replace: true
42
+ })
43
+ }
44
+ }
45
+ )
46
+
47
+ function handleSubmit(e: SyntheticEvent<HTMLFormElement>) {
48
+ e.preventDefault()
49
+ deleteOrganization({ organizationId: organization.id })
50
+ }
51
+
52
+ return (
53
+ <AlertDialog.Backdrop isOpen={isOpen} onOpenChange={onOpenChange}>
54
+ <AlertDialog.Container>
55
+ <AlertDialog.Dialog>
56
+ <Form onSubmit={handleSubmit}>
57
+ <AlertDialog.CloseTrigger />
58
+
59
+ <AlertDialog.Header>
60
+ <AlertDialog.Icon status="danger">
61
+ <TriangleExclamation />
62
+ </AlertDialog.Icon>
63
+
64
+ <AlertDialog.Heading>
65
+ {organizationLocalization.deleteOrganization}
66
+ </AlertDialog.Heading>
67
+ </AlertDialog.Header>
68
+
69
+ <AlertDialog.Body className="flex flex-col gap-4 overflow-visible">
70
+ <p className="text-muted text-sm">
71
+ {organizationLocalization.deleteOrganizationDescription}
72
+ </p>
73
+
74
+ <Card variant="secondary">
75
+ <Card.Content>
76
+ <OrganizationView organization={organization} hideRole />
77
+ </Card.Content>
78
+ </Card>
79
+ </AlertDialog.Body>
80
+
81
+ <AlertDialog.Footer>
82
+ <Button slot="close" variant="tertiary" isDisabled={isPending}>
83
+ {localization.settings.cancel}
84
+ </Button>
85
+
86
+ <Button type="submit" variant="danger" isPending={isPending}>
87
+ {isPending && <Spinner color="current" size="sm" />}
88
+
89
+ {organizationLocalization.deleteOrganization}
90
+ </Button>
91
+ </AlertDialog.Footer>
92
+ </Form>
93
+ </AlertDialog.Dialog>
94
+ </AlertDialog.Container>
95
+ </AlertDialog.Backdrop>
96
+ )
97
+ }
@@ -0,0 +1,17 @@
1
+ import { Skeleton } from "@heroui/react"
2
+
3
+ /**
4
+ * Placeholder matching {@link DeleteOrganization} while the delete permission resolves.
5
+ */
6
+ export function DeleteOrganizationSkeleton() {
7
+ return (
8
+ <div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
9
+ <div className="flex flex-col gap-1">
10
+ <Skeleton className="h-3.5 w-40 rounded-lg" />
11
+ <Skeleton className="h-3 w-64 rounded-lg" />
12
+ </div>
13
+
14
+ <Skeleton className="h-8 w-36 shrink-0 rounded-full" />
15
+ </div>
16
+ )
17
+ }
@@ -0,0 +1,77 @@
1
+ import {
2
+ type OrganizationAuthClient,
3
+ useActiveOrganization,
4
+ useAuth,
5
+ useAuthPlugin,
6
+ useHasPermission
7
+ } from "@better-auth-ui/react"
8
+ import { AlertDialog, Button } from "@heroui/react"
9
+ import { useState } from "react"
10
+
11
+ import { organizationPlugin } from "../../../lib/auth/organization-plugin"
12
+ import { DeleteOrganizationDialog } from "./delete-organization-dialog"
13
+ import { DeleteOrganizationSkeleton } from "./delete-organization-skeleton"
14
+
15
+ /**
16
+ * Danger-zone row to delete the active organization. Hidden for members without
17
+ * the `organization:delete` permission.
18
+ */
19
+ export function DeleteOrganization() {
20
+ const { authClient } = useAuth()
21
+ const { localization: organizationLocalization } =
22
+ useAuthPlugin(organizationPlugin)
23
+
24
+ const { data: activeOrganization } = useActiveOrganization(
25
+ authClient as OrganizationAuthClient
26
+ )
27
+
28
+ const { data: permission, isPending: permissionPending } = useHasPermission(
29
+ authClient as OrganizationAuthClient,
30
+ {
31
+ permissions: { organization: ["delete"] }
32
+ }
33
+ )
34
+
35
+ const [confirmOpen, setConfirmOpen] = useState(false)
36
+
37
+ if (permissionPending) {
38
+ return <DeleteOrganizationSkeleton />
39
+ }
40
+
41
+ if (!permission?.success) {
42
+ return null
43
+ }
44
+
45
+ return (
46
+ <div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
47
+ <div>
48
+ <p className="text-sm font-medium leading-tight">
49
+ {organizationLocalization.deleteOrganization}
50
+ </p>
51
+
52
+ <p className="text-muted mt-0.5 text-xs">
53
+ {organizationLocalization.deleteOrganizationDescription}
54
+ </p>
55
+ </div>
56
+
57
+ <AlertDialog>
58
+ <Button
59
+ isDisabled={!activeOrganization}
60
+ size="sm"
61
+ variant="danger-soft"
62
+ onPress={() => setConfirmOpen(true)}
63
+ >
64
+ {organizationLocalization.deleteOrganization}
65
+ </Button>
66
+
67
+ {activeOrganization && (
68
+ <DeleteOrganizationDialog
69
+ isOpen={confirmOpen}
70
+ onOpenChange={setConfirmOpen}
71
+ organization={activeOrganization}
72
+ />
73
+ )}
74
+ </AlertDialog>
75
+ </div>
76
+ )
77
+ }
@@ -0,0 +1,177 @@
1
+ import {
2
+ type OrganizationAuthClient,
3
+ useAuth,
4
+ useAuthPlugin,
5
+ useInviteMember
6
+ } from "@better-auth-ui/react"
7
+ import { PersonPlus } from "@gravity-ui/icons"
8
+ import {
9
+ AlertDialog,
10
+ Button,
11
+ FieldError,
12
+ Form,
13
+ Input,
14
+ Label,
15
+ ListBox,
16
+ Select,
17
+ Spinner,
18
+ TextField,
19
+ toast
20
+ } from "@heroui/react"
21
+ import { type SyntheticEvent, useEffect, useState } from "react"
22
+
23
+ import { organizationPlugin } from "../../../lib/auth/organization-plugin"
24
+
25
+ /** Props for the {@link InviteMemberDialog} component. */
26
+ export type InviteMemberDialogProps = {
27
+ isOpen: boolean
28
+ onOpenChange: (open: boolean) => void
29
+ }
30
+
31
+ const pickDefaultRole = (keys: string[]) =>
32
+ keys.includes("member") ? "member" : (keys.at(-1) ?? "")
33
+
34
+ /**
35
+ * Render a dialog for inviting a member to the organization.
36
+ *
37
+ * @param isOpen - Whether the dialog is open
38
+ * @param onOpenChange - Callback for when the dialog open state changes
39
+ * @returns The invite member dialog as a JSX element
40
+ */
41
+ export function InviteMemberDialog({
42
+ isOpen,
43
+ onOpenChange
44
+ }: InviteMemberDialogProps) {
45
+ const { authClient, localization } = useAuth()
46
+ const { localization: organizationLocalization, roles } =
47
+ useAuthPlugin(organizationPlugin)
48
+
49
+ const [role, setRole] = useState(() => pickDefaultRole(Object.keys(roles)))
50
+
51
+ useEffect(() => {
52
+ setRole((current) => {
53
+ const keys = Object.keys(roles)
54
+ return keys.includes(current) ? current : pickDefaultRole(keys)
55
+ })
56
+ }, [roles])
57
+
58
+ const { mutate: inviteMember, isPending: isInviting } = useInviteMember(
59
+ authClient as OrganizationAuthClient,
60
+ {
61
+ onSuccess: () => {
62
+ onOpenChange(false)
63
+ toast.success(organizationLocalization.inviteMemberSuccess)
64
+ }
65
+ }
66
+ )
67
+
68
+ const isRoleValid = Object.keys(roles).includes(role)
69
+
70
+ const handleSubmit = (e: SyntheticEvent<HTMLFormElement>) => {
71
+ e.preventDefault()
72
+
73
+ if (!isRoleValid) return
74
+
75
+ const formData = new FormData(e.target as HTMLFormElement)
76
+ const email = formData.get("email") as string
77
+
78
+ inviteMember({
79
+ email: email.trim(),
80
+ role: role as Parameters<typeof inviteMember>[0]["role"]
81
+ })
82
+ }
83
+
84
+ return (
85
+ <AlertDialog.Backdrop isOpen={isOpen} onOpenChange={onOpenChange}>
86
+ <AlertDialog.Container>
87
+ <AlertDialog.Dialog>
88
+ <Form onSubmit={handleSubmit}>
89
+ <AlertDialog.CloseTrigger />
90
+
91
+ <AlertDialog.Header>
92
+ <AlertDialog.Icon status="default">
93
+ <PersonPlus />
94
+ </AlertDialog.Icon>
95
+
96
+ <AlertDialog.Heading>
97
+ {organizationLocalization.inviteMember}
98
+ </AlertDialog.Heading>
99
+ </AlertDialog.Header>
100
+
101
+ <AlertDialog.Body className="flex flex-col gap-4 overflow-visible">
102
+ <p className="text-muted text-sm">
103
+ {organizationLocalization.inviteMemberDescription}
104
+ </p>
105
+
106
+ <TextField
107
+ id="email"
108
+ name="email"
109
+ type="email"
110
+ isDisabled={isInviting}
111
+ >
112
+ <Label>{localization.auth.email}</Label>
113
+
114
+ <Input
115
+ autoFocus
116
+ placeholder={localization.auth.email}
117
+ variant="secondary"
118
+ required
119
+ />
120
+
121
+ <FieldError />
122
+ </TextField>
123
+
124
+ <Select
125
+ name="role"
126
+ value={role}
127
+ onChange={(value) => {
128
+ if (typeof value === "string") setRole(value)
129
+ }}
130
+ isDisabled={isInviting}
131
+ variant="secondary"
132
+ fullWidth
133
+ >
134
+ <Label>{organizationLocalization.role}</Label>
135
+
136
+ <Select.Trigger>
137
+ <Select.Value />
138
+ <Select.Indicator />
139
+ </Select.Trigger>
140
+
141
+ <Select.Popover>
142
+ <ListBox>
143
+ {Object.entries(roles).map(([key, label]) => (
144
+ <ListBox.Item key={key} id={key} textValue={label}>
145
+ {label}
146
+
147
+ <ListBox.ItemIndicator />
148
+ </ListBox.Item>
149
+ ))}
150
+ </ListBox>
151
+ </Select.Popover>
152
+
153
+ <FieldError />
154
+ </Select>
155
+ </AlertDialog.Body>
156
+
157
+ <AlertDialog.Footer>
158
+ <Button slot="close" variant="tertiary" isDisabled={isInviting}>
159
+ {localization.settings.cancel}
160
+ </Button>
161
+
162
+ <Button
163
+ type="submit"
164
+ isPending={isInviting}
165
+ isDisabled={!isRoleValid}
166
+ >
167
+ {isInviting && <Spinner color="current" size="sm" />}
168
+
169
+ {organizationLocalization.inviteMember}
170
+ </Button>
171
+ </AlertDialog.Footer>
172
+ </Form>
173
+ </AlertDialog.Dialog>
174
+ </AlertDialog.Container>
175
+ </AlertDialog.Backdrop>
176
+ )
177
+ }
@@ -0,0 +1,95 @@
1
+ import {
2
+ type OrganizationAuthClient,
3
+ useAuth,
4
+ useAuthPlugin,
5
+ useLeaveOrganization
6
+ } from "@better-auth-ui/react"
7
+ import { ArrowRightFromSquare } from "@gravity-ui/icons"
8
+ import { AlertDialog, Button, Card, Spinner, toast } from "@heroui/react"
9
+ import type { Organization } from "better-auth/client"
10
+
11
+ import { organizationPlugin } from "../../../lib/auth/organization-plugin"
12
+ import { OrganizationView } from "./organization-view"
13
+
14
+ export type LeaveOrganizationDialogProps = {
15
+ isOpen: boolean
16
+ onOpenChange: (open: boolean) => void
17
+ organization: Organization
18
+ }
19
+
20
+ export function LeaveOrganizationDialog({
21
+ isOpen,
22
+ onOpenChange,
23
+ organization
24
+ }: LeaveOrganizationDialogProps) {
25
+ const { authClient, basePaths, localization, navigate } = useAuth()
26
+ const {
27
+ localization: organizationLocalization,
28
+ viewPaths: organizationPluginViewPaths
29
+ } = useAuthPlugin(organizationPlugin)
30
+
31
+ const { mutate: leaveOrganization, isPending } = useLeaveOrganization(
32
+ authClient as OrganizationAuthClient,
33
+ {
34
+ onSuccess: () => {
35
+ onOpenChange(false)
36
+ toast.success(organizationLocalization.leftOrganization)
37
+
38
+ navigate({
39
+ to: `${basePaths.settings}/${organizationPluginViewPaths.settings.organizations}`,
40
+ replace: true
41
+ })
42
+ }
43
+ }
44
+ )
45
+
46
+ return (
47
+ <AlertDialog.Backdrop isOpen={isOpen} onOpenChange={onOpenChange}>
48
+ <AlertDialog.Container>
49
+ <AlertDialog.Dialog>
50
+ <AlertDialog.CloseTrigger />
51
+
52
+ <AlertDialog.Header>
53
+ <AlertDialog.Icon status="danger">
54
+ <ArrowRightFromSquare />
55
+ </AlertDialog.Icon>
56
+
57
+ <AlertDialog.Heading>
58
+ {organizationLocalization.leaveOrganization}
59
+ </AlertDialog.Heading>
60
+ </AlertDialog.Header>
61
+
62
+ <AlertDialog.Body className="flex flex-col gap-4 overflow-visible">
63
+ <p className="text-muted text-sm">
64
+ {organizationLocalization.leaveOrganizationDescription}
65
+ </p>
66
+
67
+ <Card variant="secondary">
68
+ <Card.Content>
69
+ <OrganizationView organization={organization} hideRole />
70
+ </Card.Content>
71
+ </Card>
72
+ </AlertDialog.Body>
73
+
74
+ <AlertDialog.Footer>
75
+ <Button slot="close" variant="tertiary" isDisabled={isPending}>
76
+ {localization.settings.cancel}
77
+ </Button>
78
+
79
+ <Button
80
+ variant="danger"
81
+ isPending={isPending}
82
+ onPress={() =>
83
+ leaveOrganization({ organizationId: organization.id })
84
+ }
85
+ >
86
+ {isPending && <Spinner color="current" size="sm" />}
87
+
88
+ {organizationLocalization.leaveOrganization}
89
+ </Button>
90
+ </AlertDialog.Footer>
91
+ </AlertDialog.Dialog>
92
+ </AlertDialog.Container>
93
+ </AlertDialog.Backdrop>
94
+ )
95
+ }
@@ -0,0 +1,59 @@
1
+ import {
2
+ type OrganizationAuthClient,
3
+ useActiveOrganization,
4
+ useAuth,
5
+ useAuthPlugin
6
+ } from "@better-auth-ui/react"
7
+ import { AlertDialog, Button } from "@heroui/react"
8
+ import { useState } from "react"
9
+
10
+ import { organizationPlugin } from "../../../lib/auth/organization-plugin"
11
+ import { LeaveOrganizationDialog } from "./leave-organization-dialog"
12
+
13
+ /**
14
+ * Danger-zone row to leave the active organization.
15
+ */
16
+ export function LeaveOrganization() {
17
+ const { authClient } = useAuth()
18
+ const { localization: organizationLocalization } =
19
+ useAuthPlugin(organizationPlugin)
20
+
21
+ const { data: activeOrganization } = useActiveOrganization(
22
+ authClient as OrganizationAuthClient
23
+ )
24
+
25
+ const [confirmOpen, setConfirmOpen] = useState(false)
26
+
27
+ return (
28
+ <div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
29
+ <div>
30
+ <p className="text-sm font-medium leading-tight">
31
+ {organizationLocalization.leaveOrganization}
32
+ </p>
33
+
34
+ <p className="text-muted mt-0.5 text-xs">
35
+ {organizationLocalization.leaveOrganizationDescription}
36
+ </p>
37
+ </div>
38
+
39
+ <AlertDialog>
40
+ <Button
41
+ isDisabled={!activeOrganization}
42
+ size="sm"
43
+ variant="danger-soft"
44
+ onPress={() => setConfirmOpen(true)}
45
+ >
46
+ {organizationLocalization.leaveOrganization}
47
+ </Button>
48
+
49
+ {activeOrganization && (
50
+ <LeaveOrganizationDialog
51
+ isOpen={confirmOpen}
52
+ onOpenChange={setConfirmOpen}
53
+ organization={activeOrganization}
54
+ />
55
+ )}
56
+ </AlertDialog>
57
+ </div>
58
+ )
59
+ }
@@ -0,0 +1,68 @@
1
+ import {
2
+ type OrganizationAuthClient,
3
+ useAuth,
4
+ useHasPermission
5
+ } from "@better-auth-ui/react"
6
+ import { Card, type CardProps, cn } from "@heroui/react"
7
+ import type { ComponentProps } from "react"
8
+
9
+ import { DeleteOrganization } from "./delete-organization"
10
+ import { DeleteOrganizationSkeleton } from "./delete-organization-skeleton"
11
+ import { LeaveOrganization } from "./leave-organization"
12
+
13
+ export type OrganizationDangerZoneProps = {
14
+ className?: string
15
+ variant?: CardProps["variant"]
16
+ }
17
+
18
+ /**
19
+ * Danger zone heading with {@link LeaveOrganization} and {@link DeleteOrganization}
20
+ * for the active organization in a single card.
21
+ *
22
+ * Resolves the `organization:delete` permission before rendering anything to
23
+ * avoid flashing {@link LeaveOrganization} (and a stray separator) before the
24
+ * delete row appears or disappears. Inner {@link DeleteOrganization} also
25
+ * self-gates so it stays safe to use standalone.
26
+ */
27
+ export function OrganizationDangerZone({
28
+ className,
29
+ variant,
30
+ ...props
31
+ }: OrganizationDangerZoneProps & ComponentProps<"div">) {
32
+ const { authClient, localization } = useAuth()
33
+
34
+ const { data: deletePermission, isPending: deletePermissionPending } =
35
+ useHasPermission(authClient as OrganizationAuthClient, {
36
+ permissions: { organization: ["delete"] }
37
+ })
38
+
39
+ const canDelete = !!deletePermission?.success
40
+
41
+ return (
42
+ <div className={cn("flex w-full flex-col", className)} {...props}>
43
+ <h2 className={cn("mb-3 text-sm font-semibold text-danger")}>
44
+ {localization.settings.dangerZone}
45
+ </h2>
46
+
47
+ <Card variant={variant}>
48
+ <Card.Content className="gap-0">
49
+ {deletePermissionPending ? (
50
+ <DeleteOrganizationSkeleton />
51
+ ) : (
52
+ <>
53
+ <LeaveOrganization />
54
+
55
+ {canDelete && (
56
+ <>
57
+ <div className="border-b border-dashed -mx-4 my-4" />
58
+
59
+ <DeleteOrganization />
60
+ </>
61
+ )}
62
+ </>
63
+ )}
64
+ </Card.Content>
65
+ </Card>
66
+ </div>
67
+ )
68
+ }
@@ -0,0 +1,29 @@
1
+ import { Skeleton, Table } from "@heroui/react"
2
+
3
+ /**
4
+ * Placeholder row matching {@link OrganizationInvitationTableRow} while
5
+ * invitations load.
6
+ */
7
+ export function OrganizationInvitationRowSkeleton() {
8
+ return (
9
+ <Table.Row>
10
+ <Table.Cell>
11
+ <Skeleton className="h-4 w-48 rounded-lg" />
12
+ </Table.Cell>
13
+
14
+ <Table.Cell>
15
+ <Skeleton className="h-4 w-36 rounded-lg" />
16
+ </Table.Cell>
17
+
18
+ <Table.Cell>
19
+ <Skeleton className="h-4 w-16 rounded-lg" />
20
+ </Table.Cell>
21
+
22
+ <Table.Cell>
23
+ <Skeleton className="h-4 w-14 rounded-full" />
24
+ </Table.Cell>
25
+
26
+ <Table.Cell />
27
+ </Table.Row>
28
+ )
29
+ }