hazo_auth 1.0.4 → 1.1.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 (108) hide show
  1. package/README.md +72 -1
  2. package/hazo_auth_config.example.ini +41 -0
  3. package/instrumentation.ts +2 -2
  4. package/package.json +4 -3
  5. package/scripts/init_users.ts +378 -0
  6. package/src/app/api/hazo_auth/auth/upload_profile_picture/route.ts +8 -8
  7. package/src/app/api/hazo_auth/change_password/route.ts +7 -7
  8. package/src/app/api/hazo_auth/forgot_password/route.ts +4 -4
  9. package/src/app/api/hazo_auth/get_auth/route.ts +4 -4
  10. package/src/app/api/hazo_auth/invalidate_cache/route.ts +5 -5
  11. package/src/app/api/hazo_auth/library_photos/route.ts +3 -3
  12. package/src/app/api/hazo_auth/login/route.ts +31 -5
  13. package/src/app/api/hazo_auth/logout/route.ts +4 -4
  14. package/src/app/api/hazo_auth/me/route.ts +1 -1
  15. package/src/app/api/hazo_auth/profile_picture/[filename]/route.ts +1 -1
  16. package/src/app/api/hazo_auth/register/route.ts +17 -14
  17. package/src/app/api/hazo_auth/remove_profile_picture/route.ts +5 -5
  18. package/src/app/api/hazo_auth/resend_verification/route.ts +4 -4
  19. package/src/app/api/hazo_auth/reset_password/route.ts +5 -5
  20. package/src/app/api/hazo_auth/update_user/route.ts +5 -5
  21. package/src/app/api/hazo_auth/upload_profile_picture/route.ts +8 -8
  22. package/src/app/api/hazo_auth/user_management/permissions/route.ts +4 -4
  23. package/src/app/api/hazo_auth/user_management/roles/route.ts +5 -5
  24. package/src/app/api/hazo_auth/user_management/users/roles/route.ts +5 -5
  25. package/src/app/api/hazo_auth/user_management/users/route.ts +6 -6
  26. package/src/app/api/hazo_auth/validate_reset_token/route.ts +4 -4
  27. package/src/app/api/hazo_auth/verify_email/route.ts +4 -4
  28. package/src/app/api/migrations/apply/route.ts +3 -3
  29. package/src/app/hazo_auth/forgot_password/forgot_password_page_client.tsx +4 -4
  30. package/src/app/hazo_auth/forgot_password/page.tsx +4 -4
  31. package/src/app/hazo_auth/login/login_page_client.tsx +20 -5
  32. package/src/app/hazo_auth/login/page.tsx +17 -5
  33. package/src/app/hazo_auth/my_settings/my_settings_page_client.tsx +3 -3
  34. package/src/app/hazo_auth/my_settings/page.tsx +4 -4
  35. package/src/app/hazo_auth/register/page.tsx +15 -5
  36. package/src/app/hazo_auth/register/register_page_client.tsx +13 -4
  37. package/src/app/hazo_auth/reset_password/page.tsx +4 -4
  38. package/src/app/hazo_auth/reset_password/reset_password_page_client.tsx +4 -4
  39. package/src/app/hazo_auth/user_management/page.tsx +3 -3
  40. package/src/app/hazo_auth/user_management/user_management_page_client.tsx +1 -1
  41. package/src/app/hazo_auth/verify_email/page.tsx +4 -4
  42. package/src/app/hazo_auth/verify_email/verify_email_page_client.tsx +4 -4
  43. package/src/app/hazo_connect/api/sqlite/data/route.ts +1 -1
  44. package/src/app/hazo_connect/api/sqlite/schema/route.ts +1 -1
  45. package/src/app/hazo_connect/api/sqlite/tables/route.ts +1 -1
  46. package/src/app/layout.tsx +1 -1
  47. package/src/app/page.tsx +1 -1
  48. package/src/components/layouts/email_verification/config/email_verification_field_config.ts +2 -2
  49. package/src/components/layouts/email_verification/hooks/use_email_verification.ts +3 -3
  50. package/src/components/layouts/email_verification/index.tsx +11 -11
  51. package/src/components/layouts/forgot_password/config/forgot_password_field_config.ts +2 -2
  52. package/src/components/layouts/forgot_password/hooks/use_forgot_password_form.ts +3 -3
  53. package/src/components/layouts/forgot_password/index.tsx +10 -10
  54. package/src/components/layouts/login/config/login_field_config.ts +2 -2
  55. package/src/components/layouts/login/hooks/use_login_form.ts +18 -13
  56. package/src/components/layouts/login/index.tsx +39 -11
  57. package/src/components/layouts/my_settings/components/editable_field.tsx +3 -3
  58. package/src/components/layouts/my_settings/components/password_change_dialog.tsx +5 -5
  59. package/src/components/layouts/my_settings/components/profile_picture_dialog.tsx +4 -4
  60. package/src/components/layouts/my_settings/components/profile_picture_display.tsx +2 -2
  61. package/src/components/layouts/my_settings/components/profile_picture_gravatar_tab.tsx +3 -3
  62. package/src/components/layouts/my_settings/components/profile_picture_library_tab.tsx +5 -5
  63. package/src/components/layouts/my_settings/components/profile_picture_upload_tab.tsx +4 -4
  64. package/src/components/layouts/my_settings/config/my_settings_field_config.ts +2 -2
  65. package/src/components/layouts/my_settings/hooks/use_my_settings.ts +2 -2
  66. package/src/components/layouts/my_settings/index.tsx +5 -5
  67. package/src/components/layouts/register/config/register_field_config.ts +2 -2
  68. package/src/components/layouts/register/hooks/use_register_form.ts +8 -5
  69. package/src/components/layouts/register/index.tsx +29 -11
  70. package/src/components/layouts/reset_password/config/reset_password_field_config.ts +2 -2
  71. package/src/components/layouts/reset_password/hooks/use_reset_password_form.ts +4 -4
  72. package/src/components/layouts/reset_password/index.tsx +10 -10
  73. package/src/components/layouts/shared/components/auth_page_shell.tsx +36 -0
  74. package/src/components/layouts/shared/components/standalone_layout_wrapper.tsx +53 -0
  75. package/src/components/layouts/user_management/components/roles_matrix.tsx +7 -7
  76. package/src/components/layouts/user_management/index.tsx +10 -10
  77. package/src/components/ui/alert-dialog.tsx +2 -2
  78. package/src/components/ui/avatar.tsx +1 -1
  79. package/src/components/ui/button.tsx +1 -1
  80. package/src/components/ui/checkbox.tsx +1 -1
  81. package/src/components/ui/dialog.tsx +1 -1
  82. package/src/components/ui/dropdown-menu.tsx +1 -1
  83. package/src/components/ui/hazo_ui_tooltip.tsx +1 -1
  84. package/src/components/ui/input.tsx +1 -1
  85. package/src/components/ui/label.tsx +1 -1
  86. package/src/components/ui/separator.tsx +1 -1
  87. package/src/components/ui/sheet.tsx +1 -1
  88. package/src/components/ui/sidebar.tsx +8 -8
  89. package/src/components/ui/skeleton.tsx +1 -1
  90. package/src/components/ui/switch.tsx +1 -1
  91. package/src/components/ui/table.tsx +1 -1
  92. package/src/components/ui/tabs.tsx +1 -1
  93. package/src/components/ui/tooltip.tsx +1 -1
  94. package/src/components/ui/vertical-tabs.tsx +1 -1
  95. package/src/lib/app_logger.ts +1 -1
  96. package/src/lib/config/config_loader.server.ts +20 -5
  97. package/src/lib/login_config.server.ts +25 -0
  98. package/src/lib/register_config.server.ts +17 -1
  99. package/src/lib/services/login_service.ts +19 -3
  100. package/src/lib/services/registration_service.ts +25 -4
  101. package/src/lib/services/user_update_service.ts +16 -3
  102. package/src/lib/ui_shell_config.server.ts +73 -0
  103. package/src/lib/utils/error_sanitizer.ts +75 -0
  104. package/src/stories/email_verification_layout.stories.tsx +2 -2
  105. package/src/stories/forgot_password_layout.stories.tsx +2 -2
  106. package/src/stories/login_layout.stories.tsx +2 -2
  107. package/src/stories/register_layout.stories.tsx +2 -2
  108. package/tsconfig.json +1 -4
