Skip to content

Commit

Permalink
convert React Address component to TypeScript
Browse files Browse the repository at this point in the history
  • Loading branch information
Théo Cherblanc authored and Lucanis committed Jan 17, 2024
1 parent 3f12eee commit 5589378
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,55 @@ import React from 'react';
import Select from '../Select';
import { useForm } from 'react-hook-form';
import { useIntl } from 'react-intl';
import { isUndefined } from 'lodash-es';

export default function AddressForm({ address = {}, onSubmit = () => {} }) {
import { CheckoutAddress } from '../Checkout/type';
import { CivilityTitle } from '@js/types/common';

type CustomerTITLE = { label: string; value: number; isDefault: boolean };
type CustomerTITLES = CustomerTITLE[];

type COUNTRY = {
id: string;
title: string;
isDefault: boolean;
};

type CUSTOMER_COUNTRY = {
value: string;
label: string;
isDefault: boolean;
}[];

interface AddressFormProps {
address?: CheckoutAddress;
onSubmit: (data: any) => void;
}

export default function AddressForm({
address,
onSubmit = async (data = null) => {}
}: AddressFormProps) {
const intl = useIntl();
const { register, handleSubmit, formState, setError } = useForm();

const titles = (window.CUSTOMER_TITLES || [])
.map((t) => {
const titles: CustomerTITLES = ((window as any).CUSTOMER_TITLES || [])
.map((t: CivilityTitle) => {
return {
label: t.short,
value: t.id,
isDefault: !!t.isDefault
};
})
.sort((a, b) => b.isDefault - a.isDefault);
.sort(
(a: CustomerTITLE, b: CustomerTITLE) =>
(b.isDefault ? 1 : 0) - (a.isDefault ? 1 : 0)
);

const countries = (window.COUNTRIES || []).map((c) => {
const countries = ((window as any).COUNTRIES || []).map((c: COUNTRY) => {
return {
label: c.title,
value: c.id,
isDefault: c.id === window.DEFAULT_COUNTRY
isDefault: c.isDefault
};
});

Expand All @@ -41,11 +69,16 @@ export default function AddressForm({ address = {}, onSubmit = () => {} }) {
for (const [key, val] of Object.entries(
error?.response?.data?.schemaViolations
)) {
setError(key, {
type: 'manual',
message: val.message,
shouldFocus: true
});
setError(
key as keyof CheckoutAddress,
{
type: 'manual',
message: (val as any).message
},
{
shouldFocus: true
}
);
}
}
}
Expand All @@ -57,7 +90,7 @@ export default function AddressForm({ address = {}, onSubmit = () => {} }) {
<div className="md:w-1/2">
<Input
label={intl.formatMessage({ id: 'LABEL_LABEL' })}
defaultValue={address.label}
defaultValue={address?.label}
required={true}
{...register('label', {
required: intl.formatMessage({ id: 'MANDATORY' })
Expand All @@ -69,25 +102,28 @@ export default function AddressForm({ address = {}, onSubmit = () => {} }) {
<div className="w-1/2 lg:w-1/3">
<Select
label={intl.formatMessage({ id: 'CIVILITY_TITLE_LABEL' })}
defaultValue={
isUndefined(address.title)
? titles.find((t) => t.isDefault).value
: address.title
}
defaultValue={(
address?.civilityTitle?.id ?? titles.find((t) => t.isDefault)!.value
).toString()}
required={true}
options={titles}
{...register('civilityTitle.id', {
required: intl.formatMessage({ id: 'MANDATORY' })
})}
error={formState.errors?.title?.message}
/>
error={formState.errors?.title?.message as string}
>
{titles.map(({ label, value }) => (
<option key={value} value={value}>
{label}
</option>
))}
</Select>
</div>

<div className="flex gap-3">
<div className="w-1/2">
<Input
label={intl.formatMessage({ id: 'FIRSTNAME_LABEL' })}
defaultValue={address.firstName}
defaultValue={address?.firstName}
required={true}
{...register('firstName', {
required: intl.formatMessage({ id: 'MANDATORY' })
Expand All @@ -98,7 +134,7 @@ export default function AddressForm({ address = {}, onSubmit = () => {} }) {
<div className="w-1/2">
<Input
label={intl.formatMessage({ id: 'LASTNAME_LABEL' })}
defaultValue={address.lastName}
defaultValue={address?.lastName}
required={true}
{...register('lastName', {
required: intl.formatMessage({ id: 'MANDATORY' })
Expand All @@ -110,23 +146,23 @@ export default function AddressForm({ address = {}, onSubmit = () => {} }) {

<Input
label={intl.formatMessage({ id: 'COMPANY_LABEL' })}
defaultValue={address.company}
defaultValue={address?.company}
{...register('company')}
error={formState.errors?.company?.message}
/>

<Input
label={intl.formatMessage({ id: 'ADDRESS_1_LABEL' })}
required={true}
defaultValue={address.address1}
defaultValue={address?.address1}
{...register('address1', {
required: intl.formatMessage({ id: 'MANDATORY' })
})}
error={formState.errors?.address1?.message}
/>
<Input
label={intl.formatMessage({ id: 'ADDRESS_2_LABEL' })}
defaultValue={address.address2}
defaultValue={address?.address2}
{...register('address2')}
error={formState.errors?.address2?.message}
/>
Expand All @@ -136,7 +172,7 @@ export default function AddressForm({ address = {}, onSubmit = () => {} }) {
<Input
label={intl.formatMessage({ id: 'CITY_LABEL' })}
required={true}
defaultValue={address.city}
defaultValue={address?.city}
{...register('city', {
required: intl.formatMessage({ id: 'MANDATORY' })
})}
Expand All @@ -148,7 +184,7 @@ export default function AddressForm({ address = {}, onSubmit = () => {} }) {
<Input
label={intl.formatMessage({ id: 'ZIPCODE_LABEL' })}
required={true}
defaultValue={address.zipCode}
defaultValue={address?.zipCode}
{...register('zipCode', {
required: intl.formatMessage({ id: 'MANDATORY' })
})}
Expand All @@ -159,25 +195,30 @@ export default function AddressForm({ address = {}, onSubmit = () => {} }) {

<div className="w-1/2">
<Select
label={intl.formatMessage({ id: 'COUNTRY_LABEL' })}
defaultValue={(
address?.civilityTitle?.id ?? titles.find((t) => t.isDefault)!.value
).toString()}
id={'address_civility_title'}
label={intl.formatMessage({ id: 'CIVILITY_TITLE_LABEL' })}
required={true}
options={countries}
defaultValue={
isUndefined(address.countryCode)
? countries.find((c) => c.isDefault).value
: address.countryCode
}
{...register('countryCode', { required: 'Mandatory' })}
error={formState.errors?.countryCode?.message}
/>
{...register('civilityTitle.id', {
required: intl.formatMessage({ id: 'MANDATORY' })
})}
>
{titles.map(({ label, value }) => (
<option key={value} value={value}>
{label}
</option>
))}
</Select>
</div>

<div className="flex gap-3">
<div className="w-1/2">
<Input
label={intl.formatMessage({ id: 'CELLPHONE_LABEL' })}
required={true}
defaultValue={address.cellphone}
defaultValue={address?.cellphone}
{...register('cellphone', {
required: intl.formatMessage({ id: 'MANDATORY' })
})}
Expand All @@ -187,7 +228,7 @@ export default function AddressForm({ address = {}, onSubmit = () => {} }) {
<div className="w-1/2">
<Input
label={intl.formatMessage({ id: 'PHONE_LABEL' })}
defaultValue={address.phone}
defaultValue={address?.phone}
{...register('phone')}
error={formState.errors?.phone?.message}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default function CreateAddressModal({ className = '' }) {
}
}, [isSuccess]);

const submitForm = async (values) => {
const submitForm = async (values: any) => {
try {
await create(values);
} catch (error) {
Expand All @@ -38,7 +38,7 @@ export default function CreateAddressModal({ className = '' }) {
setIsCreatingAddress(true);
}}
>
<span className="flex items-center justify-center w-6 h-6 mr-3 text-white bg-black rounded-full">
<span className="mr-3 flex h-6 w-6 items-center justify-center rounded-full bg-black text-white">
<IconPlus className="h-[9px] w-[9px]" />
</span>

Expand All @@ -61,8 +61,8 @@ export default function CreateAddressModal({ className = '' }) {
bodyOpenClassName={null}
>
<div className="relative">
<Title title="CREATE_ADDRESS" className="pr-5 mb-8 Title--3" />
<div className="block w-full mx-auto">
<Title title="CREATE_ADDRESS" className="Title--3 mb-8 pr-5" />
<div className="mx-auto block w-full">
<button
type="button"
className="Modal-close"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import { useAddressUpdate } from '@openstudio/thelia-api-utils';
import { useIntl } from 'react-intl';
import { useLockBodyScroll } from 'react-use';
import Title from '../Title';
import { Address } from '../Checkout/type';

export default function EditAddress({ address = {} }) {
export default function EditAddress({ address }: { address: Address }) {
const intl = useIntl();
const [isEditingAddress, setIsEditingAddress] = useState(false);
useLockBodyScroll(isEditingAddress);
Expand All @@ -20,7 +21,7 @@ export default function EditAddress({ address = {} }) {
}
}, [isSuccess]);

const submitForm = async (values) => {
const submitForm = async (values: any) => {
await update({
id: address.id,
data: values
Expand Down Expand Up @@ -58,12 +59,9 @@ export default function EditAddress({ address = {} }) {
>
<IconCLose />
</button>
<div className="block w-full mx-auto">
<Title title="EDIT_AN_ADDRESS" className="pr-5 mb-8 Title--3" />
<AddressForm
address={address}
onSubmit={submitForm}
/>
<div className="mx-auto block w-full">
<Title title="EDIT_AN_ADDRESS" className="Title--3 mb-8 pr-5" />
<AddressForm address={address} onSubmit={submitForm} />
</div>
</div>
</Modal>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ export default function Payment({ isVisible, checkout, page }) {
if (!isVisible) return null;

return (
<div className="col-span-2 Checkout-page">
<Title title={`${title}`} className="mb-8 Title--2" />
<div className="Checkout-page col-span-2">
<Title title={`${title}`} className="Title--2 mb-8" />
<Suspense fallback={<Loader />}>
<PaymentModules />
</Suspense>
Expand All @@ -27,7 +27,7 @@ export default function Payment({ isVisible, checkout, page }) {
<PhoneCheck addressId={checkout?.deliveryAddressId} />
)}
{checkout?.paymentModuleId && phoneCheck && (
<label className="mt-8 Checkbox">
<label className="Checkbox mt-8">
<input
type="checkbox"
id="validTerms"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { useClickAway } from 'react-use';
import useEscape from '@js/utils/useEscape';
import closeAndFocus from '@js/utils/closeAndFocus';
import { trapTabKey } from '@js/standalone/trapItemsMenu';
import { LoginFormProps } from './MiniLogin.types';
import { LoginFormProps, MiniLoginProps } from './MiniLogin.types';

function LoginForm({ setLoginHandler, redirectionToCheckout }: LoginFormProps) {
const [email, setEmail] = useState('');
Expand Down Expand Up @@ -116,7 +116,7 @@ function IsLoggedOut({
);
}

export function MiniLogin({ isLogged }: { isLogged: boolean }) {
export function MiniLogin({ isLogged }: MiniLoginProps) {
const dispatch = useDispatch();
const { login: visible, redirectionToCheckout } = useSelector(
(state: any) => state.visibility
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { SelectHTMLAttributes } from 'react';

export type SelectProps = {
name: string;
options: { value: string; label: string; className?: string }[];
name?: string;
options?: { value: string; label: string; className?: string }[];
label?: string;
error?: string;
placeholder: string;
placeholder?: string;
defaultValue?: string | string[] | undefined;
required?: boolean;
disabled?: boolean;
Expand Down
1 change: 1 addition & 0 deletions templates/frontOffice/modern/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"@symfony/webpack-encore": "^4.1.0",
"@types/lodash": "^4.14.197",
"@types/react-dom": "^18.2.7",
"@types/react-modal": "^3.16.0",
"axios": "^1.1.3",
"eslint-config-react-app": "^7.0.1",
"infinite-scroll": "^4.0.1",
Expand Down
7 changes: 7 additions & 0 deletions templates/frontOffice/modern/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1782,6 +1782,13 @@
dependencies:
"@types/react" "*"

"@types/react-modal@^3.16.0":
version "3.16.0"
resolved "https://registry.npmjs.org/@types/react-modal/-/react-modal-3.16.0.tgz"
integrity sha512-iphdqXAyUfByLbxJn5j6d+yh93dbMgshqGP0IuBeaKbZXx0aO+OXsvEkt6QctRdxjeM9/bR+Gp3h9F9djVWTQQ==
dependencies:
"@types/react" "*"

"@types/react@*", "@types/react@16 || 17 || 18":
version "18.0.21"
resolved "https://registry.npmjs.org/@types/react/-/react-18.0.21.tgz"
Expand Down

0 comments on commit 5589378

Please sign in to comment.