FormDialog refactor

This commit is contained in:
Dawid Wysokiński 2021-06-10 18:31:55 +02:00
parent 72c0cac8b2
commit 7e33fbecf4
5 changed files with 122 additions and 129 deletions

View File

@ -1,10 +1,15 @@
import { useEffect } from 'react';
import { Controller, useForm } from 'react-hook-form';
import { useEffect, useMemo } from 'react';
import { Controller, useFieldArray, useForm } from 'react-hook-form';
import { omit, pick } from 'lodash';
import { polishPlurals } from 'polish-plurals';
import useProfessionAutocomplete from './FormDialog.useProfessionAutocomplete.js';
import useSuggestions from './FormDialog.useSuggestions';
import { FORMULAS, MAX_NAME_LENGTH } from './constants';
import { Maybe, Qualification, QualificationInput } from 'libs/graphql/types';
import {
Maybe,
Profession,
Qualification,
QualificationInput,
} from 'libs/graphql/types';
import { Input } from './types';
import { makeStyles } from '@material-ui/core/styles';
@ -20,6 +25,7 @@ import {
TextField,
} from '@material-ui/core';
import { Autocomplete } from '@material-ui/lab';
import useProfessions from './FormDialog.useProfessions';
export interface FormDialogProps extends Pick<DialogProps, 'open'> {
qualification?: Maybe<Qualification>;
@ -39,17 +45,29 @@ const Form = ({ onClose, qualification, onSubmit }: FormDialogProps) => {
formState: { isSubmitting },
} = useForm<Input>({});
const {
professions,
loading,
isLoadingSuggestions,
setSearch,
autocompleteOptions,
selectedProfessions,
} = useProfessionAutocomplete({
qualificationID: qualification?.id,
control: control,
});
suggestions,
search,
} = useSuggestions();
const { professions, loading } = useProfessions(qualification?.id);
const classes = useStyles();
const { fields: selectedProfessions } = useFieldArray<Profession, 'key'>({
control,
name: 'professions',
keyName: 'key',
});
const autocompleteOptions: typeof selectedProfessions = useMemo(() => {
return [
...suggestions.filter(
profession =>
!selectedProfessions.some(
otherProfession => otherProfession.id === profession.id
)
),
...selectedProfessions,
];
}, [suggestions, selectedProfessions]);
useEffect(() => {
reset({
professions,
@ -152,7 +170,6 @@ const Form = ({ onClose, qualification, onSubmit }: FormDialogProps) => {
getOptionLabel={option => option?.name ?? ''}
loading={isLoadingSuggestions}
value={selectedProfessions}
getOptionDisabled={option => !!option.disabled}
onChange={(_, opts) => {
setValue(
'professions',
@ -162,14 +179,16 @@ const Form = ({ onClose, qualification, onSubmit }: FormDialogProps) => {
getOptionSelected={(option, value) =>
option && value && option.id === value.id
}
inputValue={search}
onInputChange={(_, val, reason) => {
console.log(reason);
setSearch(val);
}}
renderInput={params => (
<TextField
{...params}
variant="standard"
label="Zawody"
onChange={e => {
setSearch(e.target.value);
}}
InputProps={{
...params.InputProps,
endAdornment: (

View File

@ -1,108 +0,0 @@
import { useMemo, useState } from 'react';
import { useApolloClient, useQuery } from '@apollo/client';
import { Control, useFieldArray } from 'react-hook-form';
import { useDebounce } from 'react-use';
import { QUERY_PROFESSIONS } from './queries';
import {
Maybe,
Query,
QueryProfessionsArgs,
Scalars,
} from 'libs/graphql/types';
import { ExtendedProfession } from './types';
export interface Options {
qualificationID?: Maybe<Scalars['ID']>;
control: Control;
}
const useProfessionAutocomplete = ({ qualificationID, control }: Options) => {
const [suggestions, setSuggestions] = useState<ExtendedProfession[]>([]);
const [isLoadingSuggestions, setIsLoadingSuggestions] = useState<boolean>(
false
);
const [search, setSearch] = useState<string>('');
const { fields: selectedProfessions } = useFieldArray<
ExtendedProfession,
'key'
>({
control,
name: 'professions',
keyName: 'key',
});
const client = useApolloClient();
const { data, loading } = useQuery<
Pick<Query, 'professions'>,
QueryProfessionsArgs
>(QUERY_PROFESSIONS, {
fetchPolicy: 'cache-and-network',
skip: !qualificationID,
variables: {
filter: {
qualificationID: [qualificationID ?? 0],
},
},
});
const professions = useMemo(() => data?.professions.items ?? [], [data]);
const autocompleteOptions: typeof selectedProfessions = useMemo(() => {
return [
...suggestions
.filter(
profession =>
!selectedProfessions.some(
otherProfession => otherProfession.id === profession.id
)
)
.map(p => ({ ...p, disabled: false })),
...selectedProfessions.map(p => ({
...p,
disabled: true,
})),
];
}, [suggestions, selectedProfessions]);
const loadSuggestions = async (search: string) => {
setIsLoadingSuggestions(true);
try {
const { data } = await client.query<
Pick<Query, 'professions'>,
QueryProfessionsArgs
>({
query: QUERY_PROFESSIONS,
fetchPolicy: 'no-cache',
variables: {
filter: {
nameIEQ: '%' + search + '%',
idNEQ: selectedProfessions.map(profession => profession.id ?? 0),
},
limit: 10,
},
});
if (data.professions?.items) {
setSuggestions(data.professions.items);
}
} catch (e) {}
setIsLoadingSuggestions(false);
};
useDebounce(
() => {
loadSuggestions(search);
},
500,
[search]
);
return {
professions,
loading: professions.length === 0 && loading,
isLoadingSuggestions,
suggestions,
setSearch,
search,
autocompleteOptions,
selectedProfessions,
};
};
export default useProfessionAutocomplete;

View File

@ -0,0 +1,32 @@
import { useMemo } from 'react';
import { useQuery } from '@apollo/client';
import { QUERY_PROFESSIONS } from './queries';
import {
Maybe,
Query,
QueryProfessionsArgs,
Scalars,
} from 'libs/graphql/types';
const useProfessions = (qualificationID?: Maybe<Scalars['ID']>) => {
const { data, loading } = useQuery<
Pick<Query, 'professions'>,
QueryProfessionsArgs
>(QUERY_PROFESSIONS, {
fetchPolicy: 'cache-and-network',
skip: !qualificationID,
variables: {
filter: {
qualificationID: [qualificationID ?? 0],
},
},
});
const professions = useMemo(() => data?.professions.items ?? [], [data]);
return {
professions,
loading: professions.length === 0 && loading,
};
};
export default useProfessions;

View File

@ -0,0 +1,54 @@
import { useState } from 'react';
import { useApolloClient } from '@apollo/client';
import { useDebounce } from 'react-use';
import { QUERY_PROFESSIONS } from './queries';
import { Profession, Query, QueryProfessionsArgs } from 'libs/graphql/types';
const useSuggestions = () => {
const [suggestions, setSuggestions] = useState<Profession[]>([]);
const [isLoadingSuggestions, setIsLoadingSuggestions] = useState<boolean>(
false
);
const [search, setSearch] = useState<string>('');
const client = useApolloClient();
const loadSuggestions = async (search: string) => {
setIsLoadingSuggestions(true);
try {
const { data } = await client.query<
Pick<Query, 'professions'>,
QueryProfessionsArgs
>({
query: QUERY_PROFESSIONS,
fetchPolicy: 'no-cache',
variables: {
filter: {
nameIEQ: '%' + search + '%',
},
limit: 10,
},
});
if (data.professions?.items) {
setSuggestions(data.professions.items);
}
} catch (e) {}
setIsLoadingSuggestions(false);
};
useDebounce(
() => {
loadSuggestions(search);
},
500,
[search]
);
return {
isLoadingSuggestions,
suggestions,
setSearch,
search,
};
};
export default useSuggestions;

View File

@ -1,12 +1,8 @@
import { Profession, QualificationInput } from 'libs/graphql/types';
export type ExtendedProfession = Profession & {
disabled?: boolean;
};
export type Input = Omit<
QualificationInput,
'associateProfession' | 'dissociateProfession'
> & {
professions: ExtendedProfession[];
professions: Profession[];
};