341 lines
11 KiB
TypeScript
341 lines
11 KiB
TypeScript
import Customers from "@Front/Api/LeCoffreApi/Notary/Customers/Customers";
|
|
import DocumentReminders from "@Front/Api/LeCoffreApi/Notary/DocumentReminders/DocumentReminders";
|
|
import Dropdown from "@Front/Components/DesignSystem/Dropdown";
|
|
import { IOption } from "@Front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption";
|
|
import Table from "@Front/Components/DesignSystem/Table";
|
|
import { IHead, IRowProps } from "@Front/Components/DesignSystem/Table/MuiTable";
|
|
import Tag, { ETagColor, ETagVariant } from "@Front/Components/DesignSystem/Tag";
|
|
import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography";
|
|
import BackArrow from "@Front/Components/Elements/BackArrow";
|
|
import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate";
|
|
import Module from "@Front/Config/Module";
|
|
import Customer from "le-coffre-resources/dist/Customer";
|
|
import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document";
|
|
import { DocumentReminder } from "le-coffre-resources/dist/Notary";
|
|
import { useRouter } from "next/router";
|
|
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
|
|
|
import classes from "./classes.module.scss";
|
|
import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
|
|
|
type IProps = {};
|
|
|
|
const tradDocumentStatus: Record<EDocumentStatus, string> = {
|
|
[EDocumentStatus.ASKED]: "DEMANDÉ",
|
|
[EDocumentStatus.DEPOSITED]: "À VALIDER",
|
|
[EDocumentStatus.VALIDATED]: "VALIDÉ",
|
|
[EDocumentStatus.REFUSED]: "REFUSÉ",
|
|
};
|
|
|
|
const header: readonly IHead[] = [
|
|
{
|
|
key: "remindedAt",
|
|
title: "Date de relance",
|
|
},
|
|
{
|
|
key: "customer",
|
|
title: "Client",
|
|
},
|
|
{
|
|
key: "document_type",
|
|
title: "Type de document",
|
|
},
|
|
{
|
|
key: "statut",
|
|
title: "Satut",
|
|
},
|
|
];
|
|
|
|
export default function DocumentsReminderHistory(props: IProps) {
|
|
const [reminders, setReminders] = useState<DocumentReminder[] | null>(null);
|
|
const [customers, setCustomers] = useState<Customer[] | null>(null);
|
|
const [customerOption, setCustomerOption] = useState<IOption | null>(null);
|
|
const router = useRouter();
|
|
const [page, setPage] = useState(1); // Current page number
|
|
const [pageSize, setPageSize] = useState(10); // Number of items per page
|
|
const [totalPages, setTotalPages] = useState(1); // Total number of pages
|
|
let { folderUid } = router.query;
|
|
|
|
const fetchTotalPages = useCallback(() => {
|
|
DocumentReminders.getInstance()
|
|
.count({
|
|
where: {
|
|
...(folderUid && {
|
|
document: {
|
|
folder: {
|
|
uid: folderUid as string,
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
})
|
|
.then((response) => {
|
|
const totalPages = Math.ceil(response.count / pageSize);
|
|
setTotalPages(totalPages);
|
|
})
|
|
.catch((e) => console.warn(e));
|
|
}, [pageSize]);
|
|
|
|
const fetchReminders = useCallback(() => {
|
|
DocumentReminders.getInstance()
|
|
.get({
|
|
...(customerOption && customerOption.id !== "tous" && { where: { document: { depositor: { uid: customerOption.id } } } }),
|
|
where: {
|
|
...(folderUid && {
|
|
document: {
|
|
folder: {
|
|
uid: folderUid as string,
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
include: {
|
|
document: {
|
|
include: {
|
|
depositor: {
|
|
include: {
|
|
contact: true,
|
|
},
|
|
},
|
|
document_type: true,
|
|
},
|
|
},
|
|
},
|
|
orderBy: { reminder_date: "desc" },
|
|
skip: (page - 1) * pageSize, // Skip based on the page number
|
|
take: pageSize, // Take the number of items for the page
|
|
})
|
|
.then((response) => {
|
|
setReminders(response); // Set the reminders
|
|
})
|
|
.catch((e) => console.warn(e));
|
|
}, [customerOption, page, pageSize]); // Update on page change
|
|
|
|
const fetchCustomers = useCallback(async () => {
|
|
if (!folderUid) return;
|
|
Customers.getInstance()
|
|
.get({
|
|
where: {
|
|
office_folders: {
|
|
some: {
|
|
uid: folderUid as string,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
.then(setCustomers)
|
|
.catch(console.warn);
|
|
}, [folderUid]);
|
|
|
|
const customersOptions: IOption[] = useMemo(() => {
|
|
let options = [
|
|
{
|
|
id: "tous",
|
|
label: "Tous",
|
|
},
|
|
];
|
|
|
|
customers?.forEach((customer) => {
|
|
options.push({
|
|
id: customer.uid ?? "",
|
|
label: `${customer.contact?.first_name} ${customer.contact?.last_name}`,
|
|
});
|
|
});
|
|
return options;
|
|
}, [customers]);
|
|
|
|
useEffect(() => {
|
|
fetchTotalPages();
|
|
fetchReminders();
|
|
fetchCustomers();
|
|
}, [fetchTotalPages, fetchCustomers, fetchReminders]);
|
|
|
|
const generatePageNumbers = (currentPage: number, totalPages: number) => {
|
|
const pageNumbers = [];
|
|
const maxPagesToShow = 7; // Maximum number of page buttons, including ellipsis
|
|
|
|
// Case 1: If total pages are <= 5, show all pages
|
|
if (totalPages <= 5) {
|
|
for (let i = 1; i <= totalPages; i++) {
|
|
pageNumbers.push(i);
|
|
}
|
|
}
|
|
// Case 2: If current page is <= 3, and totalPages > 5, show the first 4 pages + ellipsis
|
|
else if (currentPage <= 3) {
|
|
for (let i = 1; i <= 4; i++) {
|
|
pageNumbers.push(i);
|
|
}
|
|
pageNumbers.push("...");
|
|
}
|
|
// Case 3: If current page is in the middle, show ellipses and surrounding pages
|
|
else if (currentPage > 3 && currentPage < totalPages - 2) {
|
|
pageNumbers.push("...");
|
|
pageNumbers.push(currentPage - 1);
|
|
pageNumbers.push(currentPage);
|
|
pageNumbers.push(currentPage + 1);
|
|
pageNumbers.push("...");
|
|
}
|
|
// Case 4: If current page is near the end, show ellipsis and last 4 pages
|
|
else if (currentPage >= totalPages - 2) {
|
|
pageNumbers.push("...");
|
|
for (let i = totalPages - 3; i <= totalPages; i++) {
|
|
pageNumbers.push(i);
|
|
}
|
|
}
|
|
|
|
// Ensure the pagination length is exactly maxPagesToShow (counting ellipses as one)
|
|
if (pageNumbers.length > maxPagesToShow) {
|
|
// Remove ellipsis at the start or end if pagination exceeds max length
|
|
if (pageNumbers[0] === "...") {
|
|
pageNumbers.shift(); // Remove first ellipsis if it's the first item
|
|
}
|
|
if (pageNumbers.length > maxPagesToShow && pageNumbers[pageNumbers.length - 1] === "...") {
|
|
pageNumbers.pop(); // Remove last ellipsis if it's the last item
|
|
}
|
|
}
|
|
|
|
return pageNumbers;
|
|
};
|
|
|
|
// Handle page change
|
|
const handlePageChange = (newPage: number) => {
|
|
if (newPage >= 1 && newPage <= totalPages) {
|
|
setPage(newPage);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<DefaultTemplate title={"Historique des relances de documents"} isPadding={false}>
|
|
<div className={classes["root"]}>
|
|
<BackArrow
|
|
text="Retour"
|
|
url={Module.getInstance()
|
|
.get()
|
|
.modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", folderUid as string)}
|
|
/>
|
|
<Typography typo={ETypo.TITLE_H1} color={ETypoColor.TEXT_PRIMARY}>
|
|
Historique des relances de documents
|
|
</Typography>
|
|
<Dropdown
|
|
className={classes["customer-filter"]}
|
|
options={customersOptions}
|
|
onSelectionChange={(option) => setCustomerOption(option ?? null)}
|
|
selectedOption={customerOption ?? customersOptions?.[0]}
|
|
label="Client"
|
|
/>
|
|
{/* Page Size Selector */}
|
|
<Dropdown
|
|
className={classes["page-size-selector"]}
|
|
options={[
|
|
{ id: "10", label: "10 par page" },
|
|
{ id: "20", label: "20 par page" },
|
|
{ id: "50", label: "50 par page" },
|
|
]}
|
|
selectedOption={{ id: `${pageSize}`, label: `${pageSize} par page` }}
|
|
onSelectionChange={(option) => {
|
|
setPageSize(parseInt(option.id, 10)); // Update the page size
|
|
setPage(1); // Reset the page to 1
|
|
}}
|
|
label="Items par page"
|
|
/>
|
|
|
|
<Table className={classes["table"]} header={header} rows={buildRows(reminders)} />
|
|
|
|
<div className={classes["pagination"]}>
|
|
{/* Left Arrow (Prev) */}
|
|
<Button
|
|
variant={EButtonVariant.PRIMARY}
|
|
styletype={EButtonstyletype.OUTLINED}
|
|
className={`${page === 1 ? classes["disabled"] : ""} ${classes["prev"]}`}
|
|
onClick={() => handlePageChange(page - 1)}>
|
|
<
|
|
</Button>
|
|
{/* <button
|
|
className={`${page === 1 ? classes["disabled"] : ""} ${classes["prev"]}`}
|
|
onClick={() => handlePageChange(page - 1)}
|
|
aria-label="Previous Page">
|
|
<
|
|
</button> */}
|
|
|
|
{/* Page numbers */}
|
|
{generatePageNumbers(page, totalPages).map((pageNum, index) => (
|
|
<React.Fragment key={index}>
|
|
{pageNum === "..." ? (
|
|
<Button variant={EButtonVariant.PRIMARY}>...</Button>
|
|
) : (
|
|
<Button
|
|
variant={EButtonVariant.PRIMARY}
|
|
className={page === pageNum ? classes["active"] : ""}
|
|
onClick={() => handlePageChange(pageNum as number)}>
|
|
{pageNum}
|
|
</Button>
|
|
// <button
|
|
// className={page === pageNum ? classes["active"] : ""}
|
|
// onClick={() => handlePageChange(pageNum as number)}
|
|
// aria-label={`Go to page ${pageNum}`}>
|
|
// {pageNum}
|
|
// </button>
|
|
)}
|
|
</React.Fragment>
|
|
))}
|
|
|
|
{/* Right Arrow (Next) */}
|
|
<Button
|
|
variant={EButtonVariant.PRIMARY}
|
|
styletype={EButtonstyletype.OUTLINED}
|
|
className={`${page === totalPages ? classes["disabled"] : ""} ${classes["next"]}`}
|
|
onClick={() => handlePageChange(page + 1)}>
|
|
>
|
|
</Button>
|
|
{/* <button
|
|
className={`${page === totalPages ? classes["disabled"] : ""} ${classes["next"]}`}
|
|
onClick={() => handlePageChange(page + 1)}
|
|
aria-label="Next Page">
|
|
>
|
|
</button> */}
|
|
</div>
|
|
</div>
|
|
</DefaultTemplate>
|
|
);
|
|
}
|
|
|
|
function buildRows(reminders: DocumentReminder[] | null): IRowProps[] {
|
|
if (!reminders) return [];
|
|
return reminders.map((reminder) => ({
|
|
key: reminder.uid ?? "",
|
|
remindedAt: { sx: { width: 220 }, content: formatDateWithHours(reminder.reminder_date) },
|
|
customer: {
|
|
sx: { width: 220 },
|
|
content: `${reminder.document?.depositor?.contact?.first_name} ${reminder.document?.depositor?.contact?.last_name}`,
|
|
},
|
|
document_type: reminder.document?.document_type?.name,
|
|
statut: { sx: { width: 220 }, content: getTag(reminder.document?.document_status as EDocumentStatus) },
|
|
}));
|
|
}
|
|
|
|
function getTag(status: EDocumentStatus) {
|
|
switch (status) {
|
|
case EDocumentStatus.ASKED:
|
|
return <Tag label={tradDocumentStatus[status]} color={ETagColor.INFO} variant={ETagVariant.SEMI_BOLD} />;
|
|
case EDocumentStatus.DEPOSITED:
|
|
return <Tag label={tradDocumentStatus[status]} color={ETagColor.WARNING} variant={ETagVariant.SEMI_BOLD} />;
|
|
case EDocumentStatus.VALIDATED:
|
|
return <Tag label={tradDocumentStatus[status]} color={ETagColor.SUCCESS} variant={ETagVariant.SEMI_BOLD} />;
|
|
case EDocumentStatus.REFUSED:
|
|
return <Tag label={tradDocumentStatus[status]} color={ETagColor.ERROR} variant={ETagVariant.SEMI_BOLD} />;
|
|
default:
|
|
return <Tag label={tradDocumentStatus[status]} color={ETagColor.INFO} variant={ETagVariant.SEMI_BOLD} />;
|
|
}
|
|
}
|
|
|
|
function formatDateWithHours(date: Date | null) {
|
|
if (!date) return "-";
|
|
return new Date(date).toLocaleDateString("fr-FR", {
|
|
year: "numeric",
|
|
month: "2-digit",
|
|
day: "2-digit",
|
|
hour: "2-digit",
|
|
minute: "2-digit",
|
|
});
|
|
}
|