Skip to content
Snippets Groups Projects
Commit 8606d249 authored by Defendi Alberto's avatar Defendi Alberto
Browse files

Merge branch 'api/reservation-senior-search' into 'dev'

Camelize data and insert react-hook-form in autocomplete.

See merge request !58
parents 09857179 26c584dc
No related branches found
No related tags found
2 merge requests!60New component to search senior (see #12). Enhance responsiveness and solve #10 and #11,!58Camelize data and insert react-hook-form in autocomplete.
Pipeline #12693 failed
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
"@types/react-router-dom": "^5.1.7", "@types/react-router-dom": "^5.1.7",
"axios": "^0.21.1", "axios": "^0.21.1",
"eslint-config-airbnb-typescript": "^12.3.1", "eslint-config-airbnb-typescript": "^12.3.1",
"humps": "^2.0.1",
"react": "^17.0.1", "react": "^17.0.1",
"react-dom": "^17.0.1", "react-dom": "^17.0.1",
"react-hook-form": "^6.15.5", "react-hook-form": "^6.15.5",
...@@ -54,6 +55,7 @@ ...@@ -54,6 +55,7 @@
} }
}, },
"devDependencies": { "devDependencies": {
"@types/humps": "^2.0.0",
"@typescript-eslint/eslint-plugin": "^4.18.0", "@typescript-eslint/eslint-plugin": "^4.18.0",
"@typescript-eslint/parser": "^4.18.0", "@typescript-eslint/parser": "^4.18.0",
"eslint": "^7.2.0", "eslint": "^7.2.0",
......
export type ResponseProps = {
id: number;
user: {
email: string;
firstName: string;
lastName: string;
username: string;
};
memberCardNumber: number;
};
import axios from 'axios'; import axios from 'axios';
import { camelizeKeys } from 'humps';
import { ResponseProps } from './ResponseProps';
export const getSeniorList = async (name: string): Promise<string[]> => export const getSeniorList = async (name: string): Promise<ResponseProps[]> =>
axios.get(`/api/web/seniors/by_name/${name}`).then((res) => res.data); axios
.get(`/api/web/seniors/by_name/${name}?fields=user,id,member_card_number`)
.then((res) => camelizeKeys(res.data) as ResponseProps[]);
import axios from 'axios';
import { camelizeKeys } from 'humps';
import { ResponseProps } from './ResponseProps';
export const getSeniorListByCard = async (
card: number,
): Promise<ResponseProps[]> =>
axios
.get(
`/api/web/seniors/by_member_card/${card}?fields=user,id,member_card_number`,
)
.then((res) => camelizeKeys(res.data) as ResponseProps[])
.catch(() => [] as ResponseProps[]);
...@@ -3,4 +3,5 @@ export type ReservationProps = { ...@@ -3,4 +3,5 @@ export type ReservationProps = {
destination: string; destination: string;
time: string; time: string;
date: string; date: string;
senior?: number;
}; };
...@@ -3,41 +3,71 @@ import React, { FC, useState } from 'react'; ...@@ -3,41 +3,71 @@ import React, { FC, useState } from 'react';
import TextField from '@material-ui/core/TextField'; import TextField from '@material-ui/core/TextField';
import Autocomplete from '@material-ui/lab/Autocomplete'; import Autocomplete from '@material-ui/lab/Autocomplete';
import { getSeniorList } from 'api/getSeniorList'; import { getSeniorList } from 'api/getSeniorList';
import { ResponseProps } from 'api/ResponseProps';
import { Control, Controller } from 'react-hook-form';
import { ReservationProps } from './ReservationProps';
export const SeniorSearch: FC = () => { type SeniorSearchProps = {
const [value, setValue] = useState<string | null>(null); control: Control<ReservationProps>;
const [inputValue, setInputValue] = useState<string>(''); };
const [options, setOptions] = useState<string[]>(['']);
export const SeniorSearch: FC<SeniorSearchProps> = ({
control,
}: SeniorSearchProps) => {
const [value, setValue] = useState<ResponseProps | null>(null);
const [seniors, setSeniors] = useState<ResponseProps[]>([]);
const [query, setQuery] = useState<string>('');
// FIX: Input closing when the data is changed.
// The issue is caused by the stopped re-rendering of react hook form. Consider
// attaching the value manually or to isolate this component.
const handleChange = (newValue: string): void => { const handleChange = (newValue: string): void => {
setInputValue(newValue); const MIN_SEARCH_LENGTH = 4;
const MIN_SEARCH_LENGTH = 3; if (newValue.length >= MIN_SEARCH_LENGTH && value == null) {
if (newValue.length >= MIN_SEARCH_LENGTH) { getSeniorList(newValue).then((list) => {
getSeniorList(newValue).then((list) => console.log(list)); if (list.length !== 0) {
setSeniors(list);
} else {
setSeniors([]);
}
});
} }
}; };
return ( return (
<div> <Controller
<div>{`value: ${value !== null ? `'${value}'` : 'null'}`}</div> control={control}
<div>{`inputValue: '${inputValue}'`}</div> name="senior"
<br /> as={({ onChange }) => (
<Autocomplete <Autocomplete
value={value} value={value}
onChange={(event: any, newValue: string | null) => { id="senior-searcher"
setValue(newValue); onInputChange={(_, newValue) => handleChange(newValue)}
}} onChange={(_, val) => {
inputValue={inputValue} onChange(val?.id);
onInputChange={(event, newInputValue) => { setValue(val);
handleChange(newInputValue); }}
}} options={seniors}
id="senior-searcher" getOptionSelected={(option, val) => option.id === val.id}
options={options} getOptionLabel={(option) => option.user.lastName}
style={{ width: 300 }} renderOption={(option) => (
renderInput={(params) => ( <>
<TextField {...params} label="Search a senior" variant="outlined" /> {option.user.firstName} {option.user.lastName}{' '}
)} {option.user.username} {option.memberCardNumber}
/> </>
</div> )}
renderInput={(params) => (
<TextField
{...params}
label="Search a senior"
variant="outlined"
InputProps={{
...params.InputProps,
}}
/>
)}
/>
)}
/>
); );
}; };
...@@ -11,6 +11,7 @@ import { useReservations } from 'hooks/useReservations'; ...@@ -11,6 +11,7 @@ import { useReservations } from 'hooks/useReservations';
import { ReservationProps } from 'components/Dashboard/ReservationPage/Reservation/ReservationProps'; import { ReservationProps } from 'components/Dashboard/ReservationPage/Reservation/ReservationProps';
import { SubmitHandler, useForm } from 'react-hook-form'; import { SubmitHandler, useForm } from 'react-hook-form';
import { InputField } from 'components/Auth/InputField/InputField'; import { InputField } from 'components/Auth/InputField/InputField';
import { SeniorSearch } from './Reservation/SeniorSearch';
type ReservationDialogProps = { type ReservationDialogProps = {
handleClose: () => void; handleClose: () => void;
...@@ -20,7 +21,15 @@ export const ReservationDialog: FC<ReservationDialogProps> = ({ ...@@ -20,7 +21,15 @@ export const ReservationDialog: FC<ReservationDialogProps> = ({
handleClose, handleClose,
isOpen, isOpen,
}: ReservationDialogProps) => { }: ReservationDialogProps) => {
const { control, handleSubmit } = useForm<ReservationProps>(); const { control, handleSubmit } = useForm<ReservationProps>({
mode: 'onSubmit',
defaultValues: {
date: '',
time: '',
destination: '',
departure: '',
},
});
const reservation = useReservations(); const reservation = useReservations();
...@@ -45,6 +54,7 @@ export const ReservationDialog: FC<ReservationDialogProps> = ({ ...@@ -45,6 +54,7 @@ export const ReservationDialog: FC<ReservationDialogProps> = ({
Write here below the details of your next reservation Write here below the details of your next reservation
</DialogContentText> </DialogContentText>
<SeniorSearch control={control} />
<InputField <InputField
name="name" name="name"
label="Name Reservation" label="Name Reservation"
......
...@@ -2011,6 +2011,11 @@ ...@@ -2011,6 +2011,11 @@
resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz#9140779736aa2655635ee756e2467d787cfe8a2a" resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz#9140779736aa2655635ee756e2467d787cfe8a2a"
integrity sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A== integrity sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==
   
"@types/humps@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@types/humps/-/humps-2.0.0.tgz#9ad07801cd34f9d9ce379fa66f62d3049937d815"
integrity sha512-bP/s9HUT2oTJ0c3XGcHGISwTNs6r8eUPNfU6DuOSU8EHgtHqwvoDEyj76jPhKT/0MszS1PF/hHolxRrHSLYUPQ==
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
version "2.0.3" version "2.0.3"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762"
...@@ -6880,6 +6885,11 @@ human-signals@^1.1.1: ...@@ -6880,6 +6885,11 @@ human-signals@^1.1.1:
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
   
humps@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/humps/-/humps-2.0.1.tgz#dd02ea6081bd0568dc5d073184463957ba9ef9aa"
integrity sha1-3QLqYIG9BWjcXQcxhEY5V7qe+ao=
hunspell-spellchecker@^1.0.2: hunspell-spellchecker@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/hunspell-spellchecker/-/hunspell-spellchecker-1.0.2.tgz#a10b0bd2fa00a65ab62a4c6b734ce496d318910e" resolved "https://registry.yarnpkg.com/hunspell-spellchecker/-/hunspell-spellchecker-1.0.2.tgz#a10b0bd2fa00a65ab62a4c6b734ce496d318910e"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment