Descarga de proformas en PDF
This commit is contained in:
parent
00c647fe20
commit
9d7e18d73d
@ -5,9 +5,9 @@ export async function downloadInvoicePDFApi(
|
||||
invoiceId: string,
|
||||
params?: Record<string, unknown>
|
||||
): Promise<Blob> {
|
||||
return dataSource.custom<Blob>({
|
||||
return dataSource.custom<unknown, Blob>({
|
||||
...params,
|
||||
path: `issued-invoices/${invoiceId}/report`,
|
||||
path: `issued-invoices/${invoiceId}/report/pdf`,
|
||||
method: "get",
|
||||
responseType: "blob",
|
||||
});
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { showErrorToast, showSuccessToast } from "@repo/rdx-ui/helpers";
|
||||
import * as React from "react";
|
||||
|
||||
import { useDownloadInvoicePDFQuery } from "../../shared";
|
||||
import { useDownloadInvoicePDFQuery } from "../hooks";
|
||||
|
||||
interface PendingDownload {
|
||||
id: string;
|
||||
@ -37,7 +37,7 @@ export function useDownloadInvoicePDFController() {
|
||||
setPending({ id, invoice_number });
|
||||
|
||||
// refetch se dispara en un efecto, o aquí si prefieres:
|
||||
refetch().catch((err) => {
|
||||
refetch().catch((err: unknown) => {
|
||||
showErrorToast(
|
||||
"Error al descargar",
|
||||
err instanceof Error ? err.message : "Error desconocido"
|
||||
|
||||
@ -0,0 +1 @@
|
||||
export * from "./use-download-invoice-pdf-query";
|
||||
@ -3,7 +3,7 @@
|
||||
import { useDataSource } from "@erp/core/hooks";
|
||||
import { type QueryKey, useQuery } from "@tanstack/react-query";
|
||||
|
||||
import { downloadInvoicePDFApi } from "../../download-pdf/api";
|
||||
import { downloadInvoicePDFApi } from "../api";
|
||||
|
||||
export const ISSUED_INVOICE_QUERY_KEY = (id: string): QueryKey => ["issued_invoice", id] as const;
|
||||
|
||||
@ -1,2 +1 @@
|
||||
export * from "./use-download-invoice-pdf-query";
|
||||
export * from "./use-issued-invoice-list-query";
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
import type { IDataSource } from "@erp/core/client";
|
||||
|
||||
export async function downloadProformaPDFApi(
|
||||
dataSource: IDataSource,
|
||||
proformaId: string,
|
||||
params?: Record<string, unknown>
|
||||
): Promise<Blob> {
|
||||
return dataSource.custom<Blob>({
|
||||
...params,
|
||||
path: `proformas/${proformaId}/report/pdf`,
|
||||
method: "get",
|
||||
responseType: "blob",
|
||||
});
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
export * from "./download-proforma-pdf.api";
|
||||
@ -0,0 +1 @@
|
||||
export * from "./use-download-proforma-pdf.controller";
|
||||
@ -0,0 +1,54 @@
|
||||
import { showErrorToast, showSuccessToast } from "@repo/rdx-ui/helpers";
|
||||
import * as React from "react";
|
||||
|
||||
import { useDownloadProformaPDFQuery } from "../hooks";
|
||||
|
||||
interface PendingDownload {
|
||||
id: string;
|
||||
proforma_number: string;
|
||||
}
|
||||
|
||||
export function useDownloadProformaPDFController() {
|
||||
const [pending, setPending] = React.useState<PendingDownload | null>(null);
|
||||
|
||||
const { data, isFetching, refetch } = useDownloadProformaPDFQuery(pending?.id);
|
||||
|
||||
// Efecto: cuando hay blob + pending, disparamos la descarga
|
||||
React.useEffect(() => {
|
||||
if (!(pending && data)) return;
|
||||
|
||||
const blob = data;
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = `proforma-${pending.proforma_number}.pdf`;
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
showSuccessToast(
|
||||
"Descarga iniciada",
|
||||
`La proforma ${pending.proforma_number} se está descargando.`
|
||||
);
|
||||
|
||||
setPending(null);
|
||||
}, [data, pending]);
|
||||
|
||||
const download = (id: string, proforma_number: string) => {
|
||||
setPending({ id, proforma_number });
|
||||
|
||||
// refetch se dispara en un efecto, o aquí si prefieres:
|
||||
refetch().catch((err: unknown) => {
|
||||
showErrorToast(
|
||||
"Error al descargar",
|
||||
err instanceof Error ? err.message : "Error desconocido"
|
||||
);
|
||||
setPending(null);
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
download, // (id, reference) => void
|
||||
isLoading: isFetching,
|
||||
loadingId: pending?.id,
|
||||
};
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
export * from "./use-download-proforma-pdf-query";
|
||||
@ -0,0 +1,53 @@
|
||||
import { useDataSource } from "@erp/core/hooks";
|
||||
import { type QueryKey, useQuery } from "@tanstack/react-query";
|
||||
|
||||
import { downloadProformaPDFApi } from "../api";
|
||||
|
||||
export const PROFORMA_QUERY_KEY = (id: string): QueryKey => ["proforma", id] as const;
|
||||
|
||||
type DownloadProformaPDFOptions = {
|
||||
enabled?: boolean;
|
||||
};
|
||||
|
||||
export function useDownloadProformaPDFQuery(
|
||||
proformaId?: string,
|
||||
options?: DownloadProformaPDFOptions
|
||||
) {
|
||||
const dataSource = useDataSource();
|
||||
const enabled = (options?.enabled ?? true) && !!proformaId;
|
||||
|
||||
return useQuery({
|
||||
queryKey: PROFORMA_QUERY_KEY(proformaId ?? "unknown"),
|
||||
queryFn: async (context) => {
|
||||
if (!proformaId) throw new Error("proformaId is required");
|
||||
|
||||
const { signal } = context;
|
||||
return await downloadProformaPDFApi(dataSource, proformaId, {
|
||||
signal,
|
||||
});
|
||||
},
|
||||
enabled,
|
||||
staleTime: 0,
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
export function useQuery<
|
||||
TQueryFnData = unknown,
|
||||
TError = unknown,
|
||||
TData = TQueryFnData,
|
||||
TQueryKey extends QueryKey = QueryKey
|
||||
>
|
||||
|
||||
TQueryFnData: the type returned from the queryFn.
|
||||
TError: the type of Errors to expect from the queryFn.
|
||||
TData: the type our data property will eventually have.
|
||||
Only relevant if you use the select option,
|
||||
because then the data property can be different
|
||||
from what the queryFn returns.
|
||||
Otherwise, it will default to whatever the queryFn returns.
|
||||
TQueryKey: the type of our queryKey, only relevant
|
||||
if you use the queryKey that is passed to your queryFn.
|
||||
|
||||
*/
|
||||
@ -0,0 +1,3 @@
|
||||
export * from "./api";
|
||||
export * from "./controller";
|
||||
export * from "./hooks";
|
||||
@ -1,9 +1,12 @@
|
||||
import type { RightPanelMode } from "@repo/rdx-ui/hooks";
|
||||
import { useCallback } from "react";
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
|
||||
import { useChangeProformaStatusDialogController } from "../../change-status";
|
||||
import { useDeleteProformaDialogController } from "../../delete";
|
||||
import { useDownloadProformaPDFController } from "../../download-pdf/controller";
|
||||
import { useIssueProformaDialogController } from "../../issue-proforma";
|
||||
import type { ProformaListRow } from "../../shared";
|
||||
|
||||
import { useListProformasController } from "./use-list-proformas.controller";
|
||||
import { useProformaSummaryPanelController } from "./use-proforma-summary-panel.controller";
|
||||
@ -14,6 +17,15 @@ export const useListProformasPageController = () => {
|
||||
const issueDialogCtrl = useIssueProformaDialogController();
|
||||
const changeStatusDialogCtrl = useChangeProformaStatusDialogController();
|
||||
|
||||
const downloadPDFCtrl = useDownloadProformaPDFController();
|
||||
|
||||
const handleDownloadPDF = useCallback(
|
||||
(proforma: ProformaListRow) => {
|
||||
downloadPDFCtrl.download(proforma.id, proforma.invoiceNumber);
|
||||
},
|
||||
[downloadPDFCtrl]
|
||||
);
|
||||
|
||||
const [searchParams] = useSearchParams();
|
||||
|
||||
const proformaId = searchParams.get("proformaId") ?? "";
|
||||
@ -32,5 +44,10 @@ export const useListProformasPageController = () => {
|
||||
deleteDialogCtrl,
|
||||
issueDialogCtrl,
|
||||
changeStatusDialogCtrl,
|
||||
|
||||
downloadPDFCtrl,
|
||||
handleDownloadPDF,
|
||||
pdfDownloadingId: downloadPDFCtrl.loadingId,
|
||||
isPDFDownloading: downloadPDFCtrl.isLoading,
|
||||
};
|
||||
};
|
||||
|
||||
@ -44,8 +44,16 @@ export const ListProformasPage = () => {
|
||||
fallbackPath: "/proformas",
|
||||
});
|
||||
|
||||
const { listCtrl, panelCtrl, deleteDialogCtrl, issueDialogCtrl, changeStatusDialogCtrl } =
|
||||
useListProformasPageController();
|
||||
const {
|
||||
listCtrl,
|
||||
panelCtrl,
|
||||
deleteDialogCtrl,
|
||||
issueDialogCtrl,
|
||||
changeStatusDialogCtrl,
|
||||
handleDownloadPDF,
|
||||
isPDFDownloading: isPdfDownloading,
|
||||
pdfDownloadingId,
|
||||
} = useListProformasPageController();
|
||||
|
||||
const handleEditClick = (proformaId: string) => {
|
||||
navigate({
|
||||
@ -65,7 +73,9 @@ export const ListProformasPage = () => {
|
||||
onChangeStatusClick: (proforma) =>
|
||||
changeStatusDialogCtrl.openDialog(prepareChangeProformaStatusTargets(proforma)),
|
||||
|
||||
onDownloadPdf: (proforma) => null,
|
||||
onDownloadPdf: handleDownloadPDF,
|
||||
pdfDownloadingId,
|
||||
isPdfDownloading,
|
||||
});
|
||||
|
||||
const isPanelOpen = panelCtrl.panelState.isOpen;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user