hazo_auth 6.0.0 → 7.0.1
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.
- package/README.md +233 -8
- package/SETUP_CHECKLIST.md +240 -0
- package/cli-src/cli/validate.ts +4 -0
- package/cli-src/lib/auth/nextauth_config.ts +101 -1
- package/cli-src/lib/cookies_config.server.ts +1 -0
- package/cli-src/lib/email_verification_config.server.ts +0 -34
- package/cli-src/lib/forgot_password_config.server.ts +0 -34
- package/cli-src/lib/login_config.server.ts +14 -31
- package/cli-src/lib/my_settings_config.server.ts +0 -3
- package/cli-src/lib/oauth_config.server.ts +58 -0
- package/cli-src/lib/otp_config.server.ts +91 -0
- package/cli-src/lib/register_config.server.ts +11 -31
- package/cli-src/lib/reset_password_config.server.ts +0 -31
- package/cli-src/lib/services/email_service.ts +3 -1
- package/cli-src/lib/services/email_template_manifest.ts +17 -0
- package/cli-src/lib/services/email_templates/otp_signin_code.html +13 -0
- package/cli-src/lib/services/email_templates/otp_signin_code.txt +5 -0
- package/cli-src/lib/services/index.ts +8 -2
- package/cli-src/lib/services/oauth_service.ts +197 -0
- package/cli-src/lib/services/otp_service.ts +295 -0
- package/cli-src/lib/services/session_token_service.ts +4 -1
- package/config/hazo_auth_config.example.ini +76 -41
- package/dist/cli/validate.d.ts.map +1 -1
- package/dist/cli/validate.js +4 -0
- package/dist/client.d.ts +2 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +1 -0
- package/dist/components/layouts/create_firm/index.d.ts +4 -8
- package/dist/components/layouts/create_firm/index.d.ts.map +1 -1
- package/dist/components/layouts/create_firm/index.js +3 -3
- package/dist/components/layouts/email_verification/index.d.ts +4 -5
- package/dist/components/layouts/email_verification/index.d.ts.map +1 -1
- package/dist/components/layouts/email_verification/index.js +4 -4
- package/dist/components/layouts/forgot_password/index.d.ts +4 -5
- package/dist/components/layouts/forgot_password/index.d.ts.map +1 -1
- package/dist/components/layouts/forgot_password/index.js +2 -2
- package/dist/components/layouts/login/index.d.ts +19 -9
- package/dist/components/layouts/login/index.d.ts.map +1 -1
- package/dist/components/layouts/login/index.js +12 -6
- package/dist/components/layouts/otp/index.d.ts +17 -0
- package/dist/components/layouts/otp/index.d.ts.map +1 -0
- package/dist/components/layouts/otp/index.js +16 -0
- package/dist/components/layouts/register/index.d.ts +11 -7
- package/dist/components/layouts/register/index.d.ts.map +1 -1
- package/dist/components/layouts/register/index.js +8 -4
- package/dist/components/layouts/reset_password/index.d.ts +4 -5
- package/dist/components/layouts/reset_password/index.d.ts.map +1 -1
- package/dist/components/layouts/reset_password/index.js +5 -5
- package/dist/components/layouts/shared/components/already_logged_in_guard.d.ts +3 -5
- package/dist/components/layouts/shared/components/already_logged_in_guard.d.ts.map +1 -1
- package/dist/components/layouts/shared/components/already_logged_in_guard.js +2 -2
- package/dist/components/layouts/shared/components/facebook_sign_in_button.d.ts +25 -0
- package/dist/components/layouts/shared/components/facebook_sign_in_button.d.ts.map +1 -0
- package/dist/components/layouts/shared/components/facebook_sign_in_button.js +49 -0
- package/dist/components/layouts/shared/components/sidebar_layout_wrapper.d.ts.map +1 -1
- package/dist/components/layouts/shared/components/sidebar_layout_wrapper.js +8 -3
- package/dist/components/layouts/shared/components/two_column_auth_layout.d.ts +3 -6
- package/dist/components/layouts/shared/components/two_column_auth_layout.d.ts.map +1 -1
- package/dist/components/layouts/shared/components/two_column_auth_layout.js +8 -5
- package/dist/components/otp/OTPRequestForm.d.ts +11 -0
- package/dist/components/otp/OTPRequestForm.d.ts.map +1 -0
- package/dist/components/otp/OTPRequestForm.js +42 -0
- package/dist/components/otp/OTPVerifyForm.d.ts +16 -0
- package/dist/components/otp/OTPVerifyForm.d.ts.map +1 -0
- package/dist/components/otp/OTPVerifyForm.js +75 -0
- package/dist/components/otp/index.d.ts +5 -0
- package/dist/components/otp/index.d.ts.map +1 -0
- package/dist/components/otp/index.js +2 -0
- package/dist/components/ui/input-otp.d.ts +35 -0
- package/dist/components/ui/input-otp.d.ts.map +1 -0
- package/dist/components/ui/input-otp.js +44 -0
- package/dist/consent/consent_state.d.ts +18 -0
- package/dist/consent/consent_state.d.ts.map +1 -0
- package/dist/consent/consent_state.js +29 -0
- package/dist/consent/cookie_consent_banner.d.ts +11 -0
- package/dist/consent/cookie_consent_banner.d.ts.map +1 -0
- package/dist/consent/cookie_consent_banner.js +40 -0
- package/dist/consent/gtm_mapping.d.ts +13 -0
- package/dist/consent/gtm_mapping.d.ts.map +1 -0
- package/dist/consent/gtm_mapping.js +30 -0
- package/dist/consent/index.d.ts +7 -0
- package/dist/consent/index.d.ts.map +1 -0
- package/dist/consent/index.js +7 -0
- package/dist/consent/manage_modal.d.ts +2 -0
- package/dist/consent/manage_modal.d.ts.map +1 -0
- package/dist/consent/manage_modal.js +33 -0
- package/dist/consent/read_consent.d.ts +15 -0
- package/dist/consent/read_consent.d.ts.map +1 -0
- package/dist/consent/read_consent.js +23 -0
- package/dist/consent/use_consent.d.ts +7 -0
- package/dist/consent/use_consent.d.ts.map +1 -0
- package/dist/consent/use_consent.js +55 -0
- package/dist/lib/auth/nextauth_config.d.ts +10 -0
- package/dist/lib/auth/nextauth_config.d.ts.map +1 -1
- package/dist/lib/auth/nextauth_config.js +80 -2
- package/dist/lib/cookies_config.server.d.ts +1 -0
- package/dist/lib/cookies_config.server.d.ts.map +1 -1
- package/dist/lib/cookies_config.server.js +1 -0
- package/dist/lib/email_verification_config.server.d.ts +0 -3
- package/dist/lib/email_verification_config.server.d.ts.map +1 -1
- package/dist/lib/email_verification_config.server.js +0 -15
- package/dist/lib/forgot_password_config.server.d.ts +0 -3
- package/dist/lib/forgot_password_config.server.d.ts.map +1 -1
- package/dist/lib/forgot_password_config.server.js +0 -15
- package/dist/lib/login_config.server.d.ts +6 -3
- package/dist/lib/login_config.server.d.ts.map +1 -1
- package/dist/lib/login_config.server.js +7 -13
- package/dist/lib/my_settings_config.server.d.ts +0 -1
- package/dist/lib/my_settings_config.server.d.ts.map +1 -1
- package/dist/lib/my_settings_config.server.js +0 -2
- package/dist/lib/oauth_config.server.d.ts +17 -0
- package/dist/lib/oauth_config.server.d.ts.map +1 -1
- package/dist/lib/oauth_config.server.js +25 -0
- package/dist/lib/otp_config.server.d.ts +49 -0
- package/dist/lib/otp_config.server.d.ts.map +1 -0
- package/dist/lib/otp_config.server.js +48 -0
- package/dist/lib/register_config.server.d.ts +2 -3
- package/dist/lib/register_config.server.d.ts.map +1 -1
- package/dist/lib/register_config.server.js +4 -13
- package/dist/lib/reset_password_config.server.d.ts +0 -3
- package/dist/lib/reset_password_config.server.d.ts.map +1 -1
- package/dist/lib/reset_password_config.server.js +0 -13
- package/dist/lib/services/email_service.d.ts +1 -1
- package/dist/lib/services/email_service.d.ts.map +1 -1
- package/dist/lib/services/email_service.js +2 -0
- package/dist/lib/services/email_template_manifest.d.ts.map +1 -1
- package/dist/lib/services/email_template_manifest.js +17 -0
- package/dist/lib/services/email_templates/otp_signin_code.html +13 -0
- package/dist/lib/services/email_templates/otp_signin_code.txt +5 -0
- package/dist/lib/services/index.d.ts +2 -0
- package/dist/lib/services/index.d.ts.map +1 -1
- package/dist/lib/services/index.js +1 -0
- package/dist/lib/services/oauth_service.d.ts +24 -0
- package/dist/lib/services/oauth_service.d.ts.map +1 -1
- package/dist/lib/services/oauth_service.js +155 -0
- package/dist/lib/services/otp_service.d.ts +46 -0
- package/dist/lib/services/otp_service.d.ts.map +1 -0
- package/dist/lib/services/otp_service.js +238 -0
- package/dist/lib/services/session_token_service.d.ts +3 -1
- package/dist/lib/services/session_token_service.d.ts.map +1 -1
- package/dist/lib/services/session_token_service.js +4 -2
- package/dist/page_components/create_firm.d.ts +13 -1
- package/dist/page_components/create_firm.d.ts.map +1 -1
- package/dist/page_components/create_firm.js +10 -6
- package/dist/page_components/forgot_password.d.ts +1 -4
- package/dist/page_components/forgot_password.d.ts.map +1 -1
- package/dist/page_components/forgot_password.js +2 -6
- package/dist/page_components/login.d.ts +1 -4
- package/dist/page_components/login.d.ts.map +1 -1
- package/dist/page_components/login.js +2 -6
- package/dist/page_components/otp.d.ts +4 -0
- package/dist/page_components/otp.d.ts.map +1 -0
- package/dist/page_components/otp.js +5 -0
- package/dist/page_components/register.d.ts +1 -4
- package/dist/page_components/register.d.ts.map +1 -1
- package/dist/page_components/register.js +2 -6
- package/dist/page_components/reset_password.d.ts +1 -4
- package/dist/page_components/reset_password.d.ts.map +1 -1
- package/dist/page_components/reset_password.js +2 -6
- package/dist/page_components/verify_email.d.ts +1 -4
- package/dist/page_components/verify_email.d.ts.map +1 -1
- package/dist/page_components/verify_email.js +2 -6
- package/dist/server/routes/index.d.ts +3 -0
- package/dist/server/routes/index.d.ts.map +1 -1
- package/dist/server/routes/index.js +4 -0
- package/dist/server/routes/me.d.ts.map +1 -1
- package/dist/server/routes/me.js +43 -1
- package/dist/server/routes/oauth_facebook_callback.d.ts +8 -0
- package/dist/server/routes/oauth_facebook_callback.d.ts.map +1 -0
- package/dist/server/routes/oauth_facebook_callback.js +157 -0
- package/dist/server/routes/oauth_google_callback.js +1 -1
- package/dist/server/routes/otp/request.d.ts +3 -0
- package/dist/server/routes/otp/request.d.ts.map +1 -0
- package/dist/server/routes/otp/request.js +33 -0
- package/dist/server/routes/otp/verify.d.ts +3 -0
- package/dist/server/routes/otp/verify.d.ts.map +1 -0
- package/dist/server/routes/otp/verify.js +58 -0
- package/dist/server-lib.d.ts +3 -0
- package/dist/server-lib.d.ts.map +1 -1
- package/dist/server-lib.js +2 -0
- package/dist/server_pages/forgot_password.d.ts +13 -17
- package/dist/server_pages/forgot_password.d.ts.map +1 -1
- package/dist/server_pages/forgot_password.js +12 -8
- package/dist/server_pages/forgot_password_client_wrapper.d.ts +7 -6
- package/dist/server_pages/forgot_password_client_wrapper.d.ts.map +1 -1
- package/dist/server_pages/forgot_password_client_wrapper.js +2 -2
- package/dist/server_pages/login.d.ts +22 -21
- package/dist/server_pages/login.d.ts.map +1 -1
- package/dist/server_pages/login.js +15 -19
- package/dist/server_pages/login_client_wrapper.d.ts +10 -6
- package/dist/server_pages/login_client_wrapper.d.ts.map +1 -1
- package/dist/server_pages/login_client_wrapper.js +2 -2
- package/dist/server_pages/my_settings.d.ts +2 -0
- package/dist/server_pages/my_settings.d.ts.map +1 -1
- package/dist/server_pages/my_settings.js +8 -2
- package/dist/server_pages/otp.d.ts +56 -0
- package/dist/server_pages/otp.d.ts.map +1 -0
- package/dist/server_pages/otp.js +45 -0
- package/dist/server_pages/register.d.ts +19 -16
- package/dist/server_pages/register.d.ts.map +1 -1
- package/dist/server_pages/register.js +15 -12
- package/dist/server_pages/register_client_wrapper.d.ts +10 -6
- package/dist/server_pages/register_client_wrapper.d.ts.map +1 -1
- package/dist/server_pages/register_client_wrapper.js +2 -2
- package/dist/server_pages/reset_password.d.ts +11 -16
- package/dist/server_pages/reset_password.d.ts.map +1 -1
- package/dist/server_pages/reset_password.js +11 -9
- package/dist/server_pages/reset_password_client_wrapper.d.ts +7 -6
- package/dist/server_pages/reset_password_client_wrapper.d.ts.map +1 -1
- package/dist/server_pages/reset_password_client_wrapper.js +2 -2
- package/dist/server_pages/verify_email.d.ts +11 -17
- package/dist/server_pages/verify_email.d.ts.map +1 -1
- package/dist/server_pages/verify_email.js +11 -8
- package/dist/server_pages/verify_email_client_wrapper.d.ts +7 -6
- package/dist/server_pages/verify_email_client_wrapper.d.ts.map +1 -1
- package/dist/server_pages/verify_email_client_wrapper.js +2 -2
- package/dist/strings/default_strings.d.ts +47 -0
- package/dist/strings/default_strings.d.ts.map +1 -0
- package/dist/strings/default_strings.js +18 -0
- package/dist/strings/index.d.ts +4 -0
- package/dist/strings/index.d.ts.map +1 -0
- package/dist/strings/index.js +3 -0
- package/dist/strings/strings_context.d.ts +12 -0
- package/dist/strings/strings_context.d.ts.map +1 -0
- package/dist/strings/strings_context.js +23 -0
- package/dist/strings/strings_provider.d.ts +26 -0
- package/dist/strings/strings_provider.d.ts.map +1 -0
- package/dist/strings/strings_provider.js +45 -0
- package/dist/theme/create_theme.d.ts +7 -0
- package/dist/theme/create_theme.d.ts.map +1 -0
- package/dist/theme/create_theme.js +97 -0
- package/dist/theme/hex_to_hsl.d.ts +16 -0
- package/dist/theme/hex_to_hsl.d.ts.map +1 -0
- package/dist/theme/hex_to_hsl.js +110 -0
- package/dist/theme/index.d.ts +4 -0
- package/dist/theme/index.d.ts.map +1 -0
- package/dist/theme/index.js +3 -0
- package/dist/theme/luminance.d.ts +11 -0
- package/dist/theme/luminance.d.ts.map +1 -0
- package/dist/theme/luminance.js +45 -0
- package/dist/theme/theme_provider.d.ts +14 -0
- package/dist/theme/theme_provider.d.ts.map +1 -0
- package/dist/theme/theme_provider.js +23 -0
- package/dist/theme/theme_types.d.ts +36 -0
- package/dist/theme/theme_types.d.ts.map +1 -0
- package/dist/theme/theme_types.js +1 -0
- package/dist/themes/index.d.ts +3 -0
- package/dist/themes/index.d.ts.map +1 -0
- package/dist/themes/index.js +2 -0
- package/dist/themes/preset_indigo_sunset.d.ts +3 -0
- package/dist/themes/preset_indigo_sunset.d.ts.map +1 -0
- package/dist/themes/preset_indigo_sunset.js +20 -0
- package/dist/themes/preset_neutral.d.ts +3 -0
- package/dist/themes/preset_neutral.d.ts.map +1 -0
- package/dist/themes/preset_neutral.js +14 -0
- package/package.json +36 -2
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import type { StaticImageData } from "next/image";
|
|
2
1
|
import { type ButtonPaletteOverrides, type LayoutFieldMapOverrides, type LayoutLabelOverrides, type PasswordRequirementOverrides } from "../shared/config/layout_customization.js";
|
|
3
2
|
import { type LayoutDataClient } from "../shared/data/layout_data_client.js";
|
|
3
|
+
import type { HazoAuthTheme } from "../../../theme/theme_types";
|
|
4
4
|
export type ResetPasswordLayoutProps<TClient = unknown> = {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
image_background_color?: string;
|
|
5
|
+
/** Theme that controls visual appearance and layout mode. */
|
|
6
|
+
theme?: HazoAuthTheme;
|
|
8
7
|
field_overrides?: LayoutFieldMapOverrides;
|
|
9
8
|
labels?: LayoutLabelOverrides;
|
|
10
9
|
button_colors?: ButtonPaletteOverrides;
|
|
@@ -20,5 +19,5 @@ export type ResetPasswordLayoutProps<TClient = unknown> = {
|
|
|
20
19
|
loginPath?: string;
|
|
21
20
|
forgotPasswordPath?: string;
|
|
22
21
|
};
|
|
23
|
-
export default function reset_password_layout<TClient>({
|
|
22
|
+
export default function reset_password_layout<TClient>({ theme, field_overrides, labels, button_colors, password_requirements, data_client, alreadyLoggedInMessage, showLogoutButton, showReturnHomeButton, returnHomeButtonLabel, returnHomePath, errorMessage, successMessage, loginPath, forgotPasswordPath, }: ResetPasswordLayoutProps<TClient>): import("react/jsx-runtime").JSX.Element;
|
|
24
23
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layouts/reset_password/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layouts/reset_password/index.tsx"],"names":[],"mappings":"AAYA,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EACzB,KAAK,4BAA4B,EAClC,MAAM,uCAAuC,CAAC;AAY/C,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAE1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAGhE,MAAM,MAAM,wBAAwB,CAAC,OAAO,GAAG,OAAO,IAAI;IACxD,6DAA6D;IAC7D,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,eAAe,CAAC,EAAE,uBAAuB,CAAC;IAC1C,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,aAAa,CAAC,EAAE,sBAAsB,CAAC;IACvC,qBAAqB,CAAC,EAAE,4BAA4B,CAAC;IACrD,WAAW,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACvC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC;AAUF,MAAM,CAAC,OAAO,UAAU,qBAAqB,CAAC,OAAO,EAAE,EACrD,KAAK,EACL,eAAe,EACf,MAAM,EACN,aAAa,EACb,qBAAqB,EACrB,WAAW,EACX,sBAAsB,EACtB,gBAAuB,EACvB,oBAA4B,EAC5B,qBAAqC,EACrC,cAAoB,EACpB,YAAgH,EAChH,cAAuE,EACvE,SAA8B,EAC9B,kBAAiD,GAClD,EAAE,wBAAwB,CAAC,OAAO,CAAC,2CAqMnC"}
|
|
@@ -18,7 +18,7 @@ const ORDERED_FIELDS = [
|
|
|
18
18
|
RESET_PASSWORD_FIELD_IDS.CONFIRM_PASSWORD,
|
|
19
19
|
];
|
|
20
20
|
// section: component
|
|
21
|
-
export default function reset_password_layout({
|
|
21
|
+
export default function reset_password_layout({ theme, field_overrides, labels, button_colors, password_requirements, data_client, alreadyLoggedInMessage, showLogoutButton = true, showReturnHomeButton = false, returnHomeButtonLabel = "Return home", returnHomePath = "/", errorMessage = "Reset password link invalid or has expired. Please go to Reset Password page to get a new link.", successMessage = "Password reset successfully. Redirecting to login...", loginPath = "/hazo_auth/login", forgotPasswordPath = "/hazo_auth/forgot_password", }) {
|
|
22
22
|
const fieldDefinitions = createResetPasswordFieldDefinitions(field_overrides);
|
|
23
23
|
const resolvedLabels = resolveResetPasswordLabels(labels);
|
|
24
24
|
const resolvedButtonPalette = resolveResetPasswordButtonPalette(button_colors);
|
|
@@ -39,15 +39,15 @@ export default function reset_password_layout({ image_src, image_alt, image_back
|
|
|
39
39
|
};
|
|
40
40
|
// Show success message if password reset was successful
|
|
41
41
|
if (form.isSuccess) {
|
|
42
|
-
return (_jsx(AlreadyLoggedInGuard, {
|
|
42
|
+
return (_jsx(AlreadyLoggedInGuard, { theme: theme, message: alreadyLoggedInMessage, showLogoutButton: showLogoutButton, showReturnHomeButton: showReturnHomeButton, returnHomeButtonLabel: returnHomeButtonLabel, returnHomePath: returnHomePath, children: _jsx(TwoColumnAuthLayout, { theme: theme, formContent: _jsxs(_Fragment, { children: [_jsx(FormHeader, { heading: resolvedLabels.heading, subHeading: resolvedLabels.subHeading }), _jsxs("div", { className: "cls_reset_password_layout_success flex flex-col items-center justify-center gap-4 p-8 text-center", children: [_jsx(CheckCircle, { className: "cls_reset_password_layout_success_icon h-16 w-16 text-green-600", "aria-hidden": "true" }), _jsx("p", { className: "cls_reset_password_layout_success_message text-lg font-medium text-slate-900", children: successMessage })] })] }) }) }));
|
|
43
43
|
}
|
|
44
44
|
// Show loading state while validating token
|
|
45
45
|
if (form.isValidatingToken) {
|
|
46
|
-
return (_jsx(AlreadyLoggedInGuard, {
|
|
46
|
+
return (_jsx(AlreadyLoggedInGuard, { theme: theme, message: alreadyLoggedInMessage, showLogoutButton: showLogoutButton, showReturnHomeButton: showReturnHomeButton, returnHomeButtonLabel: returnHomeButtonLabel, returnHomePath: returnHomePath, children: _jsx(TwoColumnAuthLayout, { theme: theme, formContent: _jsxs("div", { className: "cls_reset_password_layout_validating flex flex-col items-center justify-center gap-4 py-8", children: [_jsx(Loader2, { className: "h-12 w-12 animate-spin text-slate-600", "aria-hidden": "true" }), _jsxs("div", { className: "cls_reset_password_layout_validating_text text-center", children: [_jsx("h1", { className: "cls_reset_password_layout_validating_heading text-2xl font-semibold text-slate-900", children: resolvedLabels.heading }), _jsx("p", { className: "cls_reset_password_layout_validating_subheading mt-2 text-sm text-slate-600", children: "Validating reset token..." })] })] }) }) }));
|
|
47
47
|
}
|
|
48
48
|
// Show error message if token is invalid or missing
|
|
49
49
|
if (form.tokenError || !form.token) {
|
|
50
|
-
return (_jsx(AlreadyLoggedInGuard, {
|
|
50
|
+
return (_jsx(AlreadyLoggedInGuard, { theme: theme, message: alreadyLoggedInMessage, showLogoutButton: showLogoutButton, showReturnHomeButton: showReturnHomeButton, returnHomeButtonLabel: returnHomeButtonLabel, returnHomePath: returnHomePath, children: _jsx(TwoColumnAuthLayout, { theme: theme, formContent: _jsxs("div", { className: "cls_reset_password_layout_error flex flex-col items-center justify-center gap-4 p-8 text-center", children: [_jsx(XCircle, { className: "cls_reset_password_layout_error_icon h-16 w-16 text-red-600", "aria-hidden": "true" }), _jsxs("div", { className: "cls_reset_password_layout_error_text", children: [_jsx("h1", { className: "cls_reset_password_layout_error_heading text-2xl font-semibold text-slate-900", children: "Invalid Reset Link" }), _jsx("p", { className: "cls_reset_password_layout_error_message mt-2 text-sm text-slate-600", children: form.tokenError || errorMessage })] }), _jsx(Link, { href: forgotPasswordPath, className: "cls_reset_password_layout_forgot_password_link mt-4 text-sm text-blue-600 hover:text-blue-800 underline", children: "Go to Reset Password page" })] }) }) }));
|
|
51
51
|
}
|
|
52
|
-
return (_jsx(AlreadyLoggedInGuard, {
|
|
52
|
+
return (_jsx(AlreadyLoggedInGuard, { theme: theme, message: alreadyLoggedInMessage, showLogoutButton: showLogoutButton, showReturnHomeButton: showReturnHomeButton, returnHomeButtonLabel: returnHomeButtonLabel, returnHomePath: returnHomePath, children: _jsx(TwoColumnAuthLayout, { theme: theme, formContent: _jsxs(_Fragment, { children: [_jsx(FormHeader, { heading: resolvedLabels.heading, subHeading: resolvedLabels.subHeading }), _jsxs("form", { className: "cls_reset_password_layout_form_fields flex flex-col gap-5", onSubmit: form.handleSubmit, "aria-label": "Reset password form", children: [renderFields(form), _jsx(FormActionButtons, { submitLabel: resolvedLabels.submitButton, cancelLabel: resolvedLabels.cancelButton, buttonPalette: resolvedButtonPalette, isSubmitDisabled: form.isSubmitDisabled, onCancel: form.handleCancel, submitAriaLabel: "Submit reset password form", cancelAriaLabel: "Cancel reset password form" }), form.isSubmitting && (_jsx("div", { className: "cls_reset_password_layout_submitting_indicator text-sm text-slate-600 text-center", children: "Resetting password..." }))] })] }) }) }));
|
|
53
53
|
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { HazoAuthTheme } from "../../../../theme/theme_types";
|
|
2
2
|
export type AlreadyLoggedInGuardProps = {
|
|
3
|
-
|
|
4
|
-
image_alt: string;
|
|
5
|
-
image_background_color?: string;
|
|
3
|
+
theme?: HazoAuthTheme;
|
|
6
4
|
message?: string;
|
|
7
5
|
showLogoutButton?: boolean;
|
|
8
6
|
showReturnHomeButton?: boolean;
|
|
@@ -17,5 +15,5 @@ export type AlreadyLoggedInGuardProps = {
|
|
|
17
15
|
* @param props - Component props including layout config and message customization
|
|
18
16
|
* @returns Either the "already logged in" UI or the children
|
|
19
17
|
*/
|
|
20
|
-
export declare function AlreadyLoggedInGuard({
|
|
18
|
+
export declare function AlreadyLoggedInGuard({ theme, message, showLogoutButton, showReturnHomeButton, returnHomeButtonLabel, returnHomePath, requireEmailVerified, children, }: AlreadyLoggedInGuardProps): import("react/jsx-runtime").JSX.Element;
|
|
21
19
|
//# sourceMappingURL=already_logged_in_guard.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"already_logged_in_guard.d.ts","sourceRoot":"","sources":["../../../../../src/components/layouts/shared/components/already_logged_in_guard.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"already_logged_in_guard.d.ts","sourceRoot":"","sources":["../../../../../src/components/layouts/shared/components/already_logged_in_guard.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAGnE,MAAM,MAAM,yBAAyB,GAAG;IACtC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC;AAGF;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,KAAK,EACL,OAAqC,EACrC,gBAAuB,EACvB,oBAA4B,EAC5B,qBAAqC,EACrC,cAAoB,EACpB,oBAA4B,EAC5B,QAAQ,GACT,EAAE,yBAAyB,2CA+C3B"}
|
|
@@ -16,7 +16,7 @@ import { Home } from "lucide-react";
|
|
|
16
16
|
* @param props - Component props including layout config and message customization
|
|
17
17
|
* @returns Either the "already logged in" UI or the children
|
|
18
18
|
*/
|
|
19
|
-
export function AlreadyLoggedInGuard({
|
|
19
|
+
export function AlreadyLoggedInGuard({ theme, message = "You're already logged in.", showLogoutButton = true, showReturnHomeButton = false, returnHomeButtonLabel = "Return home", returnHomePath = "/", requireEmailVerified = false, children, }) {
|
|
20
20
|
const router = useRouter();
|
|
21
21
|
const authStatus = use_auth_status();
|
|
22
22
|
// Check if user should see "already logged in" message
|
|
@@ -26,7 +26,7 @@ export function AlreadyLoggedInGuard({ image_src, image_alt, image_background_co
|
|
|
26
26
|
!authStatus.loading &&
|
|
27
27
|
(!requireEmailVerified || authStatus.email_verified === true);
|
|
28
28
|
if (shouldShowAlreadyLoggedIn) {
|
|
29
|
-
return (_jsx(TwoColumnAuthLayout, {
|
|
29
|
+
return (_jsx(TwoColumnAuthLayout, { theme: theme, formContent: _jsxs("div", { className: "cls_already_logged_in_guard flex flex-col items-center justify-center gap-4 p-8 text-center", children: [_jsx("p", { className: "cls_already_logged_in_guard_message text-lg font-medium text-slate-900", children: message }), _jsxs("div", { className: "cls_already_logged_in_guard_actions flex flex-col gap-3 items-center mt-4", children: [showLogoutButton && (_jsx(LogoutButton, { className: "cls_already_logged_in_guard_logout_button", variant: "default" })), showReturnHomeButton && (_jsxs(Button, { onClick: () => router.push(returnHomePath), variant: "outline", className: "cls_already_logged_in_guard_return_home_button", "aria-label": returnHomeButtonLabel, children: [_jsx(Home, { className: "h-4 w-4 mr-2", "aria-hidden": "true" }), returnHomeButtonLabel] }))] })] }) }));
|
|
30
30
|
}
|
|
31
31
|
return _jsx(_Fragment, { children: children });
|
|
32
32
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type FacebookSignInButtonProps = {
|
|
2
|
+
/** Text displayed on the button */
|
|
3
|
+
label?: string;
|
|
4
|
+
/** Custom click handler - if not provided, redirects to Facebook OAuth */
|
|
5
|
+
onClick?: () => void;
|
|
6
|
+
/** Disable the button */
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
/** Additional CSS classes */
|
|
9
|
+
className?: string;
|
|
10
|
+
/** Callback URL after OAuth (default: /api/hazo_auth/oauth/facebook/callback) */
|
|
11
|
+
callbackUrl?: string;
|
|
12
|
+
/** Pass enabled={false} to hide when Facebook OAuth is disabled */
|
|
13
|
+
enabled?: boolean;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Facebook Sign-In button component
|
|
17
|
+
* Displays the Facebook icon with configurable text
|
|
18
|
+
* Initiates the Facebook OAuth flow when clicked
|
|
19
|
+
* Uses next-auth/react signIn function for proper OAuth flow
|
|
20
|
+
* Pass `enabled={false}` to hide when Facebook OAuth is disabled.
|
|
21
|
+
* Returns null when Facebook OAuth is not enabled (enable_facebook=false or env vars absent)
|
|
22
|
+
*/
|
|
23
|
+
export declare function FacebookSignInButton({ label, onClick, disabled, className, callbackUrl, enabled, }: FacebookSignInButtonProps): import("react/jsx-runtime").JSX.Element | null;
|
|
24
|
+
export default FacebookSignInButton;
|
|
25
|
+
//# sourceMappingURL=facebook_sign_in_button.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facebook_sign_in_button.d.ts","sourceRoot":"","sources":["../../../../../src/components/layouts/shared/components/facebook_sign_in_button.tsx"],"names":[],"mappings":"AAYA,MAAM,MAAM,yBAAyB,GAAG;IACtC,mCAAmC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,yBAAyB;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mEAAmE;IACnE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAGF;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,KAAgC,EAChC,OAAO,EACP,QAAgB,EAChB,SAAS,EACT,WAAsD,EACtD,OAAO,GACR,EAAE,yBAAyB,kDAgD3B;AAED,eAAe,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// file_description: Facebook Sign-In button component using Facebook brand colors
|
|
2
|
+
// section: client_directive
|
|
3
|
+
"use client";
|
|
4
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
5
|
+
// section: imports
|
|
6
|
+
import { Button } from "../../../ui/button.js";
|
|
7
|
+
import { cn } from "../../../../lib/utils.js";
|
|
8
|
+
import { useState } from "react";
|
|
9
|
+
import { Loader2, Facebook } from "lucide-react";
|
|
10
|
+
import { signIn } from "next-auth/react";
|
|
11
|
+
// section: component
|
|
12
|
+
/**
|
|
13
|
+
* Facebook Sign-In button component
|
|
14
|
+
* Displays the Facebook icon with configurable text
|
|
15
|
+
* Initiates the Facebook OAuth flow when clicked
|
|
16
|
+
* Uses next-auth/react signIn function for proper OAuth flow
|
|
17
|
+
* Pass `enabled={false}` to hide when Facebook OAuth is disabled.
|
|
18
|
+
* Returns null when Facebook OAuth is not enabled (enable_facebook=false or env vars absent)
|
|
19
|
+
*/
|
|
20
|
+
export function FacebookSignInButton({ label = "Continue with Facebook", onClick, disabled = false, className, callbackUrl = "/api/hazo_auth/oauth/facebook/callback", enabled, }) {
|
|
21
|
+
if (enabled === false)
|
|
22
|
+
return null;
|
|
23
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
24
|
+
const handleClick = async () => {
|
|
25
|
+
if (disabled || isLoading)
|
|
26
|
+
return;
|
|
27
|
+
if (onClick) {
|
|
28
|
+
onClick();
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
setIsLoading(true);
|
|
32
|
+
try {
|
|
33
|
+
console.log("[FacebookSignInButton] Starting Facebook OAuth with callbackUrl:", callbackUrl);
|
|
34
|
+
await signIn("facebook", {
|
|
35
|
+
callbackUrl,
|
|
36
|
+
redirect: true,
|
|
37
|
+
});
|
|
38
|
+
// Note: redirect: true means this code won't execute after success
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
console.error("[FacebookSignInButton] Sign-in exception:", error);
|
|
42
|
+
alert(`Facebook Sign-In Exception: ${error}`);
|
|
43
|
+
setIsLoading(false);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
return (_jsxs(Button, { type: "button", onClick: handleClick, disabled: disabled || isLoading, className: cn("cls_facebook_sign_in_button w-full flex items-center justify-center gap-3 h-11 bg-[#1877F2] hover:bg-[#166FE5] text-white transition-colors", className), "aria-label": label, children: [isLoading ? (_jsx(Loader2, { className: "h-5 w-5 animate-spin text-white", "aria-hidden": "true" })) : (_jsx(Facebook, { className: "h-5 w-5 text-white", "aria-hidden": "true" })), _jsx("span", { className: "font-medium", children: isLoading ? "Signing in..." : label })] }));
|
|
48
|
+
}
|
|
49
|
+
export default FacebookSignInButton;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidebar_layout_wrapper.d.ts","sourceRoot":"","sources":["../../../../../src/components/layouts/shared/components/sidebar_layout_wrapper.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sidebar_layout_wrapper.d.ts","sourceRoot":"","sources":["../../../../../src/components/layouts/shared/components/sidebar_layout_wrapper.tsx"],"names":[],"mappings":"AA6BA,KAAK,yBAAyB,GAAG;IAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC;AAGF,wBAAgB,oBAAoB,CAAC,EAAE,QAAQ,EAAE,EAAE,yBAAyB,2CA+S3E"}
|
|
@@ -4,12 +4,17 @@
|
|
|
4
4
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
5
5
|
// section: imports
|
|
6
6
|
import Link from "next/link";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { usePathname } from "next/navigation";
|
|
8
|
+
import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupLabel, SidebarHeader, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarTrigger, SidebarInset, } from "../../../ui/sidebar.js";
|
|
9
|
+
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@radix-ui/react-collapsible";
|
|
10
|
+
import { LogIn, UserPlus, BookOpen, ExternalLink, Database, KeyRound, MailCheck, Key, User, ShieldCheck, CircleUserRound, FileJson, Building2, Palette, Settings2, Play, ChevronDown, LayoutGrid } from "lucide-react";
|
|
9
11
|
import { use_auth_status } from "../hooks/use_auth_status.js";
|
|
10
12
|
import { ProfilePicMenu } from "./profile_pic_menu.js";
|
|
11
13
|
// section: component
|
|
12
14
|
export function SidebarLayoutWrapper({ children }) {
|
|
13
15
|
const authStatus = use_auth_status();
|
|
14
|
-
return (_jsx(SidebarProvider, { children: _jsxs("div", { className: "cls_sidebar_layout_wrapper flex min-h-screen w-full", children: [_jsxs(Sidebar, { children: [_jsx(SidebarHeader, { className: "cls_sidebar_layout_header", children: _jsx("div", { className: "cls_sidebar_layout_title flex items-center gap-2 px-2 py-4", children: _jsx("h1", { className: "cls_sidebar_layout_title_text text-lg font-semibold text-sidebar-foreground", children: "hazo auth" }) }) }), _jsxs(SidebarContent, { className: "cls_sidebar_layout_content", children: [_jsxs(SidebarGroup, { className: "cls_sidebar_layout_test_group", children: [_jsx(SidebarGroupLabel, { className: "cls_sidebar_layout_group_label", children: "Test components" }), _jsxs(SidebarMenu, { className: "cls_sidebar_layout_test_menu", children: [_jsx(SidebarMenuItem, { className: "cls_sidebar_layout_test_login_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/login", className: "cls_sidebar_layout_test_login_link flex items-center gap-2", "aria-label": "Test login layout component", children: [_jsx(LogIn, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Test login" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_test_register_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/register", className: "cls_sidebar_layout_test_register_link flex items-center gap-2", "aria-label": "Test register layout component", children: [_jsx(UserPlus, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Test register" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_test_forgot_password_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/forgot_password", className: "cls_sidebar_layout_test_forgot_password_link flex items-center gap-2", "aria-label": "Test forgot password layout component", children: [_jsx(KeyRound, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Test forgot password" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_test_reset_password_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/reset_password", className: "cls_sidebar_layout_test_reset_password_link flex items-center gap-2", "aria-label": "Test reset password layout component", children: [_jsx(Key, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Test reset password" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_test_email_verification_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/verify_email", className: "cls_sidebar_layout_test_email_verification_link flex items-center gap-2", "aria-label": "Test email verification layout component", children: [_jsx(MailCheck, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Test email verification" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_sqlite_admin_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_connect/sqlite_admin", className: "cls_sidebar_layout_sqlite_admin_link flex items-center gap-2", "aria-label": "Open SQLite admin UI to browse and edit database", children: [_jsx(Database, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "SQLite Admin" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_user_management_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/user_management", className: "cls_sidebar_layout_user_management_link flex items-center gap-2", "aria-label": "Open User Management to manage users, roles, and permissions", children: [_jsx(User, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "User Management" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_rbac_test_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/rbac_test", className: "cls_sidebar_layout_rbac_test_link flex items-center gap-2", "aria-label": "Test RBAC and HRBAC access control", children: [_jsx(ShieldCheck, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "RBAC/HRBAC Test" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_profile_stamp_test_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/profile_stamp_test", className: "cls_sidebar_layout_profile_stamp_test_link flex items-center gap-2", "aria-label": "Test ProfileStamp component", children: [_jsx(CircleUserRound, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "ProfileStamp Test" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_app_user_data_test_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/app_user_data_test", className: "cls_sidebar_layout_app_user_data_test_link flex items-center gap-2", "aria-label": "Test app_user_data JSON storage", children: [_jsx(FileJson, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "App User Data Test" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_create_firm_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/create_firm", className: "cls_sidebar_layout_create_firm_link flex items-center gap-2", "aria-label": "Test create firm flow", children: [_jsx(Building2, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Create Firm" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_edit_firm_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/edit_firm", className: "cls_sidebar_layout_edit_firm_link flex items-center gap-2", "aria-label": "Test branding editor for firm", children: [_jsx(Palette, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Edit Firm" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_relationships_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/relationships", className: "cls_sidebar_layout_relationships_link flex items-center gap-2", "aria-label": "Test relationship accounts", children: [_jsx(User, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Relationships" })] }) }) })] })] }), _jsxs(SidebarGroup, { className: "cls_sidebar_layout_testing_group", children: [_jsx(SidebarGroupLabel, { className: "cls_sidebar_layout_group_label", children: "Testing" }), _jsx(SidebarMenu, { className: "cls_sidebar_layout_testing_menu", children: _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_test_scenarios_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/test_scenarios", className: "cls_sidebar_layout_test_scenarios_link flex items-center gap-2", "aria-label": "Test scenarios", children: [_jsx(Settings2, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Test Scenarios" })] }) }) }) })] }), _jsxs(SidebarGroup, { className: "cls_sidebar_layout_auto_test_group", children: [_jsx(SidebarGroupLabel, { className: "cls_sidebar_layout_group_label", children: "Auto Tests" }), _jsx(SidebarMenu, { className: "cls_sidebar_layout_auto_test_menu", children: _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_auto_test_runner_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/auto_test", className: "cls_sidebar_layout_auto_test_runner_link flex items-center gap-2", "aria-label": "Run automated tests", children: [_jsx(Play, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Auto Test Runner" })] }) }) }) })] }), _jsx(ProfilePicMenu, { variant: "sidebar", avatar_size: "sm", className: "cls_sidebar_layout_profile_menu", sidebar_group_label: "Account" }), _jsxs(SidebarGroup, { className: "cls_sidebar_layout_resources_group", children: [_jsx(SidebarGroupLabel, { className: "cls_sidebar_layout_group_label", children: "Resources" }), _jsxs(SidebarMenu, { className: "cls_sidebar_layout_resources_menu", children: [_jsx(SidebarMenuItem, { className: "cls_sidebar_layout_storybook_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs("a", { href: "http://localhost:6006", target: "_blank", rel: "noopener noreferrer", className: "cls_sidebar_layout_storybook_link flex items-center gap-2", "aria-label": "Open Storybook preview for reusable components", children: [_jsx(BookOpen, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Storybook" }), _jsx(ExternalLink, { className: "ml-auto h-3 w-3", "aria-hidden": "true" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_docs_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs("a", { href: "https://ui.shadcn.com/docs", target: "_blank", rel: "noopener noreferrer", className: "cls_sidebar_layout_docs_link flex items-center gap-2", "aria-label": "Review shadcn documentation for styling guidance", children: [_jsx(BookOpen, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Shadcn docs" }), _jsx(ExternalLink, { className: "ml-auto h-3 w-3", "aria-hidden": "true" })] }) }) })] })] })] })] }), _jsxs(SidebarInset, { className: "cls_sidebar_layout_inset", children: [_jsxs("header", { className: "cls_sidebar_layout_main_header flex h-16 shrink-0 items-center gap-2 border-b px-4", children: [_jsx(SidebarTrigger, { className: "cls_sidebar_layout_trigger" }), _jsx("div", { className: "cls_sidebar_layout_main_header_content flex flex-1 items-center gap-2", children: _jsx("h2", { className: "cls_sidebar_layout_main_title text-lg font-semibold text-foreground", children: "hazo reusable ui library workspace" }) }), _jsx(ProfilePicMenu, { className: "cls_sidebar_layout_auth_status", avatar_size: "sm" })] }), _jsx("main", { className: "cls_sidebar_layout_main_content flex flex-1 items-center justify-center p-6", children: children })] })] }) }));
|
|
16
|
+
const pathname = usePathname();
|
|
17
|
+
const login_paths = ["/hazo_auth/login", "/hazo_auth/login_variations"];
|
|
18
|
+
const login_submenu_open = login_paths.some((p) => pathname === null || pathname === void 0 ? void 0 : pathname.startsWith(p));
|
|
19
|
+
return (_jsx(SidebarProvider, { children: _jsxs("div", { className: "cls_sidebar_layout_wrapper flex min-h-screen w-full", children: [_jsxs(Sidebar, { children: [_jsx(SidebarHeader, { className: "cls_sidebar_layout_header", children: _jsx("div", { className: "cls_sidebar_layout_title flex items-center gap-2 px-2 py-4", children: _jsx("span", { className: "cls_sidebar_layout_title_text text-lg font-semibold text-sidebar-foreground", children: "hazo auth" }) }) }), _jsxs(SidebarContent, { className: "cls_sidebar_layout_content", children: [_jsxs(SidebarGroup, { className: "cls_sidebar_layout_test_group", children: [_jsx(SidebarGroupLabel, { className: "cls_sidebar_layout_group_label", children: "Test components" }), _jsxs(SidebarMenu, { className: "cls_sidebar_layout_test_menu", children: [_jsx(SidebarMenuItem, { className: "cls_sidebar_layout_login_group_item", children: _jsxs(Collapsible, { defaultOpen: login_submenu_open, className: "group/login-collapsible w-full", children: [_jsx(CollapsibleTrigger, { asChild: true, children: _jsxs(SidebarMenuButton, { className: "cls_sidebar_layout_login_trigger flex items-center gap-2 w-full", "aria-label": "Toggle login submenu", children: [_jsx(LogIn, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Login" }), _jsx(ChevronDown, { className: "ml-auto h-4 w-4 transition-transform duration-200 group-data-[state=open]/login-collapsible:rotate-180", "aria-hidden": "true" })] }) }), _jsx(CollapsibleContent, { children: _jsxs(SidebarMenuSub, { className: "cls_sidebar_layout_login_submenu", children: [_jsx(SidebarMenuSubItem, { className: "cls_sidebar_layout_login_test_item", children: _jsx(SidebarMenuSubButton, { asChild: true, children: _jsx(Link, { href: "/hazo_auth/login", className: "cls_sidebar_layout_login_test_link flex items-center gap-2", "aria-label": "Test login layout component", children: _jsx("span", { children: "Test login" }) }) }) }), _jsx(SidebarMenuSubItem, { className: "cls_sidebar_layout_login_variations_item", children: _jsx(SidebarMenuSubButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/login_variations", className: "cls_sidebar_layout_login_variations_link flex items-center gap-2", "aria-label": "View login page variations", children: [_jsx(LayoutGrid, { className: "h-3.5 w-3.5", "aria-hidden": "true" }), _jsx("span", { children: "Variations" })] }) }) })] }) })] }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_test_register_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/register", className: "cls_sidebar_layout_test_register_link flex items-center gap-2", "aria-label": "Test register layout component", children: [_jsx(UserPlus, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Test register" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_test_forgot_password_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/forgot_password", className: "cls_sidebar_layout_test_forgot_password_link flex items-center gap-2", "aria-label": "Test forgot password layout component", children: [_jsx(KeyRound, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Test forgot password" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_test_reset_password_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/reset_password", className: "cls_sidebar_layout_test_reset_password_link flex items-center gap-2", "aria-label": "Test reset password layout component", children: [_jsx(Key, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Test reset password" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_test_email_verification_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/verify_email", className: "cls_sidebar_layout_test_email_verification_link flex items-center gap-2", "aria-label": "Test email verification layout component", children: [_jsx(MailCheck, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Test email verification" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_sqlite_admin_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_connect/sqlite_admin", className: "cls_sidebar_layout_sqlite_admin_link flex items-center gap-2", "aria-label": "Open SQLite admin UI to browse and edit database", children: [_jsx(Database, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "SQLite Admin" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_user_management_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/user_management", className: "cls_sidebar_layout_user_management_link flex items-center gap-2", "aria-label": "Open User Management to manage users, roles, and permissions", children: [_jsx(User, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "User Management" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_rbac_test_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/rbac_test", className: "cls_sidebar_layout_rbac_test_link flex items-center gap-2", "aria-label": "Test RBAC and HRBAC access control", children: [_jsx(ShieldCheck, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "RBAC/HRBAC Test" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_profile_stamp_test_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/profile_stamp_test", className: "cls_sidebar_layout_profile_stamp_test_link flex items-center gap-2", "aria-label": "Test ProfileStamp component", children: [_jsx(CircleUserRound, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "ProfileStamp Test" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_app_user_data_test_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/app_user_data_test", className: "cls_sidebar_layout_app_user_data_test_link flex items-center gap-2", "aria-label": "Test app_user_data JSON storage", children: [_jsx(FileJson, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "App User Data Test" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_create_firm_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/create_firm", className: "cls_sidebar_layout_create_firm_link flex items-center gap-2", "aria-label": "Test create firm flow", children: [_jsx(Building2, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Create Firm" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_edit_firm_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/edit_firm", className: "cls_sidebar_layout_edit_firm_link flex items-center gap-2", "aria-label": "Test branding editor for firm", children: [_jsx(Palette, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Edit Firm" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_relationships_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/relationships", className: "cls_sidebar_layout_relationships_link flex items-center gap-2", "aria-label": "Test relationship accounts", children: [_jsx(User, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Relationships" })] }) }) })] })] }), _jsxs(SidebarGroup, { className: "cls_sidebar_layout_testing_group", children: [_jsx(SidebarGroupLabel, { className: "cls_sidebar_layout_group_label", children: "Testing" }), _jsx(SidebarMenu, { className: "cls_sidebar_layout_testing_menu", children: _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_test_scenarios_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/test_scenarios", className: "cls_sidebar_layout_test_scenarios_link flex items-center gap-2", "aria-label": "Test scenarios", children: [_jsx(Settings2, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Test Scenarios" })] }) }) }) })] }), _jsxs(SidebarGroup, { className: "cls_sidebar_layout_auto_test_group", children: [_jsx(SidebarGroupLabel, { className: "cls_sidebar_layout_group_label", children: "Auto Tests" }), _jsx(SidebarMenu, { className: "cls_sidebar_layout_auto_test_menu", children: _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_auto_test_runner_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/auto_test", className: "cls_sidebar_layout_auto_test_runner_link flex items-center gap-2", "aria-label": "Run automated tests", children: [_jsx(Play, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Auto Test Runner" })] }) }) }) })] }), _jsx(ProfilePicMenu, { variant: "sidebar", avatar_size: "sm", className: "cls_sidebar_layout_profile_menu", sidebar_group_label: "Account" }), _jsxs(SidebarGroup, { className: "cls_sidebar_layout_resources_group", children: [_jsx(SidebarGroupLabel, { className: "cls_sidebar_layout_group_label", children: "Resources" }), _jsxs(SidebarMenu, { className: "cls_sidebar_layout_resources_menu", children: [_jsx(SidebarMenuItem, { className: "cls_sidebar_layout_storybook_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs("a", { href: "http://localhost:6006", target: "_blank", rel: "noopener noreferrer", className: "cls_sidebar_layout_storybook_link flex items-center gap-2", "aria-label": "Open Storybook preview for reusable components", children: [_jsx(BookOpen, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Storybook" }), _jsx(ExternalLink, { className: "ml-auto h-3 w-3", "aria-hidden": "true" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_docs_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs("a", { href: "https://ui.shadcn.com/docs", target: "_blank", rel: "noopener noreferrer", className: "cls_sidebar_layout_docs_link flex items-center gap-2", "aria-label": "Review shadcn documentation for styling guidance", children: [_jsx(BookOpen, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Shadcn docs" }), _jsx(ExternalLink, { className: "ml-auto h-3 w-3", "aria-hidden": "true" })] }) }) })] })] })] })] }), _jsxs(SidebarInset, { className: "cls_sidebar_layout_inset", children: [_jsxs("header", { className: "cls_sidebar_layout_main_header flex h-16 shrink-0 items-center gap-2 border-b px-4", children: [_jsx(SidebarTrigger, { className: "cls_sidebar_layout_trigger" }), _jsx("div", { className: "cls_sidebar_layout_main_header_content flex flex-1 items-center gap-2", children: _jsx("h2", { className: "cls_sidebar_layout_main_title text-lg font-semibold text-foreground", children: "hazo reusable ui library workspace" }) }), _jsx(ProfilePicMenu, { className: "cls_sidebar_layout_auth_status", avatar_size: "sm" })] }), _jsx("main", { className: "cls_sidebar_layout_main_content flex flex-1 items-center justify-center p-6", children: children })] })] }) }));
|
|
15
20
|
}
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { HazoAuthTheme } from "../../../../theme/theme_types";
|
|
2
2
|
type TwoColumnAuthLayoutProps = {
|
|
3
|
-
|
|
4
|
-
imageAlt: string;
|
|
5
|
-
imageBackgroundColor?: string;
|
|
3
|
+
theme?: HazoAuthTheme;
|
|
6
4
|
formContent: React.ReactNode;
|
|
7
5
|
className?: string;
|
|
8
|
-
visualPanelClassName?: string;
|
|
9
6
|
formContainerClassName?: string;
|
|
10
7
|
};
|
|
11
|
-
export declare function TwoColumnAuthLayout({
|
|
8
|
+
export declare function TwoColumnAuthLayout({ theme, formContent, className, formContainerClassName, }: TwoColumnAuthLayoutProps): import("react/jsx-runtime").JSX.Element;
|
|
12
9
|
export {};
|
|
13
10
|
//# sourceMappingURL=two_column_auth_layout.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"two_column_auth_layout.d.ts","sourceRoot":"","sources":["../../../../../src/components/layouts/shared/components/two_column_auth_layout.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"two_column_auth_layout.d.ts","sourceRoot":"","sources":["../../../../../src/components/layouts/shared/components/two_column_auth_layout.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAGnE,KAAK,wBAAwB,GAAG;IAC9B,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC,CAAC;AAGF,wBAAgB,mBAAmB,CAAC,EAClC,KAAK,EACL,WAAW,EACX,SAAS,EACT,sBAAsB,GACvB,EAAE,wBAAwB,2CAkD1B"}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
// file_description: reusable two-column authentication layout shell that combines visual panel and form content
|
|
3
|
-
// section: imports
|
|
4
|
-
import { VisualPanel } from "./visual_panel.js";
|
|
5
2
|
// section: component
|
|
6
|
-
export function TwoColumnAuthLayout({
|
|
7
|
-
|
|
3
|
+
export function TwoColumnAuthLayout({ theme, formContent, className, formContainerClassName, }) {
|
|
4
|
+
const isSplit = (theme === null || theme === void 0 ? void 0 : theme.layout) === "split";
|
|
5
|
+
if (isSplit && (theme === null || theme === void 0 ? void 0 : theme.brandPanel)) {
|
|
6
|
+
const { backgroundGradient, logoSrc, tagline } = theme.brandPanel;
|
|
7
|
+
return (_jsxs("div", { className: `cls_two_column_auth_layout grid w-full max-w-5xl grid-cols-1 overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm md:grid-cols-2 md:min-h-[520px] ${className !== null && className !== void 0 ? className : ""}`, children: [_jsxs("div", { className: "cls_auth_brand_panel hidden md:flex flex-col items-center justify-center gap-6 p-10", style: { background: backgroundGradient !== null && backgroundGradient !== void 0 ? backgroundGradient : "linear-gradient(135deg, #475569, #64748B)" }, children: [logoSrc && (_jsx("img", { src: logoSrc, alt: "Brand logo", className: "cls_auth_brand_panel_logo h-16 w-auto object-contain" })), tagline && (_jsx("p", { className: "cls_auth_brand_panel_tagline text-center text-xl font-semibold text-white", children: tagline }))] }), _jsx("div", { className: `cls_two_column_auth_layout_form_container flex flex-col gap-6 p-8 ${formContainerClassName !== null && formContainerClassName !== void 0 ? formContainerClassName : ""}`, children: formContent })] }));
|
|
8
|
+
}
|
|
9
|
+
// Centered layout (default): just the form panel
|
|
10
|
+
return (_jsx("div", { className: `cls_two_column_auth_layout w-full max-w-md overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm ${className !== null && className !== void 0 ? className : ""}`, children: _jsx("div", { className: `cls_two_column_auth_layout_form_container flex flex-col gap-6 p-8 ${formContainerClassName !== null && formContainerClassName !== void 0 ? formContainerClassName : ""}`, children: formContent }) }));
|
|
8
11
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface OTPRequestFormProps {
|
|
3
|
+
on_sent?: (email: string) => void;
|
|
4
|
+
api_base?: string;
|
|
5
|
+
email_label?: string;
|
|
6
|
+
submit_label?: string;
|
|
7
|
+
pending_label?: string;
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function OTPRequestForm({ on_sent, api_base, email_label, submit_label, pending_label, className, }: OTPRequestFormProps): React.ReactElement;
|
|
11
|
+
//# sourceMappingURL=OTPRequestForm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OTPRequestForm.d.ts","sourceRoot":"","sources":["../../../src/components/otp/OTPRequestForm.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,QAA2B,EAC3B,WAA6B,EAC7B,YAA0B,EAC1B,aAA0B,EAC1B,SAAS,GACV,EAAE,mBAAmB,GAAG,KAAK,CAAC,YAAY,CAsE1C"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Button } from "../ui/button.js";
|
|
5
|
+
import { Input } from "../ui/input.js";
|
|
6
|
+
import { Label } from "../ui/label.js";
|
|
7
|
+
export function OTPRequestForm({ on_sent, api_base = "/api/hazo_auth", email_label = "Email address", submit_label = "Send code", pending_label = "Sending…", className, }) {
|
|
8
|
+
const [email, set_email] = React.useState("");
|
|
9
|
+
const [pending, set_pending] = React.useState(false);
|
|
10
|
+
const [error, set_error] = React.useState(null);
|
|
11
|
+
async function on_submit(ev) {
|
|
12
|
+
var _a;
|
|
13
|
+
ev.preventDefault();
|
|
14
|
+
set_error(null);
|
|
15
|
+
set_pending(true);
|
|
16
|
+
try {
|
|
17
|
+
const res = await fetch(`${api_base}/otp/request`, {
|
|
18
|
+
method: "POST",
|
|
19
|
+
headers: { "content-type": "application/json" },
|
|
20
|
+
body: JSON.stringify({ email }),
|
|
21
|
+
});
|
|
22
|
+
if (res.status === 429) {
|
|
23
|
+
const body = (await res.json().catch(() => ({})));
|
|
24
|
+
const wait = (_a = body.retry_after_seconds) !== null && _a !== void 0 ? _a : 0;
|
|
25
|
+
set_error(`Too many requests. Try again in ${wait}s.`);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (!res.ok) {
|
|
29
|
+
set_error("Could not send code. Please check the email address and try again.");
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
on_sent === null || on_sent === void 0 ? void 0 : on_sent(email);
|
|
33
|
+
}
|
|
34
|
+
catch (_b) {
|
|
35
|
+
set_error("Network error. Please try again.");
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
set_pending(false);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return (_jsxs("form", { onSubmit: on_submit, className: className, "aria-label": "Request sign-in code", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "otp-email", children: email_label }), _jsx(Input, { id: "otp-email", name: "email", type: "email", autoComplete: "email", required: true, value: email, onChange: (e) => set_email(e.target.value), disabled: pending })] }), error && (_jsx("p", { role: "alert", className: "mt-3 text-sm text-destructive", children: error })), _jsx(Button, { type: "submit", disabled: pending || email.length === 0, className: "mt-4 w-full", children: pending ? pending_label : submit_label })] }));
|
|
42
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface OTPVerifyFormProps {
|
|
3
|
+
email: string;
|
|
4
|
+
on_success?: (auth: {
|
|
5
|
+
user_id: string;
|
|
6
|
+
email: string;
|
|
7
|
+
}) => void;
|
|
8
|
+
api_base?: string;
|
|
9
|
+
submit_label?: string;
|
|
10
|
+
pending_label?: string;
|
|
11
|
+
resend_label?: string;
|
|
12
|
+
className?: string;
|
|
13
|
+
redirect_url?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function OTPVerifyForm({ email, on_success, api_base, submit_label, pending_label, resend_label, className, redirect_url, }: OTPVerifyFormProps): React.ReactElement;
|
|
16
|
+
//# sourceMappingURL=OTPVerifyForm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OTPVerifyForm.d.ts","sourceRoot":"","sources":["../../../src/components/otp/OTPVerifyForm.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,UAAU,EACV,QAA2B,EAC3B,YAAuB,EACvB,aAA4B,EAC5B,YAA4B,EAC5B,SAAS,EACT,YAAY,GACb,EAAE,kBAAkB,GAAG,KAAK,CAAC,YAAY,CAoIzC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Button } from "../ui/button.js";
|
|
5
|
+
import { InputOTP, InputOTPGroup, InputOTPSlot } from "../ui/input-otp.js";
|
|
6
|
+
export function OTPVerifyForm({ email, on_success, api_base = "/api/hazo_auth", submit_label = "Verify", pending_label = "Verifying…", resend_label = "Resend code", className, redirect_url, }) {
|
|
7
|
+
const [code, set_code] = React.useState("");
|
|
8
|
+
const [pending, set_pending] = React.useState(false);
|
|
9
|
+
const [error, set_error] = React.useState(null);
|
|
10
|
+
const [resend_state, set_resend_state] = React.useState("idle");
|
|
11
|
+
const [resend_wait, set_resend_wait] = React.useState(0);
|
|
12
|
+
async function on_submit(ev) {
|
|
13
|
+
ev.preventDefault();
|
|
14
|
+
if (code.length !== 6)
|
|
15
|
+
return;
|
|
16
|
+
set_error(null);
|
|
17
|
+
set_pending(true);
|
|
18
|
+
try {
|
|
19
|
+
const res = await fetch(`${api_base}/otp/verify`, {
|
|
20
|
+
method: "POST",
|
|
21
|
+
headers: { "content-type": "application/json" },
|
|
22
|
+
body: JSON.stringify({ email, code }),
|
|
23
|
+
});
|
|
24
|
+
if (!res.ok) {
|
|
25
|
+
set_error("Invalid or expired code.");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const body = (await res.json());
|
|
29
|
+
if (body.ok) {
|
|
30
|
+
on_success === null || on_success === void 0 ? void 0 : on_success({ user_id: body.user_id, email: body.email });
|
|
31
|
+
if (redirect_url) {
|
|
32
|
+
window.location.href = redirect_url;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
set_error("Invalid or expired code.");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch (_a) {
|
|
40
|
+
set_error("Network error. Please try again.");
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
set_pending(false);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async function on_resend() {
|
|
47
|
+
var _a;
|
|
48
|
+
set_resend_state("sending");
|
|
49
|
+
set_error(null);
|
|
50
|
+
try {
|
|
51
|
+
const res = await fetch(`${api_base}/otp/request`, {
|
|
52
|
+
method: "POST",
|
|
53
|
+
headers: { "content-type": "application/json" },
|
|
54
|
+
body: JSON.stringify({ email }),
|
|
55
|
+
});
|
|
56
|
+
if (res.status === 429) {
|
|
57
|
+
const body = (await res.json().catch(() => ({})));
|
|
58
|
+
set_resend_state("rate_limited");
|
|
59
|
+
set_resend_wait((_a = body.retry_after_seconds) !== null && _a !== void 0 ? _a : 0);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (!res.ok) {
|
|
63
|
+
set_error("Could not resend code.");
|
|
64
|
+
set_resend_state("idle");
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
set_resend_state("sent");
|
|
68
|
+
}
|
|
69
|
+
catch (_b) {
|
|
70
|
+
set_error("Network error.");
|
|
71
|
+
set_resend_state("idle");
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return (_jsxs("form", { onSubmit: on_submit, className: className, "aria-label": "Enter sign-in code", children: [_jsxs("p", { className: "text-sm text-muted-foreground mb-3", children: ["Enter the 6-digit code sent to ", _jsx("strong", { children: email }), "."] }), _jsx(InputOTP, { maxLength: 6, value: code, onChange: (v) => set_code(v), inputMode: "numeric", autoComplete: "one-time-code", disabled: pending, "aria-label": "One-time code", children: _jsxs(InputOTPGroup, { children: [_jsx(InputOTPSlot, { index: 0 }), _jsx(InputOTPSlot, { index: 1 }), _jsx(InputOTPSlot, { index: 2 }), _jsx(InputOTPSlot, { index: 3 }), _jsx(InputOTPSlot, { index: 4 }), _jsx(InputOTPSlot, { index: 5 })] }) }), error && (_jsx("p", { role: "alert", className: "mt-3 text-sm text-destructive", children: error })), _jsx(Button, { type: "submit", disabled: pending || code.length !== 6, className: "mt-4 w-full", children: pending ? pending_label : submit_label }), _jsx("div", { className: "mt-3 text-sm text-center", children: resend_state === "sent" ? (_jsx("span", { className: "text-muted-foreground", children: "Code sent." })) : resend_state === "rate_limited" ? (_jsxs("span", { className: "text-muted-foreground", children: ["Wait ", resend_wait, "s before resending."] })) : (_jsx("button", { type: "button", onClick: on_resend, disabled: resend_state === "sending", className: "underline text-muted-foreground hover:text-foreground", children: resend_label })) })] }));
|
|
75
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/otp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,YAAY,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
declare const InputOTP: React.ForwardRefExoticComponent<(Omit<Omit<React.InputHTMLAttributes<HTMLInputElement>, "value" | "onChange" | "maxLength" | "textAlign" | "onComplete" | "pushPasswordManagerStrategy" | "pasteTransformer" | "containerClassName" | "noScriptCSSFallback"> & {
|
|
3
|
+
value?: string;
|
|
4
|
+
onChange?: (newValue: string) => unknown;
|
|
5
|
+
maxLength: number;
|
|
6
|
+
textAlign?: "left" | "center" | "right";
|
|
7
|
+
onComplete?: (...args: any[]) => unknown;
|
|
8
|
+
pushPasswordManagerStrategy?: "increase-width" | "none";
|
|
9
|
+
pasteTransformer?: (pasted: string) => string;
|
|
10
|
+
containerClassName?: string;
|
|
11
|
+
noScriptCSSFallback?: string | null;
|
|
12
|
+
} & {
|
|
13
|
+
render: (props: import("input-otp").RenderProps) => React.ReactNode;
|
|
14
|
+
children?: never;
|
|
15
|
+
} & React.RefAttributes<HTMLInputElement>, "ref"> | Omit<Omit<React.InputHTMLAttributes<HTMLInputElement>, "value" | "onChange" | "maxLength" | "textAlign" | "onComplete" | "pushPasswordManagerStrategy" | "pasteTransformer" | "containerClassName" | "noScriptCSSFallback"> & {
|
|
16
|
+
value?: string;
|
|
17
|
+
onChange?: (newValue: string) => unknown;
|
|
18
|
+
maxLength: number;
|
|
19
|
+
textAlign?: "left" | "center" | "right";
|
|
20
|
+
onComplete?: (...args: any[]) => unknown;
|
|
21
|
+
pushPasswordManagerStrategy?: "increase-width" | "none";
|
|
22
|
+
pasteTransformer?: (pasted: string) => string;
|
|
23
|
+
containerClassName?: string;
|
|
24
|
+
noScriptCSSFallback?: string | null;
|
|
25
|
+
} & {
|
|
26
|
+
render?: never;
|
|
27
|
+
children: React.ReactNode;
|
|
28
|
+
} & React.RefAttributes<HTMLInputElement>, "ref">) & React.RefAttributes<HTMLInputElement>>;
|
|
29
|
+
declare const InputOTPGroup: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
30
|
+
declare const InputOTPSlot: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
|
|
31
|
+
index: number;
|
|
32
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
33
|
+
declare const InputOTPSeparator: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
34
|
+
export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator };
|
|
35
|
+
//# sourceMappingURL=input-otp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-otp.d.ts","sourceRoot":"","sources":["../../../src/components/ui/input-otp.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,QAAA,MAAM,QAAQ;;;;;kBAUoC,GAAG;;;;;;;;;;;;;kBAAH,GAAG;;;;;;;;2FAGnD,CAAC;AAGH,QAAA,MAAM,aAAa,mKAKjB,CAAC;AAGH,QAAA,MAAM,YAAY;WAEiC,MAAM;wCAyBvD,CAAC;AAGH,QAAA,MAAM,iBAAiB,mKAOrB,CAAC;AAGH,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,iBAAiB,EAAE,CAAC"}
|