Skip to content

Commit

Permalink
feat(redmine 1291405): add AddressAutocompleteFields (#174)
Browse files Browse the repository at this point in the history
* feat(redmine 1291405): add AddressAutocompleteFields

* feat(redmine 1291405): fix types errors

---------

Co-authored-by: pereag <perello.valentin@hotmail.fr>
  • Loading branch information
vapersmile and pereag authored Apr 17, 2024
1 parent 59acbe4 commit 65cfb35
Show file tree
Hide file tree
Showing 12 changed files with 504 additions and 33 deletions.
5 changes: 5 additions & 0 deletions .changeset/stale-dryers-move.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@smile/react-front-kit': minor
---

Add AddressAutocompleteFields
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { IAdressFields } from './AddressAutocompleteFields';
import type { IAddressGouvData } from '../FetchAutocompleteField/FetchAutoCompleteField.mock';
import type { IValue } from '../FetchAutocompleteField/FetchAutocompleteField';

export function onOptionSubmitMock(
value: IValue<IAddressGouvData>,
): IAdressFields {
const address = value.value.properties;
return {
city: address.city,
country: 'France',
number: address.housenumber,
postCode: address.postcode,
street: address.street,
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.inputContainer {
display: flex;
gap: 10px;
margin-top: 20px;
flex-wrap: wrap;
}

.input {
maxwidth: 300px;
width: calc(50% - 5px);
@mixin smaller-than $mantine-breakpoint-sm {
width: 100%;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { IAddressGouvData } from '../FetchAutocompleteField/FetchAutoCompleteField.mock';
import type { Meta, StoryObj } from '@storybook/react';

import { action } from '@storybook/addon-actions';

import { getDataAddressGouvMock } from '../FetchAutocompleteField/FetchAutoCompleteField.mock';

import { AddressAutocompleteFields as Cmp } from './AddressAutocompleteFields';
import { onOptionSubmitMock } from './AddressAutocompleteFields.mock';

const meta = {
component: Cmp<IAddressGouvData>,
tags: ['autodocs'],
title: '3-custom/Form/AddressAutocompleteFields',
} satisfies Meta<typeof Cmp<IAddressGouvData>>;

export default meta;
type IStory = StoryObj<typeof meta>;

export const AddressAutocompleteFields: IStory = {
args: {
onFetchData: getDataAddressGouvMock,
onFieldsValuesChange: action('value change'),
onOptionSubmit: onOptionSubmitMock,
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { IAdressFields } from './AddressAutocompleteFields';
import type { IValue } from '../FetchAutocompleteField/FetchAutocompleteField';

import { renderWithProviders } from '@smile/react-front-kit-shared/test-utils';

import { AddressAutocompleteFields } from './AddressAutocompleteFields';

describe('FetchAutocompleteField', () => {
beforeEach(() => {
// Prevent mantine random ID
Math.random = () => 0.42;
});
it('matches snapshot', () => {
const { container } = renderWithProviders(
<AddressAutocompleteFields
onFetchData={function (_value: string): Promise<IValue<unknown>[]> {
return [
{ label: 'test', value: { Address: 'test', Number: 'test' } },
] as unknown as Promise<IValue<unknown>[]>;
}}
onOptionSubmit={function (_value: unknown): IAdressFields {
return {
city: 'city',
country: 'country',
number: 'number',
postCode: 'postCode',
street: 'street',
};
}}
/>,
);
expect(container).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
'use client';
import type {
IFetchAutocompleteFieldProps,
IValue,
} from '../FetchAutocompleteField/FetchAutocompleteField';
import type { TextInputProps } from '@mantine/core';
import type { ReactElement } from 'react';

import { TextInput } from '@mantine/core';
import { useState } from 'react';

import { FetchAutocompleteField } from '../FetchAutocompleteField/FetchAutocompleteField';

import classes from './AddressAutocompleteFields.module.css';

export interface IAdressFields {
city?: string;
country?: string;
number?: string;
postCode?: string;
street?: string;
}

export interface ICity {
description?: string;
label?: string;
placeholder?: string;
}
export interface ICountry {
description?: string;
label?: string;
placeholder?: string;
}
export interface INumber {
description?: string;
label?: string;
placeholder?: string;
}
export interface IPostcode {
description?: string;
label?: string;
placeholder?: string;
}

export interface IStreet {
description?: string;
label?: string;
placeholder?: string;
}

export interface IAddressAutocompleteFieldsProps<T>
extends Omit<IFetchAutocompleteFieldProps<T>, 'onOptionSubmit'> {
city?: ICity;
country?: ICountry;
number?: INumber;
onFieldsValuesChange?: (value: IAdressFields) => void;
onOptionSubmit: (value: IValue<T>) => IAdressFields;
postCode?: IPostcode;
street?: IStreet;
textInputProps?: TextInputProps;
}

export function AddressAutocompleteFields<T>(
props: IAddressAutocompleteFieldsProps<T>,
): ReactElement {
const {
street = {
label: 'Street Name',
placeholder: 'Pall Mall',
},
city = {
label: 'City',
placeholder: 'London',
},
country = { label: 'Country', placeholder: 'United Kingdom' },
number = { label: 'Street number', placeholder: '89' },
onOptionSubmit,
onFieldsValuesChange,
postCode = {
label: 'Postal code',
placeholder: 'SW1Y 5HS',
},
textInputProps,
...fetchAutocompleteFieldProps
} = props;

const [streetValue, setStreetValue] = useState('');
const [numberValue, setNumberValue] = useState('');
const [cityValue, setCityValue] = useState('');
const [postCodeValue, setPostCodeValue] = useState('');
const [countryValue, setCountryValue] = useState('');

function onOptionSubmitHandle(value: IValue<T>): void {
const addressFields = onOptionSubmit(value);
setStreetValue(addressFields.street ?? '');
setNumberValue(addressFields.number ?? '');
setCityValue(addressFields.city ?? '');
setPostCodeValue(addressFields.postCode ?? '');
setCountryValue(addressFields.country ?? '');
}

function onChangeHandle(label: string, value: string): void {
onFieldsValuesChange?.({ [label]: value });
}

const inputs = [
{
description: street.description,
label: street.label,
onchange: (e: React.ChangeEvent<HTMLInputElement>) => {
setStreetValue(e.target.value);
onChangeHandle('street', e.target.value);
},
placeholder: street.placeholder,
value: streetValue,
},
{
description: number.description,
label: number.label,
onchange: (e: React.ChangeEvent<HTMLInputElement>) => {
setNumberValue(e.target.value);
onChangeHandle('number', e.target.value);
},
placeholder: number.placeholder,
value: numberValue,
},
{
description: city.description,
label: city.label,
onchange: (e: React.ChangeEvent<HTMLInputElement>) => {
setCityValue(e.target.value);
onChangeHandle('city', e.target.value);
},
placeholder: city.placeholder,
value: cityValue,
},
{
description: postCode.description,
label: postCode.label,
onchange: (e: React.ChangeEvent<HTMLInputElement>) => {
setPostCodeValue(e.target.value);
onChangeHandle('postCode', e.target.value);
},
placeholder: postCode.placeholder,
value: postCodeValue,
},
{
description: country.description,
label: country.label,
onchange: (e: React.ChangeEvent<HTMLInputElement>) => {
setCountryValue(e.target.value);
onChangeHandle('country', e.target.value);
},
placeholder: country.placeholder,
value: countryValue,
},
];

return (
<div>
<FetchAutocompleteField
onOptionSubmit={(value) => onOptionSubmitHandle(value)}
{...fetchAutocompleteFieldProps}
/>
<div className={classes.inputContainer}>
{inputs.map((input) => {
return (
<TextInput
key={input.label}
className={classes.input}
description={input.description}
label={input.label}
onChange={(e) => {
input.onchange(e);
}}
placeholder={input.placeholder}
value={input.value}
/>
);
})}
</div>
</div>
);
}
Loading

0 comments on commit 65cfb35

Please sign in to comment.