Skip to content

Commit

Permalink
Reuse dimensionComboBox to avoid duplicate code
Browse files Browse the repository at this point in the history
  • Loading branch information
kurukimi committed Jun 18, 2024
1 parent be7068a commit b14c16f
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 152 deletions.
52 changes: 30 additions & 22 deletions web/src/components/entry-dialog/DimensionComboBox.tsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,56 @@
import { useQuery } from "@apollo/client";
import { Autocomplete, TextField } from "@mui/material";
import { Control, ControllerProps, FieldValues, UseFormReturn } from "react-hook-form";
import { Autocomplete, AutocompleteProps, FormControl, Grid, TextField } from "@mui/material";
import { Control, Controller, ControllerProps, FieldValues, UseFormReturn } from "react-hook-form";
import { FindDimensionOptionsDocument } from "../../graphql/generated/graphql";
import DimensionController from "./DimensionController";

type DimensionComboBoxProps<T extends FieldValues> = {
form: UseFormReturn<T>;
name: "product" | "activity" | "issue" | "client";
title: string;
rules?: ControllerProps["rules"];
autoCompleteProps?: Partial<
AutocompleteProps<string, boolean | undefined, boolean | undefined, boolean | undefined>
>;
};

const DimensionComboBox = <T extends FieldValues>({
form,
name,
title,
rules,
autoCompleteProps,
}: DimensionComboBoxProps<T>) => {
const { data } = useQuery(FindDimensionOptionsDocument);
const options = data?.findDimensionOptions[name] || [];

return (
<DimensionController
control={form.control as unknown as Control<FieldValues>}
name={name}
rules={rules}
render={({ field: { value, onChange } }) => (
<Autocomplete
value={value}
onChange={(_, value) => onChange(value)}
options={options}
autoHighlight
renderInput={(params) => (
<TextField
{...params}
label={title}
onChange={onChange}
error={!!form.formState.errors[name]}
helperText={form.formState.errors[name]?.message as string}
<Grid item xs={12} md={6}>
<FormControl fullWidth>
<Controller
control={form.control as unknown as Control<FieldValues>}
name={name}
rules={rules}
render={({ field: { value, onChange } }) => (
<Autocomplete
value={value}
onChange={(_, value) => onChange(value)}
options={options}
autoHighlight
renderInput={(params) => (
<TextField
{...params}
label={title}
onChange={onChange}
error={!!form.formState.errors[name]}
helperText={form.formState.errors[name]?.message as string}
/>
)}
{...autoCompleteProps}
/>
)}
/>
)}
/>
</FormControl>
</Grid>
);
};

Expand Down
14 changes: 0 additions & 14 deletions web/src/components/entry-dialog/DimensionController.tsx

This file was deleted.

88 changes: 0 additions & 88 deletions web/src/jira/components/JiraIssueAutoComplete.tsx

This file was deleted.

102 changes: 74 additions & 28 deletions web/src/jira/components/JiraIssueComboBox.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { TextField } from "@mui/material";
import { Control, ControllerProps, FieldValues, UseFormReturn } from "react-hook-form";
import { ListItem } from "@mui/material";
import { ControllerProps, FieldValues, UseFormReturn } from "react-hook-form";
import { FindDimensionOptionsDocument } from "../../graphql/generated/graphql";
import { useQuery } from "@apollo/client";
import DimensionController from "../../components/entry-dialog/DimensionController";
import JiraIssueAutoComplete from "./JiraIssueAutoComplete";
import useInfiniteScroll from "react-infinite-scroll-hook";
import DimensionComboBox from "../../components/entry-dialog/DimensionComboBox";
import { useDebounceValue } from "usehooks-ts";
import { useGetIssues, useSearchIssues } from "../jiraApi";
import { issueKeyToSummary } from "../jiraUtils";
import { jiraQueryMaxResults } from "../jiraConfig";

type JiraIssueComboBoxProps<T extends FieldValues> = {
form: UseFormReturn<T>;
Expand All @@ -13,36 +17,78 @@ type JiraIssueComboBoxProps<T extends FieldValues> = {
};

const JiraIssueComboBox = <T extends FieldValues>({
form,
name,
title,
rules,
...params
}: JiraIssueComboBoxProps<T>) => {
const { data } = useQuery(FindDimensionOptionsDocument);
const { data, loading } = useQuery(FindDimensionOptionsDocument);
const options = data?.findDimensionOptions[name] || [];

const [issueFilter, setIssueFilter] = useDebounceValue("", 300);
const {
data: dataPages,
error,
fetchNextPage,
hasNextPage,
isLoading: pagesLoading,
} = useGetIssues({ issueKeys: options, enabled: !loading });

const { data: searchedIssueData, isLoading: searchLoading } = useSearchIssues({
issueKeys: options,
searchFilter: issueFilter,
});

const [sentryRef, { rootRef }] = useInfiniteScroll({
loading: pagesLoading,
hasNextPage,
disabled: !!error,
onLoadMore: fetchNextPage,
delayInMs: 0,
});

const pagedIssueData = dataPages?.pages;
const queriedKeys = [
...(pagedIssueData || []),
...(searchedIssueData ? [searchedIssueData] : []),
];
const keyToSummary = issueKeyToSummary(queriedKeys);
const queriedOptions = [
...new Set([
...options.slice(0, (dataPages?.pages.length || 1) * jiraQueryMaxResults),
...Object.keys(keyToSummary),
]),
];
const getOptionText = (option: string) =>
keyToSummary[option] ? `${option}: ${keyToSummary[option]}` : option;

return (
<DimensionController
control={form.control as unknown as Control<FieldValues>}
<DimensionComboBox
{...params}
name={name}
rules={rules}
render={({ field: { value, onChange } }) => (
<JiraIssueAutoComplete
options={options}
value={value}
onChange={(_, value) => onChange(value)}
autoHighlight
renderInput={(params) => (
<TextField
{...params}
label={title}
onChange={onChange}
error={!!form.formState.errors[name]}
helperText={form.formState.errors[name]?.message as string}
/>
)}
/>
)}
autoCompleteProps={{
loading: pagesLoading || searchLoading,
options: queriedOptions,
renderOption: (props, option, state) => {
const shouldLoadMore = (state.index + 1) % jiraQueryMaxResults === 0 && state.index > 0;
return (
<ListItem {...props} ref={shouldLoadMore ? sentryRef : undefined}>
{getOptionText(option as string)}
</ListItem>
);
},
filterOptions: (options, state) => {
const filtered = options.filter((option) =>
getOptionText(option as string)
.toLowerCase()
.trim()
.includes(state.inputValue.toLowerCase().trim()),
);
if (filtered.length === 0) setIssueFilter(state.inputValue.toLowerCase().trim());
return filtered;
},
ListboxProps: {
ref: rootRef,
},
}}
/>
);
};
Expand Down

0 comments on commit b14c16f

Please sign in to comment.