147 lines
5.1 KiB
TypeScript
147 lines
5.1 KiB
TypeScript
import { CountrySelect } from '@/components/shared/CountrySelect';
|
|
import { Icon } from '@/ui/Icon';
|
|
import { Input } from '@/ui/Input';
|
|
import { Grid } from '@/ui/primitives/Grid';
|
|
import { Stack } from '@/ui/primitives/Stack';
|
|
import { Select } from '@/ui/Select';
|
|
import { Text } from '@/ui/Text';
|
|
import { ChevronRight, Clock } from 'lucide-react';
|
|
|
|
export interface PersonalInfo {
|
|
firstName: string;
|
|
lastName: string;
|
|
displayName: string;
|
|
country: string;
|
|
timezone: string;
|
|
}
|
|
|
|
interface FormErrors {
|
|
[key: string]: string | undefined;
|
|
}
|
|
|
|
interface PersonalInfoStepProps {
|
|
personalInfo: PersonalInfo;
|
|
setPersonalInfo: (info: PersonalInfo) => void;
|
|
errors: FormErrors;
|
|
loading: boolean;
|
|
}
|
|
|
|
const TIMEZONES = [
|
|
{ value: 'America/New_York', label: 'Eastern Time (ET)' },
|
|
{ value: 'America/Chicago', label: 'Central Time (CT)' },
|
|
{ value: 'America/Denver', label: 'Mountain Time (MT)' },
|
|
{ value: 'America/Los_Angeles', label: 'Pacific Time (PT)' },
|
|
{ value: 'Europe/London', label: 'Greenwich Mean Time (GMT)' },
|
|
{ value: 'Europe/Berlin', label: 'Central European Time (CET)' },
|
|
{ value: 'Europe/Paris', label: 'Central European Time (CET)' },
|
|
{ value: 'Australia/Sydney', label: 'Australian Eastern Time (AET)' },
|
|
{ value: 'Asia/Tokyo', label: 'Japan Standard Time (JST)' },
|
|
{ value: 'America/Sao_Paulo', label: 'Brasília Time (BRT)' },
|
|
];
|
|
|
|
export function PersonalInfoStep({ personalInfo, setPersonalInfo, errors, loading }: PersonalInfoStepProps) {
|
|
return (
|
|
<Stack gap={6}>
|
|
<Grid cols={2} gap={4}>
|
|
<Stack>
|
|
<Text as="label" htmlFor="firstName" size="sm" weight="medium" color="text-gray-300" block mb={2}>
|
|
First Name *
|
|
</Text>
|
|
<Input
|
|
id="firstName"
|
|
type="text"
|
|
value={personalInfo.firstName}
|
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
|
setPersonalInfo({ ...personalInfo, firstName: e.target.value })
|
|
}
|
|
variant={errors.firstName ? 'error' : 'default'}
|
|
errorMessage={errors.firstName}
|
|
placeholder="John"
|
|
disabled={loading}
|
|
/>
|
|
</Stack>
|
|
|
|
<Stack>
|
|
<Text as="label" htmlFor="lastName" size="sm" weight="medium" color="text-gray-300" block mb={2}>
|
|
Last Name *
|
|
</Text>
|
|
<Input
|
|
id="lastName"
|
|
type="text"
|
|
value={personalInfo.lastName}
|
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
|
setPersonalInfo({ ...personalInfo, lastName: e.target.value })
|
|
}
|
|
variant={errors.lastName ? 'error' : 'default'}
|
|
errorMessage={errors.lastName}
|
|
placeholder="Racer"
|
|
disabled={loading}
|
|
/>
|
|
</Stack>
|
|
</Grid>
|
|
|
|
<Stack>
|
|
<Text as="label" htmlFor="displayName" size="sm" weight="medium" color="text-gray-300" block mb={2}>
|
|
Display Name * <Text color="text-gray-500" weight="normal">(shown publicly)</Text>
|
|
</Text>
|
|
<Input
|
|
id="displayName"
|
|
type="text"
|
|
value={personalInfo.displayName}
|
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
|
setPersonalInfo({ ...personalInfo, displayName: e.target.value })
|
|
}
|
|
variant={errors.displayName ? 'error' : 'default'}
|
|
errorMessage={errors.displayName}
|
|
placeholder="SpeedyRacer42"
|
|
disabled={loading}
|
|
/>
|
|
</Stack>
|
|
|
|
<Grid cols={2} gap={4}>
|
|
<Stack>
|
|
<Text as="label" htmlFor="country" size="sm" weight="medium" color="text-gray-300" block mb={2}>
|
|
Country *
|
|
</Text>
|
|
<CountrySelect
|
|
value={personalInfo.country}
|
|
onChange={(value: string) =>
|
|
setPersonalInfo({ ...personalInfo, country: value })
|
|
}
|
|
error={!!errors.country}
|
|
errorMessage={errors.country ?? ''}
|
|
disabled={loading}
|
|
/>
|
|
</Stack>
|
|
|
|
<Stack>
|
|
<Text as="label" htmlFor="timezone" size="sm" weight="medium" color="text-gray-300" block mb={2}>
|
|
Timezone
|
|
</Text>
|
|
<Stack position="relative">
|
|
<Stack position="absolute" left={3} top="50%" transform="translateY(-50%)" zIndex={10}>
|
|
<Icon icon={Clock} size={4} color="text-gray-500" />
|
|
</Stack>
|
|
<Select
|
|
id="timezone"
|
|
value={personalInfo.timezone}
|
|
onChange={(e: React.ChangeEvent<HTMLSelectElement>) =>
|
|
setPersonalInfo({ ...personalInfo, timezone: e.target.value })
|
|
}
|
|
options={[
|
|
{ value: '', label: 'Select timezone' },
|
|
...TIMEZONES
|
|
]}
|
|
pl={10}
|
|
disabled={loading}
|
|
/>
|
|
<Stack position="absolute" right={3} top="50%" transform="translateY(-50%)" pointerEvents="none">
|
|
<Icon icon={ChevronRight} size={4} color="text-gray-500" transform="rotate(90deg)" />
|
|
</Stack>
|
|
</Stack>
|
|
</Stack>
|
|
</Grid>
|
|
</Stack>
|
|
);
|
|
}
|