@@ -10,14 +10,14 @@ import {
10
10
  DialogHeader,
11
11
  DialogTitle,
12
12
  DialogDescription,
13
- } from "@/components/ui/dialog";
14
- import { Button } from "@/components/ui/button";
15
- import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
13
+ } from "../../../ui/dialog";
14
+ import { Button } from "../../../ui/button";
15
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from "../../../ui/tabs";
16
16
  import { ProfilePictureUploadTab } from "./profile_picture_upload_tab";
17
17
  import { ProfilePictureLibraryTab } from "./profile_picture_library_tab";
18
18
  import { ProfilePictureGravatarTab } from "./profile_picture_gravatar_tab";
19
19
  import { toast } from "sonner";
20
- import { cn } from "@/lib/utils";
20
+ import { cn } from "../../../../lib/utils";
21
21
 
22
22
  // section: types
23
23
  export type ProfilePictureDialogProps = {
@@ -3,8 +3,8 @@
3
3
  "use client";
4
4
 
5
5
  // section: imports
6
- import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
7
- import { Button } from "@/components/ui/button";
6
+ import { Avatar, AvatarImage, AvatarFallback } from "../../../ui/avatar";
7
+ import { Button } from "../../../ui/button";
8
8
  import { Pencil } from "lucide-react";
9
9
 
10
10
  // section: types
@@ -4,9 +4,9 @@
4
4
 
5
5
  // section: imports
6
6
  import { useState, useEffect } from "react";
7
- import { Switch } from "@/components/ui/switch";
8
- import { Label } from "@/components/ui/label";
9
- import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
7
+ import { Switch } from "../../../ui/switch";
8
+ import { Label } from "../../../ui/label";
9
+ import { Avatar, AvatarImage, AvatarFallback } from "../../../ui/avatar";
10
10
  import { Info } from "lucide-react";
11
11
  import gravatarUrl from "gravatar-url";
12
12
 
@@ -4,12 +4,12 @@
4
4
 
5
5
  // section: imports
6
6
  import { useState, useEffect } from "react";
7
- import { Switch } from "@/components/ui/switch";
8
- import { Label } from "@/components/ui/label";
9
- import { Avatar, AvatarFallback } from "@/components/ui/avatar";
10
- import { VerticalTabs, VerticalTabsList, VerticalTabsTrigger, VerticalTabsContent } from "@/components/ui/vertical-tabs";
7
+ import { Switch } from "../../../ui/switch";
8
+ import { Label } from "../../../ui/label";
9
+ import { Avatar, AvatarFallback } from "../../../ui/avatar";
10
+ import { VerticalTabs, VerticalTabsList, VerticalTabsTrigger, VerticalTabsContent } from "../../../ui/vertical-tabs";
11
11
  import { Loader2 } from "lucide-react";
12
- import { HazoUITooltip } from "@/components/ui/hazo_ui_tooltip";
12
+ import { HazoUITooltip } from "../../../ui/hazo_ui_tooltip";
13
13
 
14
14
  // section: types
15
15
  export type ProfilePictureLibraryTabProps = {
@@ -4,11 +4,11 @@
4
4
 
5
5
  // section: imports
6
6
  import { useState, useCallback, useEffect } from "react";
7
- import { Switch } from "@/components/ui/switch";
8
- import { Label } from "@/components/ui/label";
9
- import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
7
+ import { Switch } from "../../../ui/switch";
8
+ import { Label } from "../../../ui/label";
9
+ import { Avatar, AvatarImage, AvatarFallback } from "../../../ui/avatar";
10
10
  import { Upload, X, Loader2, Info } from "lucide-react";
11
- import { Button } from "@/components/ui/button";
11
+ import { Button } from "../../../ui/button";
12
12
  import imageCompression from "browser-image-compression";
13
13
 
14
14
  // section: types
@@ -1,12 +1,12 @@
1
1
  // file_description: my settings layout specific configuration helpers
2
2
  // section: imports
3
- import type { LayoutFieldMap } from "@/components/layouts/shared/config/layout_customization";
3
+ import type { LayoutFieldMap } from "../../shared/config/layout_customization";
4
4
  import {
5
5
  resolveButtonPalette,
6
6
  type ButtonPaletteDefaults,
7
7
  type ButtonPaletteOverrides,
8
8
  type PasswordRequirementOptions,
9
- } from "@/components/layouts/shared/config/layout_customization";
9
+ } from "../../shared/config/layout_customization";
10
10
 
11
11
  // section: field_identifiers
12
12
  export const MY_SETTINGS_FIELD_IDS = {
@@ -4,9 +4,9 @@
4
4
 
5
5
  // section: imports
6
6
  import { useState, useEffect, useCallback } from "react";
7
- import { use_auth_status, trigger_auth_status_refresh } from "@/components/layouts/shared/hooks/use_auth_status";
7
+ import { use_auth_status, trigger_auth_status_refresh } from "../../shared/hooks/use_auth_status";
8
8
  import { toast } from "sonner";
9
- import type { PasswordRequirementOptions } from "@/components/layouts/shared/config/layout_customization";
9
+ import type { PasswordRequirementOptions } from "../../shared/config/layout_customization";
10
10
 
11
11
  // section: types
12
12
  export type PasswordFields = {
@@ -3,11 +3,11 @@
3
3
  "use client";
4
4
 
5
5
  // section: imports
6
- import { Button } from "@/components/ui/button";
6
+ import { Button } from "../../ui/button";
7
7
  import { EditableField } from "./components/editable_field";
8
8
  import { ProfilePictureDisplay } from "./components/profile_picture_display";
9
9
  import { ProfilePictureDialog } from "./components/profile_picture_dialog";
10
- import { UnauthorizedGuard } from "@/components/layouts/shared/components/unauthorized_guard";
10
+ import { UnauthorizedGuard } from "../shared/components/unauthorized_guard";
11
11
  import { use_my_settings } from "./hooks/use_my_settings";
12
12
  import {
13
13
  resolveMySettingsLabels,
@@ -17,10 +17,10 @@ import {
17
17
  import type {
18
18
  PasswordRequirementOptions,
19
19
  ButtonPaletteOverrides,
20
- } from "@/components/layouts/shared/config/layout_customization";
20
+ } from "../shared/config/layout_customization";
21
21
  import { formatDistanceToNow } from "date-fns";
22
- import { PasswordField } from "@/components/layouts/shared/components/password_field";
23
- import { FormFieldWrapper } from "@/components/layouts/shared/components/form_field_wrapper";
22
+ import { PasswordField } from "../shared/components/password_field";
23
+ import { FormFieldWrapper } from "../shared/components/form_field_wrapper";
24
24
  import { Pencil, Trash2 } from "lucide-react";
25
25
 
26
26
  // section: types
@@ -1,6 +1,6 @@
1
1
  // file_description: register layout specific configuration helpers
2
2
  // section: imports
3
- import type { LayoutFieldMap, LayoutFieldMapOverrides } from "@/components/layouts/shared/config/layout_customization";
3
+ import type { LayoutFieldMap, LayoutFieldMapOverrides } from "../../shared/config/layout_customization";
4
4
  import {
5
5
  resolveButtonPalette,
6
6
  resolveFieldDefinitions,
@@ -12,7 +12,7 @@ import {
12
12
  type LayoutLabelOverrides,
13
13
  type PasswordRequirementOptions,
14
14
  type PasswordRequirementOverrides,
15
- } from "@/components/layouts/shared/config/layout_customization";
15
+ } from "../../shared/config/layout_customization";
16
16
 
17
17
  // section: field_identifiers
18
18
  export const REGISTER_FIELD_IDS = {
@@ -2,10 +2,10 @@
2
2
  // section: imports
3
3
  import { useCallback, useMemo, useState } from "react";
4
4
  import { toast } from "sonner";
5
- import type { LayoutDataClient } from "@/components/layouts/shared/data/layout_data_client";
6
- import type { PasswordRequirementOptions, PasswordRequirementOverrides } from "@/components/layouts/shared/config/layout_customization";
7
- import { REGISTER_FIELD_IDS, type RegisterFieldId } from "@/components/layouts/register/config/register_field_config";
8
- import { validateEmail, validatePassword } from "@/components/layouts/shared/utils/validation";
5
+ import type { LayoutDataClient } from "../../shared/data/layout_data_client";
6
+ import type { PasswordRequirementOptions, PasswordRequirementOverrides } from "../../shared/config/layout_customization";
7
+ import { REGISTER_FIELD_IDS, type RegisterFieldId } from "../config/register_field_config";
8
+ import { validateEmail, validatePassword } from "../../shared/utils/validation";
9
9
 
10
10
  // section: constants
11
11
  const PASSWORD_FIELDS: Array<RegisterFieldId> = [
@@ -28,6 +28,7 @@ export type UseRegisterFormParams<TClient = unknown> = {
28
28
  passwordRequirements: PasswordRequirementOptions;
29
29
  passwordRequirementOverrides?: PasswordRequirementOverrides;
30
30
  dataClient: LayoutDataClient<TClient>;
31
+ urlOnLogon?: string;
31
32
  };
32
33
 
33
34
  export type UseRegisterFormResult = {
@@ -58,6 +59,7 @@ export const use_register_form = <TClient,>({
58
59
  showNameField,
59
60
  passwordRequirements,
60
61
  dataClient,
62
+ urlOnLogon,
61
63
  }: UseRegisterFormParams<TClient>): UseRegisterFormResult => {
62
64
  const [values, setValues] = useState<RegisterFormValues>(buildInitialValues);
63
65
  const [errors, setErrors] = useState<RegisterFormErrors>({});
@@ -203,6 +205,7 @@ export const use_register_form = <TClient,>({
203
205
  name: values[REGISTER_FIELD_IDS.NAME] || undefined,
204
206
  email: values[REGISTER_FIELD_IDS.EMAIL],
205
207
  password: values[REGISTER_FIELD_IDS.PASSWORD],
208
+ url_on_logon: urlOnLogon,
206
209
  }),
207
210
  });
208
211
 
@@ -242,7 +245,7 @@ export const use_register_form = <TClient,>({
242
245
  setIsSubmitting(false);
243
246
  }
244
247
  },
245
- [values, passwordRequirements, dataClient],
248
+ [values, passwordRequirements, dataClient, urlOnLogon],
246
249
  );
247
250
 
248
251
  const handleCancel = useCallback(() => {
@@ -3,31 +3,32 @@
3
3
  "use client";
4
4
 
5
5
  // section: imports
6
- import { Input } from "@/components/ui/input";
7
- import { PasswordField } from "@/components/layouts/shared/components/password_field";
8
- import { FormFieldWrapper } from "@/components/layouts/shared/components/form_field_wrapper";
9
- import { FormHeader } from "@/components/layouts/shared/components/form_header";
10
- import { FormActionButtons } from "@/components/layouts/shared/components/form_action_buttons";
11
- import { TwoColumnAuthLayout } from "@/components/layouts/shared/components/two_column_auth_layout";
12
- import { AlreadyLoggedInGuard } from "@/components/layouts/shared/components/already_logged_in_guard";
6
+ import Link from "next/link";
7
+ import { Input } from "../../ui/input";
8
+ import { PasswordField } from "../shared/components/password_field";
9
+ import { FormFieldWrapper } from "../shared/components/form_field_wrapper";
10
+ import { FormHeader } from "../shared/components/form_header";
11
+ import { FormActionButtons } from "../shared/components/form_action_buttons";
12
+ import { TwoColumnAuthLayout } from "../shared/components/two_column_auth_layout";
13
+ import { AlreadyLoggedInGuard } from "../shared/components/already_logged_in_guard";
13
14
  import {
14
15
  type ButtonPaletteOverrides,
15
16
  type LayoutFieldMapOverrides,
16
17
  type LayoutLabelOverrides,
17
18
  type PasswordRequirementOverrides,
18
- } from "@/components/layouts/shared/config/layout_customization";
19
+ } from "../shared/config/layout_customization";
19
20
  import {
20
21
  REGISTER_FIELD_IDS,
21
22
  createRegisterFieldDefinitions,
22
23
  resolveRegisterButtonPalette,
23
24
  resolveRegisterLabels,
24
25
  resolveRegisterPasswordRequirements,
25
- } from "@/components/layouts/register/config/register_field_config";
26
+ } from "./config/register_field_config";
26
27
  import {
27
28
  use_register_form,
28
29
  type UseRegisterFormResult,
29
- } from "@/components/layouts/register/hooks/use_register_form";
30
- import { type LayoutDataClient } from "@/components/layouts/shared/data/layout_data_client";
30
+ } from "./hooks/use_register_form";
31
+ import { type LayoutDataClient } from "../shared/data/layout_data_client";
31
32
 
32
33
  // section: types
33
34
  export type RegisterLayoutProps<TClient = unknown> = {
@@ -45,6 +46,9 @@ export type RegisterLayoutProps<TClient = unknown> = {
45
46
  showReturnHomeButton?: boolean;
46
47
  returnHomeButtonLabel?: string;
47
48
  returnHomePath?: string;
49
+ signInPath?: string;
50
+ signInLabel?: string;
51
+ urlOnLogon?: string;
48
52
  };
49
53
 
50
54
  const ORDERED_FIELDS: RegisterFieldId[] = [
@@ -72,6 +76,9 @@ export default function register_layout<TClient>({
72
76
  showReturnHomeButton = false,
73
77
  returnHomeButtonLabel = "Return home",
74
78
  returnHomePath = "/",
79
+ signInPath = "/hazo_auth/login",
80
+ signInLabel = "Sign in",
81
+ urlOnLogon,
75
82
  }: RegisterLayoutProps<TClient>) {
76
83
  const fieldDefinitions = createRegisterFieldDefinitions(field_overrides);
77
84
  const resolvedLabels = resolveRegisterLabels(labels);
@@ -84,6 +91,7 @@ export default function register_layout<TClient>({
84
91
  showNameField: show_name_field,
85
92
  passwordRequirements: resolvedPasswordRequirements,
86
93
  dataClient: data_client,
94
+ urlOnLogon: urlOnLogon,
87
95
  });
88
96
 
89
97
  const renderFields = (formState: UseRegisterFormResult) => {
@@ -193,6 +201,16 @@ export default function register_layout<TClient>({
193
201
  submitAriaLabel="Submit registration form"
194
202
  cancelAriaLabel="Cancel registration form"
195
203
  />
204
+ <div className="cls_register_layout_sign_in_link flex items-center justify-center gap-1 text-sm text-muted-foreground">
205
+ <span>Already have an account?</span>
206
+ <Link
207
+ href={signInPath}
208
+ className="cls_register_layout_sign_in_link_text text-primary underline-offset-4 hover:underline"
209
+ aria-label="Go to sign in page"
210
+ >
211
+ {signInLabel}
212
+ </Link>
213
+ </div>
196
214
  {form.isSubmitting && (
197
215
  <div className="cls_register_submitting_indicator text-sm text-slate-600 text-center">
198
216
  Registering...
@@ -1,6 +1,6 @@
1
1
  // file_description: reset password layout specific configuration helpers
2
2
  // section: imports
3
- import type { LayoutFieldMap, LayoutFieldMapOverrides } from "@/components/layouts/shared/config/layout_customization";
3
+ import type { LayoutFieldMap, LayoutFieldMapOverrides } from "../../shared/config/layout_customization";
4
4
  import {
5
5
  resolveButtonPalette,
6
6
  resolveFieldDefinitions,
@@ -12,7 +12,7 @@ import {
12
12
  type PasswordRequirementOptions,
13
13
  type PasswordRequirementOverrides,
14
14
  resolvePasswordRequirements,
15
- } from "@/components/layouts/shared/config/layout_customization";
15
+ } from "../../shared/config/layout_customization";
16
16
 
17
17
  // section: field_identifiers
18
18
  export const RESET_PASSWORD_FIELD_IDS = {
@@ -3,10 +3,10 @@
3
3
  import { useCallback, useMemo, useState, useEffect } from "react";
4
4
  import { useSearchParams, useRouter } from "next/navigation";
5
5
  import { toast } from "sonner";
6
- import type { LayoutDataClient } from "@/components/layouts/shared/data/layout_data_client";
7
- import type { PasswordRequirementOptions } from "@/components/layouts/shared/config/layout_customization";
8
- import { RESET_PASSWORD_FIELD_IDS, type ResetPasswordFieldId } from "@/components/layouts/reset_password/config/reset_password_field_config";
9
- import { validatePassword } from "@/components/layouts/shared/utils/validation";
6
+ import type { LayoutDataClient } from "../../shared/data/layout_data_client";
7
+ import type { PasswordRequirementOptions } from "../../shared/config/layout_customization";
8
+ import { RESET_PASSWORD_FIELD_IDS, type ResetPasswordFieldId } from "../config/reset_password_field_config";
9
+ import { validatePassword } from "../../shared/utils/validation";
10
10
 
11
11
  // section: constants
12
12
  const PASSWORD_FIELDS: Array<ResetPasswordFieldId> = [
@@ -3,31 +3,31 @@
3
3
  "use client";
4
4
 
5
5
  // section: imports
6
- import { PasswordField } from "@/components/layouts/shared/components/password_field";
7
- import { FormFieldWrapper } from "@/components/layouts/shared/components/form_field_wrapper";
8
- import { FormHeader } from "@/components/layouts/shared/components/form_header";
9
- import { FormActionButtons } from "@/components/layouts/shared/components/form_action_buttons";
10
- import { TwoColumnAuthLayout } from "@/components/layouts/shared/components/two_column_auth_layout";
6
+ import { PasswordField } from "../shared/components/password_field";
7
+ import { FormFieldWrapper } from "../shared/components/form_field_wrapper";
8
+ import { FormHeader } from "../shared/components/form_header";
9
+ import { FormActionButtons } from "../shared/components/form_action_buttons";
10
+ import { TwoColumnAuthLayout } from "../shared/components/two_column_auth_layout";
11
11
  import { CheckCircle, XCircle, Loader2 } from "lucide-react";
12
- import { AlreadyLoggedInGuard } from "@/components/layouts/shared/components/already_logged_in_guard";
12
+ import { AlreadyLoggedInGuard } from "../shared/components/already_logged_in_guard";
13
13
  import {
14
14
  type ButtonPaletteOverrides,
15
15
  type LayoutFieldMapOverrides,
16
16
  type LayoutLabelOverrides,
17
17
  type PasswordRequirementOverrides,
18
- } from "@/components/layouts/shared/config/layout_customization";
18
+ } from "../shared/config/layout_customization";
19
19
  import {
20
20
  RESET_PASSWORD_FIELD_IDS,
21
21
  createResetPasswordFieldDefinitions,
22
22
  resolveResetPasswordButtonPalette,
23
23
  resolveResetPasswordLabels,
24
24
  resolveResetPasswordPasswordRequirements,
25
- } from "@/components/layouts/reset_password/config/reset_password_field_config";
25
+ } from "./config/reset_password_field_config";
26
26
  import {
27
27
  use_reset_password_form,
28
28
  type UseResetPasswordFormResult,
29
- } from "@/components/layouts/reset_password/hooks/use_reset_password_form";
30
- import { type LayoutDataClient } from "@/components/layouts/shared/data/layout_data_client";
29
+ } from "./hooks/use_reset_password_form";
30
+ import { type LayoutDataClient } from "../shared/data/layout_data_client";
31
31
  import Link from "next/link";
32
32
 
33
33
  // section: types
@@ -0,0 +1,36 @@
1
+ // file_description: server component that chooses between sidebar shell and standalone shell
2
+ // section: imports
3
+ import type { ReactNode } from "react";
4
+ import { SidebarLayoutWrapper } from "./sidebar_layout_wrapper";
5
+ import { StandaloneLayoutWrapper } from "./standalone_layout_wrapper";
6
+ import { get_ui_shell_config } from "../../../../lib/ui_shell_config.server";
7
+
8
+ // section: types
9
+ type AuthPageShellProps = {
10
+ children: ReactNode;
11
+ };
12
+
13
+ // section: component
14
+ export function AuthPageShell({ children }: AuthPageShellProps) {
15
+ const uiShellConfig = get_ui_shell_config();
16
+
17
+ if (uiShellConfig.layout_mode === "standalone") {
18
+ return (
19
+ <StandaloneLayoutWrapper
20
+ heading={uiShellConfig.standalone_heading}
21
+ description={uiShellConfig.standalone_description}
22
+ wrapperClassName={uiShellConfig.standalone_wrapper_class}
23
+ contentClassName={uiShellConfig.standalone_content_class}
24
+ showHeading={uiShellConfig.standalone_show_heading}
25
+ showDescription={uiShellConfig.standalone_show_description}
26
+ >
27
+ {children}
28
+ </StandaloneLayoutWrapper>
29
+ );
30
+ }
31
+
32
+ return <SidebarLayoutWrapper>{children}</SidebarLayoutWrapper>;
33
+ }
34
+
35
+
36
+
@@ -0,0 +1,53 @@
1
+ // file_description: renders a simple full-width shell without the developer sidebar
2
+ // section: client_directive
3
+ "use client";
4
+
5
+ // section: imports
6
+ import { cn } from "../../../../lib/utils";
7
+
8
+ // section: types
9
+ export type StandaloneLayoutWrapperProps = {
10
+ children: React.ReactNode;
11
+ heading?: string;
12
+ description?: string;
13
+ wrapperClassName?: string;
14
+ contentClassName?: string;
15
+ showHeading?: boolean;
16
+ showDescription?: boolean;
17
+ };
18
+
19
+ // section: component
20
+ export function StandaloneLayoutWrapper({
21
+ children,
22
+ heading = "hazo auth",
23
+ description = "Drop-in authentication flows that inherit your existing theme.",
24
+ wrapperClassName,
25
+ contentClassName,
26
+ showHeading = true,
27
+ showDescription = true,
28
+ }: StandaloneLayoutWrapperProps) {
29
+ return (
30
+ <div className={cn("cls_standalone_layout_wrapper min-h-screen w-full bg-background", wrapperClassName)}>
31
+ <div className={cn("cls_standalone_layout_content mx-auto flex w-full max-w-5xl flex-col gap-8 p-6", contentClassName)}>
32
+ {(showHeading || showDescription) && (
33
+ <div className="cls_standalone_layout_header text-center">
34
+ {showHeading && (
35
+ <h1 className="cls_standalone_layout_title text-2xl font-semibold tracking-tight text-foreground">
36
+ {heading}
37
+ </h1>
38
+ )}
39
+ {showDescription && (
40
+ <p className="cls_standalone_layout_description mt-2 text-sm text-muted-foreground">
41
+ {description}
42
+ </p>
43
+ )}
44
+ </div>
45
+ )}
46
+ <div className="cls_standalone_layout_body">{children}</div>
47
+ </div>
48
+ </div>
49
+ );
50
+ }
51
+
52
+
53
+
@@ -4,8 +4,8 @@
4
4
 
5
5
  // section: imports
6
6
  import { useState, useEffect, useMemo } from "react";
7
- import { Button } from "@/components/ui/button";
8
- import { Checkbox } from "@/components/ui/checkbox";
7
+ import { Button } from "../../../ui/button";
8
+ import { Checkbox } from "../../../ui/checkbox";
9
9
  import {
10
10
  Table,
11
11
  TableBody,
@@ -13,7 +13,7 @@ import {
13
13
  TableHead,
14
14
  TableHeader,
15
15
  TableRow,
16
- } from "@/components/ui/table";
16
+ } from "../../../ui/table";
17
17
  import {
18
18
  Dialog,
19
19
  DialogContent,
@@ -21,12 +21,12 @@ import {
21
21
  DialogFooter,
22
22
  DialogHeader,
23
23
  DialogTitle,
24
- } from "@/components/ui/dialog";
25
- import { Input } from "@/components/ui/input";
26
- import { Label } from "@/components/ui/label";
24
+ } from "../../../ui/dialog";
25
+ import { Input } from "../../../ui/input";
26
+ import { Label } from "../../../ui/label";
27
27
  import { Plus, Save, Loader2, CircleCheck, CircleX } from "lucide-react";
28
28
  import { toast } from "sonner";
29
- import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
29
+ import { Avatar, AvatarImage, AvatarFallback } from "../../../ui/avatar";
30
30
 
31
31
  // section: types
32
32
  export type RolesMatrixData = {
@@ -4,8 +4,8 @@
4
4
 
5
5
  // section: imports
6
6
  import { useState, useEffect, useCallback } from "react";
7
- import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
8
- import { use_hazo_auth } from "@/components/layouts/shared/hooks/use_hazo_auth";
7
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from "../../ui/tabs";
8
+ import { use_hazo_auth } from "../shared/hooks/use_hazo_auth";
9
9
  import {
10
10
  Table,
11
11
  TableBody,
@@ -13,9 +13,9 @@ import {
13
13
  TableHead,
14
14
  TableHeader,
15
15
  TableRow,
16
- } from "@/components/ui/table";
17
- import { Button } from "@/components/ui/button";
18
- import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
16
+ } from "../../ui/table";
17
+ import { Button } from "../../ui/button";
18
+ import { Avatar, AvatarImage, AvatarFallback } from "../../ui/avatar";
19
19
  import {
20
20
  AlertDialog,
21
21
  AlertDialogAction,
@@ -25,7 +25,7 @@ import {
25
25
  AlertDialogFooter,
26
26
  AlertDialogHeader,
27
27
  AlertDialogTitle,
28
- } from "@/components/ui/alert-dialog";
28
+ } from "../../ui/alert-dialog";
29
29
  import {
30
30
  Dialog,
31
31
  DialogContent,
@@ -33,13 +33,13 @@ import {
33
33
  DialogFooter,
34
34
  DialogHeader,
35
35
  DialogTitle,
36
- } from "@/components/ui/dialog";
37
- import { Input } from "@/components/ui/input";
38
- import { Label } from "@/components/ui/label";
36
+ } from "../../ui/dialog";
37
+ import { Input } from "../../ui/input";
38
+ import { Label } from "../../ui/label";
39
39
  import { RolesMatrix } from "./components/roles_matrix";
40
40
  import { UserX, KeyRound, Edit, Trash2, Loader2, CircleCheck, CircleX, Plus, UserPlus } from "lucide-react";
41
41
  import { toast } from "sonner";
42
- import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
42
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../../ui/tooltip";
43
43
 
44
44
  // section: types
45
45
  export type UserManagementLayoutProps = {
@@ -3,8 +3,8 @@
3
3
  import * as React from "react"
4
4
  import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
5
5
 
6
- import { cn } from "@/lib/utils"
7
- import { buttonVariants } from "@/components/ui/button"
6
+ import { cn } from "../../lib/utils"
7
+ import { buttonVariants } from "./button"
8
8
 
9
9
  const AlertDialog = AlertDialogPrimitive.Root
10
10
 
@@ -3,7 +3,7 @@
3
3
  import * as React from "react"
4
4
  import * as AvatarPrimitive from "@radix-ui/react-avatar"
5
5
 
6
- import { cn } from "@/lib/utils"
6
+ import { cn } from "../../lib/utils"
7
7
 
8
8
  const Avatar = React.forwardRef<
9
9
  React.ElementRef<typeof AvatarPrimitive.Root>,
@@ -2,7 +2,7 @@ import * as React from "react"
2
2
  import { Slot } from "@radix-ui/react-slot"
3
3
  import { cva, type VariantProps } from "class-variance-authority"
4
4
 
5
- import { cn } from "@/lib/utils"
5
+ import { cn } from "../../lib/utils"
6
6
 
7
7
  const buttonVariants = cva(
8
8
  "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
@@ -4,7 +4,7 @@ import * as React from "react"
4
4
  import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
5
5
  import { Check } from "lucide-react"
6
6
 
7
- import { cn } from "@/lib/utils"
7
+ import { cn } from "../../lib/utils"
8
8
 
9
9
  const Checkbox = React.forwardRef<
10
10
  React.ElementRef<typeof CheckboxPrimitive.Root>,
@@ -4,7 +4,7 @@ import * as React from "react"
4
4
  import * as DialogPrimitive from "@radix-ui/react-dialog"
5
5
  import { X } from "lucide-react"
6
6
 
7
- import { cn } from "@/lib/utils"
7
+ import { cn } from "../../lib/utils"
8
8
 
9
9
  const Dialog = DialogPrimitive.Root
10
10
 
@@ -4,7 +4,7 @@ import * as React from "react"
4
4
  import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
5
5
  import { Check, ChevronRight, Circle } from "lucide-react"
6
6
 
7
- import { cn } from "@/lib/utils"
7
+ import { cn } from "../../lib/utils"
8
8
 
9
9
  const DropdownMenu = DropdownMenuPrimitive.Root
10
10
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  // section: imports
6
6
  import { HelpCircle } from "lucide-react";
7
- import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
7
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./tooltip";
8
8
 
9
9
  // section: types
10
10
  export type HazoUITooltipProps = {
@@ -1,6 +1,6 @@
1
1
  import * as React from "react"
2
2
 
3
- import { cn } from "@/lib/utils"
3
+ import { cn } from "../../lib/utils"
4
4
 
5
5
  const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
6
6
  ({ className, type, ...props }, ref) => {