From a6d8948e9d0b352e3c8aeca9601cab907445e70b Mon Sep 17 00:00:00 2001 From: AlexSserb Date: Mon, 1 Sep 2025 18:50:29 +0400 Subject: [PATCH] feat: deals filters indicator and refactoring --- .../desktop/DealsTable/DealsTable.tsx | 16 +++-- .../desktop/TopToolPanel/TopToolPanel.tsx | 17 +++-- src/app/deals/contexts/DealsContext.tsx | 6 +- src/app/deals/hooks/useDealsFilters.ts | 62 +++++++++---------- .../DealsTableFiltersModal.tsx | 25 ++++---- src/hooks/lists/useDealsList.ts | 24 ++++--- 6 files changed, 81 insertions(+), 69 deletions(-) diff --git a/src/app/deals/components/desktop/DealsTable/DealsTable.tsx b/src/app/deals/components/desktop/DealsTable/DealsTable.tsx index 93f17d0..07e44b1 100644 --- a/src/app/deals/components/desktop/DealsTable/DealsTable.tsx +++ b/src/app/deals/components/desktop/DealsTable/DealsTable.tsx @@ -6,7 +6,7 @@ import { useDealsContext } from "@/app/deals/contexts/DealsContext"; import BaseTable from "@/components/ui/BaseTable/BaseTable"; const DealsTable: FC = () => { - const { deals, paginationInfo, page, setPage, dealsFilters } = + const { deals, paginationInfo, page, setPage, dealsFiltersForm } = useDealsContext(); const columns = useDealsTableColumns(); @@ -18,12 +18,18 @@ const DealsTable: FC = () => { records={[...deals]} columns={columns} sortStatus={{ - columnAccessor: dealsFilters.sortingField, - direction: dealsFilters.sortingDirection, + columnAccessor: dealsFiltersForm.values.sortingField ?? "", + direction: dealsFiltersForm.values.sortingDirection, }} onSortStatusChange={sorting => { - dealsFilters.setSortingField(sorting.columnAccessor); - dealsFilters.setSortingDirection(sorting.direction); + dealsFiltersForm.setFieldValue( + "sortingField", + sorting.columnAccessor + ); + dealsFiltersForm.setFieldValue( + "sortingDirection", + sorting.direction + ); }} emptyState={ { - const { dealsFilters } = useDealsContext(); + const { dealsFiltersForm, isChangedFilters } = useDealsContext(); const { view } = useViewContext(); const { projects, setSelectedProjectId, selectedProject, projectsCrud } = useProjectsContext(); @@ -52,11 +52,16 @@ const TopToolPanel = () => { gap={"sm"}> ( - - - + + + + + )} - filters={dealsFilters} + filtersForm={dealsFiltersForm} selectedProject={selectedProject} boardAndStatusEnabled={view === "table"} /> diff --git a/src/app/deals/contexts/DealsContext.tsx b/src/app/deals/contexts/DealsContext.tsx index 9173391..1b305a1 100644 --- a/src/app/deals/contexts/DealsContext.tsx +++ b/src/app/deals/contexts/DealsContext.tsx @@ -1,8 +1,9 @@ "use client"; import React from "react"; +import { UseFormReturnType } from "@mantine/form"; import { useStatusesContext } from "@/app/deals/contexts/StatusesContext"; -import { DealsFilters } from "@/app/deals/hooks/useDealsFilters"; +import { DealsFiltersForm } from "@/app/deals/hooks/useDealsFilters"; import { DealsCrud, useDealsCrud } from "@/hooks/cruds/useDealsCrud"; import useDealsList from "@/hooks/lists/useDealsList"; import { DealSchema, PaginationInfoSchema } from "@/lib/client"; @@ -16,7 +17,8 @@ type DealsContextState = { paginationInfo?: PaginationInfoSchema; page: number; setPage: React.Dispatch>; - dealsFilters: DealsFilters; + dealsFiltersForm: UseFormReturnType; + isChangedFilters: boolean; }; type Props = { diff --git a/src/app/deals/hooks/useDealsFilters.ts b/src/app/deals/hooks/useDealsFilters.ts index f124c99..f5ef529 100644 --- a/src/app/deals/hooks/useDealsFilters.ts +++ b/src/app/deals/hooks/useDealsFilters.ts @@ -1,52 +1,48 @@ -import { Dispatch, SetStateAction, useState } from "react"; +import { isEqual } from "lodash"; +import { useForm, UseFormReturnType } from "@mantine/form"; import { useDebouncedValue } from "@mantine/hooks"; import { BoardSchema, SortDir, StatusSchema } from "@/lib/client"; -export type DealsFilters = { +export type DealsFiltersForm = { id?: number; - debouncedId?: number; - setId: Dispatch>; - name?: string; - debouncedName?: string; - setName: Dispatch>; + name: string; board: BoardSchema | null; - setBoard: Dispatch>; status: StatusSchema | null; - setStatus: Dispatch>; - sortingField: string; - setSortingField: Dispatch>; + sortingField?: string; sortingDirection: SortDir; - setSortingDirection: Dispatch>; }; -const useDealsFilters = (): DealsFilters => { - const [id, setId] = useState(); - const [debouncedId] = useDebouncedValue(id, 300); +type ReturnType = { + debouncedId: number | undefined; + debouncedName: string; + form: UseFormReturnType; + isChangedFilters: boolean; +}; - const [name, setName] = useState(); - const [debouncedName] = useDebouncedValue(name, 300); +const useDealsFilters = (): ReturnType => { + const initialValues = { + id: undefined, + board: null, + status: null, + name: "", + sortingField: "createdAt", + sortingDirection: "asc" as SortDir, + }; - const [board, setBoard] = useState(null); - const [status, setStatus] = useState(null); + const form = useForm({ + initialValues, + }); - const [sortingField, setSortingField] = useState("createdAt"); - const [sortingDirection, setSortingDirection] = useState("asc"); + const isChangedFilters = !isEqual(form.values, initialValues); + + const [debouncedId] = useDebouncedValue(form.values.id, 300); + const [debouncedName] = useDebouncedValue(form.values.name, 300); return { - id, - setId, debouncedId, - name, - setName, debouncedName, - board, - setBoard, - status, - setStatus, - sortingField, - setSortingField, - sortingDirection, - setSortingDirection, + form, + isChangedFilters, }; }; diff --git a/src/app/deals/modals/DealsTableFiltersModal/DealsTableFiltersModal.tsx b/src/app/deals/modals/DealsTableFiltersModal/DealsTableFiltersModal.tsx index 9e47901..d2460fb 100644 --- a/src/app/deals/modals/DealsTableFiltersModal/DealsTableFiltersModal.tsx +++ b/src/app/deals/modals/DealsTableFiltersModal/DealsTableFiltersModal.tsx @@ -2,21 +2,22 @@ import { ReactNode } from "react"; import { Flex, Modal, NumberInput, rem, TextInput } from "@mantine/core"; +import { UseFormReturnType } from "@mantine/form"; import { useDisclosure } from "@mantine/hooks"; -import { DealsFilters } from "@/app/deals/hooks/useDealsFilters"; +import { DealsFiltersForm } from "@/app/deals/hooks/useDealsFilters"; import BoardSelect from "@/components/selects/BoardSelect/BoardSelect"; import StatusSelect from "@/components/selects/StatusSelect/StatusSelect"; import { ProjectSchema } from "@/lib/client"; type Props = { - filters: DealsFilters; + filtersForm: UseFormReturnType; selectedProject: ProjectSchema | null; boardAndStatusEnabled: boolean; getOpener: (open: () => void) => ReactNode; }; const DealsTableFiltersModal = ({ - filters, + filtersForm, selectedProject, boardAndStatusEnabled, getOpener, @@ -36,34 +37,32 @@ const DealsTableFiltersModal = ({ typeof value === "number" - ? filters.setId(Number(value)) - : filters.setId(undefined) + ? filtersForm.setFieldValue("id", Number(value)) + : filtersForm.setFieldValue("id", undefined) } min={1} /> filters.setName(event.target.value)} + {...filtersForm.getInputProps("name")} /> {boardAndStatusEnabled && ( <> diff --git a/src/hooks/lists/useDealsList.ts b/src/hooks/lists/useDealsList.ts index 8e1fd9a..6158296 100644 --- a/src/hooks/lists/useDealsList.ts +++ b/src/hooks/lists/useDealsList.ts @@ -1,7 +1,8 @@ import { Dispatch, SetStateAction, useState } from "react"; import { useQuery, useQueryClient } from "@tanstack/react-query"; +import { UseFormReturnType } from "@mantine/form"; import useDealsFilters, { - DealsFilters, + DealsFiltersForm, } from "@/app/deals/hooks/useDealsFilters"; import { DealSchema, GetDealsData, PaginationInfoSchema } from "@/lib/client"; import { @@ -18,7 +19,8 @@ type Props = { type ReturnType = { deals: DealSchema[]; setDeals: (deals: DealSchema[]) => void; - dealsFilters: DealsFilters; + dealsFiltersForm: UseFormReturnType; + isChangedFilters: boolean; refetchDeals: () => void; page: number; setPage: Dispatch>; @@ -34,21 +36,22 @@ const useDealsList = ({ const queryClient = useQueryClient(); const [page, setPage] = useState(1); const itemsPerPage = 10; - const dealsFilters = useDealsFilters(); + const { form, debouncedName, debouncedId, isChangedFilters } = + useDealsFilters(); const options: Omit = { query: { page: withPagination ? page : null, itemsPerPage: withPagination ? itemsPerPage : null, - sortingField: withPagination ? dealsFilters.sortingField : null, + sortingField: withPagination ? form.values.sortingField : null, sortingDirection: withPagination - ? dealsFilters.sortingDirection + ? form.values.sortingDirection : null, projectId: withPagination ? projectId : null, - boardId: withPagination ? dealsFilters.board?.id : boardId, - statusId: withPagination ? dealsFilters.status?.id : null, - name: dealsFilters.debouncedName, - id: dealsFilters.debouncedId, + boardId: withPagination ? form.values.board?.id : boardId, + statusId: withPagination ? form.values.status?.id : null, + name: debouncedName, + id: debouncedId, }, }; @@ -68,7 +71,8 @@ const useDealsList = ({ return { deals: data?.items ?? [], setDeals, - dealsFilters, + dealsFiltersForm: form, + isChangedFilters, refetchDeals: refetch, page, setPage,