Skip to content

Commit d6f638f

Browse files
authored
Merge pull request #1162 from bigcapitalhq/refactor/advancedfilter-ts-conversion
refactor(webapp): convert AdvancedFilter widget to typed TypeScript
2 parents 8d068c2 + f945f65 commit d6f638f

27 files changed

Lines changed: 333 additions & 176 deletions

File tree

packages/webapp/src/components/AdvancedFilter/AdvancedFilter.schema.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// @ts-nocheck
21
import * as Yup from 'yup';
32

43
export const getFilterDropdownSchema = () =>

packages/webapp/src/components/AdvancedFilter/AdvancedFilterCompatatorField.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
// @ts-nocheck
21
import { Classes } from '@blueprintjs/core';
32
import React from 'react';
43
import { FSelect } from '../Forms';
54
import { getConditionTypeCompatators } from './utils';
5+
import type { IDynamicFilterCompatatorFieldProps } from './interfaces';
6+
7+
type FSelectProps = React.ComponentProps<typeof FSelect>;
68

79
export default function DynamicFilterCompatatorField({
810
dataType,
911
...restProps
10-
}) {
12+
}: IDynamicFilterCompatatorFieldProps & Omit<FSelectProps, 'dataType'>) {
1113
const options = getConditionTypeCompatators(dataType);
1214

1315
return (

packages/webapp/src/components/AdvancedFilter/AdvancedFilterDropdown.tsx

Lines changed: 86 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// @ts-nocheck
21
import { Button, Classes, InputGroup, MenuItem } from '@blueprintjs/core';
3-
import { Formik, FastField, FieldArray } from 'formik';
2+
import { Formik, FastField, FieldArray, useFormikContext } from 'formik';
3+
import type { FieldInputProps, FormikContextType, ArrayHelpers } from 'formik';
44
import { get, first, defaultTo, isEqual, isEmpty } from 'lodash';
55
import React from 'react';
66
import intl from 'react-intl-universal';
@@ -17,10 +17,21 @@ import { useAdvancedFilterAutoSubmit } from './components';
1717
import {
1818
filterConditionRoles,
1919
getConditionalsOptions,
20+
getConditionTypeCompatators,
2021
transformFieldsToOptions,
2122
shouldFilterValueFieldUpdate,
22-
getConditionTypeCompatators,
2323
} from './utils';
24+
import type {
25+
IAdvancedFilterDropdown,
26+
IAdvancedFilterDropdownCondition,
27+
IAdvancedFilterDropdownConditionsProps,
28+
IAdvancedFilterDropdownFooter,
29+
IConditionOption,
30+
IFilterDropdownFormikValues,
31+
IFilterRole,
32+
IResourceField,
33+
IResourceFieldType,
34+
} from './interfaces';
2435
import {
2536
Choose,
2637
Icon,
@@ -30,10 +41,19 @@ import {
3041
} from '@/components';
3142
import { useUpdateEffect } from '@/hooks';
3243

44+
type ConditionRenderHelpers = {
45+
handleClick: (event: React.MouseEvent<HTMLElement>) => void;
46+
modifiers: { active: boolean; disabled: boolean };
47+
query: string;
48+
};
49+
3350
/**
3451
* Condition item list renderer.
3552
*/
36-
function ConditionItemRenderer(condition, { handleClick, modifiers, query }) {
53+
function ConditionItemRenderer(
54+
condition: IConditionOption,
55+
{ handleClick }: ConditionRenderHelpers,
56+
) {
3757
return (
3858
<MenuItem
3959
text={
@@ -51,7 +71,7 @@ function ConditionItemRenderer(condition, { handleClick, modifiers, query }) {
5171
/**
5272
* Filter condition field.
5373
*/
54-
function FilterConditionField() {
74+
function FilterConditionField(): JSX.Element {
5575
const conditionalsOptions = getConditionalsOptions();
5676
const { conditionIndex, getConditionFieldPath } = useFilterCondition();
5777

@@ -89,11 +109,11 @@ function FilterConditionField() {
89109
/**
90110
* Compatator field.
91111
*/
92-
function FilterCompatatorFilter() {
112+
function FilterCompatatorFilter(): JSX.Element {
93113
const { getConditionFieldPath, fieldMeta } = useFilterCondition();
94114

95115
const comparatorFieldPath = getConditionFieldPath('comparator');
96-
const fieldType = get(fieldMeta, 'fieldType');
116+
const fieldType = fieldMeta?.fieldType;
97117

98118
return (
99119
<FFormGroup
@@ -103,14 +123,20 @@ function FilterCompatatorFilter() {
103123
>
104124
<AdvancedFilterCompatatorField
105125
name={comparatorFieldPath}
106-
dataType={fieldType}
126+
dataType={fieldType as IResourceFieldType}
107127
className={Classes.FILL}
108128
fastField
109129
/>
110130
</FFormGroup>
111131
);
112132
}
113133

134+
type DefaultComparatorHookArgs = {
135+
getConditionValue: (field: keyof IFilterRole) => unknown;
136+
setConditionValue: (field: keyof IFilterRole, value: unknown) => void;
137+
fieldMeta?: IResourceField;
138+
};
139+
114140
/**
115141
* Changes default value of comparator field in the condition row once the
116142
* field option changing.
@@ -119,12 +145,12 @@ function useDefaultComparatorFieldValue({
119145
getConditionValue,
120146
setConditionValue,
121147
fieldMeta,
122-
}) {
148+
}: DefaultComparatorHookArgs) {
123149
const fieldKeyValue = getConditionValue('fieldKey');
124150

125151
const comparatorsOptions = React.useMemo(
126-
() => getConditionTypeCompatators(fieldMeta.fieldType),
127-
[fieldMeta.fieldType],
152+
() => (fieldMeta ? getConditionTypeCompatators(fieldMeta.fieldType) : []),
153+
[fieldMeta],
128154
);
129155

130156
useUpdateEffect(() => {
@@ -138,7 +164,7 @@ function useDefaultComparatorFieldValue({
138164
/**
139165
* Resource fields field.
140166
*/
141-
function FilterFieldsField() {
167+
function FilterFieldsField(): JSX.Element {
142168
const {
143169
getConditionFieldPath,
144170
getConditionValue,
@@ -159,15 +185,21 @@ function FilterFieldsField() {
159185

160186
return (
161187
<FastField name={fieldPath}>
162-
{({ field, form }) => (
188+
{({
189+
field,
190+
form,
191+
}: {
192+
field: FieldInputProps<IFilterRole['fieldKey']>;
193+
form: FormikContextType<IFilterDropdownFormikValues>;
194+
}) => (
163195
<FFormGroup className={'form-group--fieldKey'} name={fieldPath}>
164196
<FSelect
165197
selectedItem={field.value}
166198
textAccessor={'label'}
167199
valueAccessor={'value'}
168200
items={transformFieldsToOptions(fields)}
169201
className={Classes.FILL}
170-
onItemSelect={(option) => {
202+
onItemSelect={(option: IConditionOption) => {
171203
form.setFieldValue(fieldPath, option.value);
172204

173205
// Resets the value field to empty once the field option changing.
@@ -188,7 +220,7 @@ function FilterFieldsField() {
188220
/**
189221
* Advanced filter value field.
190222
*/
191-
function FilterValueField() {
223+
function FilterValueField(): JSX.Element | null {
192224
const { conditionIndex, fieldMeta, getConditionFieldPath } =
193225
useFilterCondition();
194226

@@ -197,9 +229,9 @@ function FilterValueField() {
197229
return null;
198230
}
199231
// Field meta type, name and options.
200-
const fieldType = get(fieldMeta, 'fieldType');
201-
const fieldName = get(fieldMeta, 'name');
202-
const options = get(fieldMeta, 'options');
232+
const fieldType = fieldMeta.fieldType;
233+
const fieldName = fieldMeta.name;
234+
const options = fieldMeta.options;
203235

204236
const valueFieldPath = getConditionFieldPath('value');
205237

@@ -209,11 +241,17 @@ function FilterValueField() {
209241
fieldKey={fieldType} // Pass to shouldUpdate function.
210242
shouldUpdate={shouldFilterValueFieldUpdate}
211243
>
212-
{({ form: { setFieldValue }, field }) => (
244+
{({
245+
form: { setFieldValue },
246+
field,
247+
}: {
248+
form: FormikContextType<IFilterDropdownFormikValues>;
249+
field: FieldInputProps<unknown>;
250+
}) => (
213251
<FFormGroup className={'form-group--value'} name={valueFieldPath}>
214252
<AdvancedFilterValueField
215253
isFocus={conditionIndex === 0}
216-
value={field.value}
254+
value={typeof field.value === 'string' ? field.value : ''}
217255
key={'name'}
218256
label={fieldName}
219257
fieldType={fieldType}
@@ -231,7 +269,10 @@ function FilterValueField() {
231269
/**
232270
* Advanced filter condition line.
233271
*/
234-
function AdvancedFilterDropdownCondition({ conditionIndex, onRemoveClick }) {
272+
function AdvancedFilterDropdownCondition({
273+
conditionIndex,
274+
onRemoveClick,
275+
}: IAdvancedFilterDropdownCondition) {
235276
// Handle click remove condition.
236277
const handleClickRemoveCondition = () => {
237278
onRemoveClick && onRemoveClick(conditionIndex);
@@ -259,27 +300,31 @@ function AdvancedFilterDropdownCondition({ conditionIndex, onRemoveClick }) {
259300
/**
260301
* Advanced filter dropdown condition.
261302
*/
262-
function AdvancedFilterDropdownConditions({ push, remove, replace, form }) {
303+
function AdvancedFilterDropdownConditions(
304+
props: IAdvancedFilterDropdownConditionsProps,
305+
): JSX.Element {
306+
const { push, remove, replace, form } = props;
263307
const { initialCondition } = useAdvancedFilterContext();
264308

265309
// Handle remove condition.
266-
const handleClickRemoveCondition = (conditionIndex) => {
310+
const handleClickRemoveCondition = (conditionIndex: number) => {
267311
if (form.values.conditions.length > 1) {
268312
remove(conditionIndex);
269313
} else {
270314
replace(0, { ...initialCondition });
271315
}
272316
};
273317
// Handle new condition button click.
274-
const handleNewConditionBtnClick = (index) => {
318+
const handleNewConditionBtnClick = () => {
275319
push({ ...initialCondition });
276320
};
277321

278322
return (
279323
<div className="filter-dropdonw__conditions-wrap">
280324
<div className={'filter-dropdown__conditions'}>
281-
{form.values.conditions.map((condition, index) => (
325+
{form.values.conditions.map((_condition, index) => (
282326
<AdvancedFilterDropdownCondition
327+
key={index}
283328
conditionIndex={index}
284329
onRemoveClick={handleClickRemoveCondition}
285330
/>
@@ -293,16 +338,17 @@ function AdvancedFilterDropdownConditions({ push, remove, replace, form }) {
293338
/**
294339
* Advanced filter dropdown form.
295340
*/
296-
function AdvancedFilterDropdownForm() {
341+
function AdvancedFilterDropdownForm(): JSX.Element {
297342
// Advanced filter auto-save.
298343
useAdvancedFilterAutoSubmit();
344+
const form = useFormikContext<IFilterDropdownFormikValues>();
299345

300346
return (
301347
<div className="filter-dropdown__form">
302348
<FieldArray
303349
name={'conditions'}
304-
render={({ ...fieldArrayProps }) => (
305-
<AdvancedFilterDropdownConditions {...fieldArrayProps} />
350+
render={(arrayHelpers: ArrayHelpers) => (
351+
<AdvancedFilterDropdownConditions {...arrayHelpers} form={form} />
306352
)}
307353
/>
308354
</div>
@@ -312,14 +358,12 @@ function AdvancedFilterDropdownForm() {
312358
/**
313359
* Advanced filter dropdown footer.
314360
*/
315-
function AdvancedFilterDropdownFooter({ onClick }) {
316-
// Handle new filter condition button click.
317-
const onClickNewFilter = (event) => {
318-
onClick && onClick(event);
319-
};
361+
function AdvancedFilterDropdownFooter({
362+
onClick,
363+
}: IAdvancedFilterDropdownFooter): JSX.Element {
320364
return (
321365
<div className="filter-dropdown__footer">
322-
<Button minimal={true} onClick={onClickNewFilter}>
366+
<Button minimal={true} onClick={onClick}>
323367
<T id={'new_conditional'} />
324368
</Button>
325369
</div>
@@ -337,23 +381,24 @@ export function AdvancedFilterDropdown({
337381
defaultValue,
338382
defaultCondition,
339383
onFilterChange,
340-
}) {
384+
}: IAdvancedFilterDropdown): JSX.Element {
341385
// Initial condition.
342-
const initialCondition = {
386+
const initialCondition: IFilterRole = {
343387
fieldKey: defaultFieldKey,
344388
comparator: defaultTo(defaultComparator, 'contain'),
345389
condition: defaultTo(defaultCondition, 'or'),
346390
value: defaultTo(defaultValue, ''),
347391
};
348392
// Initial conditions.
349-
const initialConditions = !isEmpty(conditions)
350-
? conditions
351-
: [initialCondition, initialCondition];
393+
const initialConditions: IFilterRole[] =
394+
conditions && !isEmpty(conditions)
395+
? conditions
396+
: [initialCondition, initialCondition];
352397

353398
const [prevConditions, setPrevConditions] = React.useState(initialConditions);
354399

355400
// Handle the filter dropdown form submit.
356-
const handleFitlerDropdownSubmit = (values) => {
401+
const handleFitlerDropdownSubmit = (values: IFilterDropdownFormikValues) => {
357402
const conditions = filterConditionRoles(values.conditions);
358403

359404
// Campare the current conditions with previous conditions, if they were equal
@@ -367,7 +412,7 @@ export function AdvancedFilterDropdown({
367412
const validationSchema = getFilterDropdownSchema();
368413

369414
// Initial values.
370-
const initialValues = {
415+
const initialValues: IFilterDropdownFormikValues = {
371416
conditions: initialConditions,
372417
};
373418

0 commit comments

Comments
 (0)