hazo_auth 1.4.2 → 1.6.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 (320) hide show
  1. package/SETUP_CHECKLIST.md +708 -0
  2. package/dist/app/api/hazo_auth/change_password/route.d.ts +8 -0
  3. package/dist/app/api/hazo_auth/change_password/route.d.ts.map +1 -0
  4. package/dist/app/api/hazo_auth/change_password/route.js +98 -0
  5. package/dist/app/api/hazo_auth/forgot_password/route.d.ts +8 -0
  6. package/dist/app/api/hazo_auth/forgot_password/route.d.ts.map +1 -0
  7. package/dist/app/api/hazo_auth/forgot_password/route.js +78 -0
  8. package/dist/app/api/hazo_auth/get_auth/route.d.ts +10 -0
  9. package/dist/app/api/hazo_auth/get_auth/route.d.ts.map +1 -0
  10. package/dist/app/api/hazo_auth/get_auth/route.js +63 -0
  11. package/dist/app/api/hazo_auth/invalidate_cache/route.d.ts +14 -0
  12. package/dist/app/api/hazo_auth/invalidate_cache/route.d.ts.map +1 -0
  13. package/dist/app/api/hazo_auth/invalidate_cache/route.js +96 -0
  14. package/dist/app/api/hazo_auth/library_photos/route.d.ts +13 -0
  15. package/dist/app/api/hazo_auth/library_photos/route.d.ts.map +1 -0
  16. package/dist/app/api/hazo_auth/library_photos/route.js +55 -0
  17. package/dist/app/api/hazo_auth/login/route.d.ts +12 -0
  18. package/dist/app/api/hazo_auth/login/route.d.ts.map +1 -0
  19. package/dist/app/api/hazo_auth/login/route.js +140 -0
  20. package/dist/app/api/hazo_auth/logout/route.d.ts +8 -0
  21. package/dist/app/api/hazo_auth/logout/route.d.ts.map +1 -0
  22. package/dist/app/api/hazo_auth/logout/route.js +71 -0
  23. package/dist/app/api/hazo_auth/me/route.d.ts +3 -0
  24. package/dist/app/api/hazo_auth/me/route.d.ts.map +1 -0
  25. package/dist/app/api/hazo_auth/me/route.js +34 -0
  26. package/dist/app/api/hazo_auth/profile_picture/[filename]/route.d.ts +7 -0
  27. package/dist/app/api/hazo_auth/profile_picture/[filename]/route.d.ts.map +1 -0
  28. package/dist/app/api/hazo_auth/profile_picture/[filename]/route.js +43 -0
  29. package/dist/app/api/hazo_auth/register/route.d.ts +9 -0
  30. package/dist/app/api/hazo_auth/register/route.d.ts.map +1 -0
  31. package/dist/app/api/hazo_auth/register/route.js +80 -0
  32. package/dist/app/api/hazo_auth/remove_profile_picture/route.d.ts +8 -0
  33. package/dist/app/api/hazo_auth/remove_profile_picture/route.d.ts.map +1 -0
  34. package/dist/app/api/hazo_auth/remove_profile_picture/route.js +64 -0
  35. package/dist/app/api/hazo_auth/resend_verification/route.d.ts +8 -0
  36. package/dist/app/api/hazo_auth/resend_verification/route.d.ts.map +1 -0
  37. package/dist/app/api/hazo_auth/resend_verification/route.js +79 -0
  38. package/dist/app/api/hazo_auth/reset_password/route.d.ts +8 -0
  39. package/dist/app/api/hazo_auth/reset_password/route.d.ts.map +1 -0
  40. package/dist/app/api/hazo_auth/reset_password/route.js +76 -0
  41. package/dist/app/api/hazo_auth/update_user/route.d.ts +9 -0
  42. package/dist/app/api/hazo_auth/update_user/route.d.ts.map +1 -0
  43. package/dist/app/api/hazo_auth/update_user/route.js +95 -0
  44. package/dist/app/api/hazo_auth/upload_profile_picture/route.d.ts +9 -0
  45. package/dist/app/api/hazo_auth/upload_profile_picture/route.d.ts.map +1 -0
  46. package/dist/app/api/hazo_auth/upload_profile_picture/route.js +204 -0
  47. package/dist/app/api/hazo_auth/validate_reset_token/route.d.ts +6 -0
  48. package/dist/app/api/hazo_auth/validate_reset_token/route.d.ts.map +1 -0
  49. package/dist/app/api/hazo_auth/validate_reset_token/route.js +58 -0
  50. package/dist/app/api/hazo_auth/verify_email/route.d.ts +11 -0
  51. package/dist/app/api/hazo_auth/verify_email/route.d.ts.map +1 -0
  52. package/dist/app/api/hazo_auth/verify_email/route.js +63 -0
  53. package/dist/cli/generate.d.ts +2 -0
  54. package/dist/cli/generate.d.ts.map +1 -0
  55. package/dist/cli/generate.js +117 -0
  56. package/dist/cli/index.d.ts +3 -0
  57. package/dist/cli/index.d.ts.map +1 -0
  58. package/dist/cli/index.js +120 -0
  59. package/dist/cli/validate.d.ts +15 -0
  60. package/dist/cli/validate.d.ts.map +1 -0
  61. package/dist/cli/validate.js +509 -0
  62. package/dist/components/ui/card.d.ts +9 -0
  63. package/dist/components/ui/card.d.ts.map +1 -0
  64. package/dist/components/ui/card.js +45 -0
  65. package/dist/hooks/use-mobile.d.ts.map +1 -1
  66. package/dist/hooks/use-mobile.js +17 -3
  67. package/dist/server/routes/change_password.d.ts +2 -0
  68. package/dist/server/routes/change_password.d.ts.map +1 -0
  69. package/dist/server/routes/change_password.js +2 -0
  70. package/dist/server/routes/forgot_password.d.ts +2 -0
  71. package/dist/server/routes/forgot_password.d.ts.map +1 -0
  72. package/dist/server/routes/forgot_password.js +2 -0
  73. package/dist/server/routes/get_auth.d.ts +2 -0
  74. package/dist/server/routes/get_auth.d.ts.map +1 -0
  75. package/dist/server/routes/get_auth.js +2 -0
  76. package/dist/server/routes/index.d.ts +18 -0
  77. package/dist/server/routes/index.d.ts.map +1 -0
  78. package/dist/server/routes/index.js +24 -0
  79. package/dist/server/routes/invalidate_cache.d.ts +2 -0
  80. package/dist/server/routes/invalidate_cache.d.ts.map +1 -0
  81. package/dist/server/routes/invalidate_cache.js +2 -0
  82. package/dist/server/routes/library_photos.d.ts +2 -0
  83. package/dist/server/routes/library_photos.d.ts.map +1 -0
  84. package/dist/server/routes/library_photos.js +2 -0
  85. package/dist/server/routes/login.d.ts +2 -0
  86. package/dist/server/routes/login.d.ts.map +1 -0
  87. package/dist/server/routes/login.js +2 -0
  88. package/dist/server/routes/logout.d.ts +2 -0
  89. package/dist/server/routes/logout.d.ts.map +1 -0
  90. package/dist/server/routes/logout.js +2 -0
  91. package/dist/server/routes/me.d.ts +2 -0
  92. package/dist/server/routes/me.d.ts.map +1 -0
  93. package/dist/server/routes/me.js +2 -0
  94. package/dist/server/routes/profile_picture_filename.d.ts +2 -0
  95. package/dist/server/routes/profile_picture_filename.d.ts.map +1 -0
  96. package/dist/server/routes/profile_picture_filename.js +3 -0
  97. package/dist/server/routes/register.d.ts +2 -0
  98. package/dist/server/routes/register.d.ts.map +1 -0
  99. package/dist/server/routes/register.js +2 -0
  100. package/dist/server/routes/remove_profile_picture.d.ts +2 -0
  101. package/dist/server/routes/remove_profile_picture.d.ts.map +1 -0
  102. package/dist/server/routes/remove_profile_picture.js +2 -0
  103. package/dist/server/routes/resend_verification.d.ts +2 -0
  104. package/dist/server/routes/resend_verification.d.ts.map +1 -0
  105. package/dist/server/routes/resend_verification.js +2 -0
  106. package/dist/server/routes/reset_password.d.ts +2 -0
  107. package/dist/server/routes/reset_password.d.ts.map +1 -0
  108. package/dist/server/routes/reset_password.js +2 -0
  109. package/dist/server/routes/update_user.d.ts +2 -0
  110. package/dist/server/routes/update_user.d.ts.map +1 -0
  111. package/dist/server/routes/update_user.js +2 -0
  112. package/dist/server/routes/upload_profile_picture.d.ts +2 -0
  113. package/dist/server/routes/upload_profile_picture.d.ts.map +1 -0
  114. package/dist/server/routes/upload_profile_picture.js +2 -0
  115. package/dist/server/routes/validate_reset_token.d.ts +2 -0
  116. package/dist/server/routes/validate_reset_token.d.ts.map +1 -0
  117. package/dist/server/routes/validate_reset_token.js +2 -0
  118. package/dist/server/routes/verify_email.d.ts +2 -0
  119. package/dist/server/routes/verify_email.d.ts.map +1 -0
  120. package/dist/server/routes/verify_email.js +2 -0
  121. package/package.json +12 -17
  122. package/components.json +0 -22
  123. package/instrumentation.ts +0 -32
  124. package/migrations/001_add_token_type_to_refresh_tokens.sql +0 -14
  125. package/migrations/002_add_name_to_hazo_users.sql +0 -7
  126. package/migrations/003_add_url_on_logon_to_hazo_users.sql +0 -8
  127. package/next.config.mjs +0 -67
  128. package/postcss.config.mjs +0 -8
  129. package/public/file.svg +0 -1
  130. package/public/globe.svg +0 -1
  131. package/public/next.svg +0 -1
  132. package/public/vercel.svg +0 -1
  133. package/public/window.svg +0 -1
  134. package/scripts/apply_migration.ts +0 -118
  135. package/scripts/init_users.ts +0 -378
  136. package/src/app/api/hazo_auth/auth/upload_profile_picture/route.ts +0 -268
  137. package/src/app/api/hazo_auth/change_password/route.ts +0 -132
  138. package/src/app/api/hazo_auth/forgot_password/route.ts +0 -107
  139. package/src/app/api/hazo_auth/get_auth/route.ts +0 -89
  140. package/src/app/api/hazo_auth/invalidate_cache/route.ts +0 -139
  141. package/src/app/api/hazo_auth/library_photos/route.ts +0 -73
  142. package/src/app/api/hazo_auth/login/route.ts +0 -181
  143. package/src/app/api/hazo_auth/logout/route.ts +0 -89
  144. package/src/app/api/hazo_auth/me/route.ts +0 -47
  145. package/src/app/api/hazo_auth/profile_picture/[filename]/route.ts +0 -67
  146. package/src/app/api/hazo_auth/register/route.ts +0 -109
  147. package/src/app/api/hazo_auth/remove_profile_picture/route.ts +0 -86
  148. package/src/app/api/hazo_auth/resend_verification/route.ts +0 -108
  149. package/src/app/api/hazo_auth/reset_password/route.ts +0 -107
  150. package/src/app/api/hazo_auth/update_user/route.ts +0 -126
  151. package/src/app/api/hazo_auth/upload_profile_picture/route.ts +0 -268
  152. package/src/app/api/hazo_auth/user_management/permissions/route.ts +0 -367
  153. package/src/app/api/hazo_auth/user_management/roles/route.ts +0 -442
  154. package/src/app/api/hazo_auth/user_management/users/roles/route.ts +0 -367
  155. package/src/app/api/hazo_auth/user_management/users/route.ts +0 -239
  156. package/src/app/api/hazo_auth/validate_reset_token/route.ts +0 -83
  157. package/src/app/api/hazo_auth/verify_email/route.ts +0 -88
  158. package/src/app/api/migrations/apply/route.ts +0 -91
  159. package/src/app/favicon.ico +0 -0
  160. package/src/app/fonts/GeistMonoVF.woff +0 -0
  161. package/src/app/fonts/GeistVF.woff +0 -0
  162. package/src/app/globals.css +0 -89
  163. package/src/app/hazo_auth/forgot_password/forgot_password_page_client.tsx +0 -60
  164. package/src/app/hazo_auth/forgot_password/page.tsx +0 -24
  165. package/src/app/hazo_auth/login/login_page_client.tsx +0 -86
  166. package/src/app/hazo_auth/login/page.tsx +0 -38
  167. package/src/app/hazo_auth/my_settings/my_settings_page_client.tsx +0 -120
  168. package/src/app/hazo_auth/my_settings/page.tsx +0 -40
  169. package/src/app/hazo_auth/register/page.tsx +0 -36
  170. package/src/app/hazo_auth/register/register_page_client.tsx +0 -81
  171. package/src/app/hazo_auth/reset_password/page.tsx +0 -29
  172. package/src/app/hazo_auth/reset_password/reset_password_page_client.tsx +0 -81
  173. package/src/app/hazo_auth/user_management/page.tsx +0 -14
  174. package/src/app/hazo_auth/user_management/user_management_page_client.tsx +0 -16
  175. package/src/app/hazo_auth/verify_email/page.tsx +0 -24
  176. package/src/app/hazo_auth/verify_email/verify_email_page_client.tsx +0 -60
  177. package/src/app/hazo_connect/api/sqlite/data/route.ts +0 -203
  178. package/src/app/hazo_connect/api/sqlite/schema/route.ts +0 -45
  179. package/src/app/hazo_connect/api/sqlite/tables/route.ts +0 -36
  180. package/src/app/hazo_connect/sqlite_admin/page.tsx +0 -51
  181. package/src/app/hazo_connect/sqlite_admin/sqlite-admin-client.tsx +0 -984
  182. package/src/app/layout.tsx +0 -43
  183. package/src/app/page.tsx +0 -170
  184. package/src/components/index.ts +0 -7
  185. package/src/components/layouts/email_verification/config/email_verification_field_config.ts +0 -86
  186. package/src/components/layouts/email_verification/hooks/use_email_verification.ts +0 -297
  187. package/src/components/layouts/email_verification/index.tsx +0 -297
  188. package/src/components/layouts/forgot_password/config/forgot_password_field_config.ts +0 -58
  189. package/src/components/layouts/forgot_password/hooks/use_forgot_password_form.ts +0 -179
  190. package/src/components/layouts/forgot_password/index.tsx +0 -168
  191. package/src/components/layouts/index.ts +0 -26
  192. package/src/components/layouts/login/config/login_field_config.ts +0 -67
  193. package/src/components/layouts/login/hooks/use_login_form.ts +0 -286
  194. package/src/components/layouts/login/index.tsx +0 -252
  195. package/src/components/layouts/my_settings/components/editable_field.tsx +0 -177
  196. package/src/components/layouts/my_settings/components/password_change_dialog.tsx +0 -301
  197. package/src/components/layouts/my_settings/components/profile_picture_dialog.tsx +0 -385
  198. package/src/components/layouts/my_settings/components/profile_picture_display.tsx +0 -66
  199. package/src/components/layouts/my_settings/components/profile_picture_gravatar_tab.tsx +0 -143
  200. package/src/components/layouts/my_settings/components/profile_picture_library_tab.tsx +0 -311
  201. package/src/components/layouts/my_settings/components/profile_picture_upload_tab.tsx +0 -341
  202. package/src/components/layouts/my_settings/config/my_settings_field_config.ts +0 -61
  203. package/src/components/layouts/my_settings/hooks/use_my_settings.ts +0 -458
  204. package/src/components/layouts/my_settings/index.tsx +0 -351
  205. package/src/components/layouts/register/config/register_field_config.ts +0 -101
  206. package/src/components/layouts/register/hooks/use_register_form.ts +0 -275
  207. package/src/components/layouts/register/index.tsx +0 -226
  208. package/src/components/layouts/reset_password/config/reset_password_field_config.ts +0 -86
  209. package/src/components/layouts/reset_password/hooks/use_reset_password_form.ts +0 -276
  210. package/src/components/layouts/reset_password/index.tsx +0 -294
  211. package/src/components/layouts/shared/components/already_logged_in_guard.tsx +0 -95
  212. package/src/components/layouts/shared/components/auth_page_shell.tsx +0 -36
  213. package/src/components/layouts/shared/components/field_error_message.tsx +0 -29
  214. package/src/components/layouts/shared/components/form_action_buttons.tsx +0 -64
  215. package/src/components/layouts/shared/components/form_field_wrapper.tsx +0 -44
  216. package/src/components/layouts/shared/components/form_header.tsx +0 -36
  217. package/src/components/layouts/shared/components/logout_button.tsx +0 -76
  218. package/src/components/layouts/shared/components/password_field.tsx +0 -72
  219. package/src/components/layouts/shared/components/profile_pic_menu.tsx +0 -321
  220. package/src/components/layouts/shared/components/profile_pic_menu_wrapper.tsx +0 -40
  221. package/src/components/layouts/shared/components/sidebar_layout_wrapper.tsx +0 -214
  222. package/src/components/layouts/shared/components/standalone_layout_wrapper.tsx +0 -53
  223. package/src/components/layouts/shared/components/two_column_auth_layout.tsx +0 -44
  224. package/src/components/layouts/shared/components/unauthorized_guard.tsx +0 -78
  225. package/src/components/layouts/shared/components/visual_panel.tsx +0 -41
  226. package/src/components/layouts/shared/config/layout_customization.ts +0 -95
  227. package/src/components/layouts/shared/data/layout_data_client.ts +0 -19
  228. package/src/components/layouts/shared/hooks/use_auth_status.ts +0 -103
  229. package/src/components/layouts/shared/hooks/use_hazo_auth.ts +0 -158
  230. package/src/components/layouts/shared/index.ts +0 -34
  231. package/src/components/layouts/shared/utils/ip_address.ts +0 -37
  232. package/src/components/layouts/shared/utils/validation.ts +0 -66
  233. package/src/components/layouts/user_management/components/roles_matrix.tsx +0 -607
  234. package/src/components/layouts/user_management/index.tsx +0 -1295
  235. package/src/components/ui/alert-dialog.tsx +0 -141
  236. package/src/components/ui/avatar.tsx +0 -50
  237. package/src/components/ui/button.tsx +0 -57
  238. package/src/components/ui/checkbox.tsx +0 -30
  239. package/src/components/ui/dialog.tsx +0 -122
  240. package/src/components/ui/dropdown-menu.tsx +0 -201
  241. package/src/components/ui/hazo_ui_tooltip.tsx +0 -67
  242. package/src/components/ui/index.ts +0 -22
  243. package/src/components/ui/input.tsx +0 -22
  244. package/src/components/ui/label.tsx +0 -26
  245. package/src/components/ui/separator.tsx +0 -31
  246. package/src/components/ui/sheet.tsx +0 -139
  247. package/src/components/ui/sidebar.tsx +0 -773
  248. package/src/components/ui/skeleton.tsx +0 -15
  249. package/src/components/ui/sonner.tsx +0 -31
  250. package/src/components/ui/switch.tsx +0 -29
  251. package/src/components/ui/table.tsx +0 -120
  252. package/src/components/ui/tabs.tsx +0 -55
  253. package/src/components/ui/tooltip.tsx +0 -32
  254. package/src/components/ui/vertical-tabs.tsx +0 -59
  255. package/src/hooks/use-mobile.tsx +0 -19
  256. package/src/index.ts +0 -7
  257. package/src/lib/already_logged_in_config.server.ts +0 -46
  258. package/src/lib/app_logger.ts +0 -24
  259. package/src/lib/auth/auth_cache.ts +0 -220
  260. package/src/lib/auth/auth_rate_limiter.ts +0 -121
  261. package/src/lib/auth/auth_types.ts +0 -65
  262. package/src/lib/auth/auth_utils.server.ts +0 -196
  263. package/src/lib/auth/hazo_get_auth.server.ts +0 -333
  264. package/src/lib/auth/index.ts +0 -23
  265. package/src/lib/auth/server_auth.ts +0 -88
  266. package/src/lib/auth_utility_config.server.ts +0 -136
  267. package/src/lib/config/config_loader.server.ts +0 -164
  268. package/src/lib/email_verification_config.server.ts +0 -32
  269. package/src/lib/file_types_config.server.ts +0 -25
  270. package/src/lib/forgot_password_config.server.ts +0 -32
  271. package/src/lib/hazo_connect_instance.server.ts +0 -101
  272. package/src/lib/hazo_connect_setup.server.ts +0 -194
  273. package/src/lib/hazo_connect_setup.ts +0 -54
  274. package/src/lib/index.ts +0 -44
  275. package/src/lib/login_config.server.ts +0 -71
  276. package/src/lib/messages_config.server.ts +0 -45
  277. package/src/lib/migrations/apply_migration.ts +0 -105
  278. package/src/lib/my_settings_config.server.ts +0 -135
  279. package/src/lib/password_requirements_config.server.ts +0 -39
  280. package/src/lib/profile_pic_menu_config.server.ts +0 -138
  281. package/src/lib/profile_picture_config.server.ts +0 -56
  282. package/src/lib/register_config.server.ts +0 -73
  283. package/src/lib/reset_password_config.server.ts +0 -75
  284. package/src/lib/services/email_service.ts +0 -581
  285. package/src/lib/services/email_verification_service.ts +0 -270
  286. package/src/lib/services/index.ts +0 -15
  287. package/src/lib/services/login_service.ts +0 -134
  288. package/src/lib/services/password_change_service.ts +0 -154
  289. package/src/lib/services/password_reset_service.ts +0 -405
  290. package/src/lib/services/profile_picture_remove_service.ts +0 -120
  291. package/src/lib/services/profile_picture_service.ts +0 -215
  292. package/src/lib/services/profile_picture_source_mapper.ts +0 -62
  293. package/src/lib/services/registration_service.ts +0 -184
  294. package/src/lib/services/token_service.ts +0 -240
  295. package/src/lib/services/user_profiles_service.ts +0 -143
  296. package/src/lib/services/user_update_service.ts +0 -141
  297. package/src/lib/ui_shell_config.server.ts +0 -73
  298. package/src/lib/ui_sizes_config.server.ts +0 -37
  299. package/src/lib/user_fields_config.server.ts +0 -31
  300. package/src/lib/user_management_config.server.ts +0 -39
  301. package/src/lib/utils/api_route_helpers.ts +0 -60
  302. package/src/lib/utils/error_sanitizer.ts +0 -75
  303. package/src/lib/utils.ts +0 -11
  304. package/src/middleware.ts +0 -94
  305. package/src/routes/index.ts +0 -34
  306. package/src/server/config/config_loader.ts +0 -496
  307. package/src/server/index.ts +0 -38
  308. package/src/server/logging/logger_service.ts +0 -56
  309. package/src/server/routes/root_router.ts +0 -16
  310. package/src/server/server.ts +0 -28
  311. package/src/server/types/app_types.ts +0 -74
  312. package/src/server/types/express.d.ts +0 -16
  313. package/src/stories/email_verification_layout.stories.tsx +0 -137
  314. package/src/stories/forgot_password_layout.stories.tsx +0 -85
  315. package/src/stories/login_layout.stories.tsx +0 -85
  316. package/src/stories/project_overview.stories.tsx +0 -33
  317. package/src/stories/register_layout.stories.tsx +0 -107
  318. package/tailwind.config.ts +0 -77
  319. package/tsconfig.build.json +0 -36
  320. package/tsconfig.json +0 -28
