mirror of
https://github.com/Tria-plc/emaui.git
synced 2026-08-26 19:12:50 +00:00
Refactor AddressFormContent and ProfilePage to integrate CountrySelect for nationality selection and update address payload handling
This commit is contained in:
@@ -2,7 +2,7 @@ import { useCallback, useMemo } from 'react';
|
||||
import { Select, SimpleGrid, Text, TextInput } from '@mantine/core';
|
||||
import type { FieldErrors, UseFormRegister, UseFormSetValue, UseFormWatch, UseFormTrigger } from 'react-hook-form';
|
||||
import { z } from 'zod';
|
||||
import { ethiopianPhone, optionalEthiopianPhone } from '@ema-platform/ui';
|
||||
import { ethiopianPhone, optionalEthiopianPhone, CountrySelect } from '@ema-platform/ui';
|
||||
import { LocationPicker } from '../../location/components/LocationPicker';
|
||||
import { useGetLocationTypesQuery } from '../../location/api/location-api';
|
||||
import type { Location } from '../../location/types/location';
|
||||
@@ -10,11 +10,11 @@ import type { Location } from '../../location/types/location';
|
||||
export const addressSchema = z.object({
|
||||
idType: z.string().min(1, 'Select ID type'),
|
||||
idNumber: z.string().trim().min(1, 'Enter ID number'),
|
||||
nationality: z.string().trim().min(1, 'Enter nationality'),
|
||||
// Alpha-2 country code from CountrySelect; converted to a full name at submit.
|
||||
nationality: z.string().min(1, 'Select nationality'),
|
||||
primaryPhoneNumber: ethiopianPhone,
|
||||
secondaryPhoneNumber: optionalEthiopianPhone,
|
||||
email: z.string().trim().email('Invalid email').optional().or(z.literal('')),
|
||||
website: z.string().trim().url('Enter a valid URL').optional().or(z.literal('')),
|
||||
regionId: z.string().optional(),
|
||||
cityId: z.string().optional(),
|
||||
subcityId: z.string().optional(),
|
||||
@@ -115,11 +115,11 @@ export function AddressFormContent({
|
||||
{...register('idNumber')}
|
||||
error={errors.idNumber?.message}
|
||||
/>
|
||||
<TextInput
|
||||
<CountrySelect
|
||||
label="Nationality"
|
||||
placeholder="e.g. Ethiopian"
|
||||
required
|
||||
{...register('nationality')}
|
||||
value={watch('nationality') || null}
|
||||
onChange={(val) => setValue('nationality', val || '', { shouldValidate: true })}
|
||||
error={errors.nationality?.message}
|
||||
/>
|
||||
<TextInput
|
||||
@@ -144,12 +144,6 @@ export function AddressFormContent({
|
||||
{...register('email')}
|
||||
error={errors.email?.message}
|
||||
/>
|
||||
<TextInput
|
||||
label="Website"
|
||||
placeholder="https://example.com"
|
||||
{...register('website')}
|
||||
error={errors.website?.message}
|
||||
/>
|
||||
</SimpleGrid>
|
||||
|
||||
<Text fw={600} fz="sm" tt="uppercase" c="gray.6" mt="lg" mb="sm">
|
||||
|
||||
@@ -47,7 +47,7 @@ import { useForm } from 'react-hook-form';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { z } from 'zod';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { notify, PageHeader, useErrorHandler, passwordSchema as strongPasswordSchema, PasswordRequirements } from '@ema-platform/ui';
|
||||
import { notify, PageHeader, useErrorHandler, passwordSchema as strongPasswordSchema, PasswordRequirements, getCountryCode } from '@ema-platform/ui';
|
||||
import { useApiMutation } from '@ema-platform/api';
|
||||
import { setUser, useCurrentProfile } from '@ema-platform/auth';
|
||||
import type { CurrentProfile } from '@ema-platform/auth';
|
||||
@@ -201,11 +201,11 @@ export function ProfilePage() {
|
||||
setLoadedAddress({
|
||||
idType: currentProfile.address?.idType || '',
|
||||
idNumber: currentProfile.address?.idNumber || '',
|
||||
nationality: currentProfile.address?.nationality || '',
|
||||
// Stored as a country name; the select works in alpha-2 codes.
|
||||
nationality: getCountryCode(currentProfile.address?.nationality) || '',
|
||||
primaryPhoneNumber: user?.phoneNumber || '',
|
||||
secondaryPhoneNumber: currentProfile.address?.secondaryPhoneNumber || '',
|
||||
email: user?.email || '',
|
||||
website: currentProfile.address?.website || '',
|
||||
regionId: currentProfile.address?.regionId || '',
|
||||
cityId: currentProfile.address?.cityId || '',
|
||||
subcityId: currentProfile.address?.subCityId || '',
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { getCountryName } from '@ema-platform/ui';
|
||||
import type { AddressValues } from '../components/AddressFormContent';
|
||||
|
||||
/** Exact request body of `POST /addresss/profile/{profileId}`. */
|
||||
@@ -14,7 +15,7 @@ export interface AddressPayload {
|
||||
primaryPhoneNumber: string;
|
||||
secondaryPhoneNumber?: string;
|
||||
email?: string;
|
||||
website?: string;
|
||||
website: null;
|
||||
postalAddress?: string;
|
||||
emergencyContactName?: string;
|
||||
emergencyContactPhone?: string;
|
||||
@@ -28,7 +29,8 @@ export function toAddressPayload(values: AddressValues): AddressPayload {
|
||||
return {
|
||||
idType: values.idType.trim(),
|
||||
idNumber: values.idNumber.trim(),
|
||||
nationality: values.nationality.trim(),
|
||||
// Form holds the alpha-2 code (CountrySelect); API stores the full name.
|
||||
nationality: getCountryName(values.nationality),
|
||||
regionId: clean(values.regionId),
|
||||
cityId: clean(values.cityId),
|
||||
subcityId: clean(values.subcityId),
|
||||
@@ -38,7 +40,7 @@ export function toAddressPayload(values: AddressValues): AddressPayload {
|
||||
primaryPhoneNumber: values.primaryPhoneNumber,
|
||||
secondaryPhoneNumber: clean(values.secondaryPhoneNumber),
|
||||
email: clean(values.email),
|
||||
website: clean(values.website),
|
||||
website: null, // no website field in the form — always sent as null
|
||||
postalAddress: clean(values.postalAddress),
|
||||
emergencyContactName: clean(values.emergencyContactName),
|
||||
emergencyContactPhone: clean(values.emergencyContactPhone),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Group, Select, Text, type ComboboxItem, type SelectProps } from '@mantine/core';
|
||||
import { registerLocale, getNames, getName } from 'i18n-iso-countries';
|
||||
import { registerLocale, getNames, getName, getAlpha2Code } from 'i18n-iso-countries';
|
||||
import * as Flags from 'country-flag-icons/react/3x2';
|
||||
import en from 'i18n-iso-countries/langs/en.json';
|
||||
import am from 'i18n-iso-countries/langs/am.json';
|
||||
@@ -21,6 +21,11 @@ export function getCountryName(code: string | null | undefined, lang: CountryLan
|
||||
return code ? (getName(code, lang) ?? '') : '';
|
||||
}
|
||||
|
||||
/** Alpha-2 code for a stored country name (e.g. "Ethiopian" data); undefined when unmatched. */
|
||||
export function getCountryCode(name: string | null | undefined, lang: CountryLang = 'en'): string | undefined {
|
||||
return name ? getAlpha2Code(name, lang) : undefined;
|
||||
}
|
||||
|
||||
function CountryFlag({ code }: { code: string }) {
|
||||
const Flag = Flags[code as keyof typeof Flags];
|
||||
return Flag ? <Flag style={{ width: 22, borderRadius: 2, display: 'block' }} /> : null;
|
||||
|
||||
Reference in New Issue
Block a user