@m5kdev/web-ui 0.7.0 → 0.8.0

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 (377) hide show
  1. package/dist/src/animations/card.motion.d.ts +7 -2
  2. package/dist/src/animations/card.motion.js +25 -6
  3. package/dist/src/animations/card.motion.js.map +1 -0
  4. package/dist/src/components/AvatarUpload.d.ts +14 -5
  5. package/dist/src/components/AvatarUpload.js +105 -63
  6. package/dist/src/components/AvatarUpload.js.map +1 -0
  7. package/dist/src/components/Button.d.ts +14 -4
  8. package/dist/src/components/Button.js +13 -4
  9. package/dist/src/components/Button.js.map +1 -0
  10. package/dist/src/components/Calendar.d.ts +33 -31
  11. package/dist/src/components/Calendar.js +14 -6
  12. package/dist/src/components/Calendar.js.map +1 -0
  13. package/dist/src/components/{Calendar.css → Calendar2.css} +757 -684
  14. package/dist/src/components/CardsSelect.d.ts +25 -21
  15. package/dist/src/components/CardsSelect.js +75 -42
  16. package/dist/src/components/CardsSelect.js.map +1 -0
  17. package/dist/src/components/CollapsibleSidebarMenuItem.d.ts +22 -9
  18. package/dist/src/components/CollapsibleSidebarMenuItem.js +31 -8
  19. package/dist/src/components/CollapsibleSidebarMenuItem.js.map +1 -0
  20. package/dist/src/components/ColorPicker.d.ts +15 -4
  21. package/dist/src/components/ColorPicker.js +46 -16
  22. package/dist/src/components/ColorPicker.js.map +1 -0
  23. package/dist/src/components/CopyButton.d.ts +18 -6
  24. package/dist/src/components/CopyButton.js +28 -19
  25. package/dist/src/components/CopyButton.js.map +1 -0
  26. package/dist/src/components/CropDialog.d.ts +20 -8
  27. package/dist/src/components/CropDialog.js +108 -62
  28. package/dist/src/components/CropDialog.js.map +1 -0
  29. package/dist/src/components/DialogProvider.d.ts +22 -14
  30. package/dist/src/components/DialogProvider.js +67 -45
  31. package/dist/src/components/DialogProvider.js.map +1 -0
  32. package/dist/src/components/ErrorFallback.d.ts +13 -4
  33. package/dist/src/components/ErrorFallback.js +29 -4
  34. package/dist/src/components/ErrorFallback.js.map +1 -0
  35. package/dist/src/components/FileDropzone.d.ts +12 -4
  36. package/dist/src/components/FileDropzone.js +98 -60
  37. package/dist/src/components/FileDropzone.js.map +1 -0
  38. package/dist/src/components/MultiSelectDropdown.d.ts +25 -22
  39. package/dist/src/components/MultiSelectDropdown.js +99 -49
  40. package/dist/src/components/MultiSelectDropdown.js.map +1 -0
  41. package/dist/src/components/Orb.d.ts +17 -6
  42. package/dist/src/components/Orb.js +263 -255
  43. package/dist/src/components/Orb.js.map +1 -0
  44. package/dist/src/components/PageAlert.d.ts +20 -15
  45. package/dist/src/components/PageAlert.js +67 -39
  46. package/dist/src/components/PageAlert.js.map +1 -0
  47. package/dist/src/components/SelectChips.d.ts +21 -10
  48. package/dist/src/components/SelectChips.js +21 -9
  49. package/dist/src/components/SelectChips.js.map +1 -0
  50. package/dist/src/components/SidebarItem.d.ts +18 -7
  51. package/dist/src/components/SidebarItem.js +16 -4
  52. package/dist/src/components/SidebarItem.js.map +1 -0
  53. package/dist/src/components/Steps.d.ts +21 -16
  54. package/dist/src/components/Steps.js +193 -27
  55. package/dist/src/components/Steps.js.map +1 -0
  56. package/dist/src/components/TablerIconPicker.d.ts +13 -2
  57. package/dist/src/components/TablerIconPicker.js +4254 -4234
  58. package/dist/src/components/TablerIconPicker.js.map +1 -0
  59. package/dist/src/components/app-header.d.ts +14 -6
  60. package/dist/src/components/app-header.js +27 -6
  61. package/dist/src/components/app-header.js.map +1 -0
  62. package/dist/src/components/blur-card.d.ts +25 -11
  63. package/dist/src/components/blur-card.js +134 -31
  64. package/dist/src/components/blur-card.js.map +1 -0
  65. package/dist/src/components/features-section-demo-1.d.ts +22 -6
  66. package/dist/src/components/features-section-demo-1.js +119 -47
  67. package/dist/src/components/features-section-demo-1.js.map +1 -0
  68. package/dist/src/components/features-section-demo-2.d.ts +7 -1
  69. package/dist/src/components/features-section-demo-2.js +80 -49
  70. package/dist/src/components/features-section-demo-2.js.map +1 -0
  71. package/dist/src/components/features-section-demo-3.d.ts +16 -8
  72. package/dist/src/components/features-section-demo-3.js +239 -103
  73. package/dist/src/components/features-section-demo-3.js.map +1 -0
  74. package/dist/src/components/mode-toggle.d.ts +7 -1
  75. package/dist/src/components/mode-toggle.js +42 -7
  76. package/dist/src/components/mode-toggle.js.map +1 -0
  77. package/dist/src/components/nav-main.d.ts +20 -12
  78. package/dist/src/components/nav-main.js +31 -5
  79. package/dist/src/components/nav-main.js.map +1 -0
  80. package/dist/src/components/pricing-cards.d.ts +7 -1
  81. package/dist/src/components/pricing-cards.js +125 -24
  82. package/dist/src/components/pricing-cards.js.map +1 -0
  83. package/dist/src/components/shared/ButtonCopy.d.ts +17 -6
  84. package/dist/src/components/shared/ButtonCopy.js +31 -20
  85. package/dist/src/components/shared/ButtonCopy.js.map +1 -0
  86. package/dist/src/components/team-switcher.d.ts +16 -8
  87. package/dist/src/components/team-switcher.js +70 -8
  88. package/dist/src/components/team-switcher.js.map +1 -0
  89. package/dist/src/components/theme-provider.d.ts +18 -8
  90. package/dist/src/components/theme-provider.js +42 -38
  91. package/dist/src/components/theme-provider.js.map +1 -0
  92. package/dist/src/components/typewriter.d.ts +35 -14
  93. package/dist/src/components/typewriter.js +45 -36
  94. package/dist/src/components/typewriter.js.map +1 -0
  95. package/dist/src/components/ui/alert-dialog.d.ts +48 -13
  96. package/dist/src/components/ui/alert-dialog.js +58 -15
  97. package/dist/src/components/ui/alert-dialog.js.map +1 -0
  98. package/dist/src/components/ui/alert.d.ts +24 -8
  99. package/dist/src/components/ui/alert.js +28 -15
  100. package/dist/src/components/ui/alert.js.map +1 -0
  101. package/dist/src/components/ui/avatar.d.ts +9 -5
  102. package/dist/src/components/ui/avatar.js +23 -7
  103. package/dist/src/components/ui/avatar.js.map +1 -0
  104. package/dist/src/components/ui/badge.d.ts +17 -8
  105. package/dist/src/components/ui/badge.js +17 -14
  106. package/dist/src/components/ui/badge.js.map +1 -0
  107. package/dist/src/components/ui/bento-grid.d.ts +26 -11
  108. package/dist/src/components/ui/bento-grid.js +30 -6
  109. package/dist/src/components/ui/bento-grid.js.map +1 -0
  110. package/dist/src/components/ui/bento-grid2.d.ts +30 -14
  111. package/dist/src/components/ui/bento-grid2.js +45 -9
  112. package/dist/src/components/ui/bento-grid2.js.map +1 -0
  113. package/dist/src/components/ui/breadcrumb.d.ts +27 -15
  114. package/dist/src/components/ui/breadcrumb.js +54 -14
  115. package/dist/src/components/ui/breadcrumb.js.map +1 -0
  116. package/dist/src/components/ui/button.d.ts +14 -9
  117. package/dist/src/components/ui/button.js +37 -26
  118. package/dist/src/components/ui/button.js.map +1 -0
  119. package/dist/src/components/ui/card.d.ts +12 -8
  120. package/dist/src/components/ui/card.js +38 -10
  121. package/dist/src/components/ui/card.js.map +1 -0
  122. package/dist/src/components/ui/checkbox.d.ts +6 -2
  123. package/dist/src/components/ui/checkbox.js +17 -5
  124. package/dist/src/components/ui/checkbox.js.map +1 -0
  125. package/dist/src/components/ui/collapsible.d.ts +9 -4
  126. package/dist/src/components/ui/collapsible.js +5 -1
  127. package/dist/src/components/ui/collapsible.js.map +1 -0
  128. package/dist/src/components/ui/dialog.d.ts +44 -12
  129. package/dist/src/components/ui/dialog.js +64 -14
  130. package/dist/src/components/ui/dialog.js.map +1 -0
  131. package/dist/src/components/ui/dropdown-menu.d.ts +32 -24
  132. package/dist/src/components/ui/dropdown-menu.js +64 -14
  133. package/dist/src/components/ui/dropdown-menu.js.map +1 -0
  134. package/dist/src/components/ui/floating-navbar.d.ts +18 -9
  135. package/dist/src/components/ui/floating-navbar.js +49 -35
  136. package/dist/src/components/ui/floating-navbar.js.map +1 -0
  137. package/dist/src/components/ui/form.d.ts +30 -21
  138. package/dist/src/components/ui/form.js +76 -44
  139. package/dist/src/components/ui/form.js.map +1 -0
  140. package/dist/src/components/ui/image.d.ts +6 -2
  141. package/dist/src/components/ui/image.js +51 -11
  142. package/dist/src/components/ui/image.js.map +1 -0
  143. package/dist/src/components/ui/input.d.ts +6 -2
  144. package/dist/src/components/ui/input.js +14 -5
  145. package/dist/src/components/ui/input.js.map +1 -0
  146. package/dist/src/components/ui/label.d.ts +8 -3
  147. package/dist/src/components/ui/label.js +13 -5
  148. package/dist/src/components/ui/label.js.map +1 -0
  149. package/dist/src/components/ui/pagination.d.ts +39 -12
  150. package/dist/src/components/ui/pagination.js +64 -14
  151. package/dist/src/components/ui/pagination.js.map +1 -0
  152. package/dist/src/components/ui/progress.d.ts +6 -2
  153. package/dist/src/components/ui/progress.js +16 -4
  154. package/dist/src/components/ui/progress.js.map +1 -0
  155. package/dist/src/components/ui/resizable-navbar.d.ts +84 -43
  156. package/dist/src/components/ui/resizable-navbar.js +126 -74
  157. package/dist/src/components/ui/resizable-navbar.js.map +1 -0
  158. package/dist/src/components/ui/segment-control.d.ts +10 -7
  159. package/dist/src/components/ui/segment-control.js +83 -38
  160. package/dist/src/components/ui/segment-control.js.map +1 -0
  161. package/dist/src/components/ui/select.d.ts +16 -12
  162. package/dist/src/components/ui/select.js +63 -14
  163. package/dist/src/components/ui/select.js.map +1 -0
  164. package/dist/src/components/ui/separator.d.ts +6 -2
  165. package/dist/src/components/ui/separator.js +14 -4
  166. package/dist/src/components/ui/separator.js.map +1 -0
  167. package/dist/src/components/ui/sheet.d.ts +30 -19
  168. package/dist/src/components/ui/sheet.js +52 -23
  169. package/dist/src/components/ui/sheet.js.map +1 -0
  170. package/dist/src/components/ui/sidebar.d.ts +69 -62
  171. package/dist/src/components/ui/sidebar.js +326 -171
  172. package/dist/src/components/ui/sidebar.js.map +1 -0
  173. package/dist/src/components/ui/skeleton.d.ts +9 -1
  174. package/dist/src/components/ui/skeleton.js +10 -3
  175. package/dist/src/components/ui/skeleton.js.map +1 -0
  176. package/dist/src/components/ui/slider.d.ts +6 -2
  177. package/dist/src/components/ui/slider.js +16 -4
  178. package/dist/src/components/ui/slider.js.map +1 -0
  179. package/dist/src/components/ui/sonner.d.ts +10 -3
  180. package/dist/src/components/ui/sonner.js +18 -11
  181. package/dist/src/components/ui/sonner.js.map +1 -0
  182. package/dist/src/components/ui/spinner.d.ts +21 -10
  183. package/dist/src/components/ui/spinner.js +24 -24
  184. package/dist/src/components/ui/spinner.js.map +1 -0
  185. package/dist/src/components/ui/switch.d.ts +6 -2
  186. package/dist/src/components/ui/switch.js +13 -4
  187. package/dist/src/components/ui/switch.js.map +1 -0
  188. package/dist/src/components/ui/table.d.ts +39 -10
  189. package/dist/src/components/ui/table.js +51 -11
  190. package/dist/src/components/ui/table.js.map +1 -0
  191. package/dist/src/components/ui/tabs.d.ts +23 -6
  192. package/dist/src/components/ui/tabs.js +27 -7
  193. package/dist/src/components/ui/tabs.js.map +1 -0
  194. package/dist/src/components/ui/textarea.d.ts +10 -2
  195. package/dist/src/components/ui/textarea.js +11 -3
  196. package/dist/src/components/ui/textarea.js.map +1 -0
  197. package/dist/src/components/ui/timeline.d.ts +16 -9
  198. package/dist/src/components/ui/timeline.js +87 -24
  199. package/dist/src/components/ui/timeline.js.map +1 -0
  200. package/dist/src/components/ui/toast.d.ts +19 -14
  201. package/dist/src/components/ui/toast.js +48 -22
  202. package/dist/src/components/ui/toast.js.map +1 -0
  203. package/dist/src/components/ui/tooltip.d.ts +23 -6
  204. package/dist/src/components/ui/tooltip.js +27 -7
  205. package/dist/src/components/ui/tooltip.js.map +1 -0
  206. package/dist/src/components/ui/typewriter-effect.d.ts +28 -14
  207. package/dist/src/components/ui/typewriter-effect.js +102 -72
  208. package/dist/src/components/ui/typewriter-effect.js.map +1 -0
  209. package/dist/src/hooks/use-mobile.d.ts +5 -1
  210. package/dist/src/hooks/use-mobile.js +18 -13
  211. package/dist/src/hooks/use-mobile.js.map +1 -0
  212. package/dist/src/hooks/useDialog.d.ts +8 -4
  213. package/dist/src/hooks/useDialog.js +24 -20
  214. package/dist/src/hooks/useDialog.js.map +1 -0
  215. package/dist/src/icons/GoogleIcon.d.ts +9 -5
  216. package/dist/src/icons/GoogleIcon.js +32 -3
  217. package/dist/src/icons/GoogleIcon.js.map +1 -0
  218. package/dist/src/icons/LinkedInIcon.d.ts +9 -5
  219. package/dist/src/icons/LinkedInIcon.js +27 -3
  220. package/dist/src/icons/LinkedInIcon.js.map +1 -0
  221. package/dist/src/icons/MicrosoftIcon.d.ts +9 -5
  222. package/dist/src/icons/MicrosoftIcon.js +31 -3
  223. package/dist/src/icons/MicrosoftIcon.js.map +1 -0
  224. package/dist/src/lib/chatwoot.d.ts +19 -10
  225. package/dist/src/lib/chatwoot.js +25 -27
  226. package/dist/src/lib/chatwoot.js.map +1 -0
  227. package/dist/src/lib/utils.d.ts +7 -2
  228. package/dist/src/lib/utils.js +7 -2
  229. package/dist/src/lib/utils.js.map +1 -0
  230. package/dist/src/modules/app/components/AppLoader.d.ts +8 -2
  231. package/dist/src/modules/app/components/AppLoader.js +14 -3
  232. package/dist/src/modules/app/components/AppLoader.js.map +1 -0
  233. package/dist/src/modules/app/components/AppShell.d.ts +15 -6
  234. package/dist/src/modules/app/components/AppShell.js +14 -5
  235. package/dist/src/modules/app/components/AppShell.js.map +1 -0
  236. package/dist/src/modules/app/components/AppSidebar.d.ts +16 -6
  237. package/dist/src/modules/app/components/AppSidebar.js +17 -4
  238. package/dist/src/modules/app/components/AppSidebar.js.map +1 -0
  239. package/dist/src/modules/app/components/AppSidebarContent.d.ts +22 -13
  240. package/dist/src/modules/app/components/AppSidebarContent.js +34 -5
  241. package/dist/src/modules/app/components/AppSidebarContent.js.map +1 -0
  242. package/dist/src/modules/app/components/AppSidebarHeader.d.ts +18 -8
  243. package/dist/src/modules/app/components/AppSidebarHeader.js +37 -6
  244. package/dist/src/modules/app/components/AppSidebarHeader.js.map +1 -0
  245. package/dist/src/modules/app/components/AppSidebarInvites.d.ts +11 -3
  246. package/dist/src/modules/app/components/AppSidebarInvites.js +39 -8
  247. package/dist/src/modules/app/components/AppSidebarInvites.js.map +1 -0
  248. package/dist/src/modules/app/components/AppSidebarUser.d.ts +20 -10
  249. package/dist/src/modules/app/components/AppSidebarUser.js +121 -12
  250. package/dist/src/modules/app/components/AppSidebarUser.js.map +1 -0
  251. package/dist/src/modules/auth/components/AdminUserManagement.d.ts +11 -4
  252. package/dist/src/modules/auth/components/AdminUserManagement.js +970 -418
  253. package/dist/src/modules/auth/components/AdminUserManagement.js.map +1 -0
  254. package/dist/src/modules/auth/components/AdminWaitlist.d.ts +11 -4
  255. package/dist/src/modules/auth/components/AdminWaitlist.js +284 -115
  256. package/dist/src/modules/auth/components/AdminWaitlist.js.map +1 -0
  257. package/dist/src/modules/auth/components/AuthLayout.d.ts +12 -4
  258. package/dist/src/modules/auth/components/AuthLayout.js +17 -3
  259. package/dist/src/modules/auth/components/AuthLayout.js.map +1 -0
  260. package/dist/src/modules/auth/components/AuthProviders.d.ts +17 -6
  261. package/dist/src/modules/auth/components/AuthProviders.js +80 -41
  262. package/dist/src/modules/auth/components/AuthProviders.js.map +1 -0
  263. package/dist/src/modules/auth/components/AuthRouter.d.ts +16 -7
  264. package/dist/src/modules/auth/components/AuthRouter.js +46 -10
  265. package/dist/src/modules/auth/components/AuthRouter.js.map +1 -0
  266. package/dist/src/modules/auth/components/ClaimAccountRoute.d.ts +12 -4
  267. package/dist/src/modules/auth/components/ClaimAccountRoute.js +202 -139
  268. package/dist/src/modules/auth/components/ClaimAccountRoute.js.map +1 -0
  269. package/dist/src/modules/auth/components/ErrorAuthRoute.d.ts +7 -1
  270. package/dist/src/modules/auth/components/ErrorAuthRoute.js +125 -89
  271. package/dist/src/modules/auth/components/ErrorAuthRoute.js.map +1 -0
  272. package/dist/src/modules/auth/components/ForgotPasswordForm.d.ts +7 -1
  273. package/dist/src/modules/auth/components/ForgotPasswordForm.js +49 -23
  274. package/dist/src/modules/auth/components/ForgotPasswordForm.js.map +1 -0
  275. package/dist/src/modules/auth/components/ForgotPasswordRoute.d.ts +7 -1
  276. package/dist/src/modules/auth/components/ForgotPasswordRoute.js +34 -6
  277. package/dist/src/modules/auth/components/ForgotPasswordRoute.js.map +1 -0
  278. package/dist/src/modules/auth/components/InviteFriends.d.ts +12 -4
  279. package/dist/src/modules/auth/components/InviteFriends.js +275 -69
  280. package/dist/src/modules/auth/components/InviteFriends.js.map +1 -0
  281. package/dist/src/modules/auth/components/LastUsedBadge.d.ts +17 -5
  282. package/dist/src/modules/auth/components/LastUsedBadge.js +16 -6
  283. package/dist/src/modules/auth/components/LastUsedBadge.js.map +1 -0
  284. package/dist/src/modules/auth/components/LoginForm.d.ts +11 -3
  285. package/dist/src/modules/auth/components/LoginForm.js +107 -40
  286. package/dist/src/modules/auth/components/LoginForm.js.map +1 -0
  287. package/dist/src/modules/auth/components/LoginRoute.d.ts +11 -3
  288. package/dist/src/modules/auth/components/LoginRoute.js +41 -8
  289. package/dist/src/modules/auth/components/LoginRoute.js.map +1 -0
  290. package/dist/src/modules/auth/components/LogoutRoute.d.ts +7 -1
  291. package/dist/src/modules/auth/components/LogoutRoute.js +18 -12
  292. package/dist/src/modules/auth/components/LogoutRoute.js.map +1 -0
  293. package/dist/src/modules/auth/components/OrganizationAcceptInvitationRoute.d.ts +21 -8
  294. package/dist/src/modules/auth/components/OrganizationAcceptInvitationRoute.js +107 -97
  295. package/dist/src/modules/auth/components/OrganizationAcceptInvitationRoute.js.map +1 -0
  296. package/dist/src/modules/auth/components/OrganizationMembersRoute.d.ts +58 -48
  297. package/dist/src/modules/auth/components/OrganizationMembersRoute.js +448 -349
  298. package/dist/src/modules/auth/components/OrganizationMembersRoute.js.map +1 -0
  299. package/dist/src/modules/auth/components/OrganizationPreferences.d.ts +27 -16
  300. package/dist/src/modules/auth/components/OrganizationPreferences.js +129 -124
  301. package/dist/src/modules/auth/components/OrganizationPreferences.js.map +1 -0
  302. package/dist/src/modules/auth/components/OrganizationSettingsRoute.d.ts +27 -18
  303. package/dist/src/modules/auth/components/OrganizationSettingsRoute.js +184 -144
  304. package/dist/src/modules/auth/components/OrganizationSettingsRoute.js.map +1 -0
  305. package/dist/src/modules/auth/components/OrganizationSwitcher.d.ts +17 -6
  306. package/dist/src/modules/auth/components/OrganizationSwitcher.js +91 -69
  307. package/dist/src/modules/auth/components/OrganizationSwitcher.js.map +1 -0
  308. package/dist/src/modules/auth/components/PreferencesEditor.d.ts +44 -33
  309. package/dist/src/modules/auth/components/PreferencesEditor.js +82 -58
  310. package/dist/src/modules/auth/components/PreferencesEditor.js.map +1 -0
  311. package/dist/src/modules/auth/components/ProfileRoute.d.ts +7 -1
  312. package/dist/src/modules/auth/components/ProfileRoute.js +79 -36
  313. package/dist/src/modules/auth/components/ProfileRoute.js.map +1 -0
  314. package/dist/src/modules/auth/components/RangeNuqsDatePicker.d.ts +44 -30
  315. package/dist/src/modules/auth/components/RangeNuqsDatePicker.js +234 -242
  316. package/dist/src/modules/auth/components/RangeNuqsDatePicker.js.map +1 -0
  317. package/dist/src/modules/auth/components/ResetPasswordForm.d.ts +7 -1
  318. package/dist/src/modules/auth/components/ResetPasswordForm.js +97 -35
  319. package/dist/src/modules/auth/components/ResetPasswordForm.js.map +1 -0
  320. package/dist/src/modules/auth/components/ResetPasswordRoute.d.ts +7 -1
  321. package/dist/src/modules/auth/components/ResetPasswordRoute.js +34 -6
  322. package/dist/src/modules/auth/components/ResetPasswordRoute.js.map +1 -0
  323. package/dist/src/modules/auth/components/SignupFormRoute.d.ts +15 -5
  324. package/dist/src/modules/auth/components/SignupFormRoute.js +142 -99
  325. package/dist/src/modules/auth/components/SignupFormRoute.js.map +1 -0
  326. package/dist/src/modules/auth/components/SignupRoute.d.ts +13 -5
  327. package/dist/src/modules/auth/components/SignupRoute.js +59 -13
  328. package/dist/src/modules/auth/components/SignupRoute.js.map +1 -0
  329. package/dist/src/modules/auth/components/UserPreferences.d.ts +22 -11
  330. package/dist/src/modules/auth/components/UserPreferences.js +24 -12
  331. package/dist/src/modules/auth/components/UserPreferences.js.map +1 -0
  332. package/dist/src/modules/auth/components/WaitlistCard.d.ts +11 -4
  333. package/dist/src/modules/auth/components/WaitlistCard.js +63 -28
  334. package/dist/src/modules/auth/components/WaitlistCard.js.map +1 -0
  335. package/dist/src/modules/auth/components/WaitlistCodeValidation.d.ts +13 -5
  336. package/dist/src/modules/auth/components/WaitlistCodeValidation.js +42 -40
  337. package/dist/src/modules/auth/components/WaitlistCodeValidation.js.map +1 -0
  338. package/dist/src/modules/billing/components/BillingBetaPage.d.ts +15 -6
  339. package/dist/src/modules/billing/components/BillingBetaPage.js +155 -8
  340. package/dist/src/modules/billing/components/BillingBetaPage.js.map +1 -0
  341. package/dist/src/modules/billing/components/BillingInvoicePage.d.ts +13 -5
  342. package/dist/src/modules/billing/components/BillingInvoicePage.js +160 -30
  343. package/dist/src/modules/billing/components/BillingInvoicePage.js.map +1 -0
  344. package/dist/src/modules/billing/components/BillingPlanSelect.d.ts +11 -4
  345. package/dist/src/modules/billing/components/BillingPlanSelect.js +10 -7
  346. package/dist/src/modules/billing/components/BillingPlanSelect.js.map +1 -0
  347. package/dist/src/modules/billing/components/BillingRouter.d.ts +15 -7
  348. package/dist/src/modules/billing/components/BillingRouter.js +19 -6
  349. package/dist/src/modules/billing/components/BillingRouter.js.map +1 -0
  350. package/dist/src/modules/billing/components/BillingSinglePlanSelect.d.ts +17 -7
  351. package/dist/src/modules/billing/components/BillingSinglePlanSelect.js +163 -42
  352. package/dist/src/modules/billing/components/BillingSinglePlanSelect.js.map +1 -0
  353. package/dist/src/modules/table/components/ColumnOrderAndVisibility.d.ts +18 -8
  354. package/dist/src/modules/table/components/ColumnOrderAndVisibility.js +81 -38
  355. package/dist/src/modules/table/components/ColumnOrderAndVisibility.js.map +1 -0
  356. package/dist/src/modules/table/components/NuqsTable.d.ts +33 -21
  357. package/dist/src/modules/table/components/NuqsTable.js +295 -221
  358. package/dist/src/modules/table/components/NuqsTable.js.map +1 -0
  359. package/dist/src/modules/table/components/TableFiltering.d.ts +33 -21
  360. package/dist/src/modules/table/components/TableFiltering.js +408 -226
  361. package/dist/src/modules/table/components/TableFiltering.js.map +1 -0
  362. package/dist/src/modules/table/components/TableGroupBy.d.ts +18 -8
  363. package/dist/src/modules/table/components/TableGroupBy.js +56 -16
  364. package/dist/src/modules/table/components/TableGroupBy.js.map +1 -0
  365. package/dist/src/modules/table/components/TablePagination.d.ts +17 -7
  366. package/dist/src/modules/table/components/TablePagination.js +64 -32
  367. package/dist/src/modules/table/components/TablePagination.js.map +1 -0
  368. package/dist/src/modules/table/components/table.types.d.ts +15 -10
  369. package/dist/src/modules/table/components/table.types.js +0 -1
  370. package/dist/src/modules/table/filterTransformers.d.ts +35 -30
  371. package/dist/src/modules/table/filterTransformers.js +198 -261
  372. package/dist/src/modules/table/filterTransformers.js.map +1 -0
  373. package/dist/src/types.d.ts +8 -3
  374. package/dist/src/types.js +0 -1
  375. package/package.json +8 -6
  376. package/dist/translations/en/web-ui.json +0 -209
  377. package/dist/tsconfig.lib.tsbuildinfo +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AdminUserManagement.js","names":[],"sources":["../../../../../src/modules/auth/components/AdminUserManagement.tsx"],"sourcesContent":["import {\r\n Button,\r\n Dropdown,\r\n DropdownItem,\r\n DropdownMenu,\r\n DropdownTrigger,\r\n Input,\r\n Modal,\r\n ModalBody,\r\n ModalContent,\r\n ModalFooter,\r\n ModalHeader,\r\n Select,\r\n SelectItem,\r\n Spinner,\r\n Table,\r\n TableBody,\r\n TableCell,\r\n TableColumn,\r\n TableHeader,\r\n TableRow,\r\n Tooltip,\r\n} from \"@heroui/react\";\r\nimport { authClient } from \"@m5kdev/frontend/modules/auth/auth.lib\";\r\nimport * as authAdmin from \"@m5kdev/frontend/modules/auth/hooks/useAuthAdmin\";\r\nimport { useMutation, useQuery, useQueryClient } from \"@tanstack/react-query\";\r\nimport {\r\n BarChart3,\r\n CalendarClock,\r\n ChevronDown,\r\n ChevronUp,\r\n Copy,\r\n Filter,\r\n Info,\r\n Link2,\r\n List,\r\n MoreHorizontal,\r\n Search,\r\n UserPlus,\r\n X,\r\n} from \"lucide-react\";\r\nimport { useCallback, useEffect, useId, useState } from \"react\";\r\nimport { useNavigate } from \"react-router\";\r\nimport { toast } from \"sonner\";\r\nimport type { UseBackendTRPC } from \"../../../types\";\r\n\r\ntype SortField = \"name\" | \"email\" | \"role\" | \"createdAt\";\r\ntype SortOrder = \"asc\" | \"desc\";\r\ntype StatusFilter = \"all\" | \"banned\" | \"active\";\r\n\r\ninterface AdminUserManagementProps {\r\n useTRPC?: UseBackendTRPC;\r\n}\r\n\r\nexport function AdminUserManagement({ useTRPC }: AdminUserManagementProps) {\r\n const banReasonInputId = useId();\r\n const customDurationId = useId();\r\n const nameInputId = useId();\r\n const emailInputId = useId();\r\n const passwordInputId = useId();\r\n const roleSelectId = useId();\r\n const [page, setPage] = useState(0);\r\n const [limit] = useState(10);\r\n const [userToDelete, setUserToDelete] = useState<string | null>(null);\r\n const [userToBan, setUserToBan] = useState<{ id: string; name: string } | null>(null);\r\n const [banReason, setBanReason] = useState(\"\");\r\n const [banExpiry, setBanExpiry] = useState(\"never\"); // \"never\", \"1d\", \"7d\", \"30d\", \"custom\"\r\n const [customBanDays, setCustomBanDays] = useState(1);\r\n const [isBanningUser, setIsBanningUser] = useState(false);\r\n const [isUnbanningUser, setIsUnbanningUser] = useState<Record<string, boolean>>({});\r\n const [isImpersonatingUser, setIsImpersonatingUser] = useState(false);\r\n const [searchQuery, setSearchQuery] = useState(\"\");\r\n const [statusFilter, setStatusFilter] = useState<StatusFilter>(\"all\");\r\n const [sortField, setSortField] = useState<SortField>(\"createdAt\");\r\n const [sortOrder, setSortOrder] = useState<SortOrder>(\"desc\");\r\n const [debouncedSearchQuery, setDebouncedSearchQuery] = useState(\"\");\r\n const [isCreateUserModalOpen, setIsCreateUserModalOpen] = useState(false);\r\n const [newUserData, setNewUserData] = useState({\r\n name: \"\",\r\n email: \"\",\r\n password: \"\",\r\n role: \"user\",\r\n });\r\n const [isCreatingUser, setIsCreatingUser] = useState(false);\r\n const [userForUsage, setUserForUsage] = useState<{ id: string; name: string } | null>(null);\r\n const [userForMagicLink, setUserForMagicLink] = useState<{\r\n id: string;\r\n name: string;\r\n email: string | null;\r\n } | null>(null);\r\n const [claimEmail, setClaimEmail] = useState(\"\");\r\n const [generatedMagicLink, setGeneratedMagicLink] = useState<string | null>(null);\r\n const [isGeneratingMagicLink, setIsGeneratingMagicLink] = useState(false);\r\n const navigate = useNavigate();\r\n const magicLinkEmailInputId = useId();\r\n const generatedMagicLinkInputId = useId();\r\n\r\n // AI Usage query\r\n const trpc = useTRPC?.();\r\n const queryClient = useQueryClient();\r\n const usageQueryEnabled = !!userForUsage && !!trpc;\r\n const usageQueryOptions = trpc?.ai.getUserUsage.queryOptions({ userId: userForUsage?.id ?? \"\" });\r\n const usageQuery = useQuery({\r\n ...(usageQueryOptions ?? {\r\n queryKey: [[\"ai\", \"getUserUsage\"], { input: { userId: \"\" } }] as const,\r\n queryFn: () =>\r\n Promise.resolve({ inputTokens: null, outputTokens: null, totalTokens: null, cost: null }),\r\n }),\r\n enabled: usageQueryEnabled,\r\n });\r\n const usageData = usageQuery.data;\r\n const isLoadingUsage = usageQuery.isLoading;\r\n\r\n const refetchUsage = () => {\r\n if (usageQueryOptions) {\r\n queryClient.invalidateQueries({ queryKey: usageQueryOptions.queryKey });\r\n }\r\n };\r\n\r\n // Reset page on filter change\r\n const resetPage = useCallback(() => {\r\n setPage(0);\r\n }, []);\r\n\r\n // Debounce search query\r\n useEffect(() => {\r\n const timer = setTimeout(() => {\r\n setDebouncedSearchQuery(searchQuery);\r\n resetPage();\r\n }, 300);\r\n\r\n return () => clearTimeout(timer);\r\n }, [searchQuery, resetPage]);\r\n\r\n // Handle status filter change\r\n const handleStatusFilterChange = useCallback(\r\n (value: StatusFilter) => {\r\n setStatusFilter(value);\r\n resetPage();\r\n },\r\n [resetPage]\r\n );\r\n\r\n const {\r\n data: listUsers = {\r\n users: [],\r\n total: 0,\r\n },\r\n isLoading,\r\n refetch,\r\n } = authAdmin.useListUsers({\r\n query: {\r\n searchField: \"name\",\r\n searchOperator: \"contains\",\r\n searchValue: debouncedSearchQuery,\r\n limit,\r\n offset: page * limit,\r\n sortBy: sortField,\r\n sortDirection: sortOrder,\r\n },\r\n });\r\n\r\n const { users, total: totalUsers } = listUsers;\r\n\r\n const { mutate: deleteUser, isPending: isDeleting } = authAdmin.useRemoveUser({\r\n onSuccess: () => {\r\n toast.success(\"User deleted successfully\");\r\n refetch();\r\n },\r\n onError: (error) => {\r\n toast.error(`Error deleting user: ${error.message}`);\r\n },\r\n });\r\n\r\n const { mutate: updateUser } = authAdmin.useUpdateUser({\r\n onSuccess: () => {\r\n toast.success(\"User updated successfully\");\r\n refetch();\r\n },\r\n onError: (error) => {\r\n toast.error(`Error updating user: ${error.message}`);\r\n },\r\n });\r\n\r\n const totalPages = totalUsers ? Math.ceil(totalUsers / limit) : 0;\r\n\r\n const confirmDelete = (userId: string) => {\r\n setUserToDelete(userId);\r\n };\r\n\r\n const handleDelete = () => {\r\n if (userToDelete) {\r\n deleteUser({ id: userToDelete });\r\n setUserToDelete(null);\r\n }\r\n };\r\n\r\n const openBanModal = (userId: string, userName: string) => {\r\n setUserToBan({ id: userId, name: userName });\r\n setBanReason(\"\");\r\n setBanExpiry(\"never\");\r\n setCustomBanDays(1);\r\n };\r\n\r\n const getBanExpiryInSeconds = () => {\r\n switch (banExpiry) {\r\n case \"never\":\r\n return undefined; // No expiry\r\n case \"1d\":\r\n return 60 * 60 * 24; // 1 day in seconds\r\n case \"7d\":\r\n return 60 * 60 * 24 * 7; // 7 days in seconds\r\n case \"30d\":\r\n return 60 * 60 * 24 * 30; // 30 days in seconds\r\n case \"custom\":\r\n return 60 * 60 * 24 * customBanDays; // Custom days in seconds\r\n default:\r\n return undefined;\r\n }\r\n };\r\n\r\n const formatBanExpiry = (expiryTimestamp: number | null) => {\r\n if (!expiryTimestamp) return \"Never\";\r\n\r\n const expiryDate = new Date(expiryTimestamp);\r\n const now = new Date();\r\n\r\n // If it's expired, return that\r\n if (expiryDate < now) return \"Expired\";\r\n\r\n // Format the date\r\n const dateString = expiryDate.toLocaleDateString(undefined, {\r\n year: \"numeric\",\r\n month: \"short\",\r\n day: \"numeric\",\r\n });\r\n\r\n // Calculate time remaining\r\n const timeRemaining = expiryDate.getTime() - now.getTime();\r\n const daysRemaining = Math.ceil(timeRemaining / (1000 * 60 * 60 * 24));\r\n\r\n return `${dateString} (${daysRemaining} days)`;\r\n };\r\n\r\n const handleBanUser = async () => {\r\n if (!userToBan) return;\r\n\r\n try {\r\n setIsBanningUser(true);\r\n await authClient.admin.banUser({\r\n userId: userToBan.id,\r\n banReason: banReason || \"No reason provided\",\r\n banExpiresIn: getBanExpiryInSeconds(),\r\n });\r\n\r\n toast.success(`User ${userToBan.name} has been banned`);\r\n setUserToBan(null);\r\n await refetch();\r\n } catch (error) {\r\n toast.error(`Failed to ban user: ${error instanceof Error ? error.message : String(error)}`);\r\n } finally {\r\n setIsBanningUser(false);\r\n }\r\n };\r\n\r\n const handleUnbanUser = async (userId: string) => {\r\n try {\r\n setIsUnbanningUser((prev) => ({ ...prev, [userId]: true }));\r\n await authClient.admin.unbanUser({\r\n userId,\r\n });\r\n\r\n toast.success(\"User has been unbanned\");\r\n await refetch();\r\n } catch (error) {\r\n toast.error(\r\n `Failed to unban user: ${error instanceof Error ? error.message : String(error)}`\r\n );\r\n } finally {\r\n setIsUnbanningUser((prev) => ({ ...prev, [userId]: false }));\r\n }\r\n };\r\n\r\n const handleSetOnboardingUser = async (userId: string) => {\r\n const onboardingStep = window.prompt(`Set onboarding step for user ${userId}`, \"4\");\r\n const onboardingStepNumber = Number.parseInt(onboardingStep || \"0\");\r\n if (onboardingStepNumber) {\r\n updateUser({\r\n userId,\r\n data: { onboarding: onboardingStepNumber },\r\n });\r\n }\r\n };\r\n\r\n const handleImpersonateUser = async (userId: string) => {\r\n try {\r\n setIsImpersonatingUser(true);\r\n await authClient.admin.impersonateUser({\r\n userId,\r\n });\r\n\r\n toast.success(\"Now impersonating user\");\r\n window.location.assign(\"/\"); // Force full reload to apply impersonated session immediately\r\n } catch (error) {\r\n setIsImpersonatingUser(false);\r\n toast.error(\r\n `Failed to impersonate user: ${error instanceof Error ? error.message : String(error)}`\r\n );\r\n }\r\n };\r\n\r\n const handlePageChange = (newPage: number) => {\r\n if (newPage >= 0 && newPage < totalPages) {\r\n setPage(newPage);\r\n }\r\n };\r\n\r\n const handleSort = (field: SortField) => {\r\n if (sortField === field) {\r\n // Toggle order if same field\r\n setSortOrder(sortOrder === \"asc\" ? \"desc\" : \"asc\");\r\n } else {\r\n // Set new field and default to ascending\r\n setSortField(field);\r\n setSortOrder(\"asc\");\r\n }\r\n };\r\n\r\n const renderSortIcon = (field: SortField) => {\r\n if (sortField !== field) return null;\r\n\r\n return sortOrder === \"asc\" ? (\r\n <ChevronUp className=\"h-4 w-4 inline ml-1\" />\r\n ) : (\r\n <ChevronDown className=\"h-4 w-4 inline ml-1\" />\r\n );\r\n };\r\n\r\n const clearFilters = () => {\r\n setSearchQuery(\"\");\r\n setStatusFilter(\"all\");\r\n setSortField(\"createdAt\");\r\n setSortOrder(\"desc\");\r\n };\r\n\r\n const openCreateUserModal = () => {\r\n setNewUserData({\r\n name: \"\",\r\n email: \"\",\r\n password: \"\",\r\n role: \"user\",\r\n });\r\n setIsCreateUserModalOpen(true);\r\n };\r\n\r\n const handleCreateUser = async () => {\r\n if (!newUserData.name || !newUserData.email || !newUserData.password) {\r\n toast.error(\"Please fill in all required fields\");\r\n return;\r\n }\r\n\r\n try {\r\n setIsCreatingUser(true);\r\n await authClient.admin.createUser({\r\n name: newUserData.name,\r\n email: newUserData.email,\r\n password: newUserData.password,\r\n role: newUserData.role as \"user\" | \"admin\",\r\n });\r\n\r\n toast.success(`User ${newUserData.name} has been created`);\r\n setIsCreateUserModalOpen(false);\r\n await refetch();\r\n } catch (error) {\r\n toast.error(\r\n `Failed to create user: ${error instanceof Error ? error.message : String(error)}`\r\n );\r\n } finally {\r\n setIsCreatingUser(false);\r\n }\r\n };\r\n\r\n const handleNewUserDataChange = (field: keyof typeof newUserData, value: string) => {\r\n setNewUserData((prev) => ({\r\n ...prev,\r\n [field]: value,\r\n }));\r\n };\r\n\r\n const openUsageModal = (userId: string, userName: string) => {\r\n setUserForUsage({ id: userId, name: userName });\r\n refetchUsage();\r\n };\r\n\r\n const formatTokenCount = (count: number | null | undefined): string => {\r\n if (count === null || count === undefined) return \"—\";\r\n return count.toLocaleString();\r\n };\r\n\r\n const formatCost = (cost: number | null | undefined): string => {\r\n if (cost === null || cost === undefined) return \"—\";\r\n return `$${cost.toFixed(4)}`;\r\n };\r\n\r\n const createAccountClaimCodeMutation = useMutation(\r\n trpc\r\n ? trpc.auth.createAccountClaimCode.mutationOptions()\r\n : {\r\n mutationFn: async () => {\r\n throw new Error(\"Account claim actions are not available in this app\");\r\n },\r\n }\r\n );\r\n\r\n const generateAccountClaimMagicLinkMutation = useMutation(\r\n trpc\r\n ? trpc.auth.generateAccountClaimMagicLink.mutationOptions()\r\n : {\r\n mutationFn: async () => {\r\n throw new Error(\"Account claim actions are not available in this app\");\r\n },\r\n }\r\n );\r\n\r\n const openMagicLinkModal = (userId: string, userName: string, userEmail: string | null) => {\r\n setUserForMagicLink({ id: userId, name: userName, email: userEmail });\r\n setClaimEmail(userEmail ?? \"\");\r\n setGeneratedMagicLink(null);\r\n };\r\n\r\n const handleGenerateMagicLink = async () => {\r\n if (!trpc) {\r\n toast.error(\"Account claim actions are not available in this app\");\r\n return;\r\n }\r\n\r\n if (!userForMagicLink) return;\r\n\r\n const normalizedEmail = claimEmail.trim().toLowerCase();\r\n if (!normalizedEmail) {\r\n toast.error(\"Email is required\");\r\n return;\r\n }\r\n\r\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\r\n if (!emailRegex.test(normalizedEmail)) {\r\n toast.error(\"Please enter a valid email address\");\r\n return;\r\n }\r\n\r\n try {\r\n setIsGeneratingMagicLink(true);\r\n const claim = await createAccountClaimCodeMutation.mutateAsync({\r\n userId: userForMagicLink.id,\r\n });\r\n const link = await generateAccountClaimMagicLinkMutation.mutateAsync({\r\n claimId: claim.id,\r\n email: normalizedEmail,\r\n });\r\n setGeneratedMagicLink(link.url);\r\n toast.success(\"Magic login link generated\");\r\n } catch (error) {\r\n toast.error(\r\n `Failed to generate magic link: ${error instanceof Error ? error.message : String(error)}`\r\n );\r\n } finally {\r\n setIsGeneratingMagicLink(false);\r\n }\r\n };\r\n\r\n const copyGeneratedMagicLink = async () => {\r\n if (!generatedMagicLink) return;\r\n\r\n try {\r\n await navigator.clipboard.writeText(generatedMagicLink);\r\n toast.success(\"Magic link copied\");\r\n } catch {\r\n toast.error(\"Failed to copy link\");\r\n }\r\n };\r\n\r\n if (isLoading) {\r\n return (\r\n <div className=\"flex justify-center p-8\">\r\n <Spinner />\r\n </div>\r\n );\r\n }\r\n\r\n const openWaitlistModal = () => {\r\n navigate(\"/admin/waitlist\");\r\n };\r\n\r\n const hasActiveFilters =\r\n debouncedSearchQuery ||\r\n statusFilter !== \"all\" ||\r\n sortField !== \"createdAt\" ||\r\n sortOrder !== \"desc\";\r\n\r\n return (\r\n <div className=\"space-y-4 p-4\">\r\n <div className=\"flex justify-between items-center\">\r\n <h2 className=\"text-xl font-semibold\">User Management</h2>\r\n <div className=\"flex items-center gap-2\">\r\n <Button onPress={openWaitlistModal} size=\"sm\">\r\n <List className=\"h-4 w-4 mr-2\" />\r\n Waitlist\r\n </Button>\r\n <Button onPress={openCreateUserModal} size=\"sm\">\r\n <UserPlus className=\"h-4 w-4 mr-2\" />\r\n Create User\r\n </Button>\r\n <div className=\"text-sm text-muted-foreground\">Total users: {totalUsers || 0}</div>\r\n </div>\r\n </div>\r\n\r\n {/* Search and filters */}\r\n <div className=\"flex flex-col sm:flex-row gap-3 items-start sm:items-center\">\r\n <form\r\n className=\"relative flex-1\"\r\n onSubmit={(e) => {\r\n e.preventDefault();\r\n setDebouncedSearchQuery(searchQuery);\r\n resetPage();\r\n }}\r\n >\r\n <Search className=\"absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground\" />\r\n <Input\r\n aria-label=\"Search users\"\r\n placeholder=\"Search users by name or email...\"\r\n className=\"pl-8 w-full\"\r\n value={searchQuery}\r\n onChange={(e) => setSearchQuery(e.target.value)}\r\n variant=\"bordered\"\r\n />\r\n {searchQuery && (\r\n <button\r\n type=\"button\"\r\n onClick={() => setSearchQuery(\"\")}\r\n className=\"absolute right-2.5 top-2.5 text-muted-foreground hover:text-foreground\"\r\n aria-label=\"Clear search\"\r\n >\r\n <X className=\"h-4 w-4\" />\r\n </button>\r\n )}\r\n </form>\r\n\r\n <div className=\"flex gap-2\">\r\n <Select\r\n aria-label=\"Status filter\"\r\n selectedKeys={new Set([statusFilter])}\r\n onSelectionChange={(keys) =>\r\n handleStatusFilterChange(Array.from(keys)[0] as StatusFilter)\r\n }\r\n className=\"w-[160px]\"\r\n startContent={<Filter className=\"mr-1 h-4 w-4\" />}\r\n >\r\n <SelectItem key=\"all\">All Users</SelectItem>\r\n <SelectItem key=\"active\">Active Only</SelectItem>\r\n <SelectItem key=\"banned\">Banned Only</SelectItem>\r\n </Select>\r\n\r\n {hasActiveFilters && (\r\n <Button variant=\"bordered\" size=\"sm\" onPress={clearFilters}>\r\n <X className=\"mr-1 h-4 w-4\" />\r\n Clear Filters\r\n </Button>\r\n )}\r\n </div>\r\n </div>\r\n\r\n <div className=\"border rounded-lg overflow-hidden\">\r\n <Table aria-label=\"Users table\" removeWrapper>\r\n <TableHeader>\r\n <TableColumn>ID</TableColumn>\r\n <TableColumn className=\"cursor-pointer\" onClick={() => handleSort(\"name\")}>\r\n Name {renderSortIcon(\"name\")}\r\n </TableColumn>\r\n <TableColumn className=\"cursor-pointer\" onClick={() => handleSort(\"email\")}>\r\n Email {renderSortIcon(\"email\")}\r\n </TableColumn>\r\n <TableColumn className=\"cursor-pointer\" onClick={() => handleSort(\"role\")}>\r\n Role {renderSortIcon(\"role\")}\r\n </TableColumn>\r\n <TableColumn>Status</TableColumn>\r\n <TableColumn>Onboarding</TableColumn>\r\n <TableColumn className=\"cursor-pointer\" onClick={() => handleSort(\"createdAt\")}>\r\n Created At {renderSortIcon(\"createdAt\")}\r\n </TableColumn>\r\n <TableColumn className=\"text-right\">Actions</TableColumn>\r\n </TableHeader>\r\n <TableBody\r\n items={users ?? []}\r\n emptyContent={\r\n hasActiveFilters ? \"No users found matching your filters\" : \"No users found\"\r\n }\r\n >\r\n {(user) => {\r\n const onboarding = (user as { onboarding?: string | number }).onboarding;\r\n return (\r\n <TableRow key={user.id}>\r\n <TableCell className=\"font-mono text-xs\">{user.id}</TableCell>\r\n <TableCell>{user.name}</TableCell>\r\n <TableCell>{user.email}</TableCell>\r\n <TableCell>{user.role || \"user\"}</TableCell>\r\n <TableCell>\r\n {user.banned ? (\r\n <Tooltip\r\n content={\r\n <div className=\"space-y-1 text-xs\">\r\n <p>\r\n <strong>Reason:</strong> {user.banReason || \"No reason provided\"}\r\n </p>\r\n {user.banExpires && (\r\n <p className=\"flex items-center gap-1\">\r\n <CalendarClock className=\"h-3 w-3\" />\r\n <span>\r\n <strong>Expires:</strong>{\" \"}\r\n {formatBanExpiry(user.banExpires.getTime())}\r\n </span>\r\n </p>\r\n )}\r\n </div>\r\n }\r\n >\r\n <span className=\"inline-flex items-center gap-1 px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800\">\r\n Banned\r\n {user.banReason && <Info className=\"h-3 w-3\" />}\r\n </span>\r\n </Tooltip>\r\n ) : (\r\n <span className=\"inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800\">\r\n Active\r\n </span>\r\n )}\r\n </TableCell>\r\n <TableCell>{onboarding ?? \"—\"}</TableCell>\r\n <TableCell>\r\n {user.createdAt ? new Date(user.createdAt).toLocaleDateString() : \"N/A\"}\r\n </TableCell>\r\n <TableCell className=\"text-right\">\r\n <Dropdown placement=\"bottom-end\">\r\n <DropdownTrigger>\r\n <Button variant=\"light\" size=\"sm\" isIconOnly>\r\n <MoreHorizontal className=\"h-4 w-4\" />\r\n </Button>\r\n </DropdownTrigger>\r\n <DropdownMenu aria-label=\"User actions\">\r\n <DropdownItem\r\n key=\"onboarding\"\r\n onClick={() => handleSetOnboardingUser(user.id)}\r\n >\r\n Set Onboarding\r\n </DropdownItem>\r\n <DropdownItem\r\n key=\"usage\"\r\n onClick={() => openUsageModal(user.id, user.name)}\r\n className={useTRPC ? \"\" : \"hidden\"}\r\n >\r\n <span className=\"flex items-center gap-2\">\r\n <BarChart3 className=\"h-4 w-4\" />\r\n View AI Usage\r\n </span>\r\n </DropdownItem>\r\n <DropdownItem\r\n key=\"impersonate\"\r\n onClick={() => handleImpersonateUser(user.id)}\r\n isDisabled={user.banned || isImpersonatingUser}\r\n >\r\n {isImpersonatingUser ? (\r\n <>\r\n <Spinner className=\"mr-2 h-3 w-3\" />\r\n Impersonating...\r\n </>\r\n ) : (\r\n \"Impersonate\"\r\n )}\r\n </DropdownItem>\r\n <DropdownItem\r\n key=\"magic-link\"\r\n onClick={() => openMagicLinkModal(user.id, user.name, user.email ?? null)}\r\n className={trpc ? \"\" : \"hidden\"}\r\n >\r\n <span className=\"flex items-center gap-2\">\r\n <Link2 className=\"h-4 w-4\" />\r\n Generate Magic Login Link\r\n </span>\r\n </DropdownItem>\r\n {user.banned ? (\r\n <DropdownItem\r\n key=\"unban\"\r\n onClick={() => handleUnbanUser(user.id)}\r\n isDisabled={isUnbanningUser[user.id]}\r\n >\r\n {isUnbanningUser[user.id] ? (\r\n <>\r\n <Spinner className=\"mr-2 h-3 w-3\" />\r\n Unbanning...\r\n </>\r\n ) : (\r\n \"Unban\"\r\n )}\r\n </DropdownItem>\r\n ) : (\r\n <DropdownItem key=\"ban\" onClick={() => openBanModal(user.id, user.name)}>\r\n Ban\r\n </DropdownItem>\r\n )}\r\n <DropdownItem key=\"remove\" onClick={() => confirmDelete(user.id)}>\r\n Remove\r\n </DropdownItem>\r\n </DropdownMenu>\r\n </Dropdown>\r\n </TableCell>\r\n </TableRow>\r\n );\r\n }}\r\n </TableBody>\r\n </Table>\r\n </div>\r\n\r\n {/* Pagination */}\r\n {totalPages > 0 && (\r\n <div className=\"flex items-center justify-end space-x-2 py-4\">\r\n <Button\r\n variant=\"bordered\"\r\n size=\"sm\"\r\n onClick={() => handlePageChange(page - 1)}\r\n isDisabled={page === 0}\r\n >\r\n Previous\r\n </Button>\r\n <div className=\"text-sm text-muted-foreground\">\r\n Page {page + 1} of {totalPages}\r\n </div>\r\n <Button\r\n variant=\"bordered\"\r\n size=\"sm\"\r\n onClick={() => handlePageChange(page + 1)}\r\n isDisabled={page === totalPages - 1}\r\n >\r\n Next\r\n </Button>\r\n </div>\r\n )}\r\n\r\n {/* Delete confirmation modal */}\r\n <Modal\r\n isOpen={!!userToDelete}\r\n onOpenChange={(open) => {\r\n if (!open) setUserToDelete(null);\r\n }}\r\n >\r\n <ModalContent>\r\n {(onClose) => (\r\n <>\r\n <ModalHeader className=\"flex flex-col gap-1\">\r\n <p className=\"text-lg font-semibold\">Are you sure?</p>\r\n <p className=\"text-sm text-default-600\">\r\n This action cannot be undone. This will permanently delete the user and all their\r\n data.\r\n </p>\r\n </ModalHeader>\r\n <ModalFooter>\r\n <Button variant=\"bordered\" onPress={onClose}>\r\n Cancel\r\n </Button>\r\n <Button color=\"danger\" onPress={handleDelete} isLoading={isDeleting}>\r\n Delete\r\n </Button>\r\n </ModalFooter>\r\n </>\r\n )}\r\n </ModalContent>\r\n </Modal>\r\n\r\n {/* Ban user modal */}\r\n <Modal\r\n isOpen={!!userToBan}\r\n onOpenChange={(open) => {\r\n if (!open) setUserToBan(null);\r\n }}\r\n >\r\n <ModalContent>\r\n {(onClose) => (\r\n <form\r\n onSubmit={(e) => {\r\n e.preventDefault();\r\n handleBanUser();\r\n }}\r\n className=\"space-y-4\"\r\n >\r\n <ModalHeader className=\"flex flex-col gap-1\">\r\n <p className=\"text-lg font-semibold\">Ban User</p>\r\n <p className=\"text-sm text-default-600\">\r\n {userToBan &&\r\n `You are about to ban ${userToBan.name}. This will prevent them from signing in.`}\r\n </p>\r\n </ModalHeader>\r\n\r\n <ModalBody className=\"space-y-4\">\r\n <div className=\"space-y-2\">\r\n <label htmlFor={banReasonInputId} className=\"text-sm font-medium\">\r\n Ban Reason\r\n </label>\r\n <Input\r\n id={banReasonInputId}\r\n placeholder=\"Enter reason for ban\"\r\n value={banReason}\r\n onChange={(e) => setBanReason(e.target.value)}\r\n variant=\"bordered\"\r\n labelPlacement=\"outside\"\r\n label=\"Ban Reason\"\r\n />\r\n </div>\r\n\r\n <div className=\"space-y-2\">\r\n <p className=\"text-sm font-medium\">Ban Duration</p>\r\n <div className=\"grid grid-cols-2 gap-2\">\r\n <Button\r\n type=\"button\"\r\n variant={banExpiry === \"never\" ? \"solid\" : \"bordered\"}\r\n onClick={() => setBanExpiry(\"never\")}\r\n >\r\n Permanent\r\n </Button>\r\n <Button\r\n type=\"button\"\r\n variant={banExpiry === \"1d\" ? \"solid\" : \"bordered\"}\r\n onClick={() => setBanExpiry(\"1d\")}\r\n >\r\n 1 Day\r\n </Button>\r\n <Button\r\n type=\"button\"\r\n variant={banExpiry === \"7d\" ? \"solid\" : \"bordered\"}\r\n onClick={() => setBanExpiry(\"7d\")}\r\n >\r\n 7 Days\r\n </Button>\r\n <Button\r\n type=\"button\"\r\n variant={banExpiry === \"30d\" ? \"solid\" : \"bordered\"}\r\n onClick={() => setBanExpiry(\"30d\")}\r\n >\r\n 30 Days\r\n </Button>\r\n </div>\r\n </div>\r\n\r\n <div className=\"space-y-2\">\r\n <div className=\"flex items-center gap-2\">\r\n <input\r\n type=\"checkbox\"\r\n id={customDurationId}\r\n checked={banExpiry === \"custom\"}\r\n onChange={(e) =>\r\n e.target.checked ? setBanExpiry(\"custom\") : setBanExpiry(\"never\")\r\n }\r\n />\r\n <label htmlFor={customDurationId} className=\"text-sm font-medium\">\r\n Custom Duration\r\n </label>\r\n </div>\r\n\r\n {banExpiry === \"custom\" && (\r\n <div className=\"flex items-center gap-2\">\r\n <Input\r\n type=\"number\"\r\n min=\"1\"\r\n value={customBanDays.toString()}\r\n onChange={(e) => setCustomBanDays(Number(e.target.value))}\r\n variant=\"bordered\"\r\n labelPlacement=\"outside\"\r\n label=\"Custom duration (days)\"\r\n />\r\n <span className=\"text-sm\">Days</span>\r\n </div>\r\n )}\r\n </div>\r\n </ModalBody>\r\n\r\n <ModalFooter>\r\n <Button variant=\"bordered\" type=\"button\" onPress={onClose}>\r\n Cancel\r\n </Button>\r\n <Button color=\"danger\" type=\"submit\" isDisabled={isBanningUser}>\r\n {isBanningUser ? <Spinner className=\"mr-2 h-4 w-4\" /> : null}\r\n {isBanningUser ? \"Banning...\" : \"Ban User\"}\r\n </Button>\r\n </ModalFooter>\r\n </form>\r\n )}\r\n </ModalContent>\r\n </Modal>\r\n\r\n {/* Create user modal */}\r\n <Modal\r\n isOpen={isCreateUserModalOpen}\r\n onOpenChange={(open) => {\r\n if (!open) setIsCreateUserModalOpen(false);\r\n }}\r\n >\r\n <ModalContent>\r\n {(onClose) => (\r\n <form\r\n onSubmit={(e) => {\r\n e.preventDefault();\r\n handleCreateUser();\r\n }}\r\n className=\"space-y-4\"\r\n >\r\n <ModalHeader className=\"flex flex-col gap-1\">\r\n <p className=\"text-lg font-semibold\">Create New User</p>\r\n <p className=\"text-sm text-default-600\">\r\n Fill in the details below to create a new user account.\r\n </p>\r\n </ModalHeader>\r\n\r\n <ModalBody className=\"space-y-4\">\r\n <div className=\"space-y-2\">\r\n <Input\r\n id={nameInputId}\r\n label=\"Name *\"\r\n labelPlacement=\"outside\"\r\n placeholder=\"Enter user's name\"\r\n value={newUserData.name}\r\n onChange={(e) => handleNewUserDataChange(\"name\", e.target.value)}\r\n variant=\"bordered\"\r\n />\r\n </div>\r\n\r\n <div className=\"space-y-2\">\r\n <Input\r\n id={emailInputId}\r\n label=\"Email *\"\r\n labelPlacement=\"outside\"\r\n type=\"email\"\r\n placeholder=\"Enter user's email\"\r\n value={newUserData.email}\r\n onChange={(e) => handleNewUserDataChange(\"email\", e.target.value)}\r\n variant=\"bordered\"\r\n />\r\n </div>\r\n\r\n <div className=\"space-y-2\">\r\n <Input\r\n id={passwordInputId}\r\n label=\"Password *\"\r\n labelPlacement=\"outside\"\r\n type=\"password\"\r\n placeholder=\"Enter password\"\r\n value={newUserData.password}\r\n onChange={(e) => handleNewUserDataChange(\"password\", e.target.value)}\r\n variant=\"bordered\"\r\n />\r\n </div>\r\n\r\n <div className=\"space-y-2\">\r\n <p className=\"text-sm font-medium\" id={roleSelectId}>\r\n Role\r\n </p>\r\n <Select\r\n aria-label=\"Select role\"\r\n aria-labelledby={roleSelectId}\r\n selectedKeys={new Set([newUserData.role])}\r\n onSelectionChange={(keys) =>\r\n handleNewUserDataChange(\"role\", Array.from(keys)[0] as string)\r\n }\r\n >\r\n <SelectItem key=\"user\">User</SelectItem>\r\n <SelectItem key=\"admin\">Admin</SelectItem>\r\n </Select>\r\n </div>\r\n </ModalBody>\r\n\r\n <ModalFooter>\r\n <Button variant=\"bordered\" type=\"button\" onPress={onClose}>\r\n Cancel\r\n </Button>\r\n <Button type=\"submit\" color=\"primary\" isDisabled={isCreatingUser}>\r\n {isCreatingUser ? <Spinner className=\"mr-2 h-4 w-4\" /> : null}\r\n {isCreatingUser ? \"Creating...\" : \"Create User\"}\r\n </Button>\r\n </ModalFooter>\r\n </form>\r\n )}\r\n </ModalContent>\r\n </Modal>\r\n\r\n {/* AI Usage modal */}\r\n <Modal\r\n isOpen={!!userForUsage}\r\n onOpenChange={(open) => {\r\n if (!open) setUserForUsage(null);\r\n }}\r\n >\r\n <ModalContent>\r\n {(onClose) => (\r\n <>\r\n <ModalHeader className=\"flex flex-col gap-1\">\r\n <p className=\"text-lg font-semibold flex items-center gap-2\">\r\n <BarChart3 className=\"h-5 w-5\" />\r\n AI Usage\r\n </p>\r\n <p className=\"text-sm text-default-600\">\r\n {userForUsage && `Usage statistics for ${userForUsage.name}`}\r\n </p>\r\n </ModalHeader>\r\n\r\n <ModalBody>\r\n {isLoadingUsage ? (\r\n <div className=\"flex justify-center py-8\">\r\n <Spinner />\r\n </div>\r\n ) : usageData ? (\r\n <div className=\"space-y-4\">\r\n <div className=\"grid grid-cols-2 gap-4\">\r\n <div className=\"p-4 rounded-lg bg-default-100\">\r\n <p className=\"text-sm text-default-600\">Input Tokens</p>\r\n <p className=\"text-2xl font-semibold\">\r\n {formatTokenCount(usageData.inputTokens)}\r\n </p>\r\n </div>\r\n <div className=\"p-4 rounded-lg bg-default-100\">\r\n <p className=\"text-sm text-default-600\">Output Tokens</p>\r\n <p className=\"text-2xl font-semibold\">\r\n {formatTokenCount(usageData.outputTokens)}\r\n </p>\r\n </div>\r\n <div className=\"p-4 rounded-lg bg-default-100\">\r\n <p className=\"text-sm text-default-600\">Total Tokens</p>\r\n <p className=\"text-2xl font-semibold\">\r\n {formatTokenCount(usageData.totalTokens)}\r\n </p>\r\n </div>\r\n <div className=\"p-4 rounded-lg bg-primary-100\">\r\n <p className=\"text-sm text-primary-600\">Estimated Cost</p>\r\n <p className=\"text-2xl font-semibold text-primary\">\r\n {formatCost(usageData.cost)}\r\n </p>\r\n </div>\r\n </div>\r\n </div>\r\n ) : (\r\n <div className=\"text-center py-8 text-default-600\">No usage data available</div>\r\n )}\r\n </ModalBody>\r\n\r\n <ModalFooter>\r\n <Button variant=\"bordered\" onPress={onClose}>\r\n Close\r\n </Button>\r\n </ModalFooter>\r\n </>\r\n )}\r\n </ModalContent>\r\n </Modal>\r\n\r\n {/* Magic login link modal */}\r\n <Modal\r\n isOpen={!!userForMagicLink}\r\n onOpenChange={(open) => {\r\n if (!open) {\r\n setUserForMagicLink(null);\r\n setGeneratedMagicLink(null);\r\n setClaimEmail(\"\");\r\n }\r\n }}\r\n >\r\n <ModalContent>\r\n {(onClose) => (\r\n <form\r\n onSubmit={(e) => {\r\n e.preventDefault();\r\n handleGenerateMagicLink();\r\n }}\r\n className=\"space-y-4\"\r\n >\r\n <ModalHeader className=\"flex flex-col gap-1\">\r\n <p className=\"text-lg font-semibold\">Generate Magic Login Link</p>\r\n <p className=\"text-sm text-default-600\">\r\n {userForMagicLink &&\r\n `Generate a one-time claim sign-in link for ${userForMagicLink.name}.`}\r\n </p>\r\n </ModalHeader>\r\n\r\n <ModalBody className=\"space-y-4\">\r\n <Input\r\n id={magicLinkEmailInputId}\r\n label=\"Claim email\"\r\n labelPlacement=\"outside\"\r\n type=\"email\"\r\n placeholder=\"person@example.com\"\r\n value={claimEmail}\r\n onChange={(e) => setClaimEmail(e.target.value)}\r\n variant=\"bordered\"\r\n description=\"This email is used for provider linking and future sign-ins.\"\r\n />\r\n\r\n <Input\r\n id={generatedMagicLinkInputId}\r\n label=\"Generated link\"\r\n labelPlacement=\"outside\"\r\n value={generatedMagicLink ?? \"\"}\r\n readOnly\r\n variant=\"bordered\"\r\n placeholder=\"Generate link to see it here\"\r\n />\r\n </ModalBody>\r\n\r\n <ModalFooter>\r\n <Button variant=\"bordered\" type=\"button\" onPress={onClose}>\r\n Close\r\n </Button>\r\n <Button\r\n variant=\"bordered\"\r\n type=\"button\"\r\n onPress={copyGeneratedMagicLink}\r\n isDisabled={!generatedMagicLink}\r\n >\r\n <Copy className=\"h-4 w-4 mr-2\" />\r\n Copy Link\r\n </Button>\r\n <Button color=\"primary\" type=\"submit\" isDisabled={isGeneratingMagicLink}>\r\n {isGeneratingMagicLink ? <Spinner className=\"mr-2 h-4 w-4\" /> : null}\r\n {isGeneratingMagicLink ? \"Generating...\" : \"Generate Link\"}\r\n </Button>\r\n </ModalFooter>\r\n </form>\r\n )}\r\n </ModalContent>\r\n </Modal>\r\n </div>\r\n );\r\n}\r\n"],"mappings":"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"}
