From 92c004d15d9b3cf5dc82e17767de064cabf6068c Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Wed, 15 Jan 2025 16:42:26 +0300 Subject: [PATCH] filters form --- client/src/components/Filters/FiltersList.tsx | 96 ++++++ client/src/components/Filters/Form.tsx | 283 +++++++----------- client/src/components/Filters/Modal.tsx | 14 +- 3 files changed, 205 insertions(+), 188 deletions(-) create mode 100644 client/src/components/Filters/FiltersList.tsx diff --git a/client/src/components/Filters/FiltersList.tsx b/client/src/components/Filters/FiltersList.tsx new file mode 100644 index 00000000..96b38d78 --- /dev/null +++ b/client/src/components/Filters/FiltersList.tsx @@ -0,0 +1,96 @@ +import React from 'react'; +import classNames from 'classnames'; +import { useFormContext } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; + +const getIconsData = (homepage: string, source: string) => [ + { + iconName: 'dashboard', + href: homepage, + className: 'ml-1', + }, + { + iconName: 'info', + href: source, + }, +]; + +const renderIcons = (iconsData: { iconName: string; href: string; className?: string }[]) => + iconsData.map(({ iconName, href, className = '' }) => ( + + + + + + )); + +type Filter = { + categoryId: string; + homepage: string; + source: string; + name: string; +}; + +type Category = { + name: string; + description: string; +}; + +type Props = { + categories: Record; + filters: Record; + selectedSources: Record; +}; + +export const FiltersList = ({ categories, filters, selectedSources }: Props) => { + const { t } = useTranslation(); + const { register } = useFormContext(); + + return ( + <> + {Object.entries(categories).map(([categoryId, category]) => { + const categoryFilters = Object.entries(filters) + .filter(([, filter]) => filter.categoryId === categoryId) + .map(([key, filter]) => ({ ...filter, id: key })); + + return ( +
+
{t(category.name)}
+

{t(category.description)}

+ {categoryFilters.map((filter) => { + const { homepage, source, name, id } = filter; + const isSelected = selectedSources[source]; + const iconsData = getIconsData(homepage, source); + + return ( +
+ + {renderIcons(iconsData)} +
+ ); + })} +
+ ); + })} + + ); +}; diff --git a/client/src/components/Filters/Form.tsx b/client/src/components/Filters/Form.tsx index 700d7480..d9a8858f 100644 --- a/client/src/components/Filters/Form.tsx +++ b/client/src/components/Filters/Form.tsx @@ -1,130 +1,45 @@ import React from 'react'; - -import { Field, reduxForm } from 'redux-form'; -import { withTranslation } from 'react-i18next'; -import flow from 'lodash/flow'; -import classNames from 'classnames'; +import { useForm, Controller, FormProvider } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; import { validatePath, validateRequiredValue } from '../../helpers/validators'; -import { CheckboxField, renderInputField } from '../../helpers/form'; -import { MODAL_OPEN_TIMEOUT, MODAL_TYPE, FORM_NAME } from '../../helpers/constants'; +import { MODAL_OPEN_TIMEOUT, MODAL_TYPE } from '../../helpers/constants'; import filtersCatalog from '../../helpers/filters/filters'; +import { FiltersList } from './FiltersList'; -const getIconsData = (homepage: any, source: any) => [ - { - iconName: 'dashboard', - href: homepage, - className: 'ml-1', - }, - { - iconName: 'info', - href: source, - }, -]; +type FormValues = { + enabled: boolean; + name: string; + url: string; +}; -const renderIcons = (iconsData: any) => - iconsData.map(({ iconName, href, className = '' }: any) => ( - - - - - - )); - -interface renderCheckboxFieldProps { - input: { - name: string; - value: string; - checked: boolean; - onChange: (...args: unknown[]) => unknown; - }; - disabled: boolean; -} - -const renderCheckboxField = (props: renderCheckboxFieldProps) => ( - -); - -const renderFilters = ({ categories, filters }: any, selectedSources: any, t: any) => - Object.keys(categories).map((categoryId) => { - const category = categories[categoryId]; - const categoryFilters: any = []; - Object.keys(filters) - .sort() - .forEach((key) => { - const filter = filters[key]; - filter.id = key; - if (filter.categoryId === categoryId) { - categoryFilters.push(filter); - } - }); - - return ( -
-
{t(category.name)}
- -

{t(category.description)}

- - {categoryFilters.map((filter) => { - const { homepage, source, name } = filter; - - const isSelected = Object.prototype.hasOwnProperty.call(selectedSources, source); - - const iconsData = getIconsData(homepage, source); - - return ( -
- - {renderIcons(iconsData)} -
- ); - })} -
- ); - }); - -interface FormProps { - t: (...args: unknown[]) => string; - closeModal: (...args: unknown[]) => unknown; - handleSubmit: (...args: unknown[]) => string; +type Props = { + closeModal: (...args: unknown[]) => void; + onSubmit: (...args: unknown[]) => void; processingAddFilter: boolean; processingConfigFilter: boolean; whitelist?: boolean; modalType: string; - toggleFilteringModal: (...args: unknown[]) => unknown; - selectedSources?: object; -} + toggleFilteringModal: (...args: unknown[]) => void; + selectedSources?: Record; + initialValues?: FormValues; +}; -const Form = (props: FormProps) => { - const { - t, - closeModal, - handleSubmit, - processingAddFilter, - processingConfigFilter, - whitelist, - modalType, - toggleFilteringModal, - selectedSources, - } = props; +export const Form = ({ + closeModal, + processingAddFilter, + processingConfigFilter, + whitelist, + modalType, + toggleFilteringModal, + selectedSources, + onSubmit, + initialValues, +}: Props) => { + const { t } = useTranslation(); + + const methods = useForm({ defaultValues: initialValues }); + const { handleSubmit, control } = methods; const openModal = (modalType: any, timeout = MODAL_OPEN_TIMEOUT) => { toggleFilteringModal(); @@ -136,72 +51,86 @@ const Form = (props: FormProps) => { const openAddFiltersModal = () => openModal(MODAL_TYPE.ADD_FILTERS); return ( -
-
- {modalType === MODAL_TYPE.SELECT_MODAL_TYPE && ( -
- + + +
+ {modalType === MODAL_TYPE.SELECT_MODAL_TYPE && ( +
+ - -
- )} - {modalType === MODAL_TYPE.CHOOSE_FILTERING_LIST && renderFilters(filtersCatalog, selectedSources, t)} - {modalType !== MODAL_TYPE.CHOOSE_FILTERING_LIST && modalType !== MODAL_TYPE.SELECT_MODAL_TYPE && ( - <> -
- data.trim()} - /> +
+ )} + {modalType === MODAL_TYPE.CHOOSE_FILTERING_LIST && ( + + )} + {modalType !== MODAL_TYPE.CHOOSE_FILTERING_LIST && modalType !== MODAL_TYPE.SELECT_MODAL_TYPE && ( + <> +
+ ( + field.onChange(e.target.value.trim())} + /> + )} + /> +
-
- data.trim()} - /> -
+
+ ( + field.onChange(e.target.value.trim())} + /> + )} + /> +
-
- {whitelist ? t('enter_valid_allowlist') : t('enter_valid_blocklist')} -
- - )} -
+
+ {whitelist ? t('enter_valid_allowlist') : t('enter_valid_blocklist')} +
+ + )} +
-
- - - {modalType !== MODAL_TYPE.SELECT_MODAL_TYPE && ( - - )} -
- + + {modalType !== MODAL_TYPE.SELECT_MODAL_TYPE && ( + + )} +
+ + ); }; - -export default flow([withTranslation(), reduxForm({ form: FORM_NAME.FILTER })])(Form); diff --git a/client/src/components/Filters/Modal.tsx b/client/src/components/Filters/Modal.tsx index 24ac7721..51f8905e 100644 --- a/client/src/components/Filters/Modal.tsx +++ b/client/src/components/Filters/Modal.tsx @@ -5,7 +5,7 @@ import { withTranslation } from 'react-i18next'; import { MODAL_TYPE } from '../../helpers/constants'; -import Form from './Form'; +import { Form } from './Form'; import '../ui/Modal.css'; import { getMap } from '../../helpers/helpers'; @@ -75,25 +75,15 @@ class Modal extends Component { render() { const { isOpen, - processingAddFilter, - processingConfigFilter, - handleSubmit, - modalType, - currentFilterData, - whitelist, - toggleFilteringModal, - filters, - t, - filtersCatalog, } = this.props; @@ -117,6 +107,8 @@ class Modal extends Component { const title = t(getTitle(modalType, whitelist)); + console.log(modalType, initialValues); + return (