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,385 +0,0 @@
1
- // file_description: profile picture dialog component with tabs for Upload, Library, and Gravatar
2
- // section: client_directive
3
- "use client";
4
-
5
- // section: imports
6
- import { useState, useEffect } 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 { Tabs, TabsContent, TabsList, TabsTrigger } from "../../../ui/tabs";
16
- import { ProfilePictureUploadTab } from "./profile_picture_upload_tab";
17
- import { ProfilePictureLibraryTab } from "./profile_picture_library_tab";
18
- import { ProfilePictureGravatarTab } from "./profile_picture_gravatar_tab";
19
- import { toast } from "sonner";
20
- import { cn } from "../../../../lib/utils";
21
-
22
- // section: types
23
- export type ProfilePictureDialogProps = {
24
- open: boolean;
25
- onOpenChange: (open: boolean) => void;
26
- onSave: (profilePictureUrl: string, profileSource: "upload" | "library" | "gravatar") => Promise<void>;
27
- email: string;
28
- allowPhotoUpload: boolean;
29
- maxPhotoSize: number; // in bytes
30
- libraryPhotoPath: string;
31
- currentProfilePictureUrl?: string;
32
- currentProfileSource?: "upload" | "library" | "gravatar" | "custom";
33
- saveButtonLabel?: string;
34
- cancelButtonLabel?: string;
35
- disabled?: boolean;
36
- messages: {
37
- photo_upload_disabled_message: string;
38
- gravatar_setup_message: string;
39
- gravatar_no_account_message: string;
40
- library_tooltip_message: string;
41
- };
42
- uiSizes: {
43
- gravatar_size: number;
44
- profile_picture_size: number;
45
- tooltip_icon_size_default: number;
46
- tooltip_icon_size_small: number;
47
- library_photo_grid_columns: number;
48
- library_photo_preview_size: number;
49
- image_compression_max_dimension: number;
50
- upload_file_hard_limit_bytes: number;
51
- };
52
- fileTypes: {
53
- allowed_image_extensions: string[];
54
- allowed_image_mime_types: string[];
55
- };
56
- };
57
-
58
- // section: component
59
- /**
60
- * Profile picture dialog component with tabs for Upload, Library, and Gravatar
61
- * Only one switch can be active at a time
62
- * @param props - Component props including open state, save handler, and configuration
63
- * @returns Profile picture dialog component
64
- */
65
- export function ProfilePictureDialog({
66
- open,
67
- onOpenChange,
68
- onSave,
69
- email,
70
- allowPhotoUpload,
71
- maxPhotoSize,
72
- libraryPhotoPath,
73
- currentProfilePictureUrl,
74
- currentProfileSource,
75
- saveButtonLabel = "Save",
76
- cancelButtonLabel = "Cancel",
77
- disabled = false,
78
- messages,
79
- uiSizes,
80
- fileTypes,
81
- }: ProfilePictureDialogProps) {
82
- const [useUpload, setUseUpload] = useState(false);
83
- const [useLibrary, setUseLibrary] = useState(false);
84
- const [useGravatar, setUseGravatar] = useState(false);
85
- const [selectedPhotoUrl, setSelectedPhotoUrl] = useState<string | null>(null);
86
- const [selectedSource, setSelectedSource] = useState<"upload" | "library" | "gravatar" | null>(null);
87
- const [uploadedFile, setUploadedFile] = useState<File | null>(null);
88
- const [uploading, setUploading] = useState(false);
89
- const [activeTab, setActiveTab] = useState(allowPhotoUpload ? "upload" : "library");
90
-
91
- // Initialize state based on current profile picture
92
- useEffect(() => {
93
- if (open) {
94
- // Determine default active tab (skip upload if not enabled)
95
- const defaultTab = allowPhotoUpload ? "upload" : "library";
96
-
97
- // Handle current profile source (may be "upload", "library", "gravatar", or "custom")
98
- // "custom" should be treated as "upload" for backwards compatibility
99
- const normalizedSource = currentProfileSource === "custom" ? "upload" : currentProfileSource;
100
-
101
- if (normalizedSource === "upload" && allowPhotoUpload) {
102
- setUseUpload(true);
103
- setUseLibrary(false);
104
- setUseGravatar(false);
105
- setSelectedSource("upload");
106
- setSelectedPhotoUrl(currentProfilePictureUrl || null); // Set current image for upload tab
107
- setActiveTab("upload");
108
- } else if (normalizedSource === "library") {
109
- setUseUpload(false);
110
- setUseLibrary(true);
111
- setUseGravatar(false);
112
- setSelectedSource("library");
113
- setSelectedPhotoUrl(currentProfilePictureUrl || null);
114
- setActiveTab("library");
115
- } else if (normalizedSource === "gravatar") {
116
- setUseUpload(false);
117
- setUseLibrary(false);
118
- setUseGravatar(true);
119
- setSelectedSource("gravatar");
120
- setActiveTab("gravatar");
121
- } else {
122
- // Reset to defaults
123
- setUseUpload(false);
124
- setUseLibrary(false);
125
- setUseGravatar(false);
126
- setSelectedSource(null);
127
- setSelectedPhotoUrl(null);
128
- setUploadedFile(null);
129
- setActiveTab(defaultTab);
130
- }
131
- }
132
- }, [open, currentProfileSource, currentProfilePictureUrl, allowPhotoUpload]);
133
-
134
- const handleUseUploadChange = (use: boolean) => {
135
- if (!allowPhotoUpload) {
136
- return; // Prevent changes if upload is not enabled
137
- }
138
- setUseUpload(use);
139
- if (use) {
140
- setUseLibrary(false);
141
- setUseGravatar(false);
142
- setSelectedPhotoUrl(null); // Clear library photo URL when upload is selected
143
- setSelectedSource("upload");
144
- } else {
145
- setSelectedSource(null);
146
- setUploadedFile(null);
147
- setSelectedPhotoUrl(null);
148
- }
149
- };
150
-
151
- const handleUseLibraryChange = (use: boolean) => {
152
- setUseLibrary(use);
153
- if (use) {
154
- if (allowPhotoUpload) {
155
- setUseUpload(false);
156
- setUploadedFile(null);
157
- }
158
- setUseGravatar(false);
159
- setSelectedSource("library");
160
- // Note: selectedPhotoUrl should already be set when a photo is selected
161
- // If no photo is selected yet, the first photo in the category will be auto-selected
162
- } else {
163
- setSelectedSource(null);
164
- setSelectedPhotoUrl(null);
165
- }
166
- };
167
-
168
- const handleUseGravatarChange = (use: boolean) => {
169
- setUseGravatar(use);
170
- if (use) {
171
- if (allowPhotoUpload) {
172
- setUseUpload(false);
173
- setUploadedFile(null);
174
- }
175
- setUseLibrary(false);
176
- setSelectedPhotoUrl(null); // Clear library photo URL when Gravatar is selected
177
- setSelectedSource("gravatar");
178
- } else {
179
- setSelectedSource(null);
180
- }
181
- };
182
-
183
- const handleFileSelect = async (file: File) => {
184
- setUploadedFile(file);
185
- setUploading(true);
186
-
187
- try {
188
- const formData = new FormData();
189
- formData.append("file", file);
190
-
191
- const response = await fetch("/api/hazo_auth/upload_profile_picture", {
192
- method: "POST",
193
- credentials: "include",
194
- body: formData,
195
- });
196
-
197
- const data = await response.json();
198
-
199
- if (!response.ok || !data.success) {
200
- const errorMessage = data.error || "Failed to upload photo";
201
- toast.error(errorMessage);
202
- setUploadedFile(null);
203
- return;
204
- }
205
-
206
- setSelectedPhotoUrl(data.profile_picture_url);
207
- toast.success("Photo uploaded successfully");
208
- } catch (error) {
209
- const errorMessage = error instanceof Error ? error.message : "Failed to upload photo";
210
- toast.error(errorMessage);
211
- setUploadedFile(null);
212
- } finally {
213
- setUploading(false);
214
- }
215
- };
216
-
217
- const handlePhotoSelect = (photoUrl: string) => {
218
- setSelectedPhotoUrl(photoUrl);
219
- // Automatically enable library photo when a photo is selected
220
- if (!useLibrary) {
221
- handleUseLibraryChange(true);
222
- }
223
- };
224
-
225
- const handleSave = async () => {
226
- if (!selectedSource) {
227
- toast.error("Please select a profile picture source");
228
- return;
229
- }
230
-
231
- if (selectedSource === "upload" && !selectedPhotoUrl) {
232
- toast.error("Please upload a photo first");
233
- return;
234
- }
235
-
236
- if (selectedSource === "library" && !selectedPhotoUrl) {
237
- toast.error("Please select a photo from the library");
238
- return;
239
- }
240
-
241
- if (selectedSource === "gravatar") {
242
- // For Gravatar, generate the URL client-side using gravatar-url
243
- // The onSave handler will use this URL directly
244
- const gravatarUrlModule = await import("gravatar-url");
245
- const gravatarUrl = gravatarUrlModule.default(email, {
246
- size: 200,
247
- default: "identicon",
248
- });
249
- await onSave(gravatarUrl, "gravatar");
250
- return;
251
- }
252
-
253
- if (selectedPhotoUrl) {
254
- await onSave(selectedPhotoUrl, selectedSource);
255
- }
256
- };
257
-
258
- const handleCancel = () => {
259
- setUseUpload(false);
260
- setUseLibrary(false);
261
- setUseGravatar(false);
262
- setSelectedPhotoUrl(null);
263
- setSelectedSource(null);
264
- setUploadedFile(null);
265
- onOpenChange(false);
266
- };
267
-
268
- return (
269
- <Dialog open={open} onOpenChange={onOpenChange}>
270
- <DialogContent className="cls_profile_picture_dialog max-w-4xl max-h-[90vh] overflow-y-auto">
271
- <DialogHeader className="cls_profile_picture_dialog_header">
272
- <DialogTitle className="cls_profile_picture_dialog_title">
273
- Change Profile Picture
274
- </DialogTitle>
275
- <DialogDescription className="cls_profile_picture_dialog_description">
276
- Choose how you want to set your profile picture
277
- </DialogDescription>
278
- </DialogHeader>
279
-
280
- <Tabs value={activeTab} onValueChange={setActiveTab} className="cls_profile_picture_dialog_tabs">
281
- <TabsList className="cls_profile_picture_dialog_tabs_list">
282
- {allowPhotoUpload && (
283
- <TabsTrigger
284
- value="upload"
285
- className={cn(
286
- "cls_profile_picture_dialog_tabs_trigger",
287
- useUpload && "!text-blue-600 font-semibold data-[state=active]:!text-blue-600"
288
- )}
289
- >
290
- Upload
291
- </TabsTrigger>
292
- )}
293
- <TabsTrigger
294
- value="library"
295
- className={cn(
296
- "cls_profile_picture_dialog_tabs_trigger",
297
- useLibrary && "!text-blue-600 font-semibold data-[state=active]:!text-blue-600"
298
- )}
299
- >
300
- Library
301
- </TabsTrigger>
302
- <TabsTrigger
303
- value="gravatar"
304
- className={cn(
305
- "cls_profile_picture_dialog_tabs_trigger",
306
- useGravatar && "!text-blue-600 font-semibold data-[state=active]:!text-blue-600"
307
- )}
308
- >
309
- Gravatar
310
- </TabsTrigger>
311
- </TabsList>
312
-
313
- {allowPhotoUpload && (
314
- <TabsContent value="upload" className="cls_profile_picture_dialog_tabs_content">
315
- <ProfilePictureUploadTab
316
- useUpload={useUpload}
317
- onUseUploadChange={handleUseUploadChange}
318
- onFileSelect={handleFileSelect}
319
- maxSize={maxPhotoSize}
320
- uploadEnabled={allowPhotoUpload}
321
- disabled={disabled || uploading}
322
- currentPreview={currentProfilePictureUrl || selectedPhotoUrl || undefined}
323
- photoUploadDisabledMessage={messages.photo_upload_disabled_message}
324
- imageCompressionMaxDimension={uiSizes.image_compression_max_dimension}
325
- uploadFileHardLimitBytes={uiSizes.upload_file_hard_limit_bytes}
326
- allowedImageMimeTypes={fileTypes.allowed_image_mime_types}
327
- />
328
- </TabsContent>
329
- )}
330
-
331
- <TabsContent value="library" className="cls_profile_picture_dialog_tabs_content">
332
- <ProfilePictureLibraryTab
333
- useLibrary={useLibrary}
334
- onUseLibraryChange={handleUseLibraryChange}
335
- onPhotoSelect={handlePhotoSelect}
336
- disabled={disabled}
337
- libraryPhotoPath={libraryPhotoPath}
338
- currentPhotoUrl={selectedPhotoUrl || undefined}
339
- libraryTooltipMessage={messages.library_tooltip_message}
340
- tooltipIconSizeSmall={uiSizes.tooltip_icon_size_small}
341
- libraryPhotoGridColumns={uiSizes.library_photo_grid_columns}
342
- libraryPhotoPreviewSize={uiSizes.library_photo_preview_size}
343
- />
344
- </TabsContent>
345
-
346
- <TabsContent value="gravatar" className="cls_profile_picture_dialog_tabs_content">
347
- <ProfilePictureGravatarTab
348
- email={email}
349
- useGravatar={useGravatar}
350
- onUseGravatarChange={handleUseGravatarChange}
351
- disabled={disabled}
352
- gravatarSetupMessage={messages.gravatar_setup_message}
353
- gravatarNoAccountMessage={messages.gravatar_no_account_message}
354
- gravatarSize={uiSizes.gravatar_size}
355
- />
356
- </TabsContent>
357
- </Tabs>
358
-
359
- {/* Actions */}
360
- <div className="cls_profile_picture_dialog_actions flex justify-end gap-3 pt-4 border-t">
361
- <Button
362
- type="button"
363
- onClick={handleSave}
364
- disabled={disabled || uploading || !selectedSource}
365
- className="cls_profile_picture_dialog_save_button"
366
- aria-label={saveButtonLabel}
367
- >
368
- {saveButtonLabel}
369
- </Button>
370
- <Button
371
- type="button"
372
- onClick={handleCancel}
373
- disabled={disabled || uploading}
374
- variant="outline"
375
- className="cls_profile_picture_dialog_cancel_button"
376
- aria-label={cancelButtonLabel}
377
- >
378
- {cancelButtonLabel}
379
- </Button>
380
- </div>
381
- </DialogContent>
382
- </Dialog>
383
- );
384
- }
385
-
@@ -1,66 +0,0 @@
1
- // file_description: component for displaying and editing profile picture (edit functionality to be implemented later)
2
- // section: client_directive
3
- "use client";
4
-
5
- // section: imports
6
- import { Avatar, AvatarImage, AvatarFallback } from "../../../ui/avatar";
7
- import { Button } from "../../../ui/button";
8
- import { Pencil } from "lucide-react";
9
-
10
- // section: types
11
- export type ProfilePictureDisplayProps = {
12
- profilePictureUrl?: string;
13
- name?: string;
14
- email?: string;
15
- onEdit?: () => void;
16
- disabled?: boolean;
17
- };
18
-
19
- // section: component
20
- /**
21
- * Profile picture display component
22
- * Shows profile picture with fallback to initials or default icon
23
- * Displays pencil icon for editing (functionality to be implemented later)
24
- * @param props - Component props including profile picture URL, name, email, onEdit callback
25
- * @returns Profile picture display component
26
- */
27
- export function ProfilePictureDisplay({
28
- profilePictureUrl,
29
- name,
30
- email,
31
- onEdit,
32
- disabled = false,
33
- }: ProfilePictureDisplayProps) {
34
- // Get initials from name or email
35
- const getInitials = (): string => {
36
- if (name) {
37
- const parts = name.trim().split(" ");
38
- if (parts.length >= 2) {
39
- return `${parts[0][0]}${parts[parts.length - 1][0]}`.toUpperCase();
40
- }
41
- return name[0]?.toUpperCase() || "";
42
- }
43
- if (email) {
44
- return email[0]?.toUpperCase() || "";
45
- }
46
- return "?";
47
- };
48
-
49
- const initials = getInitials();
50
-
51
- return (
52
- <div className="cls_profile_picture_display">
53
- <Avatar className="cls_profile_picture_display_avatar h-32 w-32">
54
- <AvatarImage
55
- src={profilePictureUrl}
56
- alt={name ? `Profile picture of ${name}` : "Profile picture"}
57
- className="cls_profile_picture_display_image"
58
- />
59
- <AvatarFallback className="cls_profile_picture_display_fallback bg-slate-200 text-slate-600 text-3xl">
60
- {initials}
61
- </AvatarFallback>
62
- </Avatar>
63
- </div>
64
- );
65
- }
66
-
@@ -1,143 +0,0 @@
1
- // file_description: Gravatar tab component for profile picture dialog
2
- // section: client_directive
3
- "use client";
4
-
5
- // section: imports
6
- import { useState, useEffect } from "react";
7
- import { Switch } from "../../../ui/switch";
8
- import { Label } from "../../../ui/label";
9
- import { Avatar, AvatarImage, AvatarFallback } from "../../../ui/avatar";
10
- import { Info } from "lucide-react";
11
- import gravatarUrl from "gravatar-url";
12
-
13
- // section: types
14
- export type ProfilePictureGravatarTabProps = {
15
- email: string;
16
- useGravatar: boolean;
17
- onUseGravatarChange: (use: boolean) => void;
18
- disabled?: boolean;
19
- gravatarSetupMessage: string;
20
- gravatarNoAccountMessage: string;
21
- gravatarSize: number;
22
- };
23
-
24
- // section: component
25
- /**
26
- * Gravatar tab component for profile picture dialog
27
- * Shows Gravatar preview and setup instructions
28
- * @param props - Component props including email, useGravatar state, and change handler
29
- * @returns Gravatar tab component
30
- */
31
- export function ProfilePictureGravatarTab({
32
- email,
33
- useGravatar,
34
- onUseGravatarChange,
35
- disabled = false,
36
- gravatarSetupMessage,
37
- gravatarNoAccountMessage,
38
- gravatarSize,
39
- }: ProfilePictureGravatarTabProps) {
40
- const [gravatarUrlState, setGravatarUrlState] = useState<string>("");
41
- const [gravatarExists, setGravatarExists] = useState<boolean | null>(null);
42
-
43
- useEffect(() => {
44
- if (email) {
45
- const url = gravatarUrl(email, {
46
- size: gravatarSize,
47
- default: "404", // Return 404 if Gravatar doesn't exist
48
- });
49
- setGravatarUrlState(url);
50
-
51
- // Check if Gravatar exists by trying to load the image
52
- const img = new Image();
53
- img.onload = () => {
54
- setGravatarExists(true);
55
- };
56
- img.onerror = () => {
57
- setGravatarExists(false);
58
- };
59
- img.src = url;
60
- }
61
- }, [email]);
62
-
63
- const getInitials = (): string => {
64
- if (email) {
65
- return email[0]?.toUpperCase() || "?";
66
- }
67
- return "?";
68
- };
69
-
70
- return (
71
- <div className="cls_profile_picture_gravatar_tab flex flex-col gap-4">
72
- {/* Switch */}
73
- <div className="cls_profile_picture_gravatar_tab_switch flex items-center gap-3">
74
- <Switch
75
- id="use-gravatar"
76
- checked={useGravatar}
77
- onCheckedChange={onUseGravatarChange}
78
- disabled={disabled}
79
- className="cls_profile_picture_gravatar_tab_switch_input"
80
- aria-label="Use Gravatar photo"
81
- />
82
- <Label
83
- htmlFor="use-gravatar"
84
- className="cls_profile_picture_gravatar_tab_switch_label text-sm font-medium text-slate-700 cursor-pointer"
85
- >
86
- Use Gravatar photo
87
- </Label>
88
- </div>
89
-
90
- {/* Preview */}
91
- <div className="cls_profile_picture_gravatar_tab_preview flex flex-col items-center gap-4 p-6 border border-slate-200 rounded-lg bg-slate-50">
92
- {gravatarExists === true ? (
93
- <>
94
- <Avatar className="cls_profile_picture_gravatar_tab_avatar h-32 w-32">
95
- <AvatarImage
96
- src={gravatarUrlState}
97
- alt="Gravatar profile picture"
98
- className="cls_profile_picture_gravatar_tab_avatar_image"
99
- />
100
- <AvatarFallback className="cls_profile_picture_gravatar_tab_avatar_fallback bg-slate-200 text-slate-600 text-3xl">
101
- {getInitials()}
102
- </AvatarFallback>
103
- </Avatar>
104
- <p className="cls_profile_picture_gravatar_tab_success_text text-sm text-slate-600 text-center">
105
- Your Gravatar is available and will be used as your profile picture.
106
- </p>
107
- </>
108
- ) : gravatarExists === false ? (
109
- <>
110
- <div className="cls_profile_picture_gravatar_tab_no_gravatar flex flex-col items-center gap-4">
111
- <div className="cls_profile_picture_gravatar_tab_no_gravatar_icon flex items-center justify-center w-16 h-16 rounded-full bg-slate-100">
112
- <Info className="h-8 w-8 text-slate-400" aria-hidden="true" />
113
- </div>
114
- <div className="cls_profile_picture_gravatar_tab_no_gravatar_content flex flex-col gap-2 text-center">
115
- <p className="cls_profile_picture_gravatar_tab_no_gravatar_title text-sm font-medium text-slate-900">
116
- No Gravatar found
117
- </p>
118
- <p className="cls_profile_picture_gravatar_tab_no_gravatar_message text-sm text-slate-600">
119
- {gravatarSetupMessage} <span className="font-semibold">{email}</span>:
120
- </p>
121
- <ol className="cls_profile_picture_gravatar_tab_no_gravatar_steps text-sm text-slate-600 list-decimal list-inside space-y-1 mt-2">
122
- <li>Visit <a href="https://gravatar.com" target="_blank" rel="noopener noreferrer" className="text-blue-600 hover:text-blue-700 underline">gravatar.com</a></li>
123
- <li>Sign up or log in with your email: <span className="font-mono text-xs">{email}</span></li>
124
- <li>Upload a profile picture</li>
125
- <li>Return here and refresh to see your Gravatar</li>
126
- </ol>
127
- </div>
128
- </div>
129
- </>
130
- ) : (
131
- <>
132
- <div className="cls_profile_picture_gravatar_tab_loading flex items-center justify-center">
133
- <p className="cls_profile_picture_gravatar_tab_loading_text text-sm text-slate-600">
134
- Checking Gravatar...
135
- </p>
136
- </div>
137
- </>
138
- )}
139
- </div>
140
- </div>
141
- );
142
- }
143
-