@@ -1,6 +1,13 @@
1
- import type { UseBackendTRPC } from "../../../types";
1
+ import { UseBackendTRPC } from "../../../types.js";
2
+ import * as _$react_jsx_runtime0 from "react/jsx-runtime";
3
+
4
+ //#region src/modules/auth/components/AdminWaitlist.d.ts
2
5
  interface AdminWaitlistProps {
3
- useTRPC: UseBackendTRPC;
6
+ useTRPC: UseBackendTRPC;
4
7
  }
5
- export declare function AdminWaitlist({ useTRPC }: AdminWaitlistProps): import("react/jsx-runtime").JSX.Element;
6
- export {};
8
+ declare function AdminWaitlist({
9
+ useTRPC
10
+ }: AdminWaitlistProps): _$react_jsx_runtime0.JSX.Element;
11
+ //#endregion
12
+ export { AdminWaitlist };
13
+ //# sourceMappingURL=AdminWaitlist.d.ts.map
@@ -1,118 +1,287 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { Button, Dropdown, DropdownItem, DropdownMenu, DropdownTrigger, Input, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader, Spinner, Table, TableBody, TableCell, TableColumn, TableHeader, TableRow, } from "@heroui/react";
3
- import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
4
- import { Mail, MoreHorizontal, Search, Trash2, UserPlus, X } from "lucide-react";
5
1
  import { useEffect, useId, useState } from "react";
