import { useState } from 'react'; import Form from 'antd/es/form'; import Input from 'antd/es/input'; import Button from 'antd/es/button'; import Alert from 'antd/es/alert'; import Collapse from 'antd/es/collapse'; import Typography from 'antd/es/typography'; import message from 'antd/es/message'; import { Customer, updateMyName, changeMyPassword, changeMyEmail } from './customerApi'; const { Title, Paragraph } = Typography; type Props = Readonly<{ customer: Customer; // Re-reads the session so the rest of the account view stops showing the old // name and the old verification state. onChanged: () => void; }>; // Changing an email address or a password has a consequence the customer cannot // see from the form: the new address needs verifying and the old one is told, // and a password change signs other devices out. Both are stated above the // fields rather than reported after the fact, so the surprise arrives while // there is still a chance to back out. export default function AccountDetails({ customer, onChanged }: Props) { const [nameError, setNameError] = useState(null); const [emailError, setEmailError] = useState(null); const [passwordError, setPasswordError] = useState(null); const [busy, setBusy] = useState<'name' | 'email' | 'password' | null>(null); const [passwordForm] = Form.useForm(); const [emailForm] = Form.useForm(); async function saveName(values: { firstName: string; lastName: string }) { setBusy('name'); setNameError(null); try { await updateMyName(values.firstName, values.lastName); onChanged(); message.success('Name updated'); } catch (err) { setNameError((err as Error).message); } finally { setBusy(null); } } async function saveEmail(values: { emailPassword: string; newEmail: string }) { setBusy('email'); setEmailError(null); try { await changeMyEmail(values.emailPassword, values.newEmail); onChanged(); emailForm.resetFields(); message.success('Email changed. Check the new address for a verification link.'); } catch (err) { setEmailError((err as Error).message); } finally { setBusy(null); } } async function savePassword(values: { currentPassword: string; newPassword: string }) { setBusy('password'); setPasswordError(null); try { await changeMyPassword(values.currentPassword, values.newPassword); // Nothing to refresh: this session is deliberately the one kept alive. // Clearing the fields matters more, since they hold both passwords. passwordForm.resetFields(); message.success('Password changed. Other devices have been signed out.'); } catch (err) { setPasswordError((err as Error).message); } finally { setBusy(null); } } return (
Your details {nameError && }
{/* Collapsed by default. Both are rare, deliberate actions, and leaving them expanded would push order history and the account controls below the fold for everyone who never uses them. */} Your new address needs verifying before it can be used to sign in or reset your password. We will also tell {customer.email} that the address was changed. {emailError && ( )}
{/* Asked for because a live session alone is not enough to move the address a password reset would be sent to. */}
) }, { key: 'password', label: 'Change your password', children: ( <> Signing in elsewhere will end. You will stay signed in on this device. {passwordError && ( )}
({ validator: (_, value) => !value || getFieldValue('newPassword') === value ? Promise.resolve() : Promise.reject(new Error('The passwords do not match')) }) ]} >
) } ]} />
); }