import { FormField, generateFieldHtml, getFormDataField } from '/lib/form-utils.tsx'; import { convertObjectToFormData } from '/lib/utils/misc.ts'; import { currencyMap, SupportedCurrencySymbol, User } from '/lib/types.ts'; import MultiFactorAuthSettings from '/islands/auth/MultiFactorAuthSettings.tsx'; import { getEnabledMultiFactorAuthMethodsFromUser } from '/lib/utils/multi-factor-auth.ts'; import { getTimeZones } from '/lib/utils/calendar.ts'; interface SettingsProps { formData: Record; error?: { title: string; message: string; }; notice?: { title: string; message: string; }; currency?: SupportedCurrencySymbol; timezoneId?: string; isExpensesAppEnabled: boolean; isMultiFactorAuthEnabled: boolean; isCalendarAppEnabled: boolean; helpEmail: string; user: { extra: Pick; }; } export type Action = | 'change-email' | 'verify-change-email' | 'change-password' | 'change-dav-password' | 'delete-account' | 'change-currency' | 'change-timezone'; export const actionWords = new Map([ ['change-email', 'change email'], ['verify-change-email', 'change email'], ['change-password', 'change password'], ['change-dav-password', 'change WebDav password'], ['delete-account', 'delete account'], ['change-currency', 'change currency'], ['change-timezone', 'change timezone'], ]); function formFields(action: Action, formData: FormData, currency?: SupportedCurrencySymbol, timezoneId?: string) { const fields: FormField[] = [ { name: 'action', label: '', type: 'hidden', value: action, overrideValue: action, required: true, readOnly: true, }, ]; if (action === 'change-email') { fields.push({ name: 'email', label: 'Email', type: 'email', placeholder: 'jane.doe@example.com', value: getFormDataField(formData, 'email'), required: true, }); } else if (action === 'verify-change-email') { fields.push({ name: 'email', label: 'Email', type: 'email', placeholder: 'jane.doe@example.com', value: getFormDataField(formData, 'email'), required: true, }, { name: 'verification-code', label: 'Verification Code', description: `The verification code to validate your new email.`, type: 'text', placeholder: '000000', required: true, }); } else if (action === 'change-password') { fields.push({ name: 'current-password', label: 'Current Password', type: 'password', placeholder: 'super-SECRET-passphrase', required: true, }, { name: 'new-password', label: 'New Password', type: 'password', placeholder: 'super-SECRET-passphrase', required: true, }); } else if (action === 'change-dav-password') { fields.push({ name: 'new-dav-password', label: 'New WebDav Password', type: 'password', placeholder: 'super-SECRET-passphrase', required: true, description: 'Alternative password used for WebDav access and/or HTTP Basic Auth.', }); } else if (action === 'delete-account') { fields.push({ name: 'current-password', label: 'Password', type: 'password', placeholder: 'super-SECRET-passphrase', description: 'You need to input your password in order to delete your account.', required: true, }); } else if (action === 'change-currency') { fields.push({ name: 'currency', label: 'Currency', type: 'select', options: Array.from(currencyMap.keys()).map((currencySymbol) => ({ value: currencySymbol, label: `${currencySymbol} (${currencyMap.get(currencySymbol)})`, })), value: getFormDataField(formData, 'currency') || currency, required: true, }); } else if (action === 'change-timezone') { const timezones = getTimeZones(); fields.push({ name: 'timezone', label: 'Timezone', type: 'select', options: timezones.map((timezone) => ({ value: timezone.id, label: timezone.label, })), value: getFormDataField(formData, 'timezone') || timezoneId, required: true, }); } return fields; } export default function Settings( { formData: formDataObject, error, notice, currency, timezoneId, isExpensesAppEnabled, isMultiFactorAuthEnabled, isCalendarAppEnabled, helpEmail, user, }: SettingsProps, ) { const formData = convertObjectToFormData(formDataObject); const multiFactorAuthMethods = getEnabledMultiFactorAuthMethodsFromUser(user); return ( <>
{error ? (

{error.title}

{error.message}

) : null} {notice ? (

{notice.title}

{notice.message}

) : null}

Change your email

{formFields( 'change-email', formData, ).map((field) => generateFieldHtml(field, formData))}

Change your password

{formFields('change-password', formData).map((field) => generateFieldHtml(field, formData))}

Change your WebDav password

{formFields('change-dav-password', formData).map((field) => generateFieldHtml(field, formData))}
{isExpensesAppEnabled ? ( <>

Change your currency

This is only used in the expenses app, visually. It changes nothing about the stored data or values.

{formFields('change-currency', formData, currency, timezoneId).map((field) => generateFieldHtml(field, formData) )}
) : null} {isCalendarAppEnabled ? ( <>

Change your timezone

This is only used in the calendar app.

{formFields('change-timezone', formData, currency, timezoneId).map((field) => generateFieldHtml(field, formData) )}
) : null} {isMultiFactorAuthEnabled ? ( ({ type: method.type, id: method.id, name: method.name, enabled: method.enabled, backupCodesCount: method.metadata.totp?.hashed_backup_codes?.length, }))} /> ) : null}

Delete your account

Deleting your account is instant and deletes all your data. {helpEmail !== '' ? ( <> If you need help, please reach out. ) : null}

{formFields('delete-account', formData).map((field) => generateFieldHtml(field, formData))}
); }