2
+ import { Button, Dropdown, DropdownItem, DropdownMenu, DropdownTrigger, Input, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader, Spinner, Table, TableBody, TableCell, TableColumn, TableHeader, TableRow } from "@heroui/react";
3
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
4
+ import { Mail, MoreHorizontal, Search, Trash2, UserPlus, X } from "lucide-react";
6
5
  import { toast } from "sonner";
7
- export function AdminWaitlist({ useTRPC }) {
8
- const trpc = useTRPC();
9
- const queryClient = useQueryClient();
10
- const { data: waitlist = [], isLoading } = useQuery(trpc.auth.listAdminWaitlist.queryOptions());
11
- const { mutate: invite, isPending: isInviting } = useMutation(trpc.auth.inviteFromWaitlist.mutationOptions({
12
- onSuccess: () => {
13
- queryClient.invalidateQueries({ queryKey: trpc.auth.listAdminWaitlist.queryKey() });
14
- toast.success("Invitation sent successfully");
15
- },
16
- onError: (error) => {
17
- toast.error(`Failed to send invitation: ${error instanceof Error ? error.message : String(error)}`);
18
- },
19
- }));
20
- const { mutate: remove, isPending: isRemoving } = useMutation(trpc.auth.removeFromWaitlist.mutationOptions({
21
- onSuccess: () => {
22
- queryClient.invalidateQueries({ queryKey: trpc.auth.listAdminWaitlist.queryKey() });
23
- toast.success("Removed from waitlist successfully");
24
- },
25
- onError: (error) => {
26
- toast.error(`Failed to remove: ${error instanceof Error ? error.message : String(error)}`);
27
- },
28
- onSettled: () => {
29
- setItemToDelete(null);
30
- },
31
- }));
32
- const { mutate: add, isPending: isAdding } = useMutation(trpc.auth.addToWaitlist.mutationOptions({
33
- onSuccess: () => {
34
- queryClient.invalidateQueries({ queryKey: trpc.auth.listAdminWaitlist.queryKey() });
35
- toast.success("Added to waitlist successfully");
36
- },
37
- onError: (error) => {
38
- toast.error(`Failed to add to waitlist: ${error instanceof Error ? error.message : String(error)}`);
39
- },
40
- }));
41
- const emailInputId = useId();
42
- const [searchQuery, setSearchQuery] = useState("");
43
- const [debouncedSearchQuery, setDebouncedSearchQuery] = useState("");
44
- const [itemToDelete, setItemToDelete] = useState(null);
45
- const [isAddModalOpen, setIsAddModalOpen] = useState(false);
46
- const [newEmail, setNewEmail] = useState("");
47
- // Debounce search query
48
- useEffect(() => {
49
- const timer = setTimeout(() => {
50
- setDebouncedSearchQuery(searchQuery);
51
- }, 300);
52
- return () => clearTimeout(timer);
53
- }, [searchQuery]);
54
- const filteredWaitlist = waitlist.filter((item) => item.email?.toLowerCase().includes(debouncedSearchQuery?.toLowerCase() ?? ""));
55
- const handleInvite = (id) => {
56
- invite({ id });
57
- };
58
- const handleRemove = () => {
59
- if (itemToDelete) {
60
- remove({ id: itemToDelete });
61
- }
62
- };
63
- const handleAdd = async () => {
64
- if (!newEmail.trim()) {
65
- toast.error("Please enter an email address");
66
- return;
67
- }
68
- // Basic email validation
69
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
70
- if (!emailRegex.test(newEmail.trim())) {
71
- toast.error("Please enter a valid email address");
72
- return;
73
- }
74
- add({ email: newEmail.trim() });
75
- setNewEmail("");
76
- setIsAddModalOpen(false);
77
- };
78
- const formatDate = (date) => {
79
- if (!date)
80
- return "N/A";
81
- const dateObj = typeof date === "string" ? new Date(date) : date;
82
- return dateObj.toLocaleDateString(undefined, {
83
- year: "numeric",
84
- month: "short",
85
- day: "numeric",
86
- hour: "2-digit",
87
- minute: "2-digit",
88
- });
89
- };
90
- const getStatusBadge = (status) => {
91
- const statusLower = status.toLowerCase();
92
- if (statusLower === "invited" || statusLower === "active") {
93
- return (_jsx("span", { className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800", children: status }));
94
- }
95
- if (statusLower === "pending") {
96
- return (_jsx("span", { className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800", children: status }));
97
- }
98
- return (_jsx("span", { className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-800", children: status }));
99
- };
100
- if (isLoading) {
101
- return (_jsx("div", { className: "flex justify-center p-8", children: _jsx(Spinner, {}) }));
102
- }
103
- return (_jsxs("div", { className: "space-y-4 p-4", children: [_jsxs("div", { className: "flex justify-between items-center", children: [_jsx("h2", { className: "text-xl font-semibold", children: "Waitlist Management" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Button, { onPress: () => setIsAddModalOpen(true), size: "sm", children: [_jsx(UserPlus, { className: "h-4 w-4 mr-2" }), "Add to Waitlist"] }), _jsxs("div", { className: "text-sm text-muted-foreground", children: ["Total: ", waitlist.length] })] })] }), _jsx("div", { className: "flex flex-col sm:flex-row gap-3 items-start sm:items-center", children: _jsxs("form", { className: "relative flex-1", onSubmit: (e) => {
104
- e.preventDefault();
105
- setDebouncedSearchQuery(searchQuery);
106
- }, children: [_jsx(Search, { className: "absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" }), _jsx(Input, { "aria-label": "Search by email", placeholder: "Search by email...", className: "pl-8 w-full", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), variant: "bordered" }), searchQuery && (_jsx("button", { type: "button", onClick: () => setSearchQuery(""), className: "absolute right-2.5 top-2.5 text-muted-foreground hover:text-foreground", "aria-label": "Clear search", children: _jsx(X, { className: "h-4 w-4" }) }))] }) }), _jsx("div", { className: "border rounded-lg overflow-hidden", children: _jsxs(Table, { "aria-label": "Waitlist table", removeWrapper: true, children: [_jsxs(TableHeader, { children: [_jsx(TableColumn, { children: "Email" }), _jsx(TableColumn, { children: "Status" }), _jsx(TableColumn, { children: "Created At" }), _jsx(TableColumn, { children: "Updated At" }), _jsx(TableColumn, { className: "text-right", children: "Actions" })] }), _jsx(TableBody, { items: filteredWaitlist, emptyContent: searchQuery
107
- ? "No waitlist entries found matching your search"
108
- : "No waitlist entries found", children: (item) => (_jsxs(TableRow, { children: [_jsx(TableCell, { className: "font-medium", children: item.email }), _jsx(TableCell, { children: getStatusBadge(item.status) }), _jsx(TableCell, { children: formatDate(item.createdAt) }), _jsx(TableCell, { children: formatDate(item.updatedAt) }), _jsx(TableCell, { className: "text-right", children: _jsxs(Dropdown, { placement: "bottom-end", children: [_jsx(DropdownTrigger, { children: _jsx(Button, { variant: "light", size: "sm", isIconOnly: true, children: _jsx(MoreHorizontal, { className: "h-4 w-4" }) }) }), _jsxs(DropdownMenu, { "aria-label": "Waitlist actions", children: [_jsx(DropdownItem, { onPress: () => handleInvite(item.id), isDisabled: isInviting, children: isInviting ? (_jsxs(_Fragment, { children: [_jsx(Spinner, { className: "mr-2 h-3 w-3" }), "Inviting..."] })) : (_jsxs(_Fragment, { children: [_jsx(Mail, { className: "mr-2 h-4 w-4" }), "Send Invitation"] })) }, "invite"), _jsxs(DropdownItem, { className: "text-danger", onClick: () => setItemToDelete(item.id), children: [_jsx(Trash2, { className: "mr-2 h-4 w-4" }), "Remove"] }, "remove")] })] }) })] }, item.id)) })] }) }), _jsx(Modal, { isOpen: !!itemToDelete, onOpenChange: (open) => {
109
- if (!open)
110
- setItemToDelete(null);
111
- }, children: _jsx(ModalContent, { children: (onClose) => (_jsxs(_Fragment, { children: [_jsxs(ModalHeader, { className: "flex flex-col gap-1", children: [_jsx("p", { className: "text-lg font-semibold", children: "Are you sure?" }), _jsx("p", { className: "text-sm text-default-600", children: "This action cannot be undone. This will permanently remove this entry from the waitlist." })] }), _jsxs(ModalFooter, { children: [_jsx(Button, { variant: "bordered", onPress: onClose, children: "Cancel" }), _jsx(Button, { color: "danger", onPress: handleRemove, isLoading: isRemoving, children: "Remove" })] })] })) }) }), _jsx(Modal, { isOpen: isAddModalOpen, onOpenChange: (open) => {
112
- if (!open)
113
- setIsAddModalOpen(false);
114
- }, children: _jsx(ModalContent, { children: (onClose) => (_jsxs("form", { onSubmit: (e) => {
115
- e.preventDefault();
116
- handleAdd();
117
- }, className: "space-y-4", children: [_jsxs(ModalHeader, { className: "flex flex-col gap-1", children: [_jsx("p", { className: "text-lg font-semibold", children: "Add to Waitlist" }), _jsx("p", { className: "text-sm text-default-600", children: "Enter an email address to add someone to the waitlist." })] }), _jsx(ModalBody, { className: "space-y-4", children: _jsx("div", { className: "space-y-2", children: _jsx(Input, { id: emailInputId, label: "Email *", labelPlacement: "outside", type: "email", placeholder: "Enter email address", value: newEmail, onChange: (e) => setNewEmail(e.target.value), variant: "bordered" }) }) }), _jsxs(ModalFooter, { children: [_jsx(Button, { variant: "bordered", type: "button", onPress: onClose, children: "Cancel" }), _jsx(Button, { type: "submit", color: "primary", isDisabled: isAdding, isLoading: isAdding, children: isAdding ? "Adding..." : "Add to Waitlist" })] })] })) }) })] }));
6
+ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
7
+ //#region src/modules/auth/components/AdminWaitlist.tsx
8
+ function AdminWaitlist({ useTRPC }) {
9
+ const trpc = useTRPC();
10
+ const queryClient = useQueryClient();
11
+ const { data: waitlist = [], isLoading } = useQuery(trpc.auth.listAdminWaitlist.queryOptions());
12
+ const { mutate: invite, isPending: isInviting } = useMutation(trpc.auth.inviteFromWaitlist.mutationOptions({
13
+ onSuccess: () => {
14
+ queryClient.invalidateQueries({ queryKey: trpc.auth.listAdminWaitlist.queryKey() });
15
+ toast.success("Invitation sent successfully");
16
+ },
17
+ onError: (error) => {
18
+ toast.error(`Failed to send invitation: ${error instanceof Error ? error.message : String(error)}`);
19
+ }
20
+ }));
21
+ const { mutate: remove, isPending: isRemoving } = useMutation(trpc.auth.removeFromWaitlist.mutationOptions({
22
+ onSuccess: () => {
23
+ queryClient.invalidateQueries({ queryKey: trpc.auth.listAdminWaitlist.queryKey() });
24
+ toast.success("Removed from waitlist successfully");
25
+ },
26
+ onError: (error) => {
27
+ toast.error(`Failed to remove: ${error instanceof Error ? error.message : String(error)}`);
28
+ },
29
+ onSettled: () => {
30
+ setItemToDelete(null);
31
+ }
32
+ }));
33
+ const { mutate: add, isPending: isAdding } = useMutation(trpc.auth.addToWaitlist.mutationOptions({
34
+ onSuccess: () => {
35
+ queryClient.invalidateQueries({ queryKey: trpc.auth.listAdminWaitlist.queryKey() });
36
+ toast.success("Added to waitlist successfully");
37
+ },
38
+ onError: (error) => {
39
+ toast.error(`Failed to add to waitlist: ${error instanceof Error ? error.message : String(error)}`);
40
+ }
41
+ }));
42
+ const emailInputId = useId();
43
+ const [searchQuery, setSearchQuery] = useState("");
44
+ const [debouncedSearchQuery, setDebouncedSearchQuery] = useState("");
45
+ const [itemToDelete, setItemToDelete] = useState(null);
46
+ const [isAddModalOpen, setIsAddModalOpen] = useState(false);
47
+ const [newEmail, setNewEmail] = useState("");
48
+ useEffect(() => {
49
+ const timer = setTimeout(() => {
50
+ setDebouncedSearchQuery(searchQuery);
51
+ }, 300);
52
+ return () => clearTimeout(timer);
53
+ }, [searchQuery]);
54
+ const filteredWaitlist = waitlist.filter((item) => item.email?.toLowerCase().includes(debouncedSearchQuery?.toLowerCase() ?? ""));
55
+ const handleInvite = (id) => {
56
+ invite({ id });
57
+ };
58
+ const handleRemove = () => {
59
+ if (itemToDelete) remove({ id: itemToDelete });
60
+ };
61
+ const handleAdd = async () => {
62
+ if (!newEmail.trim()) {
63
+ toast.error("Please enter an email address");
64
+ return;
65
+ }
66
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(newEmail.trim())) {
67
+ toast.error("Please enter a valid email address");
68
+ return;
69
+ }
70
+ add({ email: newEmail.trim() });
71
+ setNewEmail("");
72
+ setIsAddModalOpen(false);
73
+ };
74
+ const formatDate = (date) => {
75
+ if (!date) return "N/A";
76
+ return (typeof date === "string" ? new Date(date) : date).toLocaleDateString(void 0, {
77
+ year: "numeric",
78
+ month: "short",
79
+ day: "numeric",
80
+ hour: "2-digit",
81
+ minute: "2-digit"
82
+ });
83
+ };
84
+ const getStatusBadge = (status) => {
85
+ const statusLower = status.toLowerCase();
86
+ if (statusLower === "invited" || statusLower === "active") return /* @__PURE__ */ jsx("span", {
87
+ className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800",
88
+ children: status
89
+ });
90
+ if (statusLower === "pending") return /* @__PURE__ */ jsx("span", {
91
+ className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800",
92
+ children: status
93
+ });
94
+ return /* @__PURE__ */ jsx("span", {
95
+ className: "inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-800",
96
+ children: status
97
+ });
98
+ };
99
+ if (isLoading) return /* @__PURE__ */ jsx("div", {
100
+ className: "flex justify-center p-8",
101
+ children: /* @__PURE__ */ jsx(Spinner, {})
102
+ });
103
+ return /* @__PURE__ */ jsxs("div", {
104
+ className: "space-y-4 p-4",
105
+ children: [
106
+ /* @__PURE__ */ jsxs("div", {
107
+ className: "flex justify-between items-center",
108
+ children: [/* @__PURE__ */ jsx("h2", {
109
+ className: "text-xl font-semibold",
110
+ children: "Waitlist Management"
111
+ }), /* @__PURE__ */ jsxs("div", {
112
+ className: "flex items-center gap-2",
113
+ children: [/* @__PURE__ */ jsxs(Button, {
114
+ onPress: () => setIsAddModalOpen(true),
115
+ size: "sm",
116
+ children: [/* @__PURE__ */ jsx(UserPlus, { className: "h-4 w-4 mr-2" }), "Add to Waitlist"]
117
+ }), /* @__PURE__ */ jsxs("div", {
118
+ className: "text-sm text-muted-foreground",
119
+ children: ["Total: ", waitlist.length]
120
+ })]
121
+ })]
122
+ }),
123
+ /* @__PURE__ */ jsx("div", {
124
+ className: "flex flex-col sm:flex-row gap-3 items-start sm:items-center",
125
+ children: /* @__PURE__ */ jsxs("form", {
126
+ className: "relative flex-1",
127
+ onSubmit: (e) => {
128
+ e.preventDefault();
129
+ setDebouncedSearchQuery(searchQuery);
130
+ },
131
+ children: [
132
+ /* @__PURE__ */ jsx(Search, { className: "absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" }),
133
+ /* @__PURE__ */ jsx(Input, {
134
+ "aria-label": "Search by email",
135
+ placeholder: "Search by email...",
136
+ className: "pl-8 w-full",
137
+ value: searchQuery,
138
+ onChange: (e) => setSearchQuery(e.target.value),
139
+ variant: "bordered"
140
+ }),
141
+ searchQuery && /* @__PURE__ */ jsx("button", {
142
+ type: "button",
143
+ onClick: () => setSearchQuery(""),
144
+ className: "absolute right-2.5 top-2.5 text-muted-foreground hover:text-foreground",
145
+ "aria-label": "Clear search",
146
+ children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
147
+ })
148
+ ]
149
+ })
150
+ }),
151
+ /* @__PURE__ */ jsx("div", {
152
+ className: "border rounded-lg overflow-hidden",
153
+ children: /* @__PURE__ */ jsxs(Table, {
154
+ "aria-label": "Waitlist table",
155
+ removeWrapper: true,
156
+ children: [/* @__PURE__ */ jsxs(TableHeader, { children: [
157
+ /* @__PURE__ */ jsx(TableColumn, { children: "Email" }),
158
+ /* @__PURE__ */ jsx(TableColumn, { children: "Status" }),
159
+ /* @__PURE__ */ jsx(TableColumn, { children: "Created At" }),
160
+ /* @__PURE__ */ jsx(TableColumn, { children: "Updated At" }),
161
+ /* @__PURE__ */ jsx(TableColumn, {
162
+ className: "text-right",
163
+ children: "Actions"
164
+ })
165
+ ] }), /* @__PURE__ */ jsx(TableBody, {
166
+ items: filteredWaitlist,
167
+ emptyContent: searchQuery ? "No waitlist entries found matching your search" : "No waitlist entries found",
168
+ children: (item) => /* @__PURE__ */ jsxs(TableRow, { children: [
169
+ /* @__PURE__ */ jsx(TableCell, {
170
+ className: "font-medium",
171
+ children: item.email
172
+ }),
173
+ /* @__PURE__ */ jsx(TableCell, { children: getStatusBadge(item.status) }),
174
+ /* @__PURE__ */ jsx(TableCell, { children: formatDate(item.createdAt) }),
175
+ /* @__PURE__ */ jsx(TableCell, { children: formatDate(item.updatedAt) }),
176
+ /* @__PURE__ */ jsx(TableCell, {
177
+ className: "text-right",
178
+ children: /* @__PURE__ */ jsxs(Dropdown, {
179
+ placement: "bottom-end",
180
+ children: [/* @__PURE__ */ jsx(DropdownTrigger, { children: /* @__PURE__ */ jsx(Button, {
181
+ variant: "light",
182
+ size: "sm",
183
+ isIconOnly: true,
184
+ children: /* @__PURE__ */ jsx(MoreHorizontal, { className: "h-4 w-4" })
185
+ }) }), /* @__PURE__ */ jsxs(DropdownMenu, {
186
+ "aria-label": "Waitlist actions",
187
+ children: [/* @__PURE__ */ jsx(DropdownItem, {
188
+ onPress: () => handleInvite(item.id),
189
+ isDisabled: isInviting,
190
+ children: isInviting ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Spinner, { className: "mr-2 h-3 w-3" }), "Inviting..."] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Mail, { className: "mr-2 h-4 w-4" }), "Send Invitation"] })
191
+ }, "invite"), /* @__PURE__ */ jsxs(DropdownItem, {
192
+ className: "text-danger",
193
+ onClick: () => setItemToDelete(item.id),
194
+ children: [/* @__PURE__ */ jsx(Trash2, { className: "mr-2 h-4 w-4" }), "Remove"]
195
+ }, "remove")]
196
+ })]
197
+ })
198
+ })
199
+ ] }, item.id)
200
+ })]
201
+ })
202
+ }),
203
+ /* @__PURE__ */ jsx(Modal, {
204
+ isOpen: !!itemToDelete,
205
+ onOpenChange: (open) => {
206
+ if (!open) setItemToDelete(null);
207
+ },
208
+ children: /* @__PURE__ */ jsx(ModalContent, { children: (onClose) => /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(ModalHeader, {
209
+ className: "flex flex-col gap-1",
210
+ children: [/* @__PURE__ */ jsx("p", {
211
+ className: "text-lg font-semibold",
212
+ children: "Are you sure?"
213
+ }), /* @__PURE__ */ jsx("p", {
214
+ className: "text-sm text-default-600",
215
+ children: "This action cannot be undone. This will permanently remove this entry from the waitlist."
216
+ })]
217
+ }), /* @__PURE__ */ jsxs(ModalFooter, { children: [/* @__PURE__ */ jsx(Button, {
218
+ variant: "bordered",
219
+ onPress: onClose,
220
+ children: "Cancel"
221
+ }), /* @__PURE__ */ jsx(Button, {
222
+ color: "danger",
223
+ onPress: handleRemove,
224
+ isLoading: isRemoving,
225
+ children: "Remove"
226
+ })] })] }) })
227
+ }),
228
+ /* @__PURE__ */ jsx(Modal, {
229
+ isOpen: isAddModalOpen,
230
+ onOpenChange: (open) => {
231
+ if (!open) setIsAddModalOpen(false);
232
+ },
233
+ children: /* @__PURE__ */ jsx(ModalContent, { children: (onClose) => /* @__PURE__ */ jsxs("form", {
234
+ onSubmit: (e) => {
235
+ e.preventDefault();
236
+ handleAdd();
237
+ },
238
+ className: "space-y-4",
239
+ children: [
240
+ /* @__PURE__ */ jsxs(ModalHeader, {
241
+ className: "flex flex-col gap-1",
242
+ children: [/* @__PURE__ */ jsx("p", {
243
+ className: "text-lg font-semibold",
244
+ children: "Add to Waitlist"
245
+ }), /* @__PURE__ */ jsx("p", {
246
+ className: "text-sm text-default-600",
247
+ children: "Enter an email address to add someone to the waitlist."
248
+ })]
249
+ }),
250
+ /* @__PURE__ */ jsx(ModalBody, {
251
+ className: "space-y-4",
252
+ children: /* @__PURE__ */ jsx("div", {
253
+ className: "space-y-2",
254
+ children: /* @__PURE__ */ jsx(Input, {
255
+ id: emailInputId,
256
+ label: "Email *",
257
+ labelPlacement: "outside",
258
+ type: "email",
259
+ placeholder: "Enter email address",
260
+ value: newEmail,
261
+ onChange: (e) => setNewEmail(e.target.value),
262
+ variant: "bordered"
263
+ })
264
+ })
265
+ }),
266
+ /* @__PURE__ */ jsxs(ModalFooter, { children: [/* @__PURE__ */ jsx(Button, {
267
+ variant: "bordered",
268
+ type: "button",
269
+ onPress: onClose,
270
+ children: "Cancel"
271
+ }), /* @__PURE__ */ jsx(Button, {
272
+ type: "submit",
273
+ color: "primary",
274
+ isDisabled: isAdding,
275
+ isLoading: isAdding,
276
+ children: isAdding ? "Adding..." : "Add to Waitlist"
277
+ })] })
278
+ ]
279
+ }) })
280
+ })
281
+ ]
282
+ });
118
283
  }
284
+ //#endregion
285
+ export { AdminWaitlist };
286
+
287
+ //# sourceMappingURL=AdminWaitlist.js.map