diff --git a/src/admin/pages/IssuedOrders.tsx b/src/admin/pages/IssuedOrders.tsx
index 5add6a9..6e5a385 100644
--- a/src/admin/pages/IssuedOrders.tsx
+++ b/src/admin/pages/IssuedOrders.tsx
@@ -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 ;
}
@@ -256,12 +281,7 @@ export default function IssuedOrders() {
{hasPermission("orders.export") && (
- window.open(
- `${API_BASE}/issued-orders-pdf/${o.id}?lang=cs`,
- "_blank",
- )
- }
+ onClick={() => handleExportPdf(o)}
aria-label="PDF"
title="PDF"
>