diff --git a/src/storybook/mock.tsx b/src/storybook/mock.tsx index 0e6b83f0f..7b7d3e839 100644 --- a/src/storybook/mock.tsx +++ b/src/storybook/mock.tsx @@ -1,91 +1,99 @@ import React from "react"; import { SingleAutocompleteChoiceType } from "@saleor/components/SingleAutocompleteSelectField/SingleAutocompleteSelectFieldContent"; +import { FetchMoreProps } from "@saleor/types"; interface ChoiceProviderProps { - children: (props: { - choices: SingleAutocompleteChoiceType[]; - hasMore: boolean; - loading: boolean; - fetchChoices: (value: string) => void; - fetchMore: () => void; - }) => React.ReactElement; + children: ( + props: FetchMoreProps & { + choices: SingleAutocompleteChoiceType[]; + fetchChoices: (value: string) => void; + } + ) => React.ReactElement; choices: SingleAutocompleteChoiceType[]; } -interface ChoiceProviderState { - choices: SingleAutocompleteChoiceType[]; - filteredChoices: SingleAutocompleteChoiceType[]; - first: number; - loading: boolean; - timeout: any; -} const step = 5; +const loadingTime = 400; -export class ChoiceProvider extends React.Component< - ChoiceProviderProps, - ChoiceProviderState -> { - state = { - choices: [], - filteredChoices: [], - first: step, - loading: false, - timeout: null - }; - - handleChange = (inputValue: string) => { - if (!!this.state.timeout) { - clearTimeout(this.state.timeout); - } - const timeout = setTimeout(() => this.fetchChoices(inputValue), 500); - this.setState({ - loading: true, - timeout - }); - }; - - handleFetchMore = () => { - if (!!this.state.timeout) { - clearTimeout(this.state.timeout); - } - const timeout = setTimeout(this.fetchMore, 500); - this.setState({ - loading: true, - timeout - }); - }; - - fetchMore = () => - this.setState(prevState => ({ - filteredChoices: prevState.choices.slice(0, prevState.first + step), - first: prevState.first + step, - loading: false, - timeout: null - })); - - fetchChoices = (inputValue: string) => { - const choices = this.props.choices.filter( - suggestion => - !inputValue || - suggestion.label.toLowerCase().indexOf(inputValue.toLowerCase()) !== -1 - ); - this.setState({ - choices, - filteredChoices: choices.slice(0, step), - first: step, - loading: false, - timeout: null - }); - }; - - render() { - return this.props.children({ - choices: this.state.filteredChoices, - fetchChoices: this.handleChange, - fetchMore: this.handleFetchMore, - hasMore: this.state.choices.length > this.state.filteredChoices.length, - loading: this.state.loading - }); - } +export interface UseMockChoiceProviderOpts extends FetchMoreProps { + fetchChoices: (value: string) => void; } +export type UseMockChoiceProvider = [ + SingleAutocompleteChoiceType[], + UseMockChoiceProviderOpts +]; +export function useMockChoiceProvider( + choices: SingleAutocompleteChoiceType[] +): UseMockChoiceProvider { + const [filteredChoices, setFilteredChoices] = React.useState( + choices.slice(0, step) + ); + const [loading, setLoading] = React.useState(false); + const [first, setFirst] = React.useState(step); + const timeout = React.useRef(null); + + React.useEffect( + () => () => { + if (timeout.current) { + clearTimeout(timeout.current); + } + }, + [] + ); + + const handleChange = (value: string) => { + if (!!timeout.current) { + clearTimeout(timeout.current); + } + timeout.current = setTimeout(() => fetchChoices(value), loadingTime); + }; + + const fetchChoices = (value: string) => { + const filteredChoices = choices.filter( + suggestion => + !value || + suggestion.label.toLowerCase().indexOf(value.toLowerCase()) !== -1 + ); + + setLoading(true); + + timeout.current = setTimeout(() => { + setFilteredChoices(filteredChoices); + setLoading(false); + setFirst(step); + }, loadingTime); + }; + + const handleFetchMore = () => { + setLoading(true); + + timeout.current = setTimeout(() => { + setFilteredChoices(choices.slice(0, first + step)); + setLoading(false); + setFirst(first + step); + }, loadingTime); + }; + + return [ + filteredChoices, + { + fetchChoices: handleChange, + hasMore: choices.length > filteredChoices.length, + loading, + onFetchMore: handleFetchMore + } + ]; +} + +export const ChoiceProvider: React.FC = ({ + children, + choices +}) => { + const [filteredChoices, opts] = useMockChoiceProvider(choices); + + return children({ + choices: filteredChoices, + ...opts + }); +};