FormDialog refactor
This commit is contained in:
parent
72c0cac8b2
commit
7e33fbecf4
|
@ -1,10 +1,15 @@
|
||||||
import { useEffect } from 'react';
|
import { useEffect, useMemo } from 'react';
|
||||||
import { Controller, useForm } from 'react-hook-form';
|
import { Controller, useFieldArray, useForm } from 'react-hook-form';
|
||||||
import { omit, pick } from 'lodash';
|
import { omit, pick } from 'lodash';
|
||||||
import { polishPlurals } from 'polish-plurals';
|
import { polishPlurals } from 'polish-plurals';
|
||||||
import useProfessionAutocomplete from './FormDialog.useProfessionAutocomplete.js';
|
import useSuggestions from './FormDialog.useSuggestions';
|
||||||
import { FORMULAS, MAX_NAME_LENGTH } from './constants';
|
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 { Input } from './types';
|
||||||
|
|
||||||
import { makeStyles } from '@material-ui/core/styles';
|
import { makeStyles } from '@material-ui/core/styles';
|
||||||
|
@ -20,6 +25,7 @@ import {
|
||||||
TextField,
|
TextField,
|
||||||
} from '@material-ui/core';
|
} from '@material-ui/core';
|
||||||
import { Autocomplete } from '@material-ui/lab';
|
import { Autocomplete } from '@material-ui/lab';
|
||||||
|
import useProfessions from './FormDialog.useProfessions';
|
||||||
|
|
||||||
export interface FormDialogProps extends Pick<DialogProps, 'open'> {
|
export interface FormDialogProps extends Pick<DialogProps, 'open'> {
|
||||||
qualification?: Maybe<Qualification>;
|
qualification?: Maybe<Qualification>;
|
||||||
|
@ -39,17 +45,29 @@ const Form = ({ onClose, qualification, onSubmit }: FormDialogProps) => {
|
||||||
formState: { isSubmitting },
|
formState: { isSubmitting },
|
||||||
} = useForm<Input>({});
|
} = useForm<Input>({});
|
||||||
const {
|
const {
|
||||||
professions,
|
|
||||||
loading,
|
|
||||||
isLoadingSuggestions,
|
isLoadingSuggestions,
|
||||||
setSearch,
|
setSearch,
|
||||||
autocompleteOptions,
|
suggestions,
|
||||||
selectedProfessions,
|
search,
|
||||||
} = useProfessionAutocomplete({
|
} = useSuggestions();
|
||||||
qualificationID: qualification?.id,
|
const { professions, loading } = useProfessions(qualification?.id);
|
||||||
control: control,
|
|
||||||
});
|
|
||||||
const classes = useStyles();
|
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(() => {
|
useEffect(() => {
|
||||||
reset({
|
reset({
|
||||||
professions,
|
professions,
|
||||||
|
@ -152,7 +170,6 @@ const Form = ({ onClose, qualification, onSubmit }: FormDialogProps) => {
|
||||||
getOptionLabel={option => option?.name ?? ''}
|
getOptionLabel={option => option?.name ?? ''}
|
||||||
loading={isLoadingSuggestions}
|
loading={isLoadingSuggestions}
|
||||||
value={selectedProfessions}
|
value={selectedProfessions}
|
||||||
getOptionDisabled={option => !!option.disabled}
|
|
||||||
onChange={(_, opts) => {
|
onChange={(_, opts) => {
|
||||||
setValue(
|
setValue(
|
||||||
'professions',
|
'professions',
|
||||||
|
@ -162,14 +179,16 @@ const Form = ({ onClose, qualification, onSubmit }: FormDialogProps) => {
|
||||||
getOptionSelected={(option, value) =>
|
getOptionSelected={(option, value) =>
|
||||||
option && value && option.id === value.id
|
option && value && option.id === value.id
|
||||||
}
|
}
|
||||||
|
inputValue={search}
|
||||||
|
onInputChange={(_, val, reason) => {
|
||||||
|
console.log(reason);
|
||||||
|
setSearch(val);
|
||||||
|
}}
|
||||||
renderInput={params => (
|
renderInput={params => (
|
||||||
<TextField
|
<TextField
|
||||||
{...params}
|
{...params}
|
||||||
variant="standard"
|
variant="standard"
|
||||||
label="Zawody"
|
label="Zawody"
|
||||||
onChange={e => {
|
|
||||||
setSearch(e.target.value);
|
|
||||||
}}
|
|
||||||
InputProps={{
|
InputProps={{
|
||||||
...params.InputProps,
|
...params.InputProps,
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
|
|
|
@ -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;
|
|
|
@ -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;
|
|
@ -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;
|
|
@ -1,12 +1,8 @@
|
||||||
import { Profession, QualificationInput } from 'libs/graphql/types';
|
import { Profession, QualificationInput } from 'libs/graphql/types';
|
||||||
|
|
||||||
export type ExtendedProfession = Profession & {
|
|
||||||
disabled?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Input = Omit<
|
export type Input = Omit<
|
||||||
QualificationInput,
|
QualificationInput,
|
||||||
'associateProfession' | 'dissociateProfession'
|
'associateProfession' | 'dissociateProfession'
|
||||||
> & {
|
> & {
|
||||||
professions: ExtendedProfession[];
|
professions: Profession[];
|
||||||
};
|
};
|
||||||
|
|
Reference in New Issue
Block a user