import { useState } from 'react'; import Form from 'antd/es/form'; import Input from 'antd/es/input'; import Button from 'antd/es/button'; import Checkbox from 'antd/es/checkbox'; import Tabs from 'antd/es/tabs'; import Alert from 'antd/es/alert'; import Typography from 'antd/es/typography'; import { registerCustomer, loginCustomer } from './customerApi'; import { useCustomerAuth } from './CustomerAuthContext'; const { Text } = Typography; export type AuthMode = 'register' | 'login'; // Must stay identical to MARKETING_CONSENT_TEXT in backend/src/utils.ts, which // is what gets stored verbatim against the customer's consent record. The point // of storing it is that the record says what the customer actually saw, so a // label that differs from the stored string defeats the whole mechanism. Before // this was shared there were three wordings in play — this one, a shorter one in // the cart prompt, and the string the server actually recorded — and none of // them matched. // // Widened for #56 so it covers the Brevo tracker as well as email. The tracker // is gated on whether a customer's *stored* copy of this sentence matches the // current one, so changing it here does not retroactively widen the consent of // anyone who agreed to the previous wording. export const MARKETING_CONSENT_TEXT = 'I want to receive occasional emails about new one-of-a-kind items from Redefined Designs, and I agree that what I browse and buy here may be shared with our email provider to help choose what they contain. I can unsubscribe at any time.'; type Props = Readonly<{ mode: AuthMode; onModeChange: (mode: AuthMode) => void; onForgotPassword: () => void; // Called once the session exists. What that means differs by caller: the // route closes back to the page behind it, while the cart and favorite // prompts resume the action the customer was interrupted doing. onSuccess: () => void; }>; // The one implementation of signing in and registering. It was previously // written twice — once as the /login and /register pages, once inside the // prompt shown when a signed-out visitor adds to the cart — which had already // drifted in consent wording and in which links each offered. export default function AuthForm({ mode, onModeChange, onForgotPassword, onSuccess }: Props) { const [error, setError] = useState(null); const [loading, setLoading] = useState(false); const { refresh } = useCustomerAuth(); async function submit(action: () => Promise) { setLoading(true); setError(null); try { await action(); refresh(); onSuccess(); } catch (err) { setError((err as Error).message); } finally { setLoading(false); } } return ( <> {error && } { // A stale error from the other tab would read as though it applied to // the form now on screen. setError(null); onModeChange(key as AuthMode); }} items={[ { key: 'register', label: 'Create Account', children: (
submit(() => registerCustomer(values.email, values.password, values.firstName, values.lastName, !!values.marketingConsent) ) } > {MARKETING_CONSENT_TEXT} {/* Opens in a new tab deliberately: following it in place would discard a part-filled signup form, and /privacy has no way back of its own yet (#52). */} By creating an account you agree to our{' '} Privacy Policy.
) }, { key: 'login', label: 'Log In', children: (
submit(() => loginCustomer(values.email, values.password))} >
) } ]} /> ); }