diff --git a/src/components/Tables/companies/CompanyListFilters.tsx b/src/components/Tables/companies/CompanyListFilters.tsx new file mode 100644 index 0000000..0b270f8 --- /dev/null +++ b/src/components/Tables/companies/CompanyListFilters.tsx @@ -0,0 +1,98 @@ +import InputGroup from "@/components/FormElements/InputGroup"; +import { Select } from "@/components/FormElements/select"; +import { Currencies } from "@/constants/enums"; +import { + FieldValues, + UseFormHandleSubmit, + UseFormRegister, + UseFormSetValue, + UseFormWatch, +} from "react-hook-form"; + +interface CompanyListFiltersProps { + filterRegister: UseFormRegister; + setIsFilterModalOpen: (isOpen: boolean) => void; + isMutating: number; + handleFilterSubmit: UseFormHandleSubmit; + search: (data: any) => void; + watch: UseFormWatch; + setValue: UseFormSetValue; +} + +const CompanyListFilters = ({ + filterRegister, + setIsFilterModalOpen, + isMutating, + handleFilterSubmit, + search, + watch, + setValue, +}: CompanyListFiltersProps) => { + return ( +
+ + + + setValue("published", undefined)} + /> + +
+ + +
+ + ); +}; + +export default CompanyCategoryListFilters; diff --git a/src/components/Tables/companies/company-categories/index.tsx b/src/components/Tables/companies/company-categories/index.tsx index 7688e98..c429c84 100644 --- a/src/components/Tables/companies/company-categories/index.tsx +++ b/src/components/Tables/companies/company-categories/index.tsx @@ -14,10 +14,12 @@ import { import TableSkeleton from "@/components/ui/TableSkeleton"; import { _TooltipDefaultParams } from "@/constants/tooltip"; import { unixToDate } from "@/utils/shared"; -import Link from "next/link"; import { Tooltip } from "react-tooltip"; import { Skeleton } from "../../../ui/skeleton"; import useCompanyCategoriesPresenter from "./useCompanyCategoriesPresenter"; +import ListHeader from "@/components/ui/ListHeader"; +import CompanyCategoryListFilters from "./CompanyCategoryListFilters"; +import Modal from "@/components/ui/modal"; const CompanyCategoriesTable = () => { const { @@ -32,13 +34,22 @@ const CompanyCategoriesTable = () => { setCurrentCategory, isModalOpen, setIsModalOpen, + isFilterModalOpen, + setIsFilterModalOpen, + filterRegister, + handleFilterSubmit, + search, + watch, + setFilterValue, + isMutating, } = useCompanyCategoriesPresenter(); return (
- + setIsFilterModalOpen(true)} + createButtonText="Create Category" + /> @@ -123,6 +134,22 @@ const CompanyCategoriesTable = () => {
+ setIsFilterModalOpen(false)} + classNames="w-full xl:w-1/2" + showButtons={false} + > + + {isModalOpen && ( { const [isModalOpen, setIsModalOpen] = useState(false); + const [isFilterModalOpen, setIsFilterModalOpen] = useState(false); const [currentCategory, setCurrentCategory] = useState(); - const [params, setParams] = useState>({ - ...apiDefaultParams, - }); + const [params, setParams] = useState>({}); const router = useRouter(); const pathName = usePathname(); + const searchParams = useSearchParams(); + const isMutating = useIsMutating(); + + const { + register: filterRegister, + handleSubmit: handleFilterSubmit, + reset: filterFormReset, + watch, + setValue: setFilterValue, + } = useForm(); + + useEffect(() => { + const newParams: Record = { + ...apiDefaultParams, + }; + for (const [key, value] of searchParams.entries()) { + newParams[key] = value; + } + setParams(newParams); + filterFormReset(newParams); + }, [searchParams, filterFormReset]); + const { data, isLoading, isError } = useCompanyCategoriesQuery(params); const { mutate: deleteCategory } = useDeleteCompanyCategoryQuery(() => setIsModalOpen(false), ); - const {mutate:togglePublished,isPending:isToggling} = useToggleCompanyCategoryPublished() + const { mutate: togglePublished, isPending: isToggling } = + useToggleCompanyCategoryPublished(); + + const search = (data: any) => { + const newParams = { ...params, ...data }; + const cleanedParams = deleteEmptyKeys(newParams); + const queryString = new URLSearchParams(cleanedParams).toString(); + router.push(`${pathName}?${queryString}`); + setIsFilterModalOpen(false); + }; + const onConfirmDelete = () => { if (!currentCategory) return; deleteCategory(currentCategory?.id); @@ -41,6 +75,14 @@ const useCompanyCategoriesPresenter = () => { isToggling, setCurrentCategory, onConfirmDelete, + isFilterModalOpen, + setIsFilterModalOpen, + filterRegister, + handleFilterSubmit, + search, + watch, + setFilterValue, + isMutating, }; }; diff --git a/src/components/Tables/companies/index.tsx b/src/components/Tables/companies/index.tsx index 3c10765..665cad9 100644 --- a/src/components/Tables/companies/index.tsx +++ b/src/components/Tables/companies/index.tsx @@ -17,9 +17,11 @@ import { import TableSkeleton from "@/components/ui/TableSkeleton"; import { _TooltipDefaultParams } from "@/constants/tooltip"; import { formatPhoneNumber } from "@/utils/shared"; -import Link from "next/link"; import { Tooltip } from "react-tooltip"; import { useCompanyListPresenter } from "./useCompanyListPresenter"; +import ListHeader from "@/components/ui/ListHeader"; +import Modal from "@/components/ui/modal"; +import CompanyListFilters from "./CompanyListFilters"; const CompaniesTable = () => { const { @@ -33,12 +35,21 @@ const CompaniesTable = () => { setCurrentCompany, onConfirmDelete, modalConfig, + isFilterModalOpen, + setIsFilterModalOpen, + filterRegister, + handleFilterSubmit, + search, + watch, + setFilterValue, + isMutating, } = useCompanyListPresenter(); return (
- + setIsFilterModalOpen(true)} + createButtonText="Create Company" + /> @@ -149,6 +160,22 @@ const CompaniesTable = () => { )}
+ setIsFilterModalOpen(false)} + classNames="w-full xl:w-1/2" + showButtons={false} + > + + {isModalOpen && ( { const deleteModal = useRef(null); const { inView } = useInView({ threshold: 0.5 }); const [currentCompany, setCurrentCompany] = useState(null); - const [search, setSearch] = useState(""); + const [isFilterModalOpen, setIsFilterModalOpen] = useState(false); const [modalConfig, setModalConfig] = useState< Partial >({}); - const [params, setParams] = useState>({ - sort: "created_at", - }); + const [params, setParams] = useState>({}); const [isModalOpen, setIsModalOpen] = useState(false); const router = useRouter(); + const pathName = usePathname(); + const searchParams = useSearchParams(); + const isMutating = useIsMutating(); + + const { + register: filterRegister, + handleSubmit: handleFilterSubmit, + reset: filterFormReset, + watch, + setValue: setFilterValue, + } = useForm(); + const columns = [ "row", "name", @@ -31,14 +42,23 @@ export const useCompanyListPresenter = () => { "phone", "country", "state", - "language", "currency", "employee count", "actions", ]; - const pathName = usePathname(); - const debouncedSearch = useDebounce(search, 1000); + + useEffect(() => { + const newParams: Record = { + sort: "created_at", + }; + for (const [key, value] of searchParams.entries()) { + newParams[key] = value; + } + setParams(newParams); + filterFormReset(newParams); + }, [searchParams, filterFormReset]); + const { data, error, @@ -48,24 +68,23 @@ export const useCompanyListPresenter = () => { hasNextPage, isFetchingNextPage, } = useCompaniesInfiniteQuery(params); + useEffect(() => { if (inView && hasNextPage && data && data.pages.length < 5) { fetchNextPage(); } }, [inView, hasNextPage, data, fetchNextPage]); + const { mutate: deleteCompany } = useDeleteCompanyQuery(() => setIsModalOpen(false), ); - useEffect(() => { - const result = z.string().safeParse(debouncedSearch); - if (result.success) { - setParams((prevParams) => ({ - ...prevParams, - })); - } - }, [debouncedSearch]); - const handleFilterChange = (e: ChangeEvent) => { - setSearch(e.target.value); + + const search = (data: any) => { + const newParams = { ...params, ...data }; + const cleanedParams = deleteEmptyKeys(newParams); + const queryString = new URLSearchParams(cleanedParams).toString(); + router.push(`${pathName}?${queryString}`); + setIsFilterModalOpen(false); }; const onConfirmDelete = () => { if (currentCompany) { @@ -75,7 +94,6 @@ export const useCompanyListPresenter = () => { const allCompanies = data?.pages.flatMap((page) => page.data.companies) ?? []; return { allCompanies, - handleFilterChange, onConfirmDelete, deleteCompany, isFetchingNextPage, @@ -95,6 +113,13 @@ export const useCompanyListPresenter = () => { router, isPending, isError, + isFilterModalOpen, + setIsFilterModalOpen, + filterRegister, + handleFilterSubmit, search, + watch, + setFilterValue, + isMutating, }; }; diff --git a/src/components/Tables/customers/CustomerListFilters.tsx b/src/components/Tables/customers/CustomerListFilters.tsx new file mode 100644 index 0000000..1f75d5b --- /dev/null +++ b/src/components/Tables/customers/CustomerListFilters.tsx @@ -0,0 +1,90 @@ +import { Select } from "@/components/FormElements/select"; +import { AdminRoles, CustomerStatus, CustomerType } from "@/constants/enums"; +import { getEnumAsArray } from "@/utils/shared"; +import { + FieldValues, + UseFormHandleSubmit, + UseFormRegister, + UseFormSetValue, + UseFormWatch, +} from "react-hook-form"; + +interface CustomerListFiltersProps { + filterRegister: UseFormRegister; + setIsFilterModalOpen: (isOpen: boolean) => void; + isMutating: number; + handleFilterSubmit: UseFormHandleSubmit; + search: (data: any) => void; + watch: UseFormWatch; + setValue: UseFormSetValue; +} + +const CustomerListFilters = ({ + filterRegister, + setIsFilterModalOpen, + isMutating, + handleFilterSubmit, + search, + watch, + setValue, +}: CustomerListFiltersProps) => { + return ( +
+ setValue("role", undefined)} + /> + setValue("status", undefined)} + /> +