@@ -1,177 +0,0 @@
1
- // file_description: reusable component for editable fields with pencil/edit/check/cancel icons
2
- // section: client_directive
3
- "use client";
4
-
5
- // section: imports
6
- import { useState } from "react";
7
- import { Input } from "../../../ui/input";
8
- import { Label } from "../../../ui/label";
9
- import { Button } from "../../../ui/button";
10
- import { Pencil, CheckCircle2, XCircle } from "lucide-react";
11
-
12
- // section: types
13
- export type EditableFieldProps = {
14
- label: string;
15
- value: string;
16
- type?: "text" | "email" | "tel" | "url";
17
- placeholder?: string;
18
- onSave: (value: string) => Promise<void>;
19
- onCancel?: () => void;
20
- validation?: (value: string) => string | null;
21
- disabled?: boolean;
22
- ariaLabel?: string;
23
- };
24
-
25
- // section: component
26
- /**
27
- * Editable field component with pencil icon for edit mode
28
- * Shows check (green) and cancel (red) icons when in edit mode
29
- * @param props - Component props including label, value, onSave callback, etc.
30
- * @returns Editable field component
31
- */
32
- export function EditableField({
33
- label,
34
- value,
35
- type = "text",
36
- placeholder,
37
- onSave,
38
- onCancel,
39
- validation,
40
- disabled = false,
41
- ariaLabel,
42
- }: EditableFieldProps) {
43
- const [isEditing, setIsEditing] = useState(false);
44
- const [editValue, setEditValue] = useState(value);
45
- const [error, setError] = useState<string | null>(null);
46
- const [isSaving, setIsSaving] = useState(false);
47
-
48
- const handleEdit = () => {
49
- if (disabled) return;
50
- setIsEditing(true);
51
- setEditValue(value);
52
- setError(null);
53
- };
54
-
55
- const handleCancel = () => {
56
- setIsEditing(false);
57
- setEditValue(value);
58
- setError(null);
59
- onCancel?.();
60
- };
61
-
62
- const handleSave = async () => {
63
- // Validate if validation function provided
64
- if (validation) {
65
- const validationError = validation(editValue);
66
- if (validationError) {
67
- setError(validationError);
68
- return;
69
- }
70
- }
71
-
72
- // Check if value changed
73
- if (editValue === value) {
74
- setIsEditing(false);
75
- return;
76
- }
77
-
78
- setIsSaving(true);
79
- setError(null);
80
-
81
- try {
82
- await onSave(editValue);
83
- setIsEditing(false);
84
- } catch (error) {
85
- const errorMessage = error instanceof Error ? error.message : "Failed to save";
86
- setError(errorMessage);
87
- } finally {
88
- setIsSaving(false);
89
- }
90
- };
91
-
92
- const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
93
- if (e.key === "Enter") {
94
- void handleSave();
95
- } else if (e.key === "Escape") {
96
- handleCancel();
97
- }
98
- };
99
-
100
- return (
101
- <div className="cls_editable_field flex flex-col gap-2">
102
- <Label htmlFor={`editable-field-${label}`} className="cls_editable_field_label text-sm font-medium text-slate-700">
103
- {label}
104
- </Label>
105
- <div className="cls_editable_field_input_container flex items-center gap-2">
106
- {isEditing ? (
107
- <>
108
- <Input
109
- id={`editable-field-${label}`}
110
- type={type}
111
- value={editValue}
112
- onChange={(e) => setEditValue(e.target.value)}
113
- onKeyDown={handleKeyDown}
114
- placeholder={placeholder}
115
- disabled={isSaving}
116
- aria-label={ariaLabel || label}
117
- className="cls_editable_field_input flex-1"
118
- />
119
- <Button
120
- type="button"
121
- onClick={handleSave}
122
- disabled={isSaving}
123
- variant="ghost"
124
- size="icon"
125
- className="cls_editable_field_save_button text-green-600 hover:text-green-700 hover:bg-green-50"
126
- aria-label="Save changes"
127
- >
128
- <CheckCircle2 className="h-5 w-5" aria-hidden="true" />
129
- </Button>
130
- <Button
131
- type="button"
132
- onClick={handleCancel}
133
- disabled={isSaving}
134
- variant="ghost"
135
- size="icon"
136
- className="cls_editable_field_cancel_button text-red-600 hover:text-red-700 hover:bg-red-50"
137
- aria-label="Cancel editing"
138
- >
139
- <XCircle className="h-5 w-5" aria-hidden="true" />
140
- </Button>
141
- </>
142
- ) : (
143
- <>
144
- <Input
145
- id={`editable-field-${label}`}
146
- type={type}
147
- value={value || ""}
148
- readOnly
149
- disabled
150
- placeholder={value ? undefined : placeholder || "Not set"}
151
- aria-label={ariaLabel || label}
152
- className="cls_editable_field_display flex-1 bg-slate-50 cursor-not-allowed"
153
- />
154
- {!disabled && (
155
- <Button
156
- type="button"
157
- onClick={handleEdit}
158
- variant="ghost"
159
- size="icon"
160
- className="cls_editable_field_edit_button text-slate-600 hover:text-slate-700 hover:bg-slate-50"
161
- aria-label={`Edit ${label}`}
162
- >
163
- <Pencil className="h-5 w-5" aria-hidden="true" />
164
- </Button>
165
- )}
166
- </>
167
- )}
168
- </div>
169
- {error && (
170
- <p className="cls_editable_field_error text-sm text-red-600" role="alert">
171
- {error}
172
- </p>
173
- )}
174
- </div>
175
- );
176
- }
177
-
@@ -1,301 +0,0 @@
1
- // file_description: dialog component for changing password with current/new/confirm password fields
2
- // section: client_directive
3
- "use client";
4
-
5
- // section: imports
6
- import { useState } from "react";
7
- import {
8
- Dialog,
9
- DialogContent,
10
- DialogHeader,
11
- DialogTitle,
12
- DialogDescription,
13
- } from "../../../ui/dialog";
14
- import { Button } from "../../../ui/button";
15
- import { PasswordField } from "../../shared/components/password_field";
16
- import { FormFieldWrapper } from "../../shared/components/form_field_wrapper";
17
- import type { PasswordRequirementOptions } from "../../shared/config/layout_customization";
18
-
19
- // section: types
20
- export type ButtonPalette = {
21
- submitBackground: string;
22
- submitText: string;
23
- cancelBorder: string;
24
- cancelText: string;
25
- };
26
-
27
- export type PasswordChangeDialogProps = {
28
- open: boolean;
29
- onOpenChange: (open: boolean) => void;
30
- onSave: (currentPassword: string, newPassword: string) => Promise<void>;
31
- passwordRequirements: PasswordRequirementOptions;
32
- buttonPalette?: ButtonPalette;
33
- currentPasswordLabel?: string;
34
- newPasswordLabel?: string;
35
- confirmPasswordLabel?: string;
36
- saveButtonLabel?: string;
37
- cancelButtonLabel?: string;
38
- };
39
-
40
- // section: component
41
- /**
42
- * Dialog component for changing password
43
- * Shows current password, new password, and confirm password fields
44
- * Validates password requirements and ensures passwords match
45
- * @param props - Component props including open state, onSave callback, password requirements
46
- * @returns Password change dialog component
47
- */
48
- export function PasswordChangeDialog({
49
- open,
50
- onOpenChange,
51
- onSave,
52
- passwordRequirements,
53
- buttonPalette,
54
- currentPasswordLabel = "Current password",
55
- newPasswordLabel = "New password",
56
- confirmPasswordLabel = "Confirm new password",
57
- saveButtonLabel = "Save",
58
- cancelButtonLabel = "Cancel",
59
- }: PasswordChangeDialogProps) {
60
- const [currentPassword, setCurrentPassword] = useState("");
61
- const [newPassword, setNewPassword] = useState("");
62
- const [confirmPassword, setConfirmPassword] = useState("");
63
- const [currentPasswordVisible, setCurrentPasswordVisible] = useState(false);
64
- const [newPasswordVisible, setNewPasswordVisible] = useState(false);
65
- const [confirmPasswordVisible, setConfirmPasswordVisible] = useState(false);
66
- const [errors, setErrors] = useState<{
67
- currentPassword?: string;
68
- newPassword?: string | string[];
69
- confirmPassword?: string;
70
- }>({});
71
- const [isSubmitting, setIsSubmitting] = useState(false);
72
-
73
- const validatePassword = (password: string): string | null => {
74
- if (!password || password.length < passwordRequirements.minimum_length) {
75
- return `Password must be at least ${passwordRequirements.minimum_length} characters long`;
76
- }
77
-
78
- const errors: string[] = [];
79
-
80
- if (passwordRequirements.require_uppercase && !/[A-Z]/.test(password)) {
81
- errors.push("uppercase letter");
82
- }
83
-
84
- if (passwordRequirements.require_lowercase && !/[a-z]/.test(password)) {
85
- errors.push("lowercase letter");
86
- }
87
-
88
- if (passwordRequirements.require_number && !/[0-9]/.test(password)) {
89
- errors.push("number");
90
- }
91
-
92
- if (passwordRequirements.require_special && !/[^A-Za-z0-9]/.test(password)) {
93
- errors.push("special character");
94
- }
95
-
96
- if (errors.length > 0) {
97
- return `Password must contain at least one: ${errors.join(", ")}`;
98
- }
99
-
100
- return null;
101
- };
102
-
103
- const validateForm = (): boolean => {
104
- const newErrors: typeof errors = {};
105
-
106
- if (!currentPassword) {
107
- newErrors.currentPassword = "Current password is required";
108
- }
109
-
110
- const newPasswordError = validatePassword(newPassword);
111
- if (newPasswordError) {
112
- newErrors.newPassword = newPasswordError;
113
- }
114
-
115
- if (!confirmPassword) {
116
- newErrors.confirmPassword = "Please confirm your new password";
117
- } else if (newPassword !== confirmPassword) {
118
- newErrors.confirmPassword = "Passwords do not match";
119
- }
120
-
121
- setErrors(newErrors);
122
- return Object.keys(newErrors).length === 0;
123
- };
124
-
125
- const handleSave = async () => {
126
- if (!validateForm()) {
127
- return;
128
- }
129
-
130
- setIsSubmitting(true);
131
- setErrors({});
132
-
133
- try {
134
- await onSave(currentPassword, newPassword);
135
- // Reset form on success
136
- setCurrentPassword("");
137
- setNewPassword("");
138
- setConfirmPassword("");
139
- onOpenChange(false);
140
- } catch (error) {
141
- const errorMessage = error instanceof Error ? error.message : "Failed to change password";
142
- setErrors({ currentPassword: errorMessage });
143
- } finally {
144
- setIsSubmitting(false);
145
- }
146
- };
147
-
148
- const handleCancel = () => {
149
- setCurrentPassword("");
150
- setNewPassword("");
151
- setConfirmPassword("");
152
- setErrors({});
153
- onOpenChange(false);
154
- };
155
-
156
- // Format password requirements for display
157
- const getPasswordRequirements = (): string[] => {
158
- const requirements: string[] = [];
159
- requirements.push(`At least ${passwordRequirements.minimum_length} characters`);
160
- if (passwordRequirements.require_uppercase) {
161
- requirements.push("One uppercase letter");
162
- }
163
- if (passwordRequirements.require_lowercase) {
164
- requirements.push("One lowercase letter");
165
- }
166
- if (passwordRequirements.require_number) {
167
- requirements.push("One number");
168
- }
169
- if (passwordRequirements.require_special) {
170
- requirements.push("One special character");
171
- }
172
- return requirements;
173
- };
174
-
175
- const passwordRequirementsList = getPasswordRequirements();
176
-
177
- return (
178
- <Dialog open={open} onOpenChange={onOpenChange}>
179
- <DialogContent className="cls_password_change_dialog max-w-md">
180
- <DialogHeader className="cls_password_change_dialog_header">
181
- <DialogTitle className="cls_password_change_dialog_title">
182
- Change Password
183
- </DialogTitle>
184
- <DialogDescription className="cls_password_change_dialog_description">
185
- Enter your current password and choose a new password.
186
- </DialogDescription>
187
- </DialogHeader>
188
- <div className="cls_password_change_dialog_content flex flex-col gap-4 py-4">
189
- <FormFieldWrapper
190
- fieldId="current-password"
191
- label={currentPasswordLabel}
192
- input={
193
- <PasswordField
194
- inputId="current-password"
195
- ariaLabel={currentPasswordLabel}
196
- value={currentPassword}
197
- placeholder="Enter your current password"
198
- autoComplete="current-password"
199
- isVisible={currentPasswordVisible}
200
- onChange={(value) => {
201
- setCurrentPassword(value);
202
- if (errors.currentPassword) {
203
- setErrors({ ...errors, currentPassword: undefined });
204
- }
205
- }}
206
- onToggleVisibility={() => setCurrentPasswordVisible(!currentPasswordVisible)}
207
- errorMessage={errors.currentPassword}
208
- />
209
- }
210
- />
211
- <FormFieldWrapper
212
- fieldId="new-password"
213
- label={newPasswordLabel}
214
- input={
215
- <PasswordField
216
- inputId="new-password"
217
- ariaLabel={newPasswordLabel}
218
- value={newPassword}
219
- placeholder="Enter your new password"
220
- autoComplete="new-password"
221
- isVisible={newPasswordVisible}
222
- onChange={(value) => {
223
- setNewPassword(value);
224
- if (errors.newPassword) {
225
- setErrors({ ...errors, newPassword: undefined });
226
- }
227
- }}
228
- onToggleVisibility={() => setNewPasswordVisible(!newPasswordVisible)}
229
- errorMessage={errors.newPassword}
230
- />
231
- }
232
- />
233
- {passwordRequirementsList.length > 0 && (
234
- <div className="cls_password_change_dialog_requirements text-xs text-slate-600">
235
- <p className="cls_password_change_dialog_requirements_label font-medium mb-1">
236
- Password requirements:
237
- </p>
238
- <ul className="cls_password_change_dialog_requirements_list list-disc list-inside space-y-0.5">
239
- {passwordRequirementsList.map((req, index) => (
240
- <li key={index}>{req}</li>
241
- ))}
242
- </ul>
243
- </div>
244
- )}
245
- <FormFieldWrapper
246
- fieldId="confirm-password"
247
- label={confirmPasswordLabel}
248
- input={
249
- <PasswordField
250
- inputId="confirm-password"
251
- ariaLabel={confirmPasswordLabel}
252
- value={confirmPassword}
253
- placeholder="Confirm your new password"
254
- autoComplete="new-password"
255
- isVisible={confirmPasswordVisible}
256
- onChange={(value) => {
257
- setConfirmPassword(value);
258
- if (errors.confirmPassword) {
259
- setErrors({ ...errors, confirmPassword: undefined });
260
- }
261
- }}
262
- onToggleVisibility={() => setConfirmPasswordVisible(!confirmPasswordVisible)}
263
- errorMessage={errors.confirmPassword}
264
- />
265
- }
266
- />
267
- </div>
268
- <div className="cls_password_change_dialog_actions flex justify-end gap-3 pt-4 border-t">
269
- <Button
270
- type="button"
271
- onClick={handleSave}
272
- disabled={isSubmitting}
273
- className="cls_password_change_dialog_save_button"
274
- style={buttonPalette ? {
275
- backgroundColor: buttonPalette.submitBackground,
276
- color: buttonPalette.submitText,
277
- } : undefined}
278
- aria-label={saveButtonLabel}
279
- >
280
- {saveButtonLabel}
281
- </Button>
282
- <Button
283
- type="button"
284
- onClick={handleCancel}
285
- disabled={isSubmitting}
286
- variant="outline"
287
- className="cls_password_change_dialog_cancel_button"
288
- style={buttonPalette ? {
289
- borderColor: buttonPalette.cancelBorder,
290
- color: buttonPalette.cancelText,
291
- } : undefined}
292
- aria-label={cancelButtonLabel}
293
- >
294
- {cancelButtonLabel}
295
- </Button>
296
- </div>
297
- </DialogContent>
298
- </Dialog>
299
- );
300
- }
301
-