@m5kdev/web-ui 0.1.3 → 0.1.5

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