import { clsx } from 'clsx' import { AuthGuard } from '../../components/AuthGuard' import { ProfileSettingsNavigation } from '../../components/Nav/ProfileSettingsNavigation' import { Icon } from '../../components/_shared/Icon' import { PageLayout } from '../../components/_shared/PageLayout' import { useLocalize } from '../../context/localize' import { UpdateProfileInput } from '@authorizerdev/authorizer-js' import { Show, createEffect, createSignal, on } from 'solid-js' import { PasswordField } from '../../components/Nav/AuthModal/PasswordField' import { Button } from '../../components/_shared/Button' import { Loading } from '../../components/_shared/Loading' import { useConfirm } from '../../context/confirm' import { useSession } from '../../context/session' import { useSnackbar } from '../../context/snackbar' import { DEFAULT_HEADER_OFFSET } from '../../stores/router' import { validateEmail } from '../../utils/validateEmail' import styles from './Settings.module.scss' type FormField = 'oldPassword' | 'newPassword' | 'newPasswordConfirm' | 'email' export const ProfileSecurityPage = () => { const { t } = useLocalize() const { updateProfile, session, isSessionLoaded } = useSession() const { showSnackbar } = useSnackbar() const { showConfirm } = useConfirm() const [newPasswordError, setNewPasswordError] = createSignal() const [oldPasswordError, setOldPasswordError] = createSignal() const [emailError, setEmailError] = createSignal() const [isSubmitting, setIsSubmitting] = createSignal() const [isFloatingPanelVisible, setIsFloatingPanelVisible] = createSignal(false) const initialState = { oldPassword: undefined, newPassword: undefined, newPasswordConfirm: undefined, email: undefined, } const [formData, setFormData] = createSignal(initialState) const oldPasswordRef: { current: HTMLDivElement } = { current: null } const newPasswordRepeatRef: { current: HTMLDivElement } = { current: null } createEffect( on( () => session()?.user?.email, () => { setFormData((prevData) => ({ ...prevData, ['email']: session()?.user?.email, })) }, ), ) const handleInputChange = (name: FormField, value: string) => { if ( name === 'email' || (name === 'newPasswordConfirm' && value && value?.length > 0 && !emailError() && !newPasswordError()) ) { setIsFloatingPanelVisible(true) } else { setIsFloatingPanelVisible(false) } setFormData((prevData) => ({ ...prevData, [name]: value, })) } const handleCancel = async () => { const isConfirmed = await showConfirm({ confirmBody: t('Do you really want to reset all changes?'), confirmButtonVariant: 'primary', declineButtonVariant: 'secondary', }) if (isConfirmed) { setEmailError() setFormData({ ...initialState, ['email']: session()?.user?.email, }) setIsFloatingPanelVisible(false) } } const handleChangeEmail = (_value: string) => { if (!validateEmail(formData()['email'])) { setEmailError(t('Invalid email')) return } } const handleCheckNewPassword = (value: string) => { handleInputChange('newPasswordConfirm', value) if (value !== formData()['newPassword']) { const rect = newPasswordRepeatRef.current.getBoundingClientRect() const topPosition = window.scrollY + rect.top - DEFAULT_HEADER_OFFSET * 2 window.scrollTo({ top: topPosition, left: 0, behavior: 'smooth', }) showSnackbar({ type: 'error', body: t('Incorrect new password confirm') }) setNewPasswordError(t('Passwords are not equal')) } } const handleSubmit = async () => { setIsSubmitting(true) const options: UpdateProfileInput = { old_password: formData()['oldPassword'], new_password: formData()['newPassword'] || formData()['oldPassword'], confirm_new_password: formData()['newPassword'] || formData()['oldPassword'], email: formData()['email'], } try { const { errors } = await updateProfile(options) if (errors.length > 0) { console.error(errors) if (errors.some((obj) => obj.message === 'incorrect old password')) { setOldPasswordError(t('Incorrect old password')) showSnackbar({ type: 'error', body: t('Incorrect old password') }) const rect = oldPasswordRef.current.getBoundingClientRect() const topPosition = window.scrollY + rect.top - DEFAULT_HEADER_OFFSET * 2 window.scrollTo({ top: topPosition, left: 0, behavior: 'smooth', }) setIsFloatingPanelVisible(false) } return } showSnackbar({ type: 'success', body: t('Profile successfully saved') }) } catch (error) { console.error(error) } finally { setIsSubmitting(false) } } return ( }>

{t('Login and security')}

{t('Settings for account, email, password and login methods.')}

{t('Email')}

setEmailError()} onInput={(event) => handleChangeEmail(event.target.value)} />
{emailError()}

{t('Change password')}

{t('Current password')}
(oldPasswordRef.current = el)}> setOldPasswordError()} setError={oldPasswordError()} onInput={(value) => handleInputChange('oldPassword', value)} value={formData()['oldPassword'] ?? null} disabled={isSubmitting()} />
{t('New password')}
{ handleInputChange('newPassword', value) handleInputChange('newPasswordConfirm', '') }} value={formData()['newPassword'] ?? ''} disabled={isSubmitting()} disableAutocomplete={true} />
{t('Confirm your new password')}
(newPasswordRepeatRef.current = el)}> 0 ? formData()['newPasswordConfirm'] : null } onFocus={() => setNewPasswordError()} setError={newPasswordError()} onInput={(value) => handleCheckNewPassword(value)} disabled={isSubmitting()} disableAutocomplete={true} />

{t('Social networks')}

Google

VK

Facebook

Apple

) } export const Page = ProfileSecurityPage