+
({
format={`YYYY/MM/DD ${timePicker ? "HH:mm" : ""}`}
containerClassName="w-full"
inputClass={cn(
- "w-full rounded-lg border-[1.5px] border-stroke bg-transparent px-5.5 py-3 pl-12.5 text-dark outline-none transition focus:border-primary disabled:cursor-default disabled:bg-gray-2 dark:border-dark-3 dark:bg-dark-2 dark:text-white dark:focus:border-primary dark:disabled:bg-dark",
- error && "!border-red focus:!border-red dark:!border-red",
+ "w-full rounded-xl border border-stroke/70 bg-white/90 px-5.5 py-3 pl-12.5 text-dark shadow-[0_1px_2px_rgba(16,24,40,0.04),0_8px_20px_rgba(16,24,40,0.04)] outline-none backdrop-blur-[1px] transition-all duration-200 focus:border-primary/70 focus:bg-white focus:shadow-[0_0_0_2px_rgba(59,130,246,0.14),0_10px_24px_rgba(59,130,246,0.08)] disabled:cursor-default disabled:bg-gray-2/70 dark:border-dark-3/80 dark:bg-dark-2/85 dark:text-white dark:focus:border-primary/80 dark:focus:shadow-[0_0_0_2px_rgba(59,130,246,0.2),0_10px_24px_rgba(15,23,42,0.45)] dark:disabled:bg-dark",
+ error &&
+ "border-red/80 focus:border-red focus:shadow-[0_0_0_2px_rgba(239,68,68,0.16),0_10px_24px_rgba(239,68,68,0.1)] dark:border-red/80 dark:focus:shadow-[0_0_0_2px_rgba(239,68,68,0.24),0_10px_24px_rgba(127,29,29,0.45)]",
)}
placeholder={placeholder}
/>
-
+
{error && (
-
+
{error.message as string}
)}
diff --git a/src/components/Tables/companies/company-categories/index.tsx b/src/components/Tables/companies/company-categories/index.tsx
index 65bfd22..fa3ef3e 100644
--- a/src/components/Tables/companies/company-categories/index.tsx
+++ b/src/components/Tables/companies/company-categories/index.tsx
@@ -3,6 +3,7 @@ import { PencilSquareIcon, TrashIcon } from "@/assets/icons";
import { Switch } from "@/components/FormElements/switch";
import EmptyListWrapper from "@/components/HOC/EmptyListWrapper";
import ConfirmationModal from "@/components/ui/ConfirmationModal";
+import IsVisible from "@/components/ui/IsVisible";
import ListHeader from "@/components/ui/ListHeader";
import ListWrapper from "@/components/ui/ListWrapper";
import Modal from "@/components/ui/modal";
@@ -15,6 +16,7 @@ import {
TableRow,
} from "@/components/ui/table";
import TableSkeleton from "@/components/ui/TableSkeleton";
+import Pagination from "@/components/ui/pagination";
import { _TooltipDefaultParams } from "@/constants/tooltip";
import { getPaginatedRowNumber, unixToDate } from "@/utils/shared";
import { startTransition } from "react";
@@ -44,6 +46,9 @@ const CompanyCategoriesTable = () => {
setFilterValue,
columns,
isMutating,
+ metadata,
+ setParams,
+ shouldShowPagination,
} = useCompanyCategoriesPresenter();
return (
@@ -70,6 +75,7 @@ const CompanyCategoriesTable = () => {
list={optimisticCategories}
columns={columns}
emptyMessage="No categories were found"
+ isLoading={isLoading}
>
{optimisticCategories.map((category, index) => (
{
className="odd:bg-gray-2 dark:odd:bg-gray-7"
>
- {getPaginatedRowNumber({ index })}
+ {getPaginatedRowNumber({
+ index,
+ page: metadata?.page,
+ limit: metadata?.limit,
+ })}
{category.name}
{category.description}
@@ -179,6 +189,19 @@ const CompanyCategoriesTable = () => {
onCancel={() => setIsModalOpen(false)}
/>
)}
+
+ {
+ setParams((currentParams) => ({
+ ...currentParams,
+ offset: e.selected * (metadata?.limit ?? 10),
+ limit: metadata?.limit ?? 10,
+ }));
+ }}
+ />
+
);
};
diff --git a/src/components/Tables/companies/company-categories/useCompanyCategoriesPresenter.ts b/src/components/Tables/companies/company-categories/useCompanyCategoriesPresenter.ts
index 20046c3..5c0b085 100644
--- a/src/components/Tables/companies/company-categories/useCompanyCategoriesPresenter.ts
+++ b/src/components/Tables/companies/company-categories/useCompanyCategoriesPresenter.ts
@@ -35,6 +35,8 @@ const useCompanyCategoriesPresenter = () => {
useEffect(() => {
const newParams: Record = {
...apiDefaultParams,
+ offset: 0,
+ limit: 10,
};
for (const [key, value] of searchParams.entries()) {
newParams[key] = value;
@@ -45,6 +47,10 @@ const useCompanyCategoriesPresenter = () => {
const { data, isLoading, isError } = useCompanyCategoriesQuery(params);
const categories = data?.data.categories;
+ const metadata = data?.meta;
+ const shouldShowPagination =
+ !isLoading &&
+ (data?.meta?.pages ?? 1) * (data?.meta?.limit ?? 10) > 10;
const [optimisticCategories, addOptimisticPublished] = useOptimistic<
TCompanyCategory[],
TogglePublishedOptimistic
@@ -58,7 +64,7 @@ const useCompanyCategoriesPresenter = () => {
useToggleCompanyCategoryPublished();
const search = (data: any) => {
- const newParams = { ...params, ...data };
+ const newParams = { ...params, ...data, offset: 0 };
const cleanedParams = deleteEmptyKeys(newParams);
const queryString = new URLSearchParams(cleanedParams).toString();
router.push(`${pathName}?${queryString}`);
@@ -102,6 +108,8 @@ const useCompanyCategoriesPresenter = () => {
watch,
setFilterValue,
isMutating,
+ metadata,
+ shouldShowPagination,
};
};
diff --git a/src/components/Tables/companies/index.tsx b/src/components/Tables/companies/index.tsx
index a6954fd..b8d93f1 100644
--- a/src/components/Tables/companies/index.tsx
+++ b/src/components/Tables/companies/index.tsx
@@ -7,9 +7,11 @@ import {
} from "@/assets/icons";
import EmptyListWrapper from "@/components/HOC/EmptyListWrapper";
import ConfirmationModal from "@/components/ui/ConfirmationModal";
+import IsVisible from "@/components/ui/IsVisible";
import ListHeader from "@/components/ui/ListHeader";
import ListWrapper from "@/components/ui/ListWrapper";
import Modal from "@/components/ui/modal";
+import Pagination from "@/components/ui/pagination";
import {
Table,
TableBody,
@@ -45,6 +47,9 @@ const CompaniesTable = () => {
watch,
setFilterValue,
isMutating,
+ metadata,
+ setParams,
+ shouldShowPagination,
} = useCompanyListPresenter();
const companies = allCompanies.filter(
(c): c is NonNullable => c != null,
@@ -75,6 +80,7 @@ const CompaniesTable = () => {
list={companies}
columns={columns}
emptyMessage="No companies were found"
+ isLoading={isPending}
>
{companies.map((company, index) => (
{
className="odd:bg-gray-2 dark:odd:bg-gray-7"
>
- {getPaginatedRowNumber({ index })}
+ {getPaginatedRowNumber({
+ index,
+ page: metadata?.page,
+ limit: metadata?.limit,
+ })}
{company.name}
@@ -198,6 +208,19 @@ const CompaniesTable = () => {
onCancel={() => setIsModalOpen(false)}
/>
)}
+
+ {
+ setParams((currentParams) => ({
+ ...currentParams,
+ offset: e.selected * (metadata?.limit ?? 10),
+ limit: metadata?.limit ?? 10,
+ }));
+ }}
+ />
+
);
};
diff --git a/src/components/Tables/companies/useCompanyListPresenter.ts b/src/components/Tables/companies/useCompanyListPresenter.ts
index a8be1bb..1877326 100644
--- a/src/components/Tables/companies/useCompanyListPresenter.ts
+++ b/src/components/Tables/companies/useCompanyListPresenter.ts
@@ -1,20 +1,18 @@
"use client";
import { ConfirmationModalProps } from "@/components/ui/ConfirmationModal";
+import { apiDefaultParams } from "@/constants/Api_Params";
import {
- useCompaniesInfiniteQuery,
+ useCompaniesQuery,
useDeleteCompanyQuery,
} from "@/hooks/queries";
import { TCompany } from "@/lib/api";
import { deleteEmptyKeys } from "@/utils/shared";
import { useIsMutating } from "@tanstack/react-query";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
-import { useEffect, useRef, useState } from "react";
+import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
-import { useInView } from "react-intersection-observer";
export const useCompanyListPresenter = () => {
- const deleteModal = useRef(null);
- const { inView } = useInView({ threshold: 0.5 });
const [currentCompany, setCurrentCompany] = useState(null);
const [isFilterModalOpen, setIsFilterModalOpen] = useState(false);
const [modalConfig, setModalConfig] = useState<
@@ -50,7 +48,9 @@ export const useCompanyListPresenter = () => {
useEffect(() => {
const newParams: Record = {
- sort: "created_at",
+ ...apiDefaultParams,
+ offset: 0,
+ limit: 10,
};
for (const [key, value] of searchParams.entries()) {
newParams[key] = value;
@@ -59,28 +59,17 @@ export const useCompanyListPresenter = () => {
filterFormReset(newParams);
}, [searchParams, filterFormReset]);
- const {
- data,
- error,
- isPending,
- isError,
- fetchNextPage,
- hasNextPage,
- isFetchingNextPage,
- } = useCompaniesInfiniteQuery(params);
+ const { data, error, isPending, isError } = useCompaniesQuery(params);
- useEffect(() => {
- if (inView && hasNextPage && data && data.pages.length < 5) {
- fetchNextPage();
- }
- }, [inView, hasNextPage, data, fetchNextPage]);
+ const shouldShowPagination =
+ !isPending && (data?.meta?.pages ?? 1) * (data?.meta?.limit ?? 10) > 10;
const { mutate: deleteCompany } = useDeleteCompanyQuery(() =>
setIsModalOpen(false),
);
const search = (data: any) => {
- const newParams = { ...params, ...data };
+ const newParams = { ...params, ...data, offset: 0 };
const cleanedParams = deleteEmptyKeys(newParams);
const queryString = new URLSearchParams(cleanedParams).toString();
router.push(`${pathName}?${queryString}`);
@@ -91,22 +80,18 @@ export const useCompanyListPresenter = () => {
deleteCompany(currentCompany.id);
}
};
- const allCompanies = data?.pages.flatMap((page) => page.data.companies) ?? [];
+ const allCompanies = data?.data.companies ?? [];
+ const metadata = data?.meta;
return {
allCompanies,
onConfirmDelete,
- deleteCompany,
- isFetchingNextPage,
- data,
+ metadata,
columns,
pathName,
currentCompany,
- hasNextPage,
- fetchNextPage,
modalConfig,
setModalConfig,
setCurrentCompany,
- deleteModal,
error,
isModalOpen,
setIsModalOpen,
@@ -121,5 +106,7 @@ export const useCompanyListPresenter = () => {
watch,
setFilterValue,
isMutating,
+ setParams,
+ shouldShowPagination,
};
};
diff --git a/src/components/Tables/tenders/TenderListFilters.tsx b/src/components/Tables/tenders/TenderListFilters.tsx
index fee6a51..d188234 100644
--- a/src/components/Tables/tenders/TenderListFilters.tsx
+++ b/src/components/Tables/tenders/TenderListFilters.tsx
@@ -1,3 +1,4 @@
+import DatePicker from "@/components/FormElements/DatePicker/DatePicker";
import InputGroup from "@/components/FormElements/InputGroup";
import { Select } from "@/components/FormElements/select";
import { Button } from "@/components/ui-elements/button";
@@ -6,6 +7,7 @@ import { TenderStatus } from "@/constants/enums";
import { Languages } from "@/constants/languages";
import { getEnumAsArray } from "@/utils/shared";
import {
+ Control,
FieldValues,
UseFormHandleSubmit,
UseFormRegister,
@@ -15,6 +17,7 @@ import {
interface TenderListFiltersProps {
filterRegister: UseFormRegister;
+ control: Control;
setIsFilterModalOpen: (isOpen: boolean) => void;
isMutating: number;
handleFilterSubmit: UseFormHandleSubmit;
@@ -25,6 +28,7 @@ interface TenderListFiltersProps {
const TenderListFilters = ({
filterRegister,
+ control,
setIsFilterModalOpen,
isMutating,
handleFilterSubmit,
@@ -37,11 +41,22 @@ const TenderListFilters = ({
className="grid !min-w-full grid-cols-1 gap-4 xl:grid-cols-2"
onSubmit={handleFilterSubmit(search)}
>
+
+