hazo_auth 6.1.1 → 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 +163 -8
- package/SETUP_CHECKLIST.md +148 -0
- package/cli-src/lib/auth/nextauth_config.ts +101 -1
- 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 +0 -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/register_config.server.ts +11 -31
- package/cli-src/lib/reset_password_config.server.ts +0 -31
- package/cli-src/lib/services/oauth_service.ts +197 -0
- package/config/hazo_auth_config.example.ini +38 -41
- 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 +13 -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 +8 -1
- package/dist/components/layouts/otp/index.d.ts.map +1 -1
- package/dist/components/layouts/otp/index.js +4 -2
- 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.js +1 -1
- 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/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/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 +0 -3
- package/dist/lib/login_config.server.d.ts.map +1 -1
- package/dist/lib/login_config.server.js +0 -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/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/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/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/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 +1 -0
- package/dist/server/routes/index.d.ts.map +1 -1
- package/dist/server/routes/index.js +1 -0
- 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_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 +16 -2
- package/dist/server_pages/otp.d.ts.map +1 -1
- package/dist/server_pages/otp.js +10 -3
- 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 +19 -2
|
@@ -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;
|
|
@@ -16,5 +16,5 @@ export function SidebarLayoutWrapper({ children }) {
|
|
|
16
16
|
const pathname = usePathname();
|
|
17
17
|
const login_paths = ["/hazo_auth/login", "/hazo_auth/login_variations"];
|
|
18
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("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_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 })] })] }) }));
|
|
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 })] })] }) }));
|
|
20
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,18 @@
|
|
|
1
|
+
export interface ConsentState {
|
|
2
|
+
necessary: true;
|
|
3
|
+
functional: boolean;
|
|
4
|
+
analytics: boolean;
|
|
5
|
+
marketing: boolean;
|
|
6
|
+
version: 1;
|
|
7
|
+
}
|
|
8
|
+
export declare const HAZO_CONSENT_COOKIE_NAME = "hazo_consent_v1";
|
|
9
|
+
/**
|
|
10
|
+
* Parse a URL-encoded JSON cookie value into a ConsentState.
|
|
11
|
+
* Returns null if the value is invalid or has an unexpected shape.
|
|
12
|
+
*/
|
|
13
|
+
export declare function parse_consent(value: string): ConsentState | null;
|
|
14
|
+
/**
|
|
15
|
+
* Serialize a ConsentState to a URL-encoded JSON string suitable for cookie storage.
|
|
16
|
+
*/
|
|
17
|
+
export declare function serialize_consent(state: ConsentState): string;
|
|
18
|
+
//# sourceMappingURL=consent_state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consent_state.d.ts","sourceRoot":"","sources":["../../src/consent/consent_state.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,IAAI,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,CAAC,CAAC;CACZ;AAED,eAAO,MAAM,wBAAwB,oBAAoB,CAAC;AAE1D;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAgBhE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAE7D"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// file_description: isomorphic consent state types, parser, and serializer — no Node.js or browser-specific imports
|
|
2
|
+
export const HAZO_CONSENT_COOKIE_NAME = "hazo_consent_v1";
|
|
3
|
+
/**
|
|
4
|
+
* Parse a URL-encoded JSON cookie value into a ConsentState.
|
|
5
|
+
* Returns null if the value is invalid or has an unexpected shape.
|
|
6
|
+
*/
|
|
7
|
+
export function parse_consent(value) {
|
|
8
|
+
try {
|
|
9
|
+
const decoded = decodeURIComponent(value);
|
|
10
|
+
const parsed = JSON.parse(decoded);
|
|
11
|
+
// Validate shape
|
|
12
|
+
if (parsed.version !== 1 ||
|
|
13
|
+
parsed.necessary !== true ||
|
|
14
|
+
typeof parsed.functional !== "boolean" ||
|
|
15
|
+
typeof parsed.analytics !== "boolean" ||
|
|
16
|
+
typeof parsed.marketing !== "boolean")
|
|
17
|
+
return null;
|
|
18
|
+
return parsed;
|
|
19
|
+
}
|
|
20
|
+
catch (_a) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Serialize a ConsentState to a URL-encoded JSON string suitable for cookie storage.
|
|
26
|
+
*/
|
|
27
|
+
export function serialize_consent(state) {
|
|
28
|
+
return encodeURIComponent(JSON.stringify(state));
|
|
29
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ConsentState } from "./consent_state.js";
|
|
2
|
+
interface CookieConsentBannerProps {
|
|
3
|
+
enableGTM?: boolean;
|
|
4
|
+
gtmContainerId?: string;
|
|
5
|
+
onChange?: (state: ConsentState) => void;
|
|
6
|
+
/** Default: "bottom" */
|
|
7
|
+
position?: "bottom" | "top";
|
|
8
|
+
}
|
|
9
|
+
export declare function CookieConsentBanner({ enableGTM, gtmContainerId, onChange, position, }: CookieConsentBannerProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=cookie_consent_banner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookie_consent_banner.d.ts","sourceRoot":"","sources":["../../src/consent/cookie_consent_banner.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAKpD,UAAU,wBAAwB;IAChC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IACzC,wBAAwB;IACxB,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAC;CAC7B;AAED,wBAAgB,mBAAmB,CAAC,EAClC,SAAS,EACT,cAAc,EACd,QAAQ,EACR,QAAmB,GACpB,EAAE,wBAAwB,2CA4E1B"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
// file_description: cookie consent banner — shown until the user makes a consent choice; renders manage modal afterward
|
|
4
|
+
import { useEffect, useRef } from "react";
|
|
5
|
+
import { useConsent } from "./use_consent.js";
|
|
6
|
+
import { ConsentManageModal } from "./manage_modal.js";
|
|
7
|
+
import { to_gtm_signals, gtm_default_payload } from "./gtm_mapping.js";
|
|
8
|
+
export function CookieConsentBanner({ enableGTM, gtmContainerId, onChange, position = "bottom", }) {
|
|
9
|
+
const { consent, set_consent, open_manager } = useConsent();
|
|
10
|
+
const gtm_default_pushed = useRef(false);
|
|
11
|
+
// Push consent_default to GTM on first mount (before user has consented)
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (!enableGTM || !gtmContainerId)
|
|
14
|
+
return;
|
|
15
|
+
if (gtm_default_pushed.current)
|
|
16
|
+
return;
|
|
17
|
+
gtm_default_pushed.current = true;
|
|
18
|
+
window.dataLayer = window.dataLayer || [];
|
|
19
|
+
window.dataLayer.push(Object.assign({ event: "consent_default" }, gtm_default_payload()));
|
|
20
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
21
|
+
}, []); // only on mount
|
|
22
|
+
// Push consent_update to GTM whenever the user's consent changes
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
if (!consent)
|
|
25
|
+
return; // no state yet — don't push
|
|
26
|
+
onChange === null || onChange === void 0 ? void 0 : onChange(consent);
|
|
27
|
+
if (enableGTM && gtmContainerId) {
|
|
28
|
+
window.dataLayer = window.dataLayer || [];
|
|
29
|
+
window.dataLayer.push(Object.assign({ event: "consent_update" }, to_gtm_signals(consent)));
|
|
30
|
+
}
|
|
31
|
+
// onChange is intentionally excluded to avoid infinite loops with unstable prop refs
|
|
32
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
33
|
+
}, [consent, enableGTM, gtmContainerId]);
|
|
34
|
+
// Consent already captured — only render the modal so open_manager() still works
|
|
35
|
+
if (consent !== null) {
|
|
36
|
+
return _jsx(ConsentManageModal, {});
|
|
37
|
+
}
|
|
38
|
+
const positionClass = position === "top" ? "top-0" : "bottom-0";
|
|
39
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: `fixed ${positionClass} left-0 right-0 z-40 bg-primary text-primary-foreground p-4 flex flex-wrap items-center gap-3 justify-between`, children: [_jsx("p", { className: "text-sm flex-1 min-w-[200px]", children: "We use cookies to improve your experience. By continuing, you agree to our use of cookies." }), _jsxs("div", { className: "flex gap-2 flex-wrap", children: [_jsx("button", { onClick: () => set_consent({ functional: false, analytics: false, marketing: false }), className: "px-3 py-1.5 text-xs bg-primary-foreground/20 hover:bg-primary-foreground/30 rounded text-primary-foreground", children: "Decline all" }), _jsx("button", { onClick: () => open_manager(), className: "px-3 py-1.5 text-xs bg-primary-foreground/20 hover:bg-primary-foreground/30 rounded text-primary-foreground", children: "Manage" }), _jsx("button", { onClick: () => set_consent({ functional: true, analytics: true, marketing: true }), className: "px-3 py-1.5 text-xs bg-primary-foreground rounded text-primary font-medium", children: "Accept all" })] })] }), _jsx(ConsentManageModal, {})] }));
|
|
40
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ConsentState } from "./consent_state";
|
|
2
|
+
export type GtmSignal = "security_storage" | "functionality_storage" | "personalization_storage" | "analytics_storage" | "ad_storage" | "ad_user_data" | "ad_personalization";
|
|
3
|
+
/**
|
|
4
|
+
* Maps a ConsentState to GTM consent signals.
|
|
5
|
+
* security_storage is always granted; other signals follow the user's category choices.
|
|
6
|
+
*/
|
|
7
|
+
export declare function to_gtm_signals(state: ConsentState): Record<GtmSignal, "granted" | "denied">;
|
|
8
|
+
/**
|
|
9
|
+
* Default GTM consent payload before the user has made a choice.
|
|
10
|
+
* security_storage is granted; all others are denied.
|
|
11
|
+
*/
|
|
12
|
+
export declare function gtm_default_payload(): Record<GtmSignal, "granted" | "denied">;
|
|
13
|
+
//# sourceMappingURL=gtm_mapping.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gtm_mapping.d.ts","sourceRoot":"","sources":["../../src/consent/gtm_mapping.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpD,MAAM,MAAM,SAAS,GACjB,kBAAkB,GAClB,uBAAuB,GACvB,yBAAyB,GACzB,mBAAmB,GACnB,YAAY,GACZ,cAAc,GACd,oBAAoB,CAAC;AAEzB;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAAC,SAAS,EAAE,SAAS,GAAG,QAAQ,CAAC,CAU3F;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAAC,SAAS,EAAE,SAAS,GAAG,QAAQ,CAAC,CAU7E"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maps a ConsentState to GTM consent signals.
|
|
3
|
+
* security_storage is always granted; other signals follow the user's category choices.
|
|
4
|
+
*/
|
|
5
|
+
export function to_gtm_signals(state) {
|
|
6
|
+
return {
|
|
7
|
+
security_storage: "granted", // always granted
|
|
8
|
+
functionality_storage: state.functional ? "granted" : "denied",
|
|
9
|
+
personalization_storage: state.functional ? "granted" : "denied",
|
|
10
|
+
analytics_storage: state.analytics ? "granted" : "denied",
|
|
11
|
+
ad_storage: state.marketing ? "granted" : "denied",
|
|
12
|
+
ad_user_data: state.marketing ? "granted" : "denied",
|
|
13
|
+
ad_personalization: state.marketing ? "granted" : "denied",
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Default GTM consent payload before the user has made a choice.
|
|
18
|
+
* security_storage is granted; all others are denied.
|
|
19
|
+
*/
|
|
20
|
+
export function gtm_default_payload() {
|
|
21
|
+
return {
|
|
22
|
+
security_storage: "granted",
|
|
23
|
+
functionality_storage: "denied",
|
|
24
|
+
personalization_storage: "denied",
|
|
25
|
+
analytics_storage: "denied",
|
|
26
|
+
ad_storage: "denied",
|
|
27
|
+
ad_user_data: "denied",
|
|
28
|
+
ad_personalization: "denied",
|
|
29
|
+
};
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/consent/index.ts"],"names":[],"mappings":"AACA,cAAc,iBAAiB,CAAC;AAChC,cAAc,yBAAyB,CAAC;AACxC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// file_description: barrel export for the hazo_auth consent module
|
|
2
|
+
export * from "./consent_state.js";
|
|
3
|
+
export * from "./cookie_consent_banner.js";
|
|
4
|
+
export * from "./use_consent.js";
|
|
5
|
+
export * from "./read_consent.js";
|
|
6
|
+
export * from "./gtm_mapping.js";
|
|
7
|
+
export * from "./manage_modal.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manage_modal.d.ts","sourceRoot":"","sources":["../../src/consent/manage_modal.tsx"],"names":[],"mappings":"AAOA,wBAAgB,kBAAkB,4CA0GjC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
// file_description: modal dialog for managing individual cookie consent categories
|
|
4
|
+
import { useEffect, useState } from "react";
|
|
5
|
+
import * as Dialog from "@radix-ui/react-dialog";
|
|
6
|
+
import { useConsent } from "./use_consent.js";
|
|
7
|
+
export function ConsentManageModal() {
|
|
8
|
+
const { consent, set_consent } = useConsent();
|
|
9
|
+
const [open, setOpen] = useState(false);
|
|
10
|
+
const [local, setLocal] = useState({
|
|
11
|
+
functional: false,
|
|
12
|
+
analytics: false,
|
|
13
|
+
marketing: false,
|
|
14
|
+
});
|
|
15
|
+
// Listen for the open event dispatched by open_manager()
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
const handle = () => {
|
|
18
|
+
setLocal({
|
|
19
|
+
functional: !!(consent === null || consent === void 0 ? void 0 : consent.functional),
|
|
20
|
+
analytics: !!(consent === null || consent === void 0 ? void 0 : consent.analytics),
|
|
21
|
+
marketing: !!(consent === null || consent === void 0 ? void 0 : consent.marketing),
|
|
22
|
+
});
|
|
23
|
+
setOpen(true);
|
|
24
|
+
};
|
|
25
|
+
window.addEventListener("hazo_auth:open_consent_manager", handle);
|
|
26
|
+
return () => window.removeEventListener("hazo_auth:open_consent_manager", handle);
|
|
27
|
+
}, [consent]);
|
|
28
|
+
const save = () => {
|
|
29
|
+
set_consent(Object.assign(Object.assign({}, local), { necessary: true, version: 1 }));
|
|
30
|
+
setOpen(false);
|
|
31
|
+
};
|
|
32
|
+
return (_jsx(Dialog.Root, { open: open, onOpenChange: setOpen, children: _jsxs(Dialog.Portal, { children: [_jsx(Dialog.Overlay, { className: "fixed inset-0 bg-black/50 z-50" }), _jsxs(Dialog.Content, { className: "fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-background rounded-lg p-6 z-50 w-full max-w-md shadow-lg", children: [_jsx(Dialog.Title, { className: "text-lg font-semibold mb-4", children: "Cookie preferences" }), _jsxs("div", { className: "flex items-center justify-between py-3 border-b", children: [_jsxs("div", { children: [_jsx("p", { className: "font-medium", children: "Necessary" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Required for the site to function" })] }), _jsx("input", { type: "checkbox", checked: true, disabled: true, className: "h-4 w-4" })] }), _jsxs("div", { className: "flex items-center justify-between py-3 border-b", children: [_jsxs("div", { children: [_jsx("p", { className: "font-medium", children: "Functional" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Remembers your preferences" })] }), _jsx("input", { type: "checkbox", checked: local.functional, onChange: (e) => setLocal((p) => (Object.assign(Object.assign({}, p), { functional: e.target.checked }))), className: "h-4 w-4" })] }), _jsxs("div", { className: "flex items-center justify-between py-3 border-b", children: [_jsxs("div", { children: [_jsx("p", { className: "font-medium", children: "Analytics" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Helps us understand how you use the site" })] }), _jsx("input", { type: "checkbox", checked: local.analytics, onChange: (e) => setLocal((p) => (Object.assign(Object.assign({}, p), { analytics: e.target.checked }))), className: "h-4 w-4" })] }), _jsxs("div", { className: "flex items-center justify-between py-3", children: [_jsxs("div", { children: [_jsx("p", { className: "font-medium", children: "Marketing" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Used for targeted advertising" })] }), _jsx("input", { type: "checkbox", checked: local.marketing, onChange: (e) => setLocal((p) => (Object.assign(Object.assign({}, p), { marketing: e.target.checked }))), className: "h-4 w-4" })] }), _jsxs("div", { className: "mt-6 flex gap-3 justify-end", children: [_jsx("button", { className: "px-4 py-2 text-sm border rounded-md hover:bg-muted", onClick: () => setOpen(false), children: "Cancel" }), _jsx("button", { className: "px-4 py-2 text-sm bg-primary text-primary-foreground rounded-md hover:opacity-90", onClick: save, children: "Save preferences" })] })] })] }) }));
|
|
33
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ConsentState } from "./consent_state.js";
|
|
2
|
+
/** Structural type covering both `Headers` and Next.js `ReadonlyHeaders`. */
|
|
3
|
+
type AnyHeaders = {
|
|
4
|
+
get(name: string): string | null;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Reads the consent state from request headers (server-side).
|
|
8
|
+
* Returns null if the consent cookie is absent or contains invalid data.
|
|
9
|
+
*
|
|
10
|
+
* Prefix support (Phase 7): when cookie_prefix config is set, the cookie name
|
|
11
|
+
* is `${prefix}hazo_consent_v1`. Currently uses the base name only.
|
|
12
|
+
*/
|
|
13
|
+
export declare function read_consent(headers: AnyHeaders): ConsentState | null;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=read_consent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read_consent.d.ts","sourceRoot":"","sources":["../../src/consent/read_consent.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,YAAY,EAA2C,MAAM,iBAAiB,CAAC;AAE7F,6EAA6E;AAC7E,KAAK,UAAU,GAAG;IAAE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAEvD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,UAAU,GAAG,YAAY,GAAG,IAAI,CAcrE"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// file_description: server-side helper that reads consent state from request headers
|
|
2
|
+
import { HAZO_CONSENT_COOKIE_NAME, parse_consent } from "./consent_state.js";
|
|
3
|
+
/**
|
|
4
|
+
* Reads the consent state from request headers (server-side).
|
|
5
|
+
* Returns null if the consent cookie is absent or contains invalid data.
|
|
6
|
+
*
|
|
7
|
+
* Prefix support (Phase 7): when cookie_prefix config is set, the cookie name
|
|
8
|
+
* is `${prefix}hazo_consent_v1`. Currently uses the base name only.
|
|
9
|
+
*/
|
|
10
|
+
export function read_consent(headers) {
|
|
11
|
+
const cookie_header = headers.get("cookie");
|
|
12
|
+
if (!cookie_header)
|
|
13
|
+
return null;
|
|
14
|
+
const cookie_name = HAZO_CONSENT_COOKIE_NAME;
|
|
15
|
+
const match = cookie_header
|
|
16
|
+
.split(";")
|
|
17
|
+
.map((c) => c.trim())
|
|
18
|
+
.find((c) => c.startsWith(`${cookie_name}=`));
|
|
19
|
+
if (!match)
|
|
20
|
+
return null;
|
|
21
|
+
const value = match.slice(cookie_name.length + 1);
|
|
22
|
+
return parse_consent(value);
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use_consent.d.ts","sourceRoot":"","sources":["../../src/consent/use_consent.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,KAAK,YAAY,EAIlB,MAAM,iBAAiB,CAAC;AAmBzB,wBAAgB,UAAU,IAAI;IAC5B,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;IAC7B,WAAW,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IACpD,YAAY,EAAE,MAAM,IAAI,CAAC;CAC1B,CAyCA"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
// file_description: client hook to read and update the user's cookie consent state
|
|
3
|
+
import { useState, useEffect, useCallback } from "react";
|
|
4
|
+
import { HAZO_CONSENT_COOKIE_NAME, parse_consent, serialize_consent, } from "./consent_state.js";
|
|
5
|
+
function read_from_cookie() {
|
|
6
|
+
if (typeof document === "undefined")
|
|
7
|
+
return null;
|
|
8
|
+
const match = document.cookie
|
|
9
|
+
.split(";")
|
|
10
|
+
.map((c) => c.trim())
|
|
11
|
+
.find((c) => c.startsWith(`${HAZO_CONSENT_COOKIE_NAME}=`));
|
|
12
|
+
if (!match)
|
|
13
|
+
return null;
|
|
14
|
+
return parse_consent(match.slice(HAZO_CONSENT_COOKIE_NAME.length + 1));
|
|
15
|
+
}
|
|
16
|
+
function write_cookie(state) {
|
|
17
|
+
const value = serialize_consent(state);
|
|
18
|
+
const maxAge = 13 * 30 * 24 * 60 * 60; // ~13 months in seconds
|
|
19
|
+
const secure = location.protocol === "https:" ? "; Secure" : "";
|
|
20
|
+
document.cookie = `${HAZO_CONSENT_COOKIE_NAME}=${value}; Max-Age=${maxAge}; SameSite=Lax; Path=/${secure}`;
|
|
21
|
+
}
|
|
22
|
+
export function useConsent() {
|
|
23
|
+
const [consent, setConsent] = useState(null);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
// Hydrate from cookie on mount
|
|
26
|
+
setConsent(read_from_cookie());
|
|
27
|
+
// Subscribe to cross-component updates dispatched by other useConsent instances.
|
|
28
|
+
// Read state from event.detail to avoid a redundant cookie parse and prevent
|
|
29
|
+
// a double re-render when the same hook instance dispatches the event itself.
|
|
30
|
+
const handle_update = (e) => {
|
|
31
|
+
const detail = e.detail;
|
|
32
|
+
setConsent(detail);
|
|
33
|
+
};
|
|
34
|
+
window.addEventListener("hazo_auth:consent_update", handle_update);
|
|
35
|
+
return () => window.removeEventListener("hazo_auth:consent_update", handle_update);
|
|
36
|
+
}, []);
|
|
37
|
+
const set_consent = useCallback((patch) => {
|
|
38
|
+
const base = consent !== null && consent !== void 0 ? consent : {
|
|
39
|
+
necessary: true,
|
|
40
|
+
functional: false,
|
|
41
|
+
analytics: false,
|
|
42
|
+
marketing: false,
|
|
43
|
+
version: 1,
|
|
44
|
+
};
|
|
45
|
+
// necessary and version are always forced to their fixed values
|
|
46
|
+
const next = Object.assign(Object.assign(Object.assign({}, base), patch), { necessary: true, version: 1 });
|
|
47
|
+
write_cookie(next);
|
|
48
|
+
setConsent(next);
|
|
49
|
+
window.dispatchEvent(new CustomEvent("hazo_auth:consent_update", { detail: next }));
|
|
50
|
+
}, [consent]);
|
|
51
|
+
const open_manager = useCallback(() => {
|
|
52
|
+
window.dispatchEvent(new CustomEvent("hazo_auth:open_consent_manager"));
|
|
53
|
+
}, []);
|
|
54
|
+
return { consent, set_consent, open_manager };
|
|
55
|
+
}
|
|
@@ -20,6 +20,16 @@ export type NextAuthCallbackProfile = {
|
|
|
20
20
|
picture?: string;
|
|
21
21
|
email_verified?: boolean;
|
|
22
22
|
};
|
|
23
|
+
export type FacebookCallbackProfile = {
|
|
24
|
+
id?: string;
|
|
25
|
+
name?: string;
|
|
26
|
+
email?: string;
|
|
27
|
+
picture?: {
|
|
28
|
+
data?: {
|
|
29
|
+
url: string;
|
|
30
|
+
};
|
|
31
|
+
} | string;
|
|
32
|
+
};
|
|
23
33
|
/**
|
|
24
34
|
* Gets NextAuth.js configuration with enabled OAuth providers
|
|
25
35
|
* Providers are dynamically configured based on hazo_auth_config.ini settings
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nextauth_config.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/nextauth_config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAW,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"nextauth_config.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/nextauth_config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAW,MAAM,WAAW,CAAC;AAatD,MAAM,MAAM,oBAAoB,GAAG;IACjC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE;YAAE,GAAG,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,GAAG,MAAM,CAAC;CAC/C,CAAC;AAGF;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,WAAW,CA+PjD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAe7C"}
|