feat(companies): implement companies page with data table
This commit introduces a new "Companies" page to the dashboard, providing a comprehensive view of company data in a sortable and paginated table. Key changes include: - A new page at `/companies` to display the data table. - A new API route `/api/companies` that serves mock company data. - A `CompaniesTable` component built with `react-table` featuring sorting, pagination, and search functionality. - Reusable `TablePagination` and `TableActions` components to support the table. - The `moment` library has been added as a dependency to format dates within the table. - A new `CrossIcon` has been added for UI controls. - The `InputGroup` component is enhanced with an `autoComplete` prop. - A link to the new "Companies" page has been added to the sidebar navigation.
This commit is contained in:
@@ -12,9 +12,19 @@ import {
|
||||
} from "@/components/ui/table";
|
||||
|
||||
import { TendersSkeleton } from "./Skeleton";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { getStatusColor } from "@/utils/shared";
|
||||
const TendersTable = () => {
|
||||
const { allTenders, isPending } = useTenderListPresenter();
|
||||
if (isPending) return <TendersSkeleton />;
|
||||
const {
|
||||
allTenders,
|
||||
isPending,
|
||||
ref,
|
||||
isFetchingNextPage,
|
||||
data,
|
||||
fetchNextPage,
|
||||
hasNextPage,
|
||||
} = useTenderListPresenter();
|
||||
|
||||
return (
|
||||
<div className="flex flex-col rounded-[10px] bg-white px-7.5 pb-4 pt-7.5 shadow-1 dark:bg-gray-dark dark:shadow-card">
|
||||
<Table>
|
||||
@@ -38,6 +48,7 @@ const TendersTable = () => {
|
||||
<h6 key={index}>No tenders were found</h6>
|
||||
) : (
|
||||
<TableRow
|
||||
ref={index === allTenders.length - 1 ? ref : null}
|
||||
key={item.id}
|
||||
className="odd:bg-gray-2 dark:odd:bg-gray-7"
|
||||
>
|
||||
@@ -47,14 +58,31 @@ const TendersTable = () => {
|
||||
<TableCell className="text-start" colSpan={100}>
|
||||
{item.country_code}
|
||||
</TableCell>
|
||||
<TableCell className="text-start" colSpan={100}>
|
||||
{item.status}
|
||||
<TableCell className={cn(`text capitalize`)} colSpan={100}>
|
||||
<span
|
||||
className={cn(
|
||||
"rounded-2xl p-2",
|
||||
getStatusColor(item.status),
|
||||
)}
|
||||
>
|
||||
{item.status}
|
||||
</span>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
),
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
{isFetchingNextPage && <TendersSkeleton />}
|
||||
{(data?.pages.length ?? 0) >= 5 && hasNextPage && (
|
||||
<button
|
||||
onClick={() => fetchNextPage()}
|
||||
disabled={isFetchingNextPage}
|
||||
className="mt-4 rounded bg-blue-500 px-4 py-2 font-bold text-white hover:bg-blue-700"
|
||||
>
|
||||
{isFetchingNextPage ? "Loading..." : "Load More"}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -28,20 +28,20 @@ const useTenderListPresenter = () => {
|
||||
isFetchingNextPage,
|
||||
} = useTendersInfiniteQuery(params);
|
||||
|
||||
const { inView } = useInView({ threshold: 0.5 });
|
||||
const { ref, inView } = useInView({ threshold: 0.5 });
|
||||
|
||||
useEffect(() => {
|
||||
if (inView && hasNextPage && data && data.pages.length < 5) {
|
||||
if (inView && hasNextPage && (data?.pages.length ?? 0) < 5) {
|
||||
fetchNextPage();
|
||||
}
|
||||
}, [inView, hasNextPage, data, fetchNextPage]);
|
||||
}, [inView, hasNextPage, fetchNextPage, data?.pages.length]);
|
||||
|
||||
useEffect(() => {
|
||||
const result = z.string().safeParse(debouncedSearch);
|
||||
if (result.success) {
|
||||
setParams((prevParams) => ({
|
||||
...prevParams,
|
||||
q: result.data,
|
||||
search: debouncedSearch,
|
||||
}));
|
||||
}
|
||||
}, [debouncedSearch]);
|
||||
@@ -57,6 +57,7 @@ const useTenderListPresenter = () => {
|
||||
|
||||
const allTenders = data?.pages.flatMap((page) => page.data.tenders) ?? [];
|
||||
return {
|
||||
ref,
|
||||
currentTender,
|
||||
setCurrentTender,
|
||||
search,
|
||||
|
||||
Reference in New Issue
Block a user