fix(orders): authenticated PDF open in issued-orders list

The list opened the PDF route via raw window.open, an unauthenticated top-level navigation that 401s on the token-guarded endpoint. Now uses the apiFetch -> blob -> window pattern from InvoiceDetail/IssuedOrderDetail.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
BOHA
2026-06-09 11:46:50 +02:00
parent d7e0ba933d
commit e26fce092a

View File

@@ -10,6 +10,7 @@ import useTableSort from "../hooks/useTableSort";
import useDebounce from "../hooks/useDebounce";
import { usePaginatedQuery } from "../hooks/usePaginatedQuery";
import { useApiMutation } from "../lib/queries/mutations";
import apiFetch from "../utils/api";
import {
issuedOrderListOptions,
type IssuedOrder,
@@ -170,6 +171,30 @@ export default function IssuedOrders() {
}
};
const handleExportPdf = async (o: IssuedOrder) => {
// Authenticated open: apiFetch attaches the access token, then we hand the
// resulting PDF blob to a window. A raw window.open(url) would be an
// unauthenticated top-level navigation and 401 on the token-guarded route.
const newWindow = window.open("", "_blank");
try {
const response = await apiFetch(
`${API_BASE}/issued-orders-pdf/${o.id}?lang=cs`,
);
if (!response.ok) {
newWindow?.close();
alert.error("Nepodařilo se vygenerovat PDF");
return;
}
const blob = await response.blob();
const url = URL.createObjectURL(blob);
if (newWindow) newWindow.location.href = url;
setTimeout(() => URL.revokeObjectURL(url), 60000);
} catch {
newWindow?.close();
alert.error("Chyba při generování PDF");
}
};
if (isPending) {
return <LoadingState />;
}
@@ -256,12 +281,7 @@ export default function IssuedOrders() {
{hasPermission("orders.export") && (
<IconButton
size="small"
onClick={() =>
window.open(
`${API_BASE}/issued-orders-pdf/${o.id}?lang=cs`,
"_blank",
)
}
onClick={() => handleExportPdf(o)}
aria-label="PDF"
title="PDF"
>