hazo_auth 1.6.1 → 1.6.4
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 +259 -1
- package/SETUP_CHECKLIST.md +89 -3
- package/dist/app/api/hazo_auth/me/route.d.ts +30 -1
- package/dist/app/api/hazo_auth/me/route.d.ts.map +1 -1
- package/dist/app/api/hazo_auth/me/route.js +76 -16
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +5 -0
- package/dist/client.d.ts +8 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +25 -0
- package/dist/components/layouts/email_verification/index.d.ts +2 -1
- package/dist/components/layouts/email_verification/index.d.ts.map +1 -1
- package/dist/components/layouts/email_verification/index.js +3 -2
- package/dist/components/layouts/forgot_password/index.d.ts +3 -1
- package/dist/components/layouts/forgot_password/index.d.ts.map +1 -1
- package/dist/components/layouts/forgot_password/index.js +3 -2
- package/dist/components/layouts/my_settings/components/editable_field.js +1 -1
- package/dist/components/layouts/my_settings/components/password_change_dialog.js +1 -1
- package/dist/components/layouts/my_settings/components/profile_picture_display.js +1 -1
- package/dist/components/layouts/my_settings/components/profile_picture_gravatar_tab.js +1 -1
- package/dist/components/layouts/my_settings/components/profile_picture_library_tab.js +4 -4
- package/dist/components/layouts/my_settings/components/profile_picture_upload_tab.js +4 -4
- package/dist/components/layouts/my_settings/index.js +1 -1
- package/dist/components/layouts/shared/components/profile_pic_menu.d.ts +6 -2
- package/dist/components/layouts/shared/components/profile_pic_menu.d.ts.map +1 -1
- package/dist/components/layouts/shared/components/profile_pic_menu.js +41 -6
- package/dist/components/layouts/shared/components/profile_pic_menu_wrapper.d.ts +4 -2
- package/dist/components/layouts/shared/components/profile_pic_menu_wrapper.d.ts.map +1 -1
- package/dist/components/layouts/shared/components/profile_pic_menu_wrapper.js +3 -3
- package/dist/components/layouts/shared/components/sidebar_layout_wrapper.d.ts.map +1 -1
- package/dist/components/layouts/shared/components/sidebar_layout_wrapper.js +2 -2
- package/dist/components/layouts/shared/hooks/use_auth_status.d.ts +3 -0
- package/dist/components/layouts/shared/hooks/use_auth_status.d.ts.map +1 -1
- package/dist/components/layouts/shared/hooks/use_auth_status.js +4 -0
- package/dist/lib/auth_utility_config.server.js +2 -2
- package/dist/lib/services/user_profiles_cache.d.ts +76 -0
- package/dist/lib/services/user_profiles_cache.d.ts.map +1 -0
- package/dist/lib/services/user_profiles_cache.js +141 -0
- package/dist/lib/services/user_profiles_service.d.ts +17 -0
- package/dist/lib/services/user_profiles_service.d.ts.map +1 -1
- package/dist/lib/services/user_profiles_service.js +136 -44
- package/dist/lib/user_profiles_config.server.d.ts +15 -0
- package/dist/lib/user_profiles_config.server.d.ts.map +1 -0
- package/dist/lib/user_profiles_config.server.js +23 -0
- package/hazo_auth_config.example.ini +25 -5
- package/package.json +5 -1
|
@@ -13,11 +13,12 @@ import { EMAIL_VERIFICATION_FIELD_IDS, createEmailVerificationFieldDefinitions,
|
|
|
13
13
|
import { use_email_verification, } from "./hooks/use_email_verification";
|
|
14
14
|
import { CheckCircle, XCircle, Loader2 } from "lucide-react";
|
|
15
15
|
import { AlreadyLoggedInGuard } from "../shared/components/already_logged_in_guard";
|
|
16
|
+
import Link from "next/link";
|
|
16
17
|
const ORDERED_FIELDS = [
|
|
17
18
|
EMAIL_VERIFICATION_FIELD_IDS.EMAIL,
|
|
18
19
|
];
|
|
19
20
|
// section: component
|
|
20
|
-
export default function email_verification_layout({ image_src, image_alt, image_background_color = "#f1f5f9", field_overrides, labels, button_colors, success_labels, error_labels, redirect_delay = 5, login_path = "/hazo_auth/login", data_client, already_logged_in_message, showLogoutButton = true, showReturnHomeButton = false, returnHomeButtonLabel = "Return home", returnHomePath = "/", }) {
|
|
21
|
+
export default function email_verification_layout({ image_src, image_alt, image_background_color = "#f1f5f9", field_overrides, labels, button_colors, success_labels, error_labels, redirect_delay = 5, login_path = "/hazo_auth/login", sign_in_label = "Sign in", data_client, already_logged_in_message, showLogoutButton = true, showReturnHomeButton = false, returnHomeButtonLabel = "Return home", returnHomePath = "/", }) {
|
|
21
22
|
const fieldDefinitions = createEmailVerificationFieldDefinitions(field_overrides);
|
|
22
23
|
const resolvedLabels = resolveEmailVerificationLabels(labels);
|
|
23
24
|
const resolvedButtonPalette = resolveEmailVerificationButtonPalette(button_colors);
|
|
@@ -57,5 +58,5 @@ export default function email_verification_layout({ image_src, image_alt, image_
|
|
|
57
58
|
}, children: resolvedSuccessLabels.goToLoginButton }) })] }) }) }));
|
|
58
59
|
}
|
|
59
60
|
// Error state with resend form
|
|
60
|
-
return (_jsx(AlreadyLoggedInGuard, { image_src: image_src, image_alt: image_alt, image_background_color: image_background_color, message: already_logged_in_message, showLogoutButton: showLogoutButton, showReturnHomeButton: showReturnHomeButton, returnHomeButtonLabel: returnHomeButtonLabel, returnHomePath: returnHomePath, requireEmailVerified: false, children: _jsx(TwoColumnAuthLayout, { imageSrc: image_src, imageAlt: image_alt, imageBackgroundColor: image_background_color, formContent: _jsxs(_Fragment, { children: [_jsxs("div", { className: "cls_email_verification_error_header flex flex-col items-center gap-4 text-center", children: [_jsx(XCircle, { className: "h-12 w-12 text-red-600", "aria-hidden": "true" }), _jsxs("div", { className: "cls_email_verification_error_text", children: [_jsx("h1", { className: "cls_email_verification_error_heading text-2xl font-semibold text-slate-900", children: resolvedErrorLabels.heading }), _jsx("p", { className: "cls_email_verification_error_message mt-2 text-sm text-slate-600", children: verification.errorMessage || resolvedErrorLabels.message })] })] }), _jsxs("div", { className: "cls_email_verification_resend_form", children: [_jsx(FormHeader, { heading: resolvedErrorLabels.resendFormHeading, subHeading: "Enter your email address to receive a new verification link." }), _jsxs("form", { className: "cls_email_verification_layout_form_fields flex flex-col gap-5", onSubmit: verification.handleResendSubmit, "aria-label": "Resend verification email form", children: [renderFields(verification), _jsx(FormActionButtons, { submitLabel: resolvedLabels.submitButton, cancelLabel: resolvedLabels.cancelButton, buttonPalette: resolvedButtonPalette, isSubmitDisabled: verification.isSubmitDisabled, onCancel: verification.handleCancel, submitAriaLabel: "Submit resend verification email form", cancelAriaLabel: "Cancel resend verification email form" }), verification.isSubmitting && (_jsx("div", { className: "cls_email_verification_submitting_indicator text-sm text-slate-600 text-center", children: "Sending verification email..." }))] })] })] }) }) }));
|
|
61
|
+
return (_jsx(AlreadyLoggedInGuard, { image_src: image_src, image_alt: image_alt, image_background_color: image_background_color, message: already_logged_in_message, showLogoutButton: showLogoutButton, showReturnHomeButton: showReturnHomeButton, returnHomeButtonLabel: returnHomeButtonLabel, returnHomePath: returnHomePath, requireEmailVerified: false, children: _jsx(TwoColumnAuthLayout, { imageSrc: image_src, imageAlt: image_alt, imageBackgroundColor: image_background_color, formContent: _jsxs(_Fragment, { children: [_jsxs("div", { className: "cls_email_verification_error_header flex flex-col items-center gap-4 text-center", children: [_jsx(XCircle, { className: "h-12 w-12 text-red-600", "aria-hidden": "true" }), _jsxs("div", { className: "cls_email_verification_error_text", children: [_jsx("h1", { className: "cls_email_verification_error_heading text-2xl font-semibold text-slate-900", children: resolvedErrorLabels.heading }), _jsx("p", { className: "cls_email_verification_error_message mt-2 text-sm text-slate-600", children: verification.errorMessage || resolvedErrorLabels.message })] })] }), _jsxs("div", { className: "cls_email_verification_resend_form", children: [_jsx(FormHeader, { heading: resolvedErrorLabels.resendFormHeading, subHeading: "Enter your email address to receive a new verification link." }), _jsxs("form", { className: "cls_email_verification_layout_form_fields flex flex-col gap-5", onSubmit: verification.handleResendSubmit, "aria-label": "Resend verification email form", children: [renderFields(verification), _jsx(FormActionButtons, { submitLabel: resolvedLabels.submitButton, cancelLabel: resolvedLabels.cancelButton, buttonPalette: resolvedButtonPalette, isSubmitDisabled: verification.isSubmitDisabled, onCancel: verification.handleCancel, submitAriaLabel: "Submit resend verification email form", cancelAriaLabel: "Cancel resend verification email form" }), verification.isSubmitting && (_jsx("div", { className: "cls_email_verification_submitting_indicator text-sm text-slate-600 text-center", children: "Sending verification email..." }))] }), _jsxs("div", { className: "cls_email_verification_sign_in_link mt-4 text-center text-sm text-slate-600", children: ["Already verified?", " ", _jsx(Link, { href: login_path, className: "font-medium text-slate-900 hover:underline", children: sign_in_label })] })] })] }) }) }));
|
|
61
62
|
}
|
|
@@ -8,11 +8,13 @@ export type ForgotPasswordLayoutProps<TClient = unknown> = {
|
|
|
8
8
|
labels?: LayoutLabelOverrides;
|
|
9
9
|
button_colors?: ButtonPaletteOverrides;
|
|
10
10
|
data_client: LayoutDataClient<TClient>;
|
|
11
|
+
sign_in_path?: string;
|
|
12
|
+
sign_in_label?: string;
|
|
11
13
|
alreadyLoggedInMessage?: string;
|
|
12
14
|
showLogoutButton?: boolean;
|
|
13
15
|
showReturnHomeButton?: boolean;
|
|
14
16
|
returnHomeButtonLabel?: string;
|
|
15
17
|
returnHomePath?: string;
|
|
16
18
|
};
|
|
17
|
-
export default function forgot_password_layout<TClient>({ image_src, image_alt, image_background_color, field_overrides, labels, button_colors, data_client, alreadyLoggedInMessage, showLogoutButton, showReturnHomeButton, returnHomeButtonLabel, returnHomePath, }: ForgotPasswordLayoutProps<TClient>): import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
export default function forgot_password_layout<TClient>({ image_src, image_alt, image_background_color, field_overrides, labels, button_colors, data_client, sign_in_path, sign_in_label, alreadyLoggedInMessage, showLogoutButton, showReturnHomeButton, returnHomeButtonLabel, returnHomePath, }: ForgotPasswordLayoutProps<TClient>): import("react/jsx-runtime").JSX.Element;
|
|
18
20
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layouts/forgot_password/index.tsx"],"names":[],"mappings":"AAWA,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EAC1B,MAAM,uCAAuC,CAAC;AAW/C,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layouts/forgot_password/index.tsx"],"names":[],"mappings":"AAWA,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EAC1B,MAAM,uCAAuC,CAAC;AAW/C,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAI1E,MAAM,MAAM,yBAAyB,CAAC,OAAO,GAAG,OAAO,IAAI;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,eAAe,CAAC,EAAE,uBAAuB,CAAC;IAC1C,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,aAAa,CAAC,EAAE,sBAAsB,CAAC;IACvC,WAAW,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,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;CACzB,CAAC;AASF,MAAM,CAAC,OAAO,UAAU,sBAAsB,CAAC,OAAO,EAAE,EACtD,SAAS,EACT,SAAS,EACT,sBAAkC,EAClC,eAAe,EACf,MAAM,EACN,aAAa,EACb,WAAW,EACX,YAAiC,EACjC,aAAyB,EACzB,sBAAoD,EACpD,gBAAuB,EACvB,oBAA4B,EAC5B,qBAAqC,EACrC,cAAoB,GACrB,EAAE,yBAAyB,CAAC,OAAO,CAAC,2CA+GpC"}
|
|
@@ -11,11 +11,12 @@ import { TwoColumnAuthLayout } from "../shared/components/two_column_auth_layout
|
|
|
11
11
|
import { AlreadyLoggedInGuard } from "../shared/components/already_logged_in_guard";
|
|
12
12
|
import { FORGOT_PASSWORD_FIELD_IDS, createForgotPasswordFieldDefinitions, resolveForgotPasswordButtonPalette, resolveForgotPasswordLabels, } from "./config/forgot_password_field_config";
|
|
13
13
|
import { use_forgot_password_form, } from "./hooks/use_forgot_password_form";
|
|
14
|
+
import Link from "next/link";
|
|
14
15
|
const ORDERED_FIELDS = [
|
|
15
16
|
FORGOT_PASSWORD_FIELD_IDS.EMAIL,
|
|
16
17
|
];
|
|
17
18
|
// section: component
|
|
18
|
-
export default function forgot_password_layout({ image_src, image_alt, image_background_color = "#f1f5f9", field_overrides, labels, button_colors, data_client, alreadyLoggedInMessage = "You are already logged in", showLogoutButton = true, showReturnHomeButton = false, returnHomeButtonLabel = "Return home", returnHomePath = "/", }) {
|
|
19
|
+
export default function forgot_password_layout({ image_src, image_alt, image_background_color = "#f1f5f9", field_overrides, labels, button_colors, data_client, sign_in_path = "/hazo_auth/login", sign_in_label = "Sign in", alreadyLoggedInMessage = "You are already logged in", showLogoutButton = true, showReturnHomeButton = false, returnHomeButtonLabel = "Return home", returnHomePath = "/", }) {
|
|
19
20
|
const fieldDefinitions = createForgotPasswordFieldDefinitions(field_overrides);
|
|
20
21
|
const resolvedLabels = resolveForgotPasswordLabels(labels);
|
|
21
22
|
const resolvedButtonPalette = resolveForgotPasswordButtonPalette(button_colors);
|
|
@@ -39,5 +40,5 @@ export default function forgot_password_layout({ image_src, image_alt, image_bac
|
|
|
39
40
|
return (_jsx(FormFieldWrapper, { fieldId: fieldDefinition.id, label: fieldDefinition.label, input: inputElement, errorMessage: shouldShowError }, fieldId));
|
|
40
41
|
});
|
|
41
42
|
};
|
|
42
|
-
return (_jsx(AlreadyLoggedInGuard, { image_src: image_src, image_alt: image_alt, image_background_color: image_background_color, message: alreadyLoggedInMessage, showLogoutButton: showLogoutButton, showReturnHomeButton: showReturnHomeButton, returnHomeButtonLabel: returnHomeButtonLabel, returnHomePath: returnHomePath, children: _jsx(TwoColumnAuthLayout, { imageSrc: image_src, imageAlt: image_alt, imageBackgroundColor: image_background_color, formContent: _jsxs(_Fragment, { children: [_jsx(FormHeader, { heading: resolvedLabels.heading, subHeading: resolvedLabels.subHeading }), _jsxs("form", { className: "cls_forgot_password_layout_form_fields flex flex-col gap-5", onSubmit: form.handleSubmit, "aria-label": "Forgot password form", children: [renderFields(form), _jsx(FormActionButtons, { submitLabel: resolvedLabels.submitButton, cancelLabel: resolvedLabels.cancelButton, buttonPalette: resolvedButtonPalette, isSubmitDisabled: form.isSubmitDisabled, onCancel: form.handleCancel, submitAriaLabel: "Submit forgot password form", cancelAriaLabel: "Cancel forgot password form" }), form.isSubmitting && (_jsx("div", { className: "cls_forgot_password_submitting_indicator text-sm text-slate-600 text-center", children: "Sending reset link..." }))] })] }) }) }));
|
|
43
|
+
return (_jsx(AlreadyLoggedInGuard, { image_src: image_src, image_alt: image_alt, image_background_color: image_background_color, message: alreadyLoggedInMessage, showLogoutButton: showLogoutButton, showReturnHomeButton: showReturnHomeButton, returnHomeButtonLabel: returnHomeButtonLabel, returnHomePath: returnHomePath, children: _jsx(TwoColumnAuthLayout, { imageSrc: image_src, imageAlt: image_alt, imageBackgroundColor: image_background_color, formContent: _jsxs(_Fragment, { children: [_jsx(FormHeader, { heading: resolvedLabels.heading, subHeading: resolvedLabels.subHeading }), _jsxs("form", { className: "cls_forgot_password_layout_form_fields flex flex-col gap-5", onSubmit: form.handleSubmit, "aria-label": "Forgot password form", children: [renderFields(form), _jsx(FormActionButtons, { submitLabel: resolvedLabels.submitButton, cancelLabel: resolvedLabels.cancelButton, buttonPalette: resolvedButtonPalette, isSubmitDisabled: form.isSubmitDisabled, onCancel: form.handleCancel, submitAriaLabel: "Submit forgot password form", cancelAriaLabel: "Cancel forgot password form" }), form.isSubmitting && (_jsx("div", { className: "cls_forgot_password_submitting_indicator text-sm text-slate-600 text-center", children: "Sending reset link..." }))] }), _jsxs("div", { className: "cls_forgot_password_sign_in_link mt-4 text-center text-sm text-slate-600", children: ["Remember your password?", " ", _jsx(Link, { href: sign_in_path, className: "font-medium text-slate-900 hover:underline", children: sign_in_label })] })] }) }) }));
|
|
43
44
|
}
|
|
@@ -69,5 +69,5 @@ export function EditableField({ label, value, type = "text", placeholder, onSave
|
|
|
69
69
|
handleCancel();
|
|
70
70
|
}
|
|
71
71
|
};
|
|
72
|
-
return (_jsxs("div", { className: "cls_editable_field flex flex-col gap-2", children: [_jsx(Label, { htmlFor: `editable-field-${label}`, className: "cls_editable_field_label text-sm font-medium text-
|
|
72
|
+
return (_jsxs("div", { className: "cls_editable_field flex flex-col gap-2", children: [_jsx(Label, { htmlFor: `editable-field-${label}`, className: "cls_editable_field_label text-sm font-medium text-[var(--hazo-text-secondary)]", children: label }), _jsx("div", { className: "cls_editable_field_input_container flex items-center gap-2", children: isEditing ? (_jsxs(_Fragment, { children: [_jsx(Input, { id: `editable-field-${label}`, type: type, value: editValue, onChange: (e) => setEditValue(e.target.value), onKeyDown: handleKeyDown, placeholder: placeholder, disabled: isSaving, "aria-label": ariaLabel || label, className: "cls_editable_field_input flex-1" }), _jsx(Button, { type: "button", onClick: handleSave, disabled: isSaving, variant: "ghost", size: "icon", className: "cls_editable_field_save_button text-green-600 hover:text-green-700 hover:bg-green-50", "aria-label": "Save changes", children: _jsx(CheckCircle2, { className: "h-5 w-5", "aria-hidden": "true" }) }), _jsx(Button, { type: "button", onClick: handleCancel, disabled: isSaving, variant: "ghost", size: "icon", className: "cls_editable_field_cancel_button text-red-600 hover:text-red-700 hover:bg-red-50", "aria-label": "Cancel editing", children: _jsx(XCircle, { className: "h-5 w-5", "aria-hidden": "true" }) })] })) : (_jsxs(_Fragment, { children: [_jsx(Input, { id: `editable-field-${label}`, type: type, value: value || "", readOnly: true, disabled: true, placeholder: value ? undefined : placeholder || "Not set", "aria-label": ariaLabel || label, className: "cls_editable_field_display flex-1 bg-[var(--hazo-bg-subtle)] cursor-not-allowed" }), !disabled && (_jsx(Button, { type: "button", onClick: handleEdit, variant: "ghost", size: "icon", className: "cls_editable_field_edit_button text-[var(--hazo-text-muted)] hover:text-[var(--hazo-text-secondary)] hover:bg-[var(--hazo-bg-subtle)]", "aria-label": `Edit ${label}`, children: _jsx(Pencil, { className: "h-5 w-5", "aria-hidden": "true" }) }))] })) }), error && (_jsx("p", { className: "cls_editable_field_error text-sm text-red-600", role: "alert", children: error }))] }));
|
|
73
73
|
}
|
|
@@ -123,7 +123,7 @@ export function PasswordChangeDialog({ open, onOpenChange, onSave, passwordRequi
|
|
|
123
123
|
if (errors.newPassword) {
|
|
124
124
|
setErrors(Object.assign(Object.assign({}, errors), { newPassword: undefined }));
|
|
125
125
|
}
|
|
126
|
-
}, onToggleVisibility: () => setNewPasswordVisible(!newPasswordVisible), errorMessage: errors.newPassword }) }), passwordRequirementsList.length > 0 && (_jsxs("div", { className: "cls_password_change_dialog_requirements text-xs text-
|
|
126
|
+
}, onToggleVisibility: () => setNewPasswordVisible(!newPasswordVisible), errorMessage: errors.newPassword }) }), passwordRequirementsList.length > 0 && (_jsxs("div", { className: "cls_password_change_dialog_requirements text-xs text-[var(--hazo-text-muted)]", children: [_jsx("p", { className: "cls_password_change_dialog_requirements_label font-medium mb-1", children: "Password requirements:" }), _jsx("ul", { className: "cls_password_change_dialog_requirements_list list-disc list-inside space-y-0.5", children: passwordRequirementsList.map((req, index) => (_jsx("li", { children: req }, index))) })] })), _jsx(FormFieldWrapper, { fieldId: "confirm-password", label: confirmPasswordLabel, input: _jsx(PasswordField, { inputId: "confirm-password", ariaLabel: confirmPasswordLabel, value: confirmPassword, placeholder: "Confirm your new password", autoComplete: "new-password", isVisible: confirmPasswordVisible, onChange: (value) => {
|
|
127
127
|
setConfirmPassword(value);
|
|
128
128
|
if (errors.confirmPassword) {
|
|
129
129
|
setErrors(Object.assign(Object.assign({}, errors), { confirmPassword: undefined }));
|
|
@@ -29,5 +29,5 @@ export function ProfilePictureDisplay({ profilePictureUrl, name, email, onEdit,
|
|
|
29
29
|
return "?";
|
|
30
30
|
};
|
|
31
31
|
const initials = getInitials();
|
|
32
|
-
return (_jsx("div", { className: "cls_profile_picture_display", children: _jsxs(Avatar, { className: "cls_profile_picture_display_avatar h-32 w-32", children: [_jsx(AvatarImage, { src: profilePictureUrl, alt: name ? `Profile picture of ${name}` : "Profile picture", className: "cls_profile_picture_display_image" }), _jsx(AvatarFallback, { className: "cls_profile_picture_display_fallback bg-
|
|
32
|
+
return (_jsx("div", { className: "cls_profile_picture_display", children: _jsxs(Avatar, { className: "cls_profile_picture_display_avatar h-32 w-32", children: [_jsx(AvatarImage, { src: profilePictureUrl, alt: name ? `Profile picture of ${name}` : "Profile picture", className: "cls_profile_picture_display_image" }), _jsx(AvatarFallback, { className: "cls_profile_picture_display_fallback bg-[var(--hazo-bg-emphasis)] text-[var(--hazo-text-muted)] text-3xl", children: initials })] }) }));
|
|
33
33
|
}
|
|
@@ -44,5 +44,5 @@ export function ProfilePictureGravatarTab({ email, useGravatar, onUseGravatarCha
|
|
|
44
44
|
}
|
|
45
45
|
return "?";
|
|
46
46
|
};
|
|
47
|
-
return (_jsxs("div", { className: "cls_profile_picture_gravatar_tab flex flex-col gap-4", children: [_jsxs("div", { className: "cls_profile_picture_gravatar_tab_switch flex items-center gap-3", children: [_jsx(Switch, { id: "use-gravatar", checked: useGravatar, onCheckedChange: onUseGravatarChange, disabled: disabled, className: "cls_profile_picture_gravatar_tab_switch_input", "aria-label": "Use Gravatar photo" }), _jsx(Label, { htmlFor: "use-gravatar", className: "cls_profile_picture_gravatar_tab_switch_label text-sm font-medium text-
|
|
47
|
+
return (_jsxs("div", { className: "cls_profile_picture_gravatar_tab flex flex-col gap-4", children: [_jsxs("div", { className: "cls_profile_picture_gravatar_tab_switch flex items-center gap-3", children: [_jsx(Switch, { id: "use-gravatar", checked: useGravatar, onCheckedChange: onUseGravatarChange, disabled: disabled, className: "cls_profile_picture_gravatar_tab_switch_input", "aria-label": "Use Gravatar photo" }), _jsx(Label, { htmlFor: "use-gravatar", className: "cls_profile_picture_gravatar_tab_switch_label text-sm font-medium text-[var(--hazo-text-secondary)] cursor-pointer", children: "Use Gravatar photo" })] }), _jsx("div", { className: "cls_profile_picture_gravatar_tab_preview flex flex-col items-center gap-4 p-6 border border-[var(--hazo-border)] rounded-lg bg-[var(--hazo-bg-subtle)]", children: gravatarExists === true ? (_jsxs(_Fragment, { children: [_jsxs(Avatar, { className: "cls_profile_picture_gravatar_tab_avatar h-32 w-32", children: [_jsx(AvatarImage, { src: gravatarUrlState, alt: "Gravatar profile picture", className: "cls_profile_picture_gravatar_tab_avatar_image" }), _jsx(AvatarFallback, { className: "cls_profile_picture_gravatar_tab_avatar_fallback bg-[var(--hazo-bg-emphasis)] text-[var(--hazo-text-muted)] text-3xl", children: getInitials() })] }), _jsx("p", { className: "cls_profile_picture_gravatar_tab_success_text text-sm text-[var(--hazo-text-muted)] text-center", children: "Your Gravatar is available and will be used as your profile picture." })] })) : gravatarExists === false ? (_jsx(_Fragment, { children: _jsxs("div", { className: "cls_profile_picture_gravatar_tab_no_gravatar flex flex-col items-center gap-4", children: [_jsx("div", { className: "cls_profile_picture_gravatar_tab_no_gravatar_icon flex items-center justify-center w-16 h-16 rounded-full bg-[var(--hazo-bg-muted)]", children: _jsx(Info, { className: "h-8 w-8 text-[var(--hazo-text-subtle)]", "aria-hidden": "true" }) }), _jsxs("div", { className: "cls_profile_picture_gravatar_tab_no_gravatar_content flex flex-col gap-2 text-center", children: [_jsx("p", { className: "cls_profile_picture_gravatar_tab_no_gravatar_title text-sm font-medium text-[var(--hazo-text-primary)]", children: "No Gravatar found" }), _jsxs("p", { className: "cls_profile_picture_gravatar_tab_no_gravatar_message text-sm text-[var(--hazo-text-muted)]", children: [gravatarSetupMessage, " ", _jsx("span", { className: "font-semibold", children: email }), ":"] }), _jsxs("ol", { className: "cls_profile_picture_gravatar_tab_no_gravatar_steps text-sm text-[var(--hazo-text-muted)] list-decimal list-inside space-y-1 mt-2", children: [_jsxs("li", { children: ["Visit ", _jsx("a", { href: "https://gravatar.com", target: "_blank", rel: "noopener noreferrer", className: "text-blue-600 hover:text-blue-700 underline", children: "gravatar.com" })] }), _jsxs("li", { children: ["Sign up or log in with your email: ", _jsx("span", { className: "font-mono text-xs", children: email })] }), _jsx("li", { children: "Upload a profile picture" }), _jsx("li", { children: "Return here and refresh to see your Gravatar" })] })] })] }) })) : (_jsx(_Fragment, { children: _jsx("div", { className: "cls_profile_picture_gravatar_tab_loading flex items-center justify-center", children: _jsx("p", { className: "cls_profile_picture_gravatar_tab_loading_text text-sm text-[var(--hazo-text-muted)]", children: "Checking Gravatar..." }) }) })) })] }));
|
|
48
48
|
}
|
|
@@ -124,15 +124,15 @@ export function ProfilePictureLibraryTab({ useLibrary, onUseLibraryChange, onPho
|
|
|
124
124
|
};
|
|
125
125
|
return columnMap[columns] || "grid-cols-4";
|
|
126
126
|
};
|
|
127
|
-
return (_jsxs("div", { className: "cls_profile_picture_library_tab flex flex-col gap-4", children: [_jsxs("div", { className: "cls_profile_picture_library_tab_switch flex items-center gap-3", children: [_jsx(Switch, { id: "use-library", checked: useLibrary, onCheckedChange: onUseLibraryChange, disabled: disabled, className: "cls_profile_picture_library_tab_switch_input", "aria-label": "Use library photo" }), _jsxs(Label, { htmlFor: "use-library", className: "cls_profile_picture_library_tab_switch_label text-sm font-medium text-
|
|
127
|
+
return (_jsxs("div", { className: "cls_profile_picture_library_tab flex flex-col gap-4", children: [_jsxs("div", { className: "cls_profile_picture_library_tab_switch flex items-center gap-3", children: [_jsx(Switch, { id: "use-library", checked: useLibrary, onCheckedChange: onUseLibraryChange, disabled: disabled, className: "cls_profile_picture_library_tab_switch_input", "aria-label": "Use library photo" }), _jsxs(Label, { htmlFor: "use-library", className: "cls_profile_picture_library_tab_switch_label text-sm font-medium text-[var(--hazo-text-secondary)] cursor-pointer", children: ["Use library photo", _jsx(HazoUITooltip, { message: libraryTooltipMessage, iconSize: tooltipIconSizeSmall, side: "top" })] })] }), _jsxs("div", { className: "cls_profile_picture_library_tab_content grid grid-cols-12 gap-4", children: [_jsxs("div", { className: "cls_profile_picture_library_tab_categories_container flex flex-col gap-2 col-span-3", children: [_jsx(Label, { className: "cls_profile_picture_library_tab_categories_label text-sm font-medium text-[var(--hazo-text-secondary)]", children: "Categories" }), loadingCategories ? (_jsx("div", { className: "cls_profile_picture_library_tab_loading flex items-center justify-center p-8 border border-[var(--hazo-border)] rounded-lg bg-[var(--hazo-bg-subtle)] min-h-[400px]", children: _jsx(Loader2, { className: "h-6 w-6 text-[var(--hazo-text-subtle)] animate-spin", "aria-hidden": "true" }) })) : categories.length > 0 ? (_jsx(VerticalTabs, { value: selectedCategory || categories[0], onValueChange: setSelectedCategory, className: "cls_profile_picture_library_tab_vertical_tabs", children: _jsx(VerticalTabsList, { className: "cls_profile_picture_library_tab_vertical_tabs_list w-full", children: categories.map((category) => (_jsx(VerticalTabsTrigger, { value: category, className: "cls_profile_picture_library_tab_vertical_tabs_trigger w-full justify-start", children: category }, category))) }) })) : (_jsx("div", { className: "cls_profile_picture_library_tab_no_categories flex items-center justify-center p-8 border border-[var(--hazo-border)] rounded-lg bg-[var(--hazo-bg-subtle)] min-h-[400px]", children: _jsx("p", { className: "cls_profile_picture_library_tab_no_categories_text text-sm text-[var(--hazo-text-muted)]", children: "No categories available" }) }))] }), _jsxs("div", { className: "cls_profile_picture_library_tab_photos_container flex flex-col gap-2 col-span-6", children: [_jsx(Label, { className: "cls_profile_picture_library_tab_photos_label text-sm font-medium text-[var(--hazo-text-secondary)]", children: "Photos" }), loadingPhotos ? (_jsx("div", { className: "cls_profile_picture_library_tab_photos_loading flex items-center justify-center p-8 border border-[var(--hazo-border)] rounded-lg bg-[var(--hazo-bg-subtle)] min-h-[400px]", children: _jsx(Loader2, { className: "h-6 w-6 text-[var(--hazo-text-subtle)] animate-spin", "aria-hidden": "true" }) })) : photos.length > 0 ? (_jsx("div", { className: `cls_profile_picture_library_tab_photos_grid grid ${getGridColumnsClass(libraryPhotoGridColumns)} gap-3 overflow-y-auto p-4 border border-[var(--hazo-border)] rounded-lg bg-[var(--hazo-bg-subtle)] min-h-[400px] max-h-[400px]`, children: photos.map((photoUrl) => (_jsx("button", { type: "button", onClick: () => handlePhotoClick(photoUrl), className: `
|
|
128
128
|
cls_profile_picture_library_tab_photo_thumbnail
|
|
129
129
|
aspect-square rounded-lg overflow-hidden border-2 transition-colors cursor-pointer
|
|
130
|
-
${selectedPhoto === photoUrl ? "border-blue-500 ring-2 ring-blue-200" : "border-
|
|
130
|
+
${selectedPhoto === photoUrl ? "border-blue-500 ring-2 ring-blue-200" : "border-[var(--hazo-border)] hover:border-[var(--hazo-border-emphasis)]"}
|
|
131
131
|
`, "aria-label": `Select photo ${photoUrl.split('/').pop()}`, children: _jsx("img", { src: photoUrl, alt: `Library photo ${photoUrl.split('/').pop()}`, className: "cls_profile_picture_library_tab_photo_thumbnail_image w-full h-full object-cover", loading: "lazy", onError: (e) => {
|
|
132
132
|
// Fallback if image fails to load
|
|
133
133
|
const target = e.target;
|
|
134
134
|
target.style.display = 'none';
|
|
135
|
-
} }) }, photoUrl))) })) : (_jsx("div", { className: "cls_profile_picture_library_tab_no_photos flex items-center justify-center p-8 border border-
|
|
135
|
+
} }) }, photoUrl))) })) : (_jsx("div", { className: "cls_profile_picture_library_tab_no_photos flex items-center justify-center p-8 border border-[var(--hazo-border)] rounded-lg bg-[var(--hazo-bg-subtle)] min-h-[400px]", children: _jsx("p", { className: "cls_profile_picture_library_tab_no_photos_text text-sm text-[var(--hazo-text-muted)]", children: "No photos in this category" }) }))] }), _jsxs("div", { className: "cls_profile_picture_library_tab_preview_container flex flex-col gap-2 col-span-3", children: [_jsx(Label, { className: "cls_profile_picture_library_tab_preview_label text-sm font-medium text-[var(--hazo-text-secondary)]", children: "Preview" }), selectedPhoto ? (_jsxs("div", { className: "cls_profile_picture_library_tab_preview flex flex-col items-center gap-4 p-4 border border-[var(--hazo-border)] rounded-lg bg-[var(--hazo-bg-subtle)] min-h-[400px] justify-center", children: [_jsx("div", { className: "cls_profile_picture_library_tab_preview_image_wrapper w-full flex items-center justify-center", children: _jsx("img", { src: selectedPhoto, alt: "Selected library photo preview", className: "cls_profile_picture_library_tab_preview_image max-w-full max-h-[350px] rounded-lg object-contain", onError: (e) => {
|
|
136
136
|
// Fallback if preview image fails to load
|
|
137
137
|
const target = e.target;
|
|
138
138
|
target.style.display = 'none';
|
|
@@ -140,5 +140,5 @@ export function ProfilePictureLibraryTab({ useLibrary, onUseLibraryChange, onPho
|
|
|
140
140
|
if (wrapper) {
|
|
141
141
|
wrapper.innerHTML = '<p class="text-sm text-red-500">Failed to load preview</p>';
|
|
142
142
|
}
|
|
143
|
-
} }) }), _jsx("p", { className: "cls_profile_picture_library_tab_preview_text text-sm text-
|
|
143
|
+
} }) }), _jsx("p", { className: "cls_profile_picture_library_tab_preview_text text-sm text-[var(--hazo-text-muted)] text-center", children: "Selected photo preview" })] })) : (_jsxs("div", { className: "cls_profile_picture_library_tab_preview_empty flex flex-col items-center justify-center gap-2 p-8 border border-[var(--hazo-border)] rounded-lg bg-[var(--hazo-bg-subtle)] min-h-[400px]", children: [_jsx(Avatar, { className: "cls_profile_picture_library_tab_preview_empty_avatar h-32 w-32", children: _jsx(AvatarFallback, { className: "cls_profile_picture_library_tab_preview_empty_avatar_fallback bg-[var(--hazo-bg-emphasis)] text-[var(--hazo-text-muted)] text-3xl", children: getInitials() }) }), _jsx("p", { className: "cls_profile_picture_library_tab_preview_empty_text text-sm text-[var(--hazo-text-muted)] text-center", children: "Select a photo to see preview" })] }))] })] })] }));
|
|
144
144
|
}
|
|
@@ -153,17 +153,17 @@ allowedImageMimeTypes = ["image/jpeg", "image/jpg", "image/png"], }) {
|
|
|
153
153
|
const getInitials = () => {
|
|
154
154
|
return "U";
|
|
155
155
|
};
|
|
156
|
-
return (_jsxs("div", { className: "cls_profile_picture_upload_tab flex flex-col gap-4", children: [_jsxs("div", { className: "cls_profile_picture_upload_tab_switch flex items-center gap-3", children: [_jsx(Switch, { id: "use-upload", checked: useUpload, onCheckedChange: onUseUploadChange, disabled: disabled || !uploadEnabled, className: "cls_profile_picture_upload_tab_switch_input", "aria-label": "Use uploaded photo" }), _jsx(Label, { htmlFor: "use-upload", className: "cls_profile_picture_upload_tab_switch_label text-sm font-medium text-
|
|
156
|
+
return (_jsxs("div", { className: "cls_profile_picture_upload_tab flex flex-col gap-4", children: [_jsxs("div", { className: "cls_profile_picture_upload_tab_switch flex items-center gap-3", children: [_jsx(Switch, { id: "use-upload", checked: useUpload, onCheckedChange: onUseUploadChange, disabled: disabled || !uploadEnabled, className: "cls_profile_picture_upload_tab_switch_input", "aria-label": "Use uploaded photo" }), _jsx(Label, { htmlFor: "use-upload", className: "cls_profile_picture_upload_tab_switch_label text-sm font-medium text-[var(--hazo-text-secondary)] cursor-pointer", children: "Use uploaded photo" })] }), !uploadEnabled && (_jsxs("div", { className: "cls_profile_picture_upload_tab_disabled flex items-center gap-2 p-3 bg-yellow-50 border border-yellow-200 rounded-lg", children: [_jsx(Info, { className: "h-4 w-4 text-yellow-600", "aria-hidden": "true" }), _jsx("p", { className: "cls_profile_picture_upload_tab_disabled_text text-sm text-yellow-800", children: photoUploadDisabledMessage })] })), _jsxs("div", { className: "cls_profile_picture_upload_tab_content grid grid-cols-1 md:grid-cols-2 gap-6", children: [_jsxs("div", { className: "cls_profile_picture_upload_tab_dropzone_container flex flex-col gap-2", children: [_jsx(Label, { className: "cls_profile_picture_upload_tab_dropzone_label text-sm font-medium text-[var(--hazo-text-secondary)]", children: "Upload Photo" }), _jsxs("div", { className: `
|
|
157
157
|
cls_profile_picture_upload_tab_dropzone
|
|
158
158
|
flex flex-col items-center justify-center
|
|
159
159
|
border-2 border-dashed rounded-lg p-8
|
|
160
160
|
transition-colors
|
|
161
|
-
${dragActive ? "border-blue-500 bg-blue-50" : "border-
|
|
162
|
-
${disabled || !uploadEnabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer hover:border-
|
|
161
|
+
${dragActive ? "border-blue-500 bg-blue-50" : "border-[var(--hazo-border-emphasis)] bg-[var(--hazo-bg-subtle)]"}
|
|
162
|
+
${disabled || !uploadEnabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer hover:border-[var(--hazo-border-emphasis)]"}
|
|
163
163
|
`, onDragEnter: handleDrag, onDragLeave: handleDrag, onDragOver: handleDrag, onDrop: handleDrop, onClick: () => {
|
|
164
164
|
var _a;
|
|
165
165
|
if (!disabled && uploadEnabled) {
|
|
166
166
|
(_a = document.getElementById("file-upload-input")) === null || _a === void 0 ? void 0 : _a.click();
|
|
167
167
|
}
|
|
168
|
-
}, children: [_jsx("input", { id: "file-upload-input", type: "file", accept: allowedImageMimeTypes.join(","), onChange: handleChange, disabled: disabled || !uploadEnabled, className: "hidden", "aria-label": "Upload profile picture" }), _jsx(Upload, { className: "h-8 w-8 text-
|
|
168
|
+
}, children: [_jsx("input", { id: "file-upload-input", type: "file", accept: allowedImageMimeTypes.join(","), onChange: handleChange, disabled: disabled || !uploadEnabled, className: "hidden", "aria-label": "Upload profile picture" }), _jsx(Upload, { className: "h-8 w-8 text-[var(--hazo-text-subtle)] mb-2", "aria-hidden": "true" }), _jsx("p", { className: "cls_profile_picture_upload_tab_dropzone_text text-sm text-[var(--hazo-text-muted)] text-center", children: "Drag and drop an image here, or click to select" }), _jsxs("p", { className: "cls_profile_picture_upload_tab_dropzone_hint text-xs text-[var(--hazo-text-muted)] text-center mt-1", children: ["JPG or PNG, max ", Math.round(maxSize / 1024), "KB"] })] }), error && (_jsx("p", { className: "cls_profile_picture_upload_tab_error text-sm text-red-600", role: "alert", children: error }))] }), _jsxs("div", { className: "cls_profile_picture_upload_tab_preview_container flex flex-col gap-2", children: [_jsx(Label, { className: "cls_profile_picture_upload_tab_preview_label text-sm font-medium text-[var(--hazo-text-secondary)]", children: isNewImage ? "Preview (new)" : "Preview (current)" }), _jsx("div", { className: "cls_profile_picture_upload_tab_preview_content flex flex-col items-center justify-center border border-[var(--hazo-border)] rounded-lg p-6 bg-[var(--hazo-bg-subtle)] min-h-[200px]", children: compressing ? (_jsxs("div", { className: "cls_profile_picture_upload_tab_compressing flex flex-col items-center gap-2", children: [_jsx(Loader2, { className: "h-8 w-8 text-[var(--hazo-text-subtle)] animate-spin", "aria-hidden": "true" }), _jsx("p", { className: "cls_profile_picture_upload_tab_compressing_text text-sm text-[var(--hazo-text-muted)]", children: "Compressing image..." })] })) : uploading ? (_jsxs("div", { className: "cls_profile_picture_upload_tab_uploading flex flex-col items-center gap-2", children: [_jsx(Loader2, { className: "h-8 w-8 text-[var(--hazo-text-subtle)] animate-spin", "aria-hidden": "true" }), _jsx("p", { className: "cls_profile_picture_upload_tab_uploading_text text-sm text-[var(--hazo-text-muted)]", children: "Uploading..." })] })) : preview ? (_jsxs("div", { className: "cls_profile_picture_upload_tab_preview_image_container flex flex-col items-center gap-4", children: [_jsxs("div", { className: "cls_profile_picture_upload_tab_preview_image_wrapper relative", children: [_jsxs(Avatar, { className: "cls_profile_picture_upload_tab_preview_avatar h-32 w-32", children: [_jsx(AvatarImage, { src: preview, alt: "Uploaded profile picture preview", className: "cls_profile_picture_upload_tab_preview_avatar_image" }), _jsx(AvatarFallback, { className: "cls_profile_picture_upload_tab_preview_avatar_fallback bg-[var(--hazo-bg-emphasis)] text-[var(--hazo-text-muted)] text-3xl", children: getInitials() })] }), _jsx(Button, { type: "button", onClick: handleRemove, variant: "ghost", size: "icon", className: "cls_profile_picture_upload_tab_preview_remove absolute -top-2 -right-2 rounded-full h-6 w-6 border border-[var(--hazo-border-emphasis)] bg-white hover:bg-[var(--hazo-bg-subtle)]", "aria-label": "Remove preview", children: _jsx(X, { className: "h-4 w-4", "aria-hidden": "true" }) })] }), _jsx("p", { className: "cls_profile_picture_upload_tab_preview_success_text text-sm text-[var(--hazo-text-muted)] text-center", children: "Preview of your uploaded photo" })] })) : (_jsxs("div", { className: "cls_profile_picture_upload_tab_preview_empty flex flex-col items-center gap-2", children: [_jsx(Avatar, { className: "cls_profile_picture_upload_tab_preview_empty_avatar h-32 w-32", children: _jsx(AvatarFallback, { className: "cls_profile_picture_upload_tab_preview_empty_avatar_fallback bg-[var(--hazo-bg-emphasis)] text-[var(--hazo-text-muted)] text-3xl", children: getInitials() }) }), _jsx("p", { className: "cls_profile_picture_upload_tab_preview_empty_text text-sm text-[var(--hazo-text-muted)] text-center", children: "Upload an image to see preview" })] })) })] })] })] }));
|
|
169
169
|
}
|
|
@@ -28,7 +28,7 @@ export default function my_settings_layout({ labels, button_colors, password_req
|
|
|
28
28
|
const settings = use_my_settings({
|
|
29
29
|
passwordRequirements: password_requirements,
|
|
30
30
|
});
|
|
31
|
-
return (_jsx(UnauthorizedGuard, { message: unauthorizedMessage, loginButtonLabel: loginButtonLabel, loginPath: loginPath, children: _jsxs("div", { className: "cls_my_settings_layout flex flex-col gap-6 p-6 max-w-4xl mx-auto min-h-screen bg-
|
|
31
|
+
return (_jsx(UnauthorizedGuard, { message: unauthorizedMessage, loginButtonLabel: loginButtonLabel, loginPath: loginPath, children: _jsxs("div", { className: "cls_my_settings_layout flex flex-col gap-6 p-6 max-w-4xl mx-auto min-h-screen bg-[var(--hazo-bg-subtle)]", children: [_jsxs("div", { className: "cls_my_settings_layout_header flex flex-col gap-2", children: [_jsx("h1", { className: "cls_my_settings_layout_heading text-3xl font-bold text-[var(--hazo-text-primary)]", children: heading }), _jsx("p", { className: "cls_my_settings_layout_subheading text-[var(--hazo-text-muted)]", children: subHeading })] }), _jsxs("div", { className: "cls_my_settings_layout_profile_photo_section bg-white rounded-lg border border-[var(--hazo-border)] p-6", children: [_jsx("h2", { className: "cls_my_settings_layout_section_heading text-lg font-semibold text-[var(--hazo-text-primary)] mb-4", children: profilePhotoLabel }), _jsx("div", { className: "cls_my_settings_layout_profile_photo_content flex flex-col items-center", children: _jsxs("div", { className: "cls_my_settings_layout_profile_photo_display relative", children: [_jsx(ProfilePictureDisplay, { profilePictureUrl: settings.profilePictureUrl, name: settings.name, email: settings.email, onEdit: settings.handleProfilePictureEdit }), _jsxs("div", { className: "cls_my_settings_layout_profile_photo_actions absolute left-0 right-0 flex items-center justify-between px-2", style: { bottom: '-20px' }, children: [_jsx(Button, { type: "button", onClick: settings.handleProfilePictureEdit, disabled: settings.loading, variant: "ghost", size: "icon", className: "cls_my_settings_layout_upload_photo_button", "aria-label": uploadPhotoButtonLabel, children: _jsx(Pencil, { className: "h-4 w-4", "aria-hidden": "true" }) }), _jsx(Button, { type: "button", onClick: settings.handleProfilePictureRemove, disabled: settings.loading || !settings.profilePictureUrl, variant: "ghost", size: "icon", className: "cls_my_settings_layout_remove_photo_button text-red-600 hover:text-red-700 hover:bg-red-50", "aria-label": removePhotoButtonLabel, children: _jsx(Trash2, { className: "h-4 w-4", "aria-hidden": "true" }) })] })] }) })] }), _jsxs("div", { className: "cls_my_settings_layout_profile_information_section bg-white rounded-lg border border-[var(--hazo-border)] p-6", children: [_jsx("h2", { className: "cls_my_settings_layout_section_heading text-lg font-semibold text-[var(--hazo-text-primary)] mb-4", children: profileInformationLabel }), _jsxs("div", { className: "cls_my_settings_layout_profile_information_fields grid grid-cols-1 md:grid-cols-2 gap-6", children: [userFields.show_name_field && (_jsx(EditableField, { label: "Full Name", value: settings.name, type: "text", placeholder: "Enter your full name", onSave: settings.handleNameSave, validation: validateName, disabled: settings.loading, ariaLabel: "Full name input field" })), userFields.show_email_field && (_jsx(EditableField, { label: "Email Address", value: settings.email, type: "email", placeholder: "Enter your email address", onSave: settings.handleEmailSave, validation: validateEmail, disabled: settings.loading, ariaLabel: "Email address input field" }))] })] }), userFields.show_password_field && (_jsxs("div", { className: "cls_my_settings_layout_password_section bg-white rounded-lg border border-[var(--hazo-border)] p-6", children: [_jsx("h2", { className: "cls_my_settings_layout_section_heading text-lg font-semibold text-[var(--hazo-text-primary)] mb-4", children: passwordLabel }), _jsxs("div", { className: "cls_my_settings_layout_password_fields flex flex-col gap-6", children: [_jsx(FormFieldWrapper, { fieldId: "current-password", label: currentPasswordLabel, input: _jsx(PasswordField, { inputId: "current-password", ariaLabel: currentPasswordLabel, value: ((_a = settings.passwordFields) === null || _a === void 0 ? void 0 : _a.currentPassword) || "", placeholder: "Enter your current password", autoComplete: "current-password", isVisible: ((_b = settings.passwordFields) === null || _b === void 0 ? void 0 : _b.currentPasswordVisible) || false, onChange: (value) => settings.handlePasswordFieldChange("currentPassword", value), onToggleVisibility: () => settings.togglePasswordVisibility("currentPassword"), errorMessage: (_d = (_c = settings.passwordFields) === null || _c === void 0 ? void 0 : _c.errors) === null || _d === void 0 ? void 0 : _d.currentPassword }) }), _jsxs("div", { className: "cls_my_settings_layout_password_fields_row grid grid-cols-1 md:grid-cols-2 gap-6", children: [_jsx(FormFieldWrapper, { fieldId: "new-password", label: newPasswordLabel, input: _jsx(PasswordField, { inputId: "new-password", ariaLabel: newPasswordLabel, value: ((_e = settings.passwordFields) === null || _e === void 0 ? void 0 : _e.newPassword) || "", placeholder: "Enter your new password", autoComplete: "new-password", isVisible: ((_f = settings.passwordFields) === null || _f === void 0 ? void 0 : _f.newPasswordVisible) || false, onChange: (value) => settings.handlePasswordFieldChange("newPassword", value), onToggleVisibility: () => settings.togglePasswordVisibility("newPassword"), errorMessage: (_h = (_g = settings.passwordFields) === null || _g === void 0 ? void 0 : _g.errors) === null || _h === void 0 ? void 0 : _h.newPassword }) }), _jsx(FormFieldWrapper, { fieldId: "confirm-password", label: confirmPasswordLabel, input: _jsx(PasswordField, { inputId: "confirm-password", ariaLabel: confirmPasswordLabel, value: ((_j = settings.passwordFields) === null || _j === void 0 ? void 0 : _j.confirmPassword) || "", placeholder: "Confirm your new password", autoComplete: "new-password", isVisible: ((_k = settings.passwordFields) === null || _k === void 0 ? void 0 : _k.confirmPasswordVisible) || false, onChange: (value) => settings.handlePasswordFieldChange("confirmPassword", value), onToggleVisibility: () => settings.togglePasswordVisibility("confirmPassword"), errorMessage: (_m = (_l = settings.passwordFields) === null || _l === void 0 ? void 0 : _l.errors) === null || _m === void 0 ? void 0 : _m.confirmPassword }) })] })] }), _jsx("div", { className: "cls_my_settings_layout_password_actions flex justify-end mt-4", children: _jsx(Button, { type: "button", onClick: settings.handlePasswordSave, disabled: settings.loading || settings.isPasswordSaveDisabled, className: "cls_my_settings_layout_save_password_button", style: {
|
|
32
32
|
backgroundColor: resolvedButtonPalette.submitBackground,
|
|
33
33
|
color: resolvedButtonPalette.submitText,
|
|
34
34
|
}, "aria-label": "Save password", children: "Save Password" }) })] })), _jsx(ProfilePictureDialog, { open: settings.profilePictureDialogOpen, onOpenChange: (open) => {
|
|
@@ -10,13 +10,17 @@ export type ProfilePicMenuProps = {
|
|
|
10
10
|
custom_menu_items?: ProfilePicMenuMenuItem[];
|
|
11
11
|
className?: string;
|
|
12
12
|
avatar_size?: "default" | "sm" | "lg";
|
|
13
|
+
variant?: "dropdown" | "sidebar";
|
|
14
|
+
sidebar_group_label?: string;
|
|
13
15
|
};
|
|
14
16
|
/**
|
|
15
17
|
* Profile picture menu component
|
|
16
18
|
* Shows user profile picture when authenticated, or sign up/sign in buttons when not authenticated
|
|
17
|
-
*
|
|
19
|
+
* Supports two variants:
|
|
20
|
+
* - "dropdown" (default): Clicking profile picture opens dropdown menu (for navbar/header)
|
|
21
|
+
* - "sidebar": Shows profile picture and name in sidebar, clicking opens dropdown menu (for sidebar navigation)
|
|
18
22
|
* @param props - Component props including configuration options
|
|
19
23
|
* @returns Profile picture menu component
|
|
20
24
|
*/
|
|
21
|
-
export declare function ProfilePicMenu({ show_single_button, sign_up_label, sign_in_label, register_path, login_path, settings_path, logout_path, custom_menu_items, className, avatar_size, }: ProfilePicMenuProps): import("react/jsx-runtime").JSX.Element;
|
|
25
|
+
export declare function ProfilePicMenu({ show_single_button, sign_up_label, sign_in_label, register_path, login_path, settings_path, logout_path, custom_menu_items, className, avatar_size, variant, sidebar_group_label, }: ProfilePicMenuProps): import("react/jsx-runtime").JSX.Element;
|
|
22
26
|
//# sourceMappingURL=profile_pic_menu.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profile_pic_menu.d.ts","sourceRoot":"","sources":["../../../../../src/components/layouts/shared/components/profile_pic_menu.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"profile_pic_menu.d.ts","sourceRoot":"","sources":["../../../../../src/components/layouts/shared/components/profile_pic_menu.tsx"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gDAAgD,CAAC;AAG7F,MAAM,MAAM,mBAAmB,GAAG;IAChC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,sBAAsB,EAAE,CAAC;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,SAAS,GAAG,IAAI,GAAG,IAAI,CAAC;IACtC,OAAO,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IACjC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAGF;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,EAC7B,kBAA0B,EAC1B,aAAyB,EACzB,aAAyB,EACzB,aAAqC,EACrC,UAA+B,EAC/B,aAAwC,EACxC,WAAqC,EACrC,iBAAsB,EACtB,SAAS,EACT,WAAuB,EACvB,OAAoB,EACpB,mBAA+B,GAChC,EAAE,mBAAmB,2CAmarB"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// file_description: profile picture menu component for navbar or sidebar - shows profile picture when logged in, or sign up/sign in buttons when not logged in
|
|
2
|
+
// Supports both dropdown (navbar) and sidebar variants
|
|
2
3
|
// section: client_directive
|
|
3
4
|
"use client";
|
|
4
|
-
import { jsx as _jsx,
|
|
5
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
5
6
|
// section: imports
|
|
6
7
|
import { useState, useMemo } from "react";
|
|
7
8
|
import { useRouter } from "next/navigation";
|
|
@@ -9,6 +10,7 @@ import Link from "next/link";
|
|
|
9
10
|
import { Avatar, AvatarImage, AvatarFallback } from "../../../ui/avatar";
|
|
10
11
|
import { Button } from "../../../ui/button";
|
|
11
12
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "../../../ui/dropdown-menu";
|
|
13
|
+
import { SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarMenuItem, SidebarMenuButton, } from "../../../ui/sidebar";
|
|
12
14
|
import { Settings, LogOut } from "lucide-react";
|
|
13
15
|
import { toast } from "sonner";
|
|
14
16
|
import { use_auth_status, trigger_auth_status_refresh } from "../hooks/use_auth_status";
|
|
@@ -16,11 +18,13 @@ import { use_auth_status, trigger_auth_status_refresh } from "../hooks/use_auth_
|
|
|
16
18
|
/**
|
|
17
19
|
* Profile picture menu component
|
|
18
20
|
* Shows user profile picture when authenticated, or sign up/sign in buttons when not authenticated
|
|
19
|
-
*
|
|
21
|
+
* Supports two variants:
|
|
22
|
+
* - "dropdown" (default): Clicking profile picture opens dropdown menu (for navbar/header)
|
|
23
|
+
* - "sidebar": Shows profile picture and name in sidebar, clicking opens dropdown menu (for sidebar navigation)
|
|
20
24
|
* @param props - Component props including configuration options
|
|
21
25
|
* @returns Profile picture menu component
|
|
22
26
|
*/
|
|
23
|
-
export function ProfilePicMenu({ show_single_button = false, sign_up_label = "Sign Up", sign_in_label = "Sign In", register_path = "/hazo_auth/register", login_path = "/hazo_auth/login", settings_path = "/hazo_auth/my_settings", logout_path = "/api/hazo_auth/logout", custom_menu_items = [], className, avatar_size = "default", }) {
|
|
27
|
+
export function ProfilePicMenu({ show_single_button = false, sign_up_label = "Sign Up", sign_in_label = "Sign In", register_path = "/hazo_auth/register", login_path = "/hazo_auth/login", settings_path = "/hazo_auth/my_settings", logout_path = "/api/hazo_auth/logout", custom_menu_items = [], className, avatar_size = "default", variant = "dropdown", sidebar_group_label = "Account", }) {
|
|
24
28
|
const router = useRouter();
|
|
25
29
|
const authStatus = use_auth_status();
|
|
26
30
|
const [isLoggingOut, setIsLoggingOut] = useState(false);
|
|
@@ -138,14 +142,45 @@ export function ProfilePicMenu({ show_single_button = false, sign_up_label = "Si
|
|
|
138
142
|
};
|
|
139
143
|
// Show loading state
|
|
140
144
|
if (authStatus.loading) {
|
|
141
|
-
|
|
145
|
+
if (variant === "sidebar") {
|
|
146
|
+
return (_jsxs(SidebarGroup, { className: `cls_profile_pic_menu_sidebar ${className || ""}`, children: [_jsx(SidebarGroupLabel, { children: sidebar_group_label }), _jsx(SidebarMenu, { children: _jsx(SidebarMenuItem, { children: _jsx("div", { className: "h-10 w-10 rounded-full bg-[var(--hazo-bg-emphasis)] animate-pulse" }) }) })] }));
|
|
147
|
+
}
|
|
148
|
+
return (_jsx("div", { className: `cls_profile_pic_menu ${className || ""}`, children: _jsx("div", { className: "h-10 w-10 rounded-full bg-[var(--hazo-bg-emphasis)] animate-pulse" }) }));
|
|
142
149
|
}
|
|
143
150
|
// Not authenticated - show sign up/sign in buttons
|
|
144
151
|
if (!authStatus.authenticated) {
|
|
152
|
+
if (variant === "sidebar") {
|
|
153
|
+
return (_jsxs(SidebarGroup, { className: `cls_profile_pic_menu_sidebar ${className || ""}`, children: [_jsx(SidebarGroupLabel, { children: sidebar_group_label }), _jsx(SidebarMenu, { children: show_single_button ? (_jsx(SidebarMenuItem, { children: _jsx(SidebarMenuButton, { asChild: true, children: _jsx(Link, { href: register_path, className: "cls_profile_pic_menu_sign_up", children: sign_up_label }) }) })) : (_jsxs(_Fragment, { children: [_jsx(SidebarMenuItem, { children: _jsx(SidebarMenuButton, { asChild: true, children: _jsx(Link, { href: register_path, className: "cls_profile_pic_menu_sign_up", children: sign_up_label }) }) }), _jsx(SidebarMenuItem, { children: _jsx(SidebarMenuButton, { asChild: true, children: _jsx(Link, { href: login_path, className: "cls_profile_pic_menu_sign_in", children: sign_in_label }) }) })] })) })] }));
|
|
154
|
+
}
|
|
145
155
|
return (_jsx("div", { className: `cls_profile_pic_menu flex items-center gap-2 ${className || ""}`, children: show_single_button ? (_jsx(Button, { asChild: true, variant: "default", size: "sm", children: _jsx(Link, { href: register_path, className: "cls_profile_pic_menu_sign_up", children: sign_up_label }) })) : (_jsxs(_Fragment, { children: [_jsx(Button, { asChild: true, variant: "outline", size: "sm", children: _jsx(Link, { href: register_path, className: "cls_profile_pic_menu_sign_up", children: sign_up_label }) }), _jsx(Button, { asChild: true, variant: "default", size: "sm", children: _jsx(Link, { href: login_path, className: "cls_profile_pic_menu_sign_in", children: sign_in_label }) })] })) }));
|
|
146
156
|
}
|
|
147
|
-
// Authenticated -
|
|
148
|
-
|
|
157
|
+
// Authenticated - render based on variant
|
|
158
|
+
if (variant === "sidebar") {
|
|
159
|
+
// Sidebar variant: show profile picture and name only, clicking opens dropdown
|
|
160
|
+
return (_jsxs(SidebarGroup, { className: `cls_profile_pic_menu_sidebar ${className || ""}`, children: [_jsx(SidebarGroupLabel, { className: "cls_profile_pic_menu_sidebar_label", children: sidebar_group_label }), _jsx(SidebarMenu, { className: "cls_profile_pic_menu_sidebar_menu", children: _jsx(SidebarMenuItem, { className: "cls_profile_pic_menu_sidebar_user_info", children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("button", { className: "cls_profile_pic_menu_sidebar_trigger w-full focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary rounded-md", "aria-label": "Profile menu", children: _jsxs("div", { className: "cls_profile_pic_menu_sidebar_user flex items-center gap-3 px-2 py-2 hover:bg-sidebar-accent rounded-md transition-colors", children: [_jsxs(Avatar, { className: `cls_profile_pic_menu_avatar ${avatarSizeClasses[avatar_size]} cursor-pointer`, children: [_jsx(AvatarImage, { src: authStatus.profile_picture_url, alt: authStatus.name ? `Profile picture of ${authStatus.name}` : "Profile picture", className: "cls_profile_pic_menu_image" }), _jsx(AvatarFallback, { className: "cls_profile_pic_menu_fallback bg-[var(--hazo-bg-emphasis)] text-[var(--hazo-text-muted)]", children: getInitials() })] }), authStatus.name && (_jsx("span", { className: "cls_profile_pic_menu_sidebar_user_name text-sm font-medium text-sidebar-foreground truncate", children: authStatus.name }))] }) }) }), _jsx(DropdownMenuContent, { align: "end", className: "cls_profile_pic_menu_dropdown w-56", children: menuItems.map((item) => {
|
|
161
|
+
if (item.type === "separator") {
|
|
162
|
+
return _jsx(DropdownMenuSeparator, { className: "cls_profile_pic_menu_separator" }, item.id);
|
|
163
|
+
}
|
|
164
|
+
if (item.type === "info") {
|
|
165
|
+
return (_jsx("div", { className: "cls_profile_pic_menu_info", children: item.value && (_jsx("div", { className: "cls_profile_pic_menu_info_value px-2 py-1.5 text-sm text-foreground", children: item.value })) }, item.id));
|
|
166
|
+
}
|
|
167
|
+
if (item.type === "link") {
|
|
168
|
+
// Special handling for logout
|
|
169
|
+
if (item.id === "default_logout") {
|
|
170
|
+
return (_jsxs(DropdownMenuItem, { onClick: handleLogout, disabled: isLoggingOut, className: "cls_profile_pic_menu_logout cursor-pointer text-destructive focus:text-destructive", children: [_jsx(LogOut, { className: "mr-2 h-4 w-4" }), isLoggingOut ? "Logging out..." : item.label] }, item.id));
|
|
171
|
+
}
|
|
172
|
+
// Special handling for settings
|
|
173
|
+
if (item.id === "default_settings") {
|
|
174
|
+
return (_jsx(DropdownMenuItem, { asChild: true, className: "cls_profile_pic_menu_settings cursor-pointer", children: _jsxs(Link, { href: item.href || settings_path, children: [_jsx(Settings, { className: "mr-2 h-4 w-4" }), item.label] }) }, item.id));
|
|
175
|
+
}
|
|
176
|
+
// Generic link handling
|
|
177
|
+
return (_jsx(DropdownMenuItem, { asChild: true, className: "cls_profile_pic_menu_link cursor-pointer", children: _jsx(Link, { href: item.href || "#", children: item.label }) }, item.id));
|
|
178
|
+
}
|
|
179
|
+
return null;
|
|
180
|
+
}) })] }) }) })] }));
|
|
181
|
+
}
|
|
182
|
+
// Default dropdown variant: show profile picture with dropdown menu
|
|
183
|
+
return (_jsx("div", { className: `cls_profile_pic_menu ${className || ""}`, children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("button", { className: "cls_profile_pic_menu_trigger focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary rounded-full", "aria-label": "Profile menu", children: _jsxs(Avatar, { className: `cls_profile_pic_menu_avatar ${avatarSizeClasses[avatar_size]} cursor-pointer`, children: [_jsx(AvatarImage, { src: authStatus.profile_picture_url, alt: authStatus.name ? `Profile picture of ${authStatus.name}` : "Profile picture", className: "cls_profile_pic_menu_image" }), _jsx(AvatarFallback, { className: "cls_profile_pic_menu_fallback bg-[var(--hazo-bg-emphasis)] text-[var(--hazo-text-muted)]", children: getInitials() })] }) }) }), _jsx(DropdownMenuContent, { align: "end", className: "cls_profile_pic_menu_dropdown w-56", children: menuItems.map((item) => {
|
|
149
184
|
if (item.type === "separator") {
|
|
150
185
|
return _jsx(DropdownMenuSeparator, { className: "cls_profile_pic_menu_separator" }, item.id);
|
|
151
186
|
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
export type ProfilePicMenuWrapperProps = {
|
|
2
2
|
className?: string;
|
|
3
3
|
avatar_size?: "default" | "sm" | "lg";
|
|
4
|
+
variant?: "dropdown" | "sidebar";
|
|
5
|
+
sidebar_group_label?: string;
|
|
4
6
|
};
|
|
5
7
|
/**
|
|
6
8
|
* Server wrapper component that loads profile picture menu configuration from hazo_auth_config.ini
|
|
7
9
|
* and passes it to the client ProfilePicMenu component
|
|
8
|
-
* @param props - Component props including className and
|
|
10
|
+
* @param props - Component props including className, avatar_size, variant, and sidebar_group_label
|
|
9
11
|
* @returns ProfilePicMenu component with loaded configuration
|
|
10
12
|
*/
|
|
11
|
-
export declare function ProfilePicMenuWrapper({ className, avatar_size, }: ProfilePicMenuWrapperProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare function ProfilePicMenuWrapper({ className, avatar_size, variant, sidebar_group_label, }: ProfilePicMenuWrapperProps): import("react/jsx-runtime").JSX.Element;
|
|
12
14
|
//# sourceMappingURL=profile_pic_menu_wrapper.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profile_pic_menu_wrapper.d.ts","sourceRoot":"","sources":["../../../../../src/components/layouts/shared/components/profile_pic_menu_wrapper.tsx"],"names":[],"mappings":"AAMA,MAAM,MAAM,0BAA0B,GAAG;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,SAAS,GAAG,IAAI,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"profile_pic_menu_wrapper.d.ts","sourceRoot":"","sources":["../../../../../src/components/layouts/shared/components/profile_pic_menu_wrapper.tsx"],"names":[],"mappings":"AAMA,MAAM,MAAM,0BAA0B,GAAG;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,SAAS,GAAG,IAAI,GAAG,IAAI,CAAC;IACtC,OAAO,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IACjC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAGF;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,SAAS,EACT,WAAW,EACX,OAAoB,EACpB,mBAA+B,GAChC,EAAE,0BAA0B,2CAmB5B"}
|
|
@@ -7,10 +7,10 @@ import { get_profile_pic_menu_config } from "../../../../lib/profile_pic_menu_co
|
|
|
7
7
|
/**
|
|
8
8
|
* Server wrapper component that loads profile picture menu configuration from hazo_auth_config.ini
|
|
9
9
|
* and passes it to the client ProfilePicMenu component
|
|
10
|
-
* @param props - Component props including className and
|
|
10
|
+
* @param props - Component props including className, avatar_size, variant, and sidebar_group_label
|
|
11
11
|
* @returns ProfilePicMenu component with loaded configuration
|
|
12
12
|
*/
|
|
13
|
-
export function ProfilePicMenuWrapper({ className, avatar_size, }) {
|
|
13
|
+
export function ProfilePicMenuWrapper({ className, avatar_size, variant = "dropdown", sidebar_group_label = "Account", }) {
|
|
14
14
|
const config = get_profile_pic_menu_config();
|
|
15
|
-
return (_jsx(ProfilePicMenu, { show_single_button: config.show_single_button, sign_up_label: config.sign_up_label, sign_in_label: config.sign_in_label, register_path: config.register_path, login_path: config.login_path, settings_path: config.settings_path, logout_path: config.logout_path, custom_menu_items: config.custom_menu_items, className: className, avatar_size: avatar_size }));
|
|
15
|
+
return (_jsx(ProfilePicMenu, { show_single_button: config.show_single_button, sign_up_label: config.sign_up_label, sign_in_label: config.sign_in_label, register_path: config.register_path, login_path: config.login_path, settings_path: config.settings_path, logout_path: config.logout_path, custom_menu_items: config.custom_menu_items, className: className, avatar_size: avatar_size, variant: variant, sidebar_group_label: sidebar_group_label }));
|
|
16
16
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidebar_layout_wrapper.d.ts","sourceRoot":"","sources":["../../../../../src/components/layouts/shared/components/sidebar_layout_wrapper.tsx"],"names":[],"mappings":"AAwBA,KAAK,yBAAyB,GAAG;IAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC;AAGF,wBAAgB,oBAAoB,CAAC,EAAE,QAAQ,EAAE,EAAE,yBAAyB,
|
|
1
|
+
{"version":3,"file":"sidebar_layout_wrapper.d.ts","sourceRoot":"","sources":["../../../../../src/components/layouts/shared/components/sidebar_layout_wrapper.tsx"],"names":[],"mappings":"AAwBA,KAAK,yBAAyB,GAAG;IAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC;AAGF,wBAAgB,oBAAoB,CAAC,EAAE,QAAQ,EAAE,EAAE,yBAAyB,2CAyK3E"}
|
|
@@ -5,11 +5,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
5
5
|
// section: imports
|
|
6
6
|
import Link from "next/link";
|
|
7
7
|
import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupLabel, SidebarHeader, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarProvider, SidebarTrigger, SidebarInset, } from "../../../ui/sidebar";
|
|
8
|
-
import { LogIn, UserPlus, BookOpen, ExternalLink, Database, KeyRound, MailCheck, Key,
|
|
8
|
+
import { LogIn, UserPlus, BookOpen, ExternalLink, Database, KeyRound, MailCheck, Key, User } from "lucide-react";
|
|
9
9
|
import { use_auth_status } from "../hooks/use_auth_status";
|
|
10
10
|
import { ProfilePicMenu } from "./profile_pic_menu";
|
|
11
11
|
// section: component
|
|
12
12
|
export function SidebarLayoutWrapper({ children }) {
|
|
13
13
|
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" })] }) }) })] })] }),
|
|
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(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
15
|
}
|
|
@@ -7,6 +7,9 @@ export type AuthStatusData = {
|
|
|
7
7
|
last_logon?: string;
|
|
8
8
|
profile_picture_url?: string;
|
|
9
9
|
profile_source?: "upload" | "library" | "gravatar" | "custom";
|
|
10
|
+
permissions?: string[];
|
|
11
|
+
permission_ok?: boolean;
|
|
12
|
+
missing_permissions?: string[];
|
|
10
13
|
loading: boolean;
|
|
11
14
|
};
|
|
12
15
|
export type AuthStatus = AuthStatusData & {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use_auth_status.d.ts","sourceRoot":"","sources":["../../../../../src/components/layouts/shared/hooks/use_auth_status.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,cAAc,GAAG;IAC3B,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,cAAc,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,CAAC;IAC9D,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG;IACxC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B,CAAC;AAMF;;GAEG;AACH,wBAAgB,2BAA2B,IAAI,IAAI,CAIlD;AAGD,wBAAgB,eAAe,IAAI,UAAU,
|
|
1
|
+
{"version":3,"file":"use_auth_status.d.ts","sourceRoot":"","sources":["../../../../../src/components/layouts/shared/hooks/use_auth_status.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,cAAc,GAAG;IAC3B,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,cAAc,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,CAAC;IAC9D,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG;IACxC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B,CAAC;AAMF;;GAEG;AACH,wBAAgB,2BAA2B,IAAI,IAAI,CAIlD;AAGD,wBAAgB,eAAe,IAAI,UAAU,CAkE5C"}
|
|
@@ -21,6 +21,7 @@ export function use_auth_status() {
|
|
|
21
21
|
loading: true,
|
|
22
22
|
});
|
|
23
23
|
const checkAuth = useCallback(async () => {
|
|
24
|
+
var _a;
|
|
24
25
|
setAuthStatus((prev) => (Object.assign(Object.assign({}, prev), { loading: true })));
|
|
25
26
|
try {
|
|
26
27
|
const response = await fetch("/api/hazo_auth/me", {
|
|
@@ -38,6 +39,9 @@ export function use_auth_status() {
|
|
|
38
39
|
last_logon: data.last_logon,
|
|
39
40
|
profile_picture_url: data.profile_picture_url,
|
|
40
41
|
profile_source: data.profile_source,
|
|
42
|
+
permissions: data.permissions || [],
|
|
43
|
+
permission_ok: (_a = data.permission_ok) !== null && _a !== void 0 ? _a : true,
|
|
44
|
+
missing_permissions: data.missing_permissions,
|
|
41
45
|
loading: false,
|
|
42
46
|
});
|
|
43
47
|
}
|
|
@@ -40,8 +40,8 @@ export function get_auth_utility_config() {
|
|
|
40
40
|
const section_name = "hazo_auth__auth_utility";
|
|
41
41
|
// Cache settings
|
|
42
42
|
const cache_max_users = get_config_number(section_name, "cache_max_users", 10000);
|
|
43
|
-
const cache_ttl_minutes = get_config_number(section_name, "cache_ttl_minutes",
|
|
44
|
-
const cache_max_age_minutes = get_config_number(section_name, "cache_max_age_minutes",
|
|
43
|
+
const cache_ttl_minutes = get_config_number(section_name, "cache_ttl_minutes", 5);
|
|
44
|
+
const cache_max_age_minutes = get_config_number(section_name, "cache_max_age_minutes", 10);
|
|
45
45
|
// Rate limiting
|
|
46
46
|
const rate_limit_per_user = get_config_number(section_name, "rate_limit_per_user", 100);
|
|
47
47
|
const rate_limit_per_ip = get_config_number(section_name, "rate_limit_per_ip", 200);
|