@hszrdm/core 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,14 +2,14 @@ import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
2
  import { defineWidgetConfig, defineRouteConfig } from "@medusajs/admin-sdk";
3
3
  import { Container, Heading, Text, Button, toast, Input, Switch, Select, Checkbox } from "@medusajs/ui";
4
4
  import * as React from "react";
5
- import { useState, useMemo, useEffect, useCallback } from "react";
5
+ import { useState, useEffect, useMemo, useCallback } from "react";
6
6
  const BankTransferOrderWidget = ({ data: order }) => {
7
7
  const transfer = order?.metadata?.bank_transfer;
8
8
  if (!transfer?.reference) return null;
9
9
  return /* @__PURE__ */ jsxs(Container, { className: "divide-y p-0", children: [
10
10
  /* @__PURE__ */ jsxs("div", { className: "px-6 py-4", children: [
11
11
  /* @__PURE__ */ jsx(Heading, { level: "h2", children: "Banki átutalás adatai" }),
12
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "A fizetési állapotot a Medusa Payment panel kezeli." })
12
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "A fizetési állapotot a HSZRDM Commerce Payment panel kezeli." })
13
13
  ] }),
14
14
  /* @__PURE__ */ jsxs("div", { className: "grid gap-2 px-6 py-4 text-sm", children: [
15
15
  /* @__PURE__ */ jsxs(Text, { children: [
@@ -246,8 +246,86 @@ const BillingoOrderWidget = ({ data: order }) => {
246
246
  defineWidgetConfig({
247
247
  zone: "order.details.after"
248
248
  });
249
- const brandName = "Webshop Admin";
249
+ const platformName = "HSZRDM Commerce";
250
+ const brandIconSvg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><rect width="512" height="512" rx="88" fill="#080b10"/><path d="M96 112h64v112h104V112h64v288h-64V288H160v112H96z" fill="#f0f2f5"/><path d="M400 112h48l-72 288h-48z" fill="#77a9ff"/></svg>';
251
+ const brandIconDataUri = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(brandIconSvg)}`;
252
+ const configuredBrandName = platformName;
253
+ const storeName = configuredBrandName.replace(/\s*[–-]\s*HSZRDM Commerce$/i, "").trim();
254
+ const visibleStoreName = storeName && storeName.toLowerCase() !== platformName.toLowerCase() ? storeName : "";
255
+ const nativeLoginCopy = /* @__PURE__ */ new Map([
256
+ ["Welcome to Medusa", platformName],
257
+ ["Sign in to access the account area", "Jelentkezz be az admin felület eléréséhez"]
258
+ ]);
259
+ function installFavicon() {
260
+ for (const element of Array.from(document.querySelectorAll('link[rel~="icon"]'))) {
261
+ if (element.dataset.hszrdmFavicon !== "true") element.remove();
262
+ }
263
+ let link = document.querySelector('link[data-hszrdm-favicon="true"]');
264
+ if (!link) {
265
+ link = document.createElement("link");
266
+ link.rel = "icon";
267
+ link.type = "image/svg+xml";
268
+ link.dataset.hszrdmFavicon = "true";
269
+ document.head.appendChild(link);
270
+ }
271
+ link.href = brandIconDataUri;
272
+ }
273
+ function installNativeLoginIcon() {
274
+ const title = Array.from(document.querySelectorAll("h1,h2,h3")).find((element) => element.textContent?.trim() === platformName);
275
+ if (!title) return;
276
+ const titleBlock = title.parentElement;
277
+ const possibleHosts = [
278
+ titleBlock?.previousElementSibling,
279
+ titleBlock?.parentElement?.previousElementSibling
280
+ ].filter((element) => element instanceof HTMLElement);
281
+ const host = possibleHosts.find((element) => {
282
+ const rect = element.getBoundingClientRect();
283
+ return rect.width > 0 && rect.height > 0 && rect.width <= 96 && rect.height <= 96;
284
+ });
285
+ if (!host || host.dataset.hszrdmLoginIcon === "true") return;
286
+ host.innerHTML = brandIconSvg;
287
+ host.dataset.hszrdmLoginIcon = "true";
288
+ const svg = host.querySelector("svg");
289
+ if (svg) {
290
+ svg.setAttribute("aria-label", "HSZRDM Commerce");
291
+ svg.setAttribute("role", "img");
292
+ svg.style.display = "block";
293
+ svg.style.width = "100%";
294
+ svg.style.height = "100%";
295
+ }
296
+ }
297
+ function rewriteNativeLoginBranding() {
298
+ document.title = visibleStoreName ? `${visibleStoreName} – ${platformName}` : platformName;
299
+ installFavicon();
300
+ const walker = document.createTreeWalker(
301
+ document.body,
302
+ NodeFilter.SHOW_TEXT
303
+ );
304
+ let current = walker.nextNode();
305
+ while (current) {
306
+ const value = current.nodeValue?.trim();
307
+ const replacement = value ? nativeLoginCopy.get(value) : void 0;
308
+ if (replacement && current.nodeValue) {
309
+ current.nodeValue = current.nodeValue.replace(value, replacement);
310
+ }
311
+ current = walker.nextNode();
312
+ }
313
+ installNativeLoginIcon();
314
+ }
250
315
  const CoreLoginBrand = () => {
316
+ useEffect(() => {
317
+ rewriteNativeLoginBranding();
318
+ const observer = new MutationObserver(() => {
319
+ rewriteNativeLoginBranding();
320
+ });
321
+ observer.observe(document.body, {
322
+ childList: true,
323
+ subtree: true,
324
+ characterData: true
325
+ });
326
+ return () => observer.disconnect();
327
+ }, []);
328
+ if (!visibleStoreName) return null;
251
329
  return /* @__PURE__ */ jsx(
252
330
  "div",
253
331
  {
@@ -259,7 +337,7 @@ const CoreLoginBrand = () => {
259
337
  letterSpacing: "-0.02em",
260
338
  marginBottom: "8px"
261
339
  },
262
- children: brandName
340
+ children: visibleStoreName
263
341
  }
264
342
  );
265
343
  };
@@ -812,6 +890,9 @@ defineWidgetConfig({
812
890
  const backendUrl$c = (__BACKEND_URL__ || "").replace(/\/+$/, "");
813
891
  const adminBase$9 = (__BASE__ || "/app").replace(/\/+$/, "");
814
892
  const apiUrl$c = (path) => `${backendUrl$c}${path.startsWith("/") ? path : `/${path}`}`;
893
+ const showDeveloperDetails = Boolean(
894
+ false
895
+ );
815
896
  const AnalyticsPage = () => {
816
897
  const initial = useMemo(() => presetRange("30d"), []);
817
898
  const [preset, setPreset] = useState("30d");
@@ -857,7 +938,7 @@ const AnalyticsPage = () => {
857
938
  /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-4 border-b px-6 py-5", children: [
858
939
  /* @__PURE__ */ jsxs("div", { children: [
859
940
  /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Analitika" }),
860
- /* @__PURE__ */ jsx(Text, { className: "mt-1 text-ui-fg-subtle", children: "A fő forgalmi és viselkedési mérés közvetlenül a webshopból érkezik; a rendelés, vásárló és bevétel forrása a Medusa. A GA4 külön kontrolladat." })
941
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 text-ui-fg-subtle", children: showDeveloperDetails ? "A fő forgalmi és viselkedési mérés közvetlenül a webshopból érkezik; a rendelés, vásárló és bevétel forrása a HSZRDM Commerce rendelési rendszere. A GA4 külön kontrolladat." : "Forgalom, vásárlói viselkedés, rendelések és bevétel egy helyen." })
861
942
  ] }),
862
943
  /* @__PURE__ */ jsx(Button, { variant: "secondary", isLoading: loading, onClick: () => void load(), children: "Frissítés" })
863
944
  ] }),
@@ -943,7 +1024,7 @@ const AnalyticsPage = () => {
943
1024
  /* @__PURE__ */ jsxs("div", { className: "mb-4 flex flex-wrap items-center justify-between gap-3", children: [
944
1025
  /* @__PURE__ */ jsxs("div", { children: [
945
1026
  /* @__PURE__ */ jsx(Heading, { level: "h2", children: "Top termékek" }),
946
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Eladás szerint Medusából, viselkedés szerint a saját webshop-mérésből." })
1027
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: showDeveloperDetails ? "Eladás szerint a HSZRDM Commerce rendelési rendszeréből, viselkedés szerint a saját webshop-mérésből." : "A legjobban teljesítő termékek bevétel és vásárlói viselkedés alapján." })
947
1028
  ] }),
948
1029
  /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
949
1030
  /* @__PURE__ */ jsx(Button, { size: "small", variant: productMode === "revenue" ? "primary" : "secondary", onClick: () => setProductMode("revenue"), children: "Bevétel" }),
@@ -989,7 +1070,7 @@ const AnalyticsPage = () => {
989
1070
  /* @__PURE__ */ jsxs("div", { className: "mb-4 flex flex-wrap items-start justify-between gap-2", children: [
990
1071
  /* @__PURE__ */ jsxs("div", { children: [
991
1072
  /* @__PURE__ */ jsx(Heading, { level: "h2", children: "Google Analytics összehasonlítás" }),
992
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Kontrolladat; nem ez a webshop üzleti source of truth-ja." })
1073
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: showDeveloperDetails ? "Kontrolladat; nem ez a webshop üzleti source of truth-ja." : "Kiegészítő összehasonlítás a Google Analytics 4 adataival." })
993
1074
  ] }),
994
1075
  /* @__PURE__ */ jsx(SourceBadge, { source: "ga4" })
995
1076
  ] }),
@@ -1009,7 +1090,7 @@ const AnalyticsPage = () => {
1009
1090
  data.currency,
1010
1091
  " bevételi összegzésbe."
1011
1092
  ] }) : null,
1012
- /* @__PURE__ */ jsx("div", { className: "rounded-lg bg-ui-bg-subtle p-4", children: /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "A látogató-, session-, forrás-, termékviselkedési és funnel adatok elsődleges forrása a HSZRDM Webshop Analytics. A rendelés, vásárló és bevétel üzleti forrása a Medusa adatbázisa. A GA4 csak külső kontroll és marketing riportforrás." }) })
1093
+ showDeveloperDetails ? /* @__PURE__ */ jsx("div", { className: "rounded-lg bg-ui-bg-subtle p-4", children: /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "A látogató-, session-, forrás-, termékviselkedési és funnel adatok elsődleges forrása a HSZRDM Webshop Analytics. A rendelés, vásárló és bevétel üzleti forrása a HSZRDM Commerce adatbázisa. A GA4 csak külső kontroll és marketing riportforrás." }) }) : null
1013
1094
  ] }) : loading ? /* @__PURE__ */ jsx("div", { className: "p-10 text-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Analitika betöltése…" }) }) : null
1014
1095
  ] });
1015
1096
  };
@@ -1030,7 +1111,8 @@ function KpiCard({ label, metric, compare, format = "number", currency = "HUF" }
1030
1111
  ] });
1031
1112
  }
1032
1113
  function SourceBadge({ source, compact = false }) {
1033
- const label = source === "ga4" ? "GA4" : source === "webshop" ? "Webshop mérés" : source === "combined" ? "Webshop + Medusa" : "Medusa";
1114
+ if (!showDeveloperDetails) return null;
1115
+ const label = source === "ga4" ? "GA4" : source === "webshop" ? "Webshop mérés" : source === "combined" ? "Webshop + HSZRDM Commerce" : "HSZRDM Commerce";
1034
1116
  return /* @__PURE__ */ jsx("span", { className: `rounded-full border bg-ui-bg-subtle text-ui-fg-subtle ${compact ? "px-1.5 py-0.5 text-[10px]" : "px-2 py-1 text-xs"}`, children: label });
1035
1117
  }
1036
1118
  function RevenueChart({ series, currency }) {
@@ -1197,6 +1279,53 @@ function formatNullablePercent(value) {
1197
1279
  return value == null ? "—" : formatPercent(value);
1198
1280
  }
1199
1281
  const config$c = defineRouteConfig({ label: "Analitika" });
1282
+ const adminBase$8 = (__BASE__ || "/app").replace(/\/+$/, "");
1283
+ const links$1 = [
1284
+ {
1285
+ label: "Analitika",
1286
+ description: "Látogatók, vásárlási tölcsér, bevétel, vásárlók, top termékek és checkout állapot egy közös dashboardon.",
1287
+ href: `${adminBase$8}/analytics`
1288
+ },
1289
+ {
1290
+ label: "SEO",
1291
+ description: "Termék-, kategória- és oldal SEO title, description, canonical, robots és Open Graph kezelése.",
1292
+ href: `${adminBase$8}/marketing/seo`
1293
+ },
1294
+ {
1295
+ label: "SEO átirányítások",
1296
+ description: "Régi URL-ek 301/308 átirányítása, be/ki kapcsolás és query paraméter kezelés.",
1297
+ href: `${adminBase$8}/marketing/seo/redirects`
1298
+ },
1299
+ {
1300
+ label: "Google Merchant",
1301
+ description: "Google Merchant Center termékfeed előnézet, diagnosztika és publikus feed URL.",
1302
+ href: `${adminBase$8}/marketing/google-merchant`
1303
+ },
1304
+ {
1305
+ label: "Árukereső",
1306
+ description: "Árukereső.hu XML feed előnézet, diagnosztika és publikus feed URL.",
1307
+ href: `${adminBase$8}/marketing/arukereso`
1308
+ }
1309
+ ];
1310
+ const MarketingPage = () => /* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
1311
+ /* @__PURE__ */ jsxs("div", { className: "border-b px-6 py-5", children: [
1312
+ /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Marketing" }),
1313
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 text-ui-fg-subtle", children: "Analitika, SEO, termékfeedek és külső marketing/értékesítési csatornák kezelése. Az integrációk technikai alapbeállításai a Settings → Integrációk alatt találhatók." })
1314
+ ] }),
1315
+ /* @__PURE__ */ jsx("div", { className: "grid gap-4 p-6 md:grid-cols-2 xl:grid-cols-3", children: links$1.map((item) => /* @__PURE__ */ jsxs(
1316
+ "a",
1317
+ {
1318
+ href: item.href,
1319
+ className: "rounded-lg border p-5 transition-colors hover:bg-ui-bg-subtle",
1320
+ children: [
1321
+ /* @__PURE__ */ jsx(Heading, { level: "h2", children: item.label }),
1322
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 text-ui-fg-subtle", children: item.description })
1323
+ ]
1324
+ },
1325
+ item.href
1326
+ )) })
1327
+ ] });
1328
+ const config$b = defineRouteConfig({ label: "Marketing" });
1200
1329
  var __defProp$1 = Object.defineProperty;
1201
1330
  var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols;
1202
1331
  var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
@@ -1314,412 +1443,335 @@ const TruckFast = React.forwardRef(
1314
1443
  }
1315
1444
  );
1316
1445
  TruckFast.displayName = "TruckFast";
1446
+ const LABEL_FORMAT_STORAGE_KEY = "core.shipping.labelFormat";
1447
+ const DIRECT_PRINT_STORAGE_KEY = "core.shipping.directPrint";
1317
1448
  const backendUrl$b = (__BACKEND_URL__ || "").replace(/\/+$/, "");
1318
- const adminBase$8 = (__BASE__ || "/app").replace(/\/+$/, "");
1319
- const apiUrl$b = (path) => `${backendUrl$b}${path.startsWith("/") ? path : `/${path}`}`;
1320
- const LegalPage = () => {
1321
- const [documents, setDocuments] = useState([]);
1322
- const [consents, setConsents] = useState([]);
1323
- const [loading, setLoading] = useState(true);
1324
- const [busy, setBusy] = useState(null);
1449
+ const adminBase$7 = (__BASE__ || "/app").replace(/\/+$/, "");
1450
+ function apiUrl$b(path) {
1451
+ return `${backendUrl$b}${path.startsWith("/") ? path : `/${path}`}`;
1452
+ }
1453
+ const ShippingPage = () => {
1454
+ const [orders, setOrders] = useState([]);
1455
+ const [selected, setSelected] = useState([]);
1456
+ const [format, setFormat] = useState("A6");
1457
+ const [packageSize, setPackageSize] = useState("M");
1458
+ const [directPrint, setDirectPrint] = useState(false);
1459
+ const [loading, setLoading] = useState(null);
1460
+ const [ordersLoading, setOrdersLoading] = useState(true);
1325
1461
  const [loadError, setLoadError] = useState(null);
1326
- const [title, setTitle] = useState("");
1327
- const [key, setKey] = useState("");
1328
- const [kind, setKind] = useState("custom");
1329
- const [fileName, setFileName] = useState("");
1330
- const [fileBase64, setFileBase64] = useState("");
1331
- const [enabled, setEnabled] = useState(true);
1332
- const [required, setRequired] = useState(false);
1462
+ const selectedSet = useMemo(() => new Set(selected), [selected]);
1463
+ const selectedMplOrders = useMemo(
1464
+ () => orders.filter((order) => selectedSet.has(order.id) && order.carrier === "mpl"),
1465
+ [orders, selectedSet]
1466
+ );
1333
1467
  const load = useCallback(async () => {
1334
- setLoading(true);
1468
+ setOrdersLoading(true);
1335
1469
  setLoadError(null);
1336
1470
  try {
1337
- const [documentsResponse, consentsResponse] = await Promise.all([
1338
- fetch(apiUrl$b("/admin/legal/documents"), { credentials: "include" }),
1339
- fetch(apiUrl$b("/admin/legal/consents"), { credentials: "include" })
1340
- ]);
1341
- const documentsPayload = await documentsResponse.json().catch(() => ({}));
1342
- const consentsPayload = await consentsResponse.json().catch(() => ({}));
1343
- if (!documentsResponse.ok) {
1344
- throw new Error(
1345
- documentsPayload.message || "A jogi dokumentumok nem tölthetők be."
1346
- );
1347
- }
1348
- if (!consentsResponse.ok) {
1349
- throw new Error(
1350
- consentsPayload.message || "Az elfogadások nem tölthetők be."
1351
- );
1471
+ const response = await fetch(apiUrl$b("/admin/shipping/orders"), {
1472
+ credentials: "include"
1473
+ });
1474
+ const data = await response.json().catch(() => ({}));
1475
+ if (!response.ok) {
1476
+ throw new Error(data.message || "A szállítási rendelések betöltése nem sikerült.");
1352
1477
  }
1353
- setDocuments(documentsPayload.documents || []);
1354
- setConsents(consentsPayload.consents || []);
1478
+ const nextOrders = data.orders || [];
1479
+ setOrders(nextOrders);
1480
+ setSelected((current) => current.filter((id) => nextOrders.some((order) => order.id === id)));
1355
1481
  } catch (error) {
1356
- setLoadError(
1357
- error instanceof Error ? error.message : "A jogi dokumentumok nem tölthetők be."
1358
- );
1482
+ const message = error instanceof Error ? error.message : "A szállítási rendelések betöltése nem sikerült.";
1483
+ setOrders([]);
1484
+ setLoadError(message);
1359
1485
  } finally {
1360
- setLoading(false);
1486
+ setOrdersLoading(false);
1361
1487
  }
1362
1488
  }, []);
1363
1489
  useEffect(() => {
1490
+ setFormat(localStorage.getItem(LABEL_FORMAT_STORAGE_KEY) || "A6");
1491
+ setDirectPrint(localStorage.getItem(DIRECT_PRINT_STORAGE_KEY) === "true");
1364
1492
  void load();
1365
1493
  }, [load]);
1366
- const createDocument = async () => {
1367
- setBusy("create");
1494
+ const setSavedFormat = (value) => {
1495
+ setFormat(value);
1496
+ localStorage.setItem(LABEL_FORMAT_STORAGE_KEY, value);
1497
+ };
1498
+ const setSavedPrint = (value) => {
1499
+ setDirectPrint(value);
1500
+ localStorage.setItem(DIRECT_PRINT_STORAGE_KEY, String(value));
1501
+ };
1502
+ const toggle = (id) => {
1503
+ setSelected((current) => current.includes(id) ? current.filter((item) => item !== id) : [...current, id]);
1504
+ };
1505
+ const create = async () => {
1506
+ if (!selected.length) {
1507
+ toast.error("Jelölj ki legalább egy rendelést.");
1508
+ return false;
1509
+ }
1510
+ setLoading("create");
1368
1511
  try {
1369
- if (!title.trim() || !key.trim()) {
1370
- throw new Error("A név és a kulcs kötelező.");
1371
- }
1372
- if (!fileBase64) throw new Error("Válassz PDF fájlt.");
1373
- const response = await fetch(apiUrl$b("/admin/legal/documents"), {
1512
+ const response = await fetch(apiUrl$b("/admin/shipping/bulk/create"), {
1374
1513
  method: "POST",
1375
1514
  credentials: "include",
1376
1515
  headers: { "Content-Type": "application/json" },
1377
- body: JSON.stringify({
1378
- title,
1379
- key,
1380
- kind,
1381
- fileBase64,
1382
- fileName,
1383
- enabled,
1384
- requiredAtCheckout: required
1385
- })
1516
+ body: JSON.stringify({ orderIds: selected, packageSize })
1386
1517
  });
1387
- const payload = await response.json().catch(() => ({}));
1388
- if (!response.ok) {
1389
- throw new Error(
1390
- payload.message || "A dokumentum létrehozása nem sikerült."
1391
- );
1518
+ const data = await response.json().catch(() => ({}));
1519
+ if (!response.ok && response.status !== 207) {
1520
+ throw new Error(data.message || "A tömeges csomagkészítés nem sikerült.");
1392
1521
  }
1393
- toast.success("Jogi PDF létrehozva és verziózva.");
1394
- setTitle("");
1395
- setKey("");
1396
- setKind("custom");
1397
- setFileName("");
1398
- setFileBase64("");
1399
- setEnabled(true);
1400
- setRequired(false);
1522
+ const failed = data.results?.filter((item) => !item.ok) || [];
1523
+ if (failed.length) toast.error(`${failed.length} csomag nem készült el.`);
1524
+ else toast.success(`${selected.length} csomag elkészült.`);
1401
1525
  await load();
1526
+ return failed.length === 0;
1402
1527
  } catch (error) {
1403
- toast.error(
1404
- error instanceof Error ? error.message : "A dokumentum létrehozása nem sikerült."
1405
- );
1528
+ toast.error(error instanceof Error ? error.message : "A tömeges csomagkészítés nem sikerült.");
1529
+ return false;
1406
1530
  } finally {
1407
- setBusy(null);
1531
+ setLoading(null);
1408
1532
  }
1409
1533
  };
1410
- const updateDocument = async (document2, changes) => {
1411
- setBusy(`update:${document2.id}`);
1534
+ const labels = async (print = directPrint) => {
1535
+ if (!selected.length) {
1536
+ toast.error("Jelölj ki legalább egy rendelést.");
1537
+ return;
1538
+ }
1539
+ setLoading("labels");
1412
1540
  try {
1413
- const response = await fetch(
1414
- apiUrl$b(`/admin/legal/documents/${document2.id}`),
1415
- {
1416
- method: "POST",
1417
- credentials: "include",
1418
- headers: { "Content-Type": "application/json" },
1419
- body: JSON.stringify(changes)
1420
- }
1421
- );
1422
- const payload = await response.json().catch(() => ({}));
1541
+ const response = await fetch(apiUrl$b("/admin/shipping/bulk/labels"), {
1542
+ method: "POST",
1543
+ credentials: "include",
1544
+ headers: { "Content-Type": "application/json" },
1545
+ body: JSON.stringify({ orderIds: selected, format })
1546
+ });
1423
1547
  if (!response.ok) {
1424
- throw new Error(payload.message || "A dokumentum mentése nem sikerült.");
1548
+ const data = await response.json().catch(() => ({}));
1549
+ throw new Error(data.message || "A közös PDF nem készíthető el.");
1425
1550
  }
1426
- await load();
1551
+ openPdf(await response.blob(), `shipping-labels-${format}.pdf`, print);
1427
1552
  } catch (error) {
1428
- toast.error(
1429
- error instanceof Error ? error.message : "A dokumentum mentése nem sikerült."
1430
- );
1553
+ toast.error(error instanceof Error ? error.message : "A közös PDF nem készíthető el.");
1431
1554
  } finally {
1432
- setBusy(null);
1555
+ setLoading(null);
1433
1556
  }
1434
1557
  };
1435
- const uploadNewVersion = async (document2, file) => {
1436
- setBusy(`version:${document2.id}`);
1558
+ const closeMpl = async () => {
1559
+ if (!selectedMplOrders.length) {
1560
+ toast.error("Jelölj ki legalább egy MPL rendelést.");
1561
+ return;
1562
+ }
1563
+ setLoading("mpl-close");
1437
1564
  try {
1438
- const response = await fetch(
1439
- apiUrl$b(`/admin/legal/documents/${document2.id}/versions`),
1440
- {
1441
- method: "POST",
1442
- credentials: "include",
1443
- headers: { "Content-Type": "application/json" },
1444
- body: JSON.stringify({
1445
- fileBase64: await fileToBase64(file),
1446
- fileName: file.name
1447
- })
1448
- }
1449
- );
1450
- const payload = await response.json().catch(() => ({}));
1565
+ const response = await fetch(apiUrl$b("/admin/shipping/mpl/close"), {
1566
+ method: "POST",
1567
+ credentials: "include",
1568
+ headers: { "Content-Type": "application/json" },
1569
+ body: JSON.stringify({
1570
+ orderIds: selectedMplOrders.map((order) => order.id),
1571
+ checkList: true
1572
+ })
1573
+ });
1574
+ const data = await response.json().catch(() => ({}));
1451
1575
  if (!response.ok) {
1452
- throw new Error(payload.message || "Az új PDF-verzió mentése nem sikerült.");
1576
+ throw new Error(data.message || "Az MPL jegyzékzárás nem sikerült.");
1453
1577
  }
1454
- toast.success(
1455
- payload.created ? "Új PDF-verzió elmentve." : "Ez a PDF-verzió már el volt mentve."
1456
- );
1578
+ toast.success(`${data.trackingNumbers?.length ?? selectedMplOrders.length} MPL küldemény lezárva.`);
1457
1579
  await load();
1458
1580
  } catch (error) {
1459
- toast.error(
1460
- error instanceof Error ? error.message : "Az új PDF-verzió mentése nem sikerült."
1461
- );
1581
+ toast.error(error instanceof Error ? error.message : "Az MPL jegyzékzárás nem sikerült.");
1462
1582
  } finally {
1463
- setBusy(null);
1583
+ setLoading(null);
1464
1584
  }
1465
1585
  };
1466
- return /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
1586
+ const createAndLabels = async () => {
1587
+ if (await create()) await labels();
1588
+ };
1589
+ return /* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
1467
1590
  /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-4 border-b px-6 py-4", children: [
1468
1591
  /* @__PURE__ */ jsxs("div", { children: [
1469
- /* @__PURE__ */ jsx(Heading, { children: "Jogi dokumentumok" }),
1470
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Feltöltött PDF-ek, verziók és checkout-elfogadások. A Fogyasztó Barát ettől külön, opcionális embed." })
1592
+ /* @__PURE__ */ jsx(Heading, { children: "Szállítás" }),
1593
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "FOXPOST, GLS, Packeta, DPD és MPL tömeges csomag- és címkekezelés." })
1471
1594
  ] }),
1472
- /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
1473
- /* @__PURE__ */ jsx("a", { href: `${adminBase$8}/settings/integrations`, children: /* @__PURE__ */ jsx(Button, { variant: "secondary", children: "Fogyasztó Barát embed" }) }),
1474
- /* @__PURE__ */ jsx(
1475
- Button,
1476
- {
1477
- variant: "secondary",
1478
- isLoading: loading,
1479
- onClick: () => void load(),
1480
- children: "Frissítés"
1481
- }
1482
- )
1595
+ /* @__PURE__ */ jsxs(Text, { children: [
1596
+ selected.length,
1597
+ " kijelölve"
1483
1598
  ] })
1484
1599
  ] }),
1485
- loadError ? /* @__PURE__ */ jsxs("div", { className: "m-6 rounded-lg border border-ui-border-error p-4", children: [
1486
- /* @__PURE__ */ jsx(Text, { className: "font-medium text-ui-fg-error", children: "A jogi modul nem tölthető be." }),
1487
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: loadError })
1488
- ] }) : null,
1489
- /* @__PURE__ */ jsxs("div", { className: "border-b px-6 py-4", children: [
1490
- /* @__PURE__ */ jsx(Heading, { level: "h2", children: "Új PDF dokumentum" }),
1491
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Mindegy, honnan származik a PDF: a Core ugyanúgy verziózza és SHA-256 hash-sel rögzíti. Dokumentumonként külön állítható, hogy checkoutnál kötelező-e elfogadni." })
1492
- ] }),
1493
- /* @__PURE__ */ jsxs("div", { className: "grid gap-4 border-b px-6 py-5 md:grid-cols-2", children: [
1494
- /* @__PURE__ */ jsx(Field$4, { label: "Dokumentum neve", children: /* @__PURE__ */ jsx(
1495
- Input,
1600
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3 border-b px-6 py-4", children: [
1601
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
1602
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "FOXPOST csomagméret" }),
1603
+ /* @__PURE__ */ jsxs(Select, { value: packageSize, onValueChange: setPackageSize, children: [
1604
+ /* @__PURE__ */ jsx(Select.Trigger, { className: "w-36", children: /* @__PURE__ */ jsx(Select.Value, { placeholder: "Méret" }) }),
1605
+ /* @__PURE__ */ jsx(Select.Content, { children: ["XS", "S", "M", "L", "XL"].map((item) => /* @__PURE__ */ jsx(Select.Item, { value: item, children: item }, item)) })
1606
+ ] })
1607
+ ] }),
1608
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
1609
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Címkeméret" }),
1610
+ /* @__PURE__ */ jsxs(Select, { value: format, onValueChange: setSavedFormat, children: [
1611
+ /* @__PURE__ */ jsx(Select.Trigger, { className: "w-32", children: /* @__PURE__ */ jsx(Select.Value, { placeholder: "Címkeméret" }) }),
1612
+ /* @__PURE__ */ jsx(Select.Content, { children: ["A6", "A7", "85X85"].map((item) => /* @__PURE__ */ jsx(Select.Item, { value: item, children: item === "85X85" ? "85×85" : item }, item)) })
1613
+ ] })
1614
+ ] }),
1615
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
1616
+ /* @__PURE__ */ jsx(Switch, { checked: directPrint, onCheckedChange: setSavedPrint }),
1617
+ /* @__PURE__ */ jsx(Text, { children: "Közvetlen nyomtatás" })
1618
+ ] }),
1619
+ /* @__PURE__ */ jsx(
1620
+ Button,
1496
1621
  {
1497
- value: title,
1498
- onChange: (event) => setTitle(event.target.value),
1499
- placeholder: "Általános Szerződési Feltételek"
1622
+ isLoading: loading === "create",
1623
+ disabled: Boolean(loading),
1624
+ onClick: () => void create(),
1625
+ children: "Csomagok létrehozása"
1500
1626
  }
1501
- ) }),
1502
- /* @__PURE__ */ jsx(Field$4, { label: "Kulcs", children: /* @__PURE__ */ jsx(
1503
- Input,
1627
+ ),
1628
+ /* @__PURE__ */ jsx(
1629
+ Button,
1504
1630
  {
1505
- value: key,
1506
- onChange: (event) => setKey(event.target.value.toLowerCase()),
1507
- placeholder: "terms"
1631
+ variant: "secondary",
1632
+ isLoading: loading === "labels",
1633
+ disabled: Boolean(loading),
1634
+ onClick: () => void labels(false),
1635
+ children: "Közös PDF"
1508
1636
  }
1509
- ) }),
1510
- /* @__PURE__ */ jsx(Field$4, { label: "Típus", children: /* @__PURE__ */ jsxs(
1511
- "select",
1637
+ ),
1638
+ /* @__PURE__ */ jsxs(
1639
+ Button,
1512
1640
  {
1513
- className: "h-8 rounded-md border bg-ui-bg-field px-2 text-sm",
1514
- value: kind,
1515
- onChange: (event) => setKind(event.target.value),
1641
+ variant: "secondary",
1642
+ disabled: Boolean(loading),
1643
+ onClick: () => void createAndLabels(),
1516
1644
  children: [
1517
- /* @__PURE__ */ jsx("option", { value: "terms", children: "ÁSZF" }),
1518
- /* @__PURE__ */ jsx("option", { value: "privacy", children: "Adatkezelési tájékoztató" }),
1519
- /* @__PURE__ */ jsx("option", { value: "withdrawal", children: "Elállási nyilatkozat" }),
1520
- /* @__PURE__ */ jsx("option", { value: "custom", children: "Egyedi nyilatkozat" })
1645
+ "Létrehozás + ",
1646
+ directPrint ? "nyomtatás" : "PDF"
1521
1647
  ]
1522
1648
  }
1523
- ) }),
1524
- /* @__PURE__ */ jsxs(Field$4, { label: "PDF fájl (max. 5 MB)", children: [
1525
- /* @__PURE__ */ jsx(
1526
- "input",
1527
- {
1528
- type: "file",
1529
- accept: "application/pdf,.pdf",
1530
- onChange: (event) => {
1531
- const file = event.target.files?.[0];
1532
- if (!file) return;
1533
- setFileName(file.name);
1534
- void fileToBase64(file).then(setFileBase64).catch((error) => {
1535
- toast.error(
1536
- error instanceof Error ? error.message : "A PDF nem olvasható."
1537
- );
1538
- });
1539
- }
1540
- }
1541
- ),
1542
- fileName ? /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: fileName }) : null
1543
- ] }),
1544
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-6", children: [
1545
- /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
1546
- /* @__PURE__ */ jsx(Switch, { checked: enabled, onCheckedChange: setEnabled }),
1547
- /* @__PURE__ */ jsx(Text, { children: "Aktív" })
1548
- ] }),
1549
- /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
1550
- /* @__PURE__ */ jsx(Switch, { checked: required, onCheckedChange: setRequired }),
1551
- /* @__PURE__ */ jsx(Text, { children: "Checkoutnál kötelező elfogadni" })
1552
- ] })
1553
- ] }),
1554
- /* @__PURE__ */ jsx("div", { className: "flex items-end justify-end", children: /* @__PURE__ */ jsx(
1649
+ ),
1650
+ /* @__PURE__ */ jsx(
1555
1651
  Button,
1556
1652
  {
1557
- isLoading: busy === "create",
1558
- disabled: Boolean(busy),
1559
- onClick: () => void createDocument(),
1560
- children: "Dokumentum hozzáadása"
1653
+ variant: "secondary",
1654
+ isLoading: loading === "mpl-close",
1655
+ disabled: Boolean(loading) || !selectedMplOrders.length,
1656
+ onClick: () => void closeMpl(),
1657
+ children: "MPL jegyzék zárása"
1561
1658
  }
1562
- ) })
1659
+ )
1563
1660
  ] }),
1564
- /* @__PURE__ */ jsxs("div", { className: "overflow-x-auto border-b", children: [
1661
+ /* @__PURE__ */ jsxs("div", { className: "overflow-x-auto", children: [
1565
1662
  /* @__PURE__ */ jsxs("table", { className: "w-full text-left text-sm", children: [
1566
1663
  /* @__PURE__ */ jsx("thead", { className: "border-b bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
1567
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Dokumentum" }),
1568
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Aktív" }),
1569
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Elfogadás" }),
1570
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Aktuális PDF" }),
1571
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Műveletek" })
1572
- ] }) }),
1573
- /* @__PURE__ */ jsx("tbody", { children: documents.map((document2) => /* @__PURE__ */ jsxs("tr", { className: "border-b align-top", children: [
1574
- /* @__PURE__ */ jsxs("td", { className: "p-4", children: [
1575
- /* @__PURE__ */ jsx("strong", { children: document2.title }),
1576
- /* @__PURE__ */ jsxs("div", { className: "text-ui-fg-subtle", children: [
1577
- /* @__PURE__ */ jsx("code", { children: document2.key }),
1578
- " · ",
1579
- kindLabel(document2.kind)
1580
- ] })
1581
- ] }),
1582
- /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx(
1583
- Switch,
1664
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: /* @__PURE__ */ jsx(
1665
+ Checkbox,
1584
1666
  {
1585
- checked: document2.enabled,
1586
- disabled: Boolean(busy),
1587
- onCheckedChange: (value) => void updateDocument(document2, { enabled: value })
1667
+ checked: orders.length > 0 && selected.length === orders.length,
1668
+ onCheckedChange: () => setSelected(
1669
+ selected.length === orders.length ? [] : orders.map((order) => order.id)
1670
+ )
1588
1671
  }
1589
1672
  ) }),
1590
- /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1591
- /* @__PURE__ */ jsx(
1592
- Switch,
1593
- {
1594
- checked: document2.requiredAtCheckout,
1595
- disabled: !document2.currentVersion || Boolean(busy),
1596
- onCheckedChange: (value) => void updateDocument(document2, {
1597
- requiredAtCheckout: value
1598
- })
1599
- }
1600
- ),
1601
- /* @__PURE__ */ jsx("span", { children: document2.requiredAtCheckout ? "Kötelező" : "Nem kötelező" })
1602
- ] }) }),
1603
- /* @__PURE__ */ jsx("td", { className: "p-4", children: document2.currentVersion ? /* @__PURE__ */ jsxs(Fragment, { children: [
1604
- /* @__PURE__ */ jsx("code", { title: document2.currentVersion.sha256, children: shortHash(document2.currentVersion.sha256) }),
1605
- /* @__PURE__ */ jsxs("div", { className: "text-ui-fg-subtle", children: [
1606
- formatDate$4(document2.currentVersion.createdAt),
1607
- " ·",
1608
- " ",
1609
- formatBytes(document2.currentVersion.contentLength)
1610
- ] })
1611
- ] }) : /* @__PURE__ */ jsx("span", { className: "text-ui-fg-error", children: "Nincs PDF-verzió" }) }),
1612
- /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsxs("div", { className: "flex min-w-52 flex-wrap gap-2", children: [
1613
- document2.currentVersion ? /* @__PURE__ */ jsx(
1614
- "a",
1673
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Rendelés" }),
1674
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Szolgáltató" }),
1675
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Csomagazonosító" }),
1676
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Státusz" }),
1677
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Utolsó művelet" })
1678
+ ] }) }),
1679
+ /* @__PURE__ */ jsx("tbody", { children: orders.map((order) => {
1680
+ const shipment = order.metadata?.[order.carrier] || {};
1681
+ const last = order.operations?.at(-1);
1682
+ return /* @__PURE__ */ jsxs("tr", { className: "border-b", children: [
1683
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx(
1684
+ Checkbox,
1615
1685
  {
1616
- href: apiUrl$b(
1617
- `/admin/legal/documents/${document2.id}/versions/${document2.currentVersion.id}/pdf`
1618
- ),
1619
- target: "_blank",
1620
- rel: "noreferrer",
1621
- children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "PDF" })
1686
+ checked: selectedSet.has(order.id),
1687
+ onCheckedChange: () => toggle(order.id)
1622
1688
  }
1623
- ) : null,
1624
- /* @__PURE__ */ jsxs("label", { className: "inline-flex cursor-pointer items-center rounded-md border px-2.5 py-1 text-xs font-medium", children: [
1625
- "Új PDF-verzió",
1626
- /* @__PURE__ */ jsx(
1627
- "input",
1628
- {
1629
- className: "hidden",
1630
- type: "file",
1631
- accept: "application/pdf,.pdf",
1632
- disabled: Boolean(busy),
1633
- onChange: (event) => {
1634
- const file = event.target.files?.[0];
1635
- if (file) void uploadNewVersion(document2, file);
1636
- event.currentTarget.value = "";
1637
- }
1638
- }
1639
- )
1640
- ] })
1641
- ] }) })
1642
- ] }, document2.id)) })
1689
+ ) }),
1690
+ /* @__PURE__ */ jsxs("td", { className: "p-4", children: [
1691
+ /* @__PURE__ */ jsxs("a", { className: "text-blue-600", href: `${adminBase$7}/orders/${order.id}`, children: [
1692
+ "#",
1693
+ order.display_id ?? order.id
1694
+ ] }),
1695
+ /* @__PURE__ */ jsx("div", { className: "text-ui-fg-subtle", children: order.email || "—" })
1696
+ ] }),
1697
+ /* @__PURE__ */ jsx("td", { className: "p-4 font-medium", children: carrierName(order.carrier) }),
1698
+ /* @__PURE__ */ jsxs("td", { className: "p-4", children: [
1699
+ String(
1700
+ shipment.trackingNumber || shipment.parcelNumber || shipment.packetId || shipment.packageId || shipment.shipmentId || "—"
1701
+ ),
1702
+ order.carrier === "mpl" && shipment.closedAt ? /* @__PURE__ */ jsx("div", { className: "text-ui-fg-subtle", children: "jegyzék lezárva" }) : null
1703
+ ] }),
1704
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: String(shipment.status || "—") }),
1705
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: last ? /* @__PURE__ */ jsx("span", { className: last.status === "failed" ? "text-red-600" : "text-green-700", children: last.message }) : "—" })
1706
+ ] }, order.id);
1707
+ }) })
1643
1708
  ] }),
1644
- !loading && !documents.length ? /* @__PURE__ */ jsx("div", { className: "p-8 text-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Még nincs feltöltött jogi dokumentum." }) }) : null
1645
- ] }),
1646
- /* @__PURE__ */ jsxs("div", { className: "border-b px-6 py-4", children: [
1647
- /* @__PURE__ */ jsx(Heading, { level: "h2", children: "Legutóbbi elfogadások" }),
1648
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "A consent mindig a konkrét PDF-verzióhoz, kosárhoz és később a rendeléshez kapcsolódik." })
1649
- ] }),
1650
- /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-left text-sm", children: [
1651
- /* @__PURE__ */ jsx("thead", { className: "border-b bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
1652
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Elfogadva" }),
1653
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Dokumentum" }),
1654
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Rendelés" }),
1655
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Cart" }),
1656
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Verzió" })
1657
- ] }) }),
1658
- /* @__PURE__ */ jsx("tbody", { children: consents.map((consent) => /* @__PURE__ */ jsxs("tr", { className: "border-b", children: [
1659
- /* @__PURE__ */ jsx("td", { className: "p-4", children: formatDate$4(consent.acceptedAt) }),
1660
- /* @__PURE__ */ jsx("td", { className: "p-4", children: consent.documentTitle }),
1661
- /* @__PURE__ */ jsx("td", { className: "p-4", children: consent.orderId ? /* @__PURE__ */ jsx(
1662
- "a",
1663
- {
1664
- className: "text-ui-fg-interactive",
1665
- href: `${adminBase$8}/orders/${consent.orderId}`,
1666
- children: consent.orderId
1667
- }
1668
- ) : "Még nincs rendelés" }),
1669
- /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx("code", { children: consent.cartId }) }),
1670
- /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx("code", { children: consent.documentVersionId }) })
1671
- ] }, consent.id)) })
1672
- ] }) })
1673
- ] }) });
1674
- };
1675
- function Field$4({
1676
- label,
1677
- children
1678
- }) {
1679
- return /* @__PURE__ */ jsxs("label", { className: "flex min-w-0 flex-col gap-1.5", children: [
1680
- /* @__PURE__ */ jsx(Text, { className: "font-medium", children: label }),
1681
- children
1709
+ ordersLoading ? /* @__PURE__ */ jsx("div", { className: "p-8 text-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Szállítási rendelések betöltése…" }) }) : null,
1710
+ !ordersLoading && loadError ? /* @__PURE__ */ jsxs("div", { className: "m-6 flex flex-wrap items-center justify-between gap-4 rounded-lg border border-ui-border-error bg-ui-bg-base p-4", children: [
1711
+ /* @__PURE__ */ jsxs("div", { children: [
1712
+ /* @__PURE__ */ jsx(Text, { className: "font-medium text-ui-fg-error", children: "A szállítási lista nem tölthető be" }),
1713
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: loadError })
1714
+ ] }),
1715
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => void load(), children: "Újrapróbálás" })
1716
+ ] }) : null,
1717
+ !ordersLoading && !loadError && !orders.length ? /* @__PURE__ */ jsx("div", { className: "p-8 text-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Nincs támogatott Core szállítású rendelés." }) }) : null
1718
+ ] })
1682
1719
  ] });
1720
+ };
1721
+ function carrierName(carrier) {
1722
+ if (carrier === "foxpost") return "FOXPOST";
1723
+ if (carrier === "gls") return "GLS";
1724
+ if (carrier === "packeta") return "Packeta";
1725
+ if (carrier === "dpd") return "DPD";
1726
+ return "MPL";
1683
1727
  }
1684
- function fileToBase64(file) {
1685
- if (file.size > 5 * 1024 * 1024) {
1686
- return Promise.reject(new Error("A PDF legfeljebb 5 MB lehet."));
1728
+ function openPdf(blob, filename, print) {
1729
+ const url = URL.createObjectURL(blob);
1730
+ if (print) {
1731
+ const frame = document.createElement("iframe");
1732
+ frame.style.display = "none";
1733
+ frame.src = url;
1734
+ frame.onload = () => {
1735
+ frame.contentWindow?.print();
1736
+ setTimeout(() => {
1737
+ frame.remove();
1738
+ URL.revokeObjectURL(url);
1739
+ }, 6e4);
1740
+ };
1741
+ document.body.appendChild(frame);
1742
+ } else {
1743
+ const link = document.createElement("a");
1744
+ link.href = url;
1745
+ link.download = filename;
1746
+ link.click();
1747
+ setTimeout(() => URL.revokeObjectURL(url), 1e4);
1687
1748
  }
1688
- return new Promise((resolve, reject) => {
1689
- const reader = new FileReader();
1690
- reader.onload = () => resolve(String(reader.result || ""));
1691
- reader.onerror = () => reject(new Error("A PDF fájl nem olvasható."));
1692
- reader.readAsDataURL(file);
1693
- });
1694
- }
1695
- function kindLabel(value) {
1696
- return value === "terms" ? "ÁSZF" : value === "privacy" ? "Adatkezelés" : value === "withdrawal" ? "Elállás" : "Egyedi";
1697
- }
1698
- function shortHash(value) {
1699
- return value.length > 20 ? `${value.slice(0, 12)}…${value.slice(-8)}` : value;
1700
1749
  }
1701
- function formatBytes(value) {
1702
- if (!Number.isFinite(value)) return "—";
1703
- if (value < 1024) return `${value} B`;
1704
- if (value < 1024 * 1024) return `${Math.round(value / 1024)} kB`;
1705
- return `${(value / 1024 / 1024).toFixed(2)} MB`;
1706
- }
1707
- function formatDate$4(value) {
1708
- if (!value) return "—";
1709
- const date = new Date(value);
1710
- if (Number.isNaN(date.getTime())) return "—";
1711
- return new Intl.DateTimeFormat("hu-HU", {
1712
- dateStyle: "short",
1713
- timeStyle: "short"
1714
- }).format(date);
1715
- }
1716
- const config$b = defineRouteConfig({
1717
- label: "Jogi dokumentumok",
1718
- icon: Newspaper,
1719
- rank: 40
1750
+ const config$a = defineRouteConfig({
1751
+ label: "Szállítás",
1752
+ icon: TruckFast,
1753
+ rank: 35
1720
1754
  });
1755
+ const adminBase$6 = (__BASE__ || "/app").replace(/\/+$/, "");
1756
+ const links = [
1757
+ { label: "Production readiness", description: "Élesítési blokkolók: infrastruktúra, commerce, security, legal, e-mail és SEO.", href: `${adminBase$6}/system-monitoring/readiness` },
1758
+ { label: "Integrációs műveletek", description: "Retry, reconciliation és külső API műveletek kezelése.", href: `${adminBase$6}/system-monitoring/operations` },
1759
+ { label: "Integrációk állapota", description: "Provider állapotok, konfigurációk és hibák áttekintése.", href: `${adminBase$6}/system-monitoring/health` },
1760
+ { label: "Audit napló", description: "Core és integrációs admin események visszakeresése.", href: `${adminBase$6}/system-monitoring/audit` }
1761
+ ];
1762
+ const SystemMonitoringPage = () => /* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
1763
+ /* @__PURE__ */ jsxs("div", { className: "border-b px-6 py-5", children: [
1764
+ /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Rendszerfelügyelet" }),
1765
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 text-ui-fg-subtle", children: "Technikai állapotok, élesítési feltételek, külső műveletek és audit események." })
1766
+ ] }),
1767
+ /* @__PURE__ */ jsx("div", { className: "grid gap-4 p-6 md:grid-cols-2 xl:grid-cols-4", children: links.map((item) => /* @__PURE__ */ jsxs("a", { href: item.href, className: "rounded-lg border p-5 hover:bg-ui-bg-subtle", children: [
1768
+ /* @__PURE__ */ jsx(Heading, { level: "h2", children: item.label }),
1769
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 text-ui-fg-subtle", children: item.description })
1770
+ ] }, item.href)) })
1771
+ ] });
1772
+ const config$9 = defineRouteConfig({ label: "Rendszerfelügyelet" });
1721
1773
  const backendUrl$a = (__BACKEND_URL__ || "").replace(/\/+$/, "");
1722
- const adminBase$7 = (__BASE__ || "/app").replace(/\/+$/, "");
1774
+ const adminBase$5 = (__BASE__ || "/app").replace(/\/+$/, "");
1723
1775
  function apiUrl$a(path) {
1724
1776
  return `${backendUrl$a}${path.startsWith("/") ? path : `/${path}`}`;
1725
1777
  }
@@ -1882,7 +1934,7 @@ const BillingPage = () => {
1882
1934
  /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-4 border-b px-6 py-4", children: [
1883
1935
  /* @__PURE__ */ jsxs("div", { children: [
1884
1936
  /* @__PURE__ */ jsx(Heading, { children: "Számlázás" }),
1885
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Billingo számlák, sztornók és teljes jóváírások kezelése a Medusa rendeléseiből." }),
1937
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Billingo számlák, sztornók és teljes jóváírások kezelése a HSZRDM Commerce rendeléseiből." }),
1886
1938
  configuration?.autoInvoice ? /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
1887
1939
  "Az automatikus számlázás aktív",
1888
1940
  configuration.autoSend ? ", automatikus e-mail küldéssel" : "",
@@ -1987,7 +2039,7 @@ const BillingPage = () => {
1987
2039
  "a",
1988
2040
  {
1989
2041
  className: "text-ui-fg-interactive",
1990
- href: `${adminBase$7}/orders/${order.id}`,
2042
+ href: `${adminBase$5}/orders/${order.id}`,
1991
2043
  children: [
1992
2044
  "#",
1993
2045
  order.display_id ?? order.id
@@ -2105,385 +2157,415 @@ function formatMoney(value, currency) {
2105
2157
  maximumFractionDigits: currency?.toUpperCase() === "HUF" ? 0 : 2
2106
2158
  }).format(value);
2107
2159
  }
2108
- const config$a = defineRouteConfig({
2160
+ const config$8 = defineRouteConfig({
2109
2161
  label: "Számlázás",
2110
2162
  icon: Newspaper,
2111
2163
  rank: 36
2112
2164
  });
2113
- const adminBase$6 = (__BASE__ || "/app").replace(/\/+$/, "");
2114
- const links$1 = [
2115
- {
2116
- label: "Analitika",
2117
- description: "Látogatók, vásárlási tölcsér, bevétel, vásárlók, top termékek és checkout állapot egy közös dashboardon.",
2118
- href: `${adminBase$6}/analytics`
2119
- },
2120
- {
2121
- label: "SEO",
2122
- description: "Termék-, kategória- és oldal SEO title, description, canonical, robots és Open Graph kezelése.",
2123
- href: `${adminBase$6}/marketing/seo`
2124
- },
2125
- {
2126
- label: "SEO átirányítások",
2127
- description: "Régi URL-ek 301/308 átirányítása, be/ki kapcsolás és query paraméter kezelés.",
2128
- href: `${adminBase$6}/marketing/seo/redirects`
2129
- },
2130
- {
2131
- label: "Google Merchant",
2132
- description: "Google Merchant Center termékfeed előnézet, diagnosztika és publikus feed URL.",
2133
- href: `${adminBase$6}/marketing/google-merchant`
2134
- },
2135
- {
2136
- label: "Árukereső",
2137
- description: "Árukereső.hu XML feed előnézet, diagnosztika és publikus feed URL.",
2138
- href: `${adminBase$6}/marketing/arukereso`
2139
- }
2140
- ];
2141
- const MarketingPage = () => /* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
2142
- /* @__PURE__ */ jsxs("div", { className: "border-b px-6 py-5", children: [
2143
- /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Marketing" }),
2144
- /* @__PURE__ */ jsx(Text, { className: "mt-1 text-ui-fg-subtle", children: "Analitika, SEO, termékfeedek és külső marketing/értékesítési csatornák kezelése. Az integrációk technikai alapbeállításai a Settings → Integrációk alatt találhatók." })
2145
- ] }),
2146
- /* @__PURE__ */ jsx("div", { className: "grid gap-4 p-6 md:grid-cols-2 xl:grid-cols-3", children: links$1.map((item) => /* @__PURE__ */ jsxs(
2147
- "a",
2148
- {
2149
- href: item.href,
2150
- className: "rounded-lg border p-5 transition-colors hover:bg-ui-bg-subtle",
2151
- children: [
2152
- /* @__PURE__ */ jsx(Heading, { level: "h2", children: item.label }),
2153
- /* @__PURE__ */ jsx(Text, { className: "mt-1 text-ui-fg-subtle", children: item.description })
2154
- ]
2155
- },
2156
- item.href
2157
- )) })
2158
- ] });
2159
- const config$9 = defineRouteConfig({ label: "Marketing" });
2160
- const LABEL_FORMAT_STORAGE_KEY = "core.shipping.labelFormat";
2161
- const DIRECT_PRINT_STORAGE_KEY = "core.shipping.directPrint";
2162
2165
  const backendUrl$9 = (__BACKEND_URL__ || "").replace(/\/+$/, "");
2163
- const adminBase$5 = (__BASE__ || "/app").replace(/\/+$/, "");
2164
- function apiUrl$9(path) {
2165
- return `${backendUrl$9}${path.startsWith("/") ? path : `/${path}`}`;
2166
- }
2167
- const ShippingPage = () => {
2168
- const [orders, setOrders] = useState([]);
2169
- const [selected, setSelected] = useState([]);
2170
- const [format, setFormat] = useState("A6");
2171
- const [packageSize, setPackageSize] = useState("M");
2172
- const [directPrint, setDirectPrint] = useState(false);
2173
- const [loading, setLoading] = useState(null);
2174
- const [ordersLoading, setOrdersLoading] = useState(true);
2166
+ const adminBase$4 = (__BASE__ || "/app").replace(/\/+$/, "");
2167
+ const apiUrl$9 = (path) => `${backendUrl$9}${path.startsWith("/") ? path : `/${path}`}`;
2168
+ const LegalPage = () => {
2169
+ const [documents, setDocuments] = useState([]);
2170
+ const [consents, setConsents] = useState([]);
2171
+ const [loading, setLoading] = useState(true);
2172
+ const [busy, setBusy] = useState(null);
2175
2173
  const [loadError, setLoadError] = useState(null);
2176
- const selectedSet = useMemo(() => new Set(selected), [selected]);
2177
- const selectedMplOrders = useMemo(
2178
- () => orders.filter((order) => selectedSet.has(order.id) && order.carrier === "mpl"),
2179
- [orders, selectedSet]
2180
- );
2174
+ const [title, setTitle] = useState("");
2175
+ const [key, setKey] = useState("");
2176
+ const [kind, setKind] = useState("custom");
2177
+ const [fileName, setFileName] = useState("");
2178
+ const [fileBase64, setFileBase64] = useState("");
2179
+ const [enabled, setEnabled] = useState(true);
2180
+ const [required, setRequired] = useState(false);
2181
2181
  const load = useCallback(async () => {
2182
- setOrdersLoading(true);
2182
+ setLoading(true);
2183
2183
  setLoadError(null);
2184
2184
  try {
2185
- const response = await fetch(apiUrl$9("/admin/shipping/orders"), {
2186
- credentials: "include"
2187
- });
2188
- const data = await response.json().catch(() => ({}));
2189
- if (!response.ok) {
2190
- throw new Error(data.message || "A szállítási rendelések betöltése nem sikerült.");
2185
+ const [documentsResponse, consentsResponse] = await Promise.all([
2186
+ fetch(apiUrl$9("/admin/legal/documents"), { credentials: "include" }),
2187
+ fetch(apiUrl$9("/admin/legal/consents"), { credentials: "include" })
2188
+ ]);
2189
+ const documentsPayload = await documentsResponse.json().catch(() => ({}));
2190
+ const consentsPayload = await consentsResponse.json().catch(() => ({}));
2191
+ if (!documentsResponse.ok) {
2192
+ throw new Error(
2193
+ documentsPayload.message || "A jogi dokumentumok nem tölthetők be."
2194
+ );
2191
2195
  }
2192
- const nextOrders = data.orders || [];
2193
- setOrders(nextOrders);
2194
- setSelected((current) => current.filter((id) => nextOrders.some((order) => order.id === id)));
2196
+ if (!consentsResponse.ok) {
2197
+ throw new Error(
2198
+ consentsPayload.message || "Az elfogadások nem tölthetők be."
2199
+ );
2200
+ }
2201
+ setDocuments(documentsPayload.documents || []);
2202
+ setConsents(consentsPayload.consents || []);
2195
2203
  } catch (error) {
2196
- const message = error instanceof Error ? error.message : "A szállítási rendelések betöltése nem sikerült.";
2197
- setOrders([]);
2198
- setLoadError(message);
2204
+ setLoadError(
2205
+ error instanceof Error ? error.message : "A jogi dokumentumok nem tölthetők be."
2206
+ );
2199
2207
  } finally {
2200
- setOrdersLoading(false);
2208
+ setLoading(false);
2201
2209
  }
2202
2210
  }, []);
2203
2211
  useEffect(() => {
2204
- setFormat(localStorage.getItem(LABEL_FORMAT_STORAGE_KEY) || "A6");
2205
- setDirectPrint(localStorage.getItem(DIRECT_PRINT_STORAGE_KEY) === "true");
2206
2212
  void load();
2207
2213
  }, [load]);
2208
- const setSavedFormat = (value) => {
2209
- setFormat(value);
2210
- localStorage.setItem(LABEL_FORMAT_STORAGE_KEY, value);
2211
- };
2212
- const setSavedPrint = (value) => {
2213
- setDirectPrint(value);
2214
- localStorage.setItem(DIRECT_PRINT_STORAGE_KEY, String(value));
2215
- };
2216
- const toggle = (id) => {
2217
- setSelected((current) => current.includes(id) ? current.filter((item) => item !== id) : [...current, id]);
2218
- };
2219
- const create = async () => {
2220
- if (!selected.length) {
2221
- toast.error("Jelölj ki legalább egy rendelést.");
2222
- return false;
2223
- }
2224
- setLoading("create");
2214
+ const createDocument = async () => {
2215
+ setBusy("create");
2225
2216
  try {
2226
- const response = await fetch(apiUrl$9("/admin/shipping/bulk/create"), {
2217
+ if (!title.trim() || !key.trim()) {
2218
+ throw new Error("A név és a kulcs kötelező.");
2219
+ }
2220
+ if (!fileBase64) throw new Error("Válassz PDF fájlt.");
2221
+ const response = await fetch(apiUrl$9("/admin/legal/documents"), {
2227
2222
  method: "POST",
2228
2223
  credentials: "include",
2229
2224
  headers: { "Content-Type": "application/json" },
2230
- body: JSON.stringify({ orderIds: selected, packageSize })
2231
- });
2232
- const data = await response.json().catch(() => ({}));
2233
- if (!response.ok && response.status !== 207) {
2234
- throw new Error(data.message || "A tömeges csomagkészítés nem sikerült.");
2235
- }
2236
- const failed = data.results?.filter((item) => !item.ok) || [];
2237
- if (failed.length) toast.error(`${failed.length} csomag nem készült el.`);
2238
- else toast.success(`${selected.length} csomag elkészült.`);
2225
+ body: JSON.stringify({
2226
+ title,
2227
+ key,
2228
+ kind,
2229
+ fileBase64,
2230
+ fileName,
2231
+ enabled,
2232
+ requiredAtCheckout: required
2233
+ })
2234
+ });
2235
+ const payload = await response.json().catch(() => ({}));
2236
+ if (!response.ok) {
2237
+ throw new Error(
2238
+ payload.message || "A dokumentum létrehozása nem sikerült."
2239
+ );
2240
+ }
2241
+ toast.success("Jogi PDF létrehozva és verziózva.");
2242
+ setTitle("");
2243
+ setKey("");
2244
+ setKind("custom");
2245
+ setFileName("");
2246
+ setFileBase64("");
2247
+ setEnabled(true);
2248
+ setRequired(false);
2239
2249
  await load();
2240
- return failed.length === 0;
2241
2250
  } catch (error) {
2242
- toast.error(error instanceof Error ? error.message : "A tömeges csomagkészítés nem sikerült.");
2243
- return false;
2251
+ toast.error(
2252
+ error instanceof Error ? error.message : "A dokumentum létrehozása nem sikerült."
2253
+ );
2244
2254
  } finally {
2245
- setLoading(null);
2255
+ setBusy(null);
2246
2256
  }
2247
2257
  };
2248
- const labels = async (print = directPrint) => {
2249
- if (!selected.length) {
2250
- toast.error("Jelölj ki legalább egy rendelést.");
2251
- return;
2252
- }
2253
- setLoading("labels");
2258
+ const updateDocument = async (document2, changes) => {
2259
+ setBusy(`update:${document2.id}`);
2254
2260
  try {
2255
- const response = await fetch(apiUrl$9("/admin/shipping/bulk/labels"), {
2256
- method: "POST",
2257
- credentials: "include",
2258
- headers: { "Content-Type": "application/json" },
2259
- body: JSON.stringify({ orderIds: selected, format })
2260
- });
2261
+ const response = await fetch(
2262
+ apiUrl$9(`/admin/legal/documents/${document2.id}`),
2263
+ {
2264
+ method: "POST",
2265
+ credentials: "include",
2266
+ headers: { "Content-Type": "application/json" },
2267
+ body: JSON.stringify(changes)
2268
+ }
2269
+ );
2270
+ const payload = await response.json().catch(() => ({}));
2261
2271
  if (!response.ok) {
2262
- const data = await response.json().catch(() => ({}));
2263
- throw new Error(data.message || "A közös PDF nem készíthető el.");
2272
+ throw new Error(payload.message || "A dokumentum mentése nem sikerült.");
2264
2273
  }
2265
- openPdf(await response.blob(), `shipping-labels-${format}.pdf`, print);
2274
+ await load();
2266
2275
  } catch (error) {
2267
- toast.error(error instanceof Error ? error.message : "A közös PDF nem készíthető el.");
2276
+ toast.error(
2277
+ error instanceof Error ? error.message : "A dokumentum mentése nem sikerült."
2278
+ );
2268
2279
  } finally {
2269
- setLoading(null);
2280
+ setBusy(null);
2270
2281
  }
2271
2282
  };
2272
- const closeMpl = async () => {
2273
- if (!selectedMplOrders.length) {
2274
- toast.error("Jelölj ki legalább egy MPL rendelést.");
2275
- return;
2276
- }
2277
- setLoading("mpl-close");
2283
+ const uploadNewVersion = async (document2, file) => {
2284
+ setBusy(`version:${document2.id}`);
2278
2285
  try {
2279
- const response = await fetch(apiUrl$9("/admin/shipping/mpl/close"), {
2280
- method: "POST",
2281
- credentials: "include",
2282
- headers: { "Content-Type": "application/json" },
2283
- body: JSON.stringify({
2284
- orderIds: selectedMplOrders.map((order) => order.id),
2285
- checkList: true
2286
- })
2287
- });
2288
- const data = await response.json().catch(() => ({}));
2286
+ const response = await fetch(
2287
+ apiUrl$9(`/admin/legal/documents/${document2.id}/versions`),
2288
+ {
2289
+ method: "POST",
2290
+ credentials: "include",
2291
+ headers: { "Content-Type": "application/json" },
2292
+ body: JSON.stringify({
2293
+ fileBase64: await fileToBase64(file),
2294
+ fileName: file.name
2295
+ })
2296
+ }
2297
+ );
2298
+ const payload = await response.json().catch(() => ({}));
2289
2299
  if (!response.ok) {
2290
- throw new Error(data.message || "Az MPL jegyzékzárás nem sikerült.");
2300
+ throw new Error(payload.message || "Az új PDF-verzió mentése nem sikerült.");
2291
2301
  }
2292
- toast.success(`${data.trackingNumbers?.length ?? selectedMplOrders.length} MPL küldemény lezárva.`);
2302
+ toast.success(
2303
+ payload.created ? "Új PDF-verzió elmentve." : "Ez a PDF-verzió már el volt mentve."
2304
+ );
2293
2305
  await load();
2294
2306
  } catch (error) {
2295
- toast.error(error instanceof Error ? error.message : "Az MPL jegyzékzárás nem sikerült.");
2307
+ toast.error(
2308
+ error instanceof Error ? error.message : "Az új PDF-verzió mentése nem sikerült."
2309
+ );
2296
2310
  } finally {
2297
- setLoading(null);
2311
+ setBusy(null);
2298
2312
  }
2299
2313
  };
2300
- const createAndLabels = async () => {
2301
- if (await create()) await labels();
2302
- };
2303
- return /* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
2314
+ return /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4", children: /* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
2304
2315
  /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-4 border-b px-6 py-4", children: [
2305
2316
  /* @__PURE__ */ jsxs("div", { children: [
2306
- /* @__PURE__ */ jsx(Heading, { children: "Szállítás" }),
2307
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "FOXPOST, GLS, Packeta, DPD és MPL tömeges csomag- és címkekezelés." })
2317
+ /* @__PURE__ */ jsx(Heading, { children: "Jogi dokumentumok" }),
2318
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Feltöltött PDF-ek, verziók és checkout-elfogadások. A Fogyasztó Barát ettől külön, opcionális embed." })
2308
2319
  ] }),
2309
- /* @__PURE__ */ jsxs(Text, { children: [
2310
- selected.length,
2311
- " kijelölve"
2320
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
2321
+ /* @__PURE__ */ jsx("a", { href: `${adminBase$4}/settings/integrations`, children: /* @__PURE__ */ jsx(Button, { variant: "secondary", children: "Fogyasztó Barát embed" }) }),
2322
+ /* @__PURE__ */ jsx(
2323
+ Button,
2324
+ {
2325
+ variant: "secondary",
2326
+ isLoading: loading,
2327
+ onClick: () => void load(),
2328
+ children: "Frissítés"
2329
+ }
2330
+ )
2312
2331
  ] })
2313
2332
  ] }),
2314
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3 border-b px-6 py-4", children: [
2315
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
2316
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "FOXPOST csomagméret" }),
2317
- /* @__PURE__ */ jsxs(Select, { value: packageSize, onValueChange: setPackageSize, children: [
2318
- /* @__PURE__ */ jsx(Select.Trigger, { className: "w-36", children: /* @__PURE__ */ jsx(Select.Value, { placeholder: "Méret" }) }),
2319
- /* @__PURE__ */ jsx(Select.Content, { children: ["XS", "S", "M", "L", "XL"].map((item) => /* @__PURE__ */ jsx(Select.Item, { value: item, children: item }, item)) })
2320
- ] })
2321
- ] }),
2322
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
2323
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Címkeméret" }),
2324
- /* @__PURE__ */ jsxs(Select, { value: format, onValueChange: setSavedFormat, children: [
2325
- /* @__PURE__ */ jsx(Select.Trigger, { className: "w-32", children: /* @__PURE__ */ jsx(Select.Value, { placeholder: "Címkeméret" }) }),
2326
- /* @__PURE__ */ jsx(Select.Content, { children: ["A6", "A7", "85X85"].map((item) => /* @__PURE__ */ jsx(Select.Item, { value: item, children: item === "85X85" ? "85×85" : item }, item)) })
2327
- ] })
2328
- ] }),
2329
- /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
2330
- /* @__PURE__ */ jsx(Switch, { checked: directPrint, onCheckedChange: setSavedPrint }),
2331
- /* @__PURE__ */ jsx(Text, { children: "Közvetlen nyomtatás" })
2332
- ] }),
2333
- /* @__PURE__ */ jsx(
2334
- Button,
2333
+ loadError ? /* @__PURE__ */ jsxs("div", { className: "m-6 rounded-lg border border-ui-border-error p-4", children: [
2334
+ /* @__PURE__ */ jsx(Text, { className: "font-medium text-ui-fg-error", children: "A jogi modul nem tölthető be." }),
2335
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: loadError })
2336
+ ] }) : null,
2337
+ /* @__PURE__ */ jsxs("div", { className: "border-b px-6 py-4", children: [
2338
+ /* @__PURE__ */ jsx(Heading, { level: "h2", children: "Új PDF dokumentum" }),
2339
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Mindegy, honnan származik a PDF: a Core ugyanúgy verziózza és SHA-256 hash-sel rögzíti. Dokumentumonként külön állítható, hogy checkoutnál kötelező-e elfogadni." })
2340
+ ] }),
2341
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-4 border-b px-6 py-5 md:grid-cols-2", children: [
2342
+ /* @__PURE__ */ jsx(Field$4, { label: "Dokumentum neve", children: /* @__PURE__ */ jsx(
2343
+ Input,
2335
2344
  {
2336
- isLoading: loading === "create",
2337
- disabled: Boolean(loading),
2338
- onClick: () => void create(),
2339
- children: "Csomagok létrehozása"
2345
+ value: title,
2346
+ onChange: (event) => setTitle(event.target.value),
2347
+ placeholder: "Általános Szerződési Feltételek"
2340
2348
  }
2341
- ),
2342
- /* @__PURE__ */ jsx(
2343
- Button,
2349
+ ) }),
2350
+ /* @__PURE__ */ jsx(Field$4, { label: "Kulcs", children: /* @__PURE__ */ jsx(
2351
+ Input,
2344
2352
  {
2345
- variant: "secondary",
2346
- isLoading: loading === "labels",
2347
- disabled: Boolean(loading),
2348
- onClick: () => void labels(false),
2349
- children: "Közös PDF"
2353
+ value: key,
2354
+ onChange: (event) => setKey(event.target.value.toLowerCase()),
2355
+ placeholder: "terms"
2350
2356
  }
2351
- ),
2352
- /* @__PURE__ */ jsxs(
2353
- Button,
2357
+ ) }),
2358
+ /* @__PURE__ */ jsx(Field$4, { label: "Típus", children: /* @__PURE__ */ jsxs(
2359
+ "select",
2354
2360
  {
2355
- variant: "secondary",
2356
- disabled: Boolean(loading),
2357
- onClick: () => void createAndLabels(),
2361
+ className: "h-8 rounded-md border bg-ui-bg-field px-2 text-sm",
2362
+ value: kind,
2363
+ onChange: (event) => setKind(event.target.value),
2358
2364
  children: [
2359
- "Létrehozás + ",
2360
- directPrint ? "nyomtatás" : "PDF"
2365
+ /* @__PURE__ */ jsx("option", { value: "terms", children: "ÁSZF" }),
2366
+ /* @__PURE__ */ jsx("option", { value: "privacy", children: "Adatkezelési tájékoztató" }),
2367
+ /* @__PURE__ */ jsx("option", { value: "withdrawal", children: "Elállási nyilatkozat" }),
2368
+ /* @__PURE__ */ jsx("option", { value: "custom", children: "Egyedi nyilatkozat" })
2361
2369
  ]
2362
2370
  }
2363
- ),
2364
- /* @__PURE__ */ jsx(
2371
+ ) }),
2372
+ /* @__PURE__ */ jsxs(Field$4, { label: "PDF fájl (max. 5 MB)", children: [
2373
+ /* @__PURE__ */ jsx(
2374
+ "input",
2375
+ {
2376
+ type: "file",
2377
+ accept: "application/pdf,.pdf",
2378
+ onChange: (event) => {
2379
+ const file = event.target.files?.[0];
2380
+ if (!file) return;
2381
+ setFileName(file.name);
2382
+ void fileToBase64(file).then(setFileBase64).catch((error) => {
2383
+ toast.error(
2384
+ error instanceof Error ? error.message : "A PDF nem olvasható."
2385
+ );
2386
+ });
2387
+ }
2388
+ }
2389
+ ),
2390
+ fileName ? /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: fileName }) : null
2391
+ ] }),
2392
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-6", children: [
2393
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
2394
+ /* @__PURE__ */ jsx(Switch, { checked: enabled, onCheckedChange: setEnabled }),
2395
+ /* @__PURE__ */ jsx(Text, { children: "Aktív" })
2396
+ ] }),
2397
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
2398
+ /* @__PURE__ */ jsx(Switch, { checked: required, onCheckedChange: setRequired }),
2399
+ /* @__PURE__ */ jsx(Text, { children: "Checkoutnál kötelező elfogadni" })
2400
+ ] })
2401
+ ] }),
2402
+ /* @__PURE__ */ jsx("div", { className: "flex items-end justify-end", children: /* @__PURE__ */ jsx(
2365
2403
  Button,
2366
2404
  {
2367
- variant: "secondary",
2368
- isLoading: loading === "mpl-close",
2369
- disabled: Boolean(loading) || !selectedMplOrders.length,
2370
- onClick: () => void closeMpl(),
2371
- children: "MPL jegyzék zárása"
2405
+ isLoading: busy === "create",
2406
+ disabled: Boolean(busy),
2407
+ onClick: () => void createDocument(),
2408
+ children: "Dokumentum hozzáadása"
2372
2409
  }
2373
- )
2410
+ ) })
2374
2411
  ] }),
2375
- /* @__PURE__ */ jsxs("div", { className: "overflow-x-auto", children: [
2412
+ /* @__PURE__ */ jsxs("div", { className: "overflow-x-auto border-b", children: [
2376
2413
  /* @__PURE__ */ jsxs("table", { className: "w-full text-left text-sm", children: [
2377
2414
  /* @__PURE__ */ jsx("thead", { className: "border-b bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
2378
- /* @__PURE__ */ jsx("th", { className: "p-4", children: /* @__PURE__ */ jsx(
2379
- Checkbox,
2415
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Dokumentum" }),
2416
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Aktív" }),
2417
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Elfogadás" }),
2418
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Aktuális PDF" }),
2419
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Műveletek" })
2420
+ ] }) }),
2421
+ /* @__PURE__ */ jsx("tbody", { children: documents.map((document2) => /* @__PURE__ */ jsxs("tr", { className: "border-b align-top", children: [
2422
+ /* @__PURE__ */ jsxs("td", { className: "p-4", children: [
2423
+ /* @__PURE__ */ jsx("strong", { children: document2.title }),
2424
+ /* @__PURE__ */ jsxs("div", { className: "text-ui-fg-subtle", children: [
2425
+ /* @__PURE__ */ jsx("code", { children: document2.key }),
2426
+ " · ",
2427
+ kindLabel(document2.kind)
2428
+ ] })
2429
+ ] }),
2430
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx(
2431
+ Switch,
2380
2432
  {
2381
- checked: orders.length > 0 && selected.length === orders.length,
2382
- onCheckedChange: () => setSelected(
2383
- selected.length === orders.length ? [] : orders.map((order) => order.id)
2384
- )
2433
+ checked: document2.enabled,
2434
+ disabled: Boolean(busy),
2435
+ onCheckedChange: (value) => void updateDocument(document2, { enabled: value })
2385
2436
  }
2386
2437
  ) }),
2387
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Rendelés" }),
2388
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Szolgáltató" }),
2389
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Csomagazonosító" }),
2390
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Státusz" }),
2391
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Utolsó művelet" })
2392
- ] }) }),
2393
- /* @__PURE__ */ jsx("tbody", { children: orders.map((order) => {
2394
- const shipment = order.metadata?.[order.carrier] || {};
2395
- const last = order.operations?.at(-1);
2396
- return /* @__PURE__ */ jsxs("tr", { className: "border-b", children: [
2397
- /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx(
2398
- Checkbox,
2438
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2439
+ /* @__PURE__ */ jsx(
2440
+ Switch,
2399
2441
  {
2400
- checked: selectedSet.has(order.id),
2401
- onCheckedChange: () => toggle(order.id)
2442
+ checked: document2.requiredAtCheckout,
2443
+ disabled: !document2.currentVersion || Boolean(busy),
2444
+ onCheckedChange: (value) => void updateDocument(document2, {
2445
+ requiredAtCheckout: value
2446
+ })
2402
2447
  }
2403
- ) }),
2404
- /* @__PURE__ */ jsxs("td", { className: "p-4", children: [
2405
- /* @__PURE__ */ jsxs("a", { className: "text-blue-600", href: `${adminBase$5}/orders/${order.id}`, children: [
2406
- "#",
2407
- order.display_id ?? order.id
2408
- ] }),
2409
- /* @__PURE__ */ jsx("div", { className: "text-ui-fg-subtle", children: order.email || "—" })
2410
- ] }),
2411
- /* @__PURE__ */ jsx("td", { className: "p-4 font-medium", children: carrierName(order.carrier) }),
2412
- /* @__PURE__ */ jsxs("td", { className: "p-4", children: [
2413
- String(
2414
- shipment.trackingNumber || shipment.parcelNumber || shipment.packetId || shipment.packageId || shipment.shipmentId || "—"
2415
- ),
2416
- order.carrier === "mpl" && shipment.closedAt ? /* @__PURE__ */ jsx("div", { className: "text-ui-fg-subtle", children: "jegyzék lezárva" }) : null
2417
- ] }),
2418
- /* @__PURE__ */ jsx("td", { className: "p-4", children: String(shipment.status || "—") }),
2419
- /* @__PURE__ */ jsx("td", { className: "p-4", children: last ? /* @__PURE__ */ jsx("span", { className: last.status === "failed" ? "text-red-600" : "text-green-700", children: last.message }) : "—" })
2420
- ] }, order.id);
2421
- }) })
2448
+ ),
2449
+ /* @__PURE__ */ jsx("span", { children: document2.requiredAtCheckout ? "Kötelező" : "Nem kötelező" })
2450
+ ] }) }),
2451
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: document2.currentVersion ? /* @__PURE__ */ jsxs(Fragment, { children: [
2452
+ /* @__PURE__ */ jsx("code", { title: document2.currentVersion.sha256, children: shortHash(document2.currentVersion.sha256) }),
2453
+ /* @__PURE__ */ jsxs("div", { className: "text-ui-fg-subtle", children: [
2454
+ formatDate$4(document2.currentVersion.createdAt),
2455
+ " ·",
2456
+ " ",
2457
+ formatBytes(document2.currentVersion.contentLength)
2458
+ ] })
2459
+ ] }) : /* @__PURE__ */ jsx("span", { className: "text-ui-fg-error", children: "Nincs PDF-verzió" }) }),
2460
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsxs("div", { className: "flex min-w-52 flex-wrap gap-2", children: [
2461
+ document2.currentVersion ? /* @__PURE__ */ jsx(
2462
+ "a",
2463
+ {
2464
+ href: apiUrl$9(
2465
+ `/admin/legal/documents/${document2.id}/versions/${document2.currentVersion.id}/pdf`
2466
+ ),
2467
+ target: "_blank",
2468
+ rel: "noreferrer",
2469
+ children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "PDF" })
2470
+ }
2471
+ ) : null,
2472
+ /* @__PURE__ */ jsxs("label", { className: "inline-flex cursor-pointer items-center rounded-md border px-2.5 py-1 text-xs font-medium", children: [
2473
+ "Új PDF-verzió",
2474
+ /* @__PURE__ */ jsx(
2475
+ "input",
2476
+ {
2477
+ className: "hidden",
2478
+ type: "file",
2479
+ accept: "application/pdf,.pdf",
2480
+ disabled: Boolean(busy),
2481
+ onChange: (event) => {
2482
+ const file = event.target.files?.[0];
2483
+ if (file) void uploadNewVersion(document2, file);
2484
+ event.currentTarget.value = "";
2485
+ }
2486
+ }
2487
+ )
2488
+ ] })
2489
+ ] }) })
2490
+ ] }, document2.id)) })
2422
2491
  ] }),
2423
- ordersLoading ? /* @__PURE__ */ jsx("div", { className: "p-8 text-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Szállítási rendelések betöltése…" }) }) : null,
2424
- !ordersLoading && loadError ? /* @__PURE__ */ jsxs("div", { className: "m-6 flex flex-wrap items-center justify-between gap-4 rounded-lg border border-ui-border-error bg-ui-bg-base p-4", children: [
2425
- /* @__PURE__ */ jsxs("div", { children: [
2426
- /* @__PURE__ */ jsx(Text, { className: "font-medium text-ui-fg-error", children: "A szállítási lista nem tölthető be" }),
2427
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: loadError })
2428
- ] }),
2429
- /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => void load(), children: "Újrapróbálás" })
2430
- ] }) : null,
2431
- !ordersLoading && !loadError && !orders.length ? /* @__PURE__ */ jsx("div", { className: "p-8 text-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Nincs támogatott Core szállítású rendelés." }) }) : null
2432
- ] })
2433
- ] });
2492
+ !loading && !documents.length ? /* @__PURE__ */ jsx("div", { className: "p-8 text-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Még nincs feltöltött jogi dokumentum." }) }) : null
2493
+ ] }),
2494
+ /* @__PURE__ */ jsxs("div", { className: "border-b px-6 py-4", children: [
2495
+ /* @__PURE__ */ jsx(Heading, { level: "h2", children: "Legutóbbi elfogadások" }),
2496
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "A consent mindig a konkrét PDF-verzióhoz, kosárhoz és később a rendeléshez kapcsolódik." })
2497
+ ] }),
2498
+ /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-left text-sm", children: [
2499
+ /* @__PURE__ */ jsx("thead", { className: "border-b bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
2500
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Elfogadva" }),
2501
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Dokumentum" }),
2502
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Rendelés" }),
2503
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Cart" }),
2504
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Verzió" })
2505
+ ] }) }),
2506
+ /* @__PURE__ */ jsx("tbody", { children: consents.map((consent) => /* @__PURE__ */ jsxs("tr", { className: "border-b", children: [
2507
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: formatDate$4(consent.acceptedAt) }),
2508
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: consent.documentTitle }),
2509
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: consent.orderId ? /* @__PURE__ */ jsx(
2510
+ "a",
2511
+ {
2512
+ className: "text-ui-fg-interactive",
2513
+ href: `${adminBase$4}/orders/${consent.orderId}`,
2514
+ children: consent.orderId
2515
+ }
2516
+ ) : "Még nincs rendelés" }),
2517
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx("code", { children: consent.cartId }) }),
2518
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx("code", { children: consent.documentVersionId }) })
2519
+ ] }, consent.id)) })
2520
+ ] }) })
2521
+ ] }) });
2434
2522
  };
2435
- function carrierName(carrier) {
2436
- if (carrier === "foxpost") return "FOXPOST";
2437
- if (carrier === "gls") return "GLS";
2438
- if (carrier === "packeta") return "Packeta";
2439
- if (carrier === "dpd") return "DPD";
2440
- return "MPL";
2523
+ function Field$4({
2524
+ label,
2525
+ children
2526
+ }) {
2527
+ return /* @__PURE__ */ jsxs("label", { className: "flex min-w-0 flex-col gap-1.5", children: [
2528
+ /* @__PURE__ */ jsx(Text, { className: "font-medium", children: label }),
2529
+ children
2530
+ ] });
2441
2531
  }
2442
- function openPdf(blob, filename, print) {
2443
- const url = URL.createObjectURL(blob);
2444
- if (print) {
2445
- const frame = document.createElement("iframe");
2446
- frame.style.display = "none";
2447
- frame.src = url;
2448
- frame.onload = () => {
2449
- frame.contentWindow?.print();
2450
- setTimeout(() => {
2451
- frame.remove();
2452
- URL.revokeObjectURL(url);
2453
- }, 6e4);
2454
- };
2455
- document.body.appendChild(frame);
2456
- } else {
2457
- const link = document.createElement("a");
2458
- link.href = url;
2459
- link.download = filename;
2460
- link.click();
2461
- setTimeout(() => URL.revokeObjectURL(url), 1e4);
2532
+ function fileToBase64(file) {
2533
+ if (file.size > 5 * 1024 * 1024) {
2534
+ return Promise.reject(new Error("A PDF legfeljebb 5 MB lehet."));
2462
2535
  }
2536
+ return new Promise((resolve, reject) => {
2537
+ const reader = new FileReader();
2538
+ reader.onload = () => resolve(String(reader.result || ""));
2539
+ reader.onerror = () => reject(new Error("A PDF fájl nem olvasható."));
2540
+ reader.readAsDataURL(file);
2541
+ });
2463
2542
  }
2464
- const config$8 = defineRouteConfig({
2465
- label: "Szállítás",
2466
- icon: TruckFast,
2467
- rank: 35
2543
+ function kindLabel(value) {
2544
+ return value === "terms" ? "ÁSZF" : value === "privacy" ? "Adatkezelés" : value === "withdrawal" ? "Elállás" : "Egyedi";
2545
+ }
2546
+ function shortHash(value) {
2547
+ return value.length > 20 ? `${value.slice(0, 12)}…${value.slice(-8)}` : value;
2548
+ }
2549
+ function formatBytes(value) {
2550
+ if (!Number.isFinite(value)) return "—";
2551
+ if (value < 1024) return `${value} B`;
2552
+ if (value < 1024 * 1024) return `${Math.round(value / 1024)} kB`;
2553
+ return `${(value / 1024 / 1024).toFixed(2)} MB`;
2554
+ }
2555
+ function formatDate$4(value) {
2556
+ if (!value) return "—";
2557
+ const date = new Date(value);
2558
+ if (Number.isNaN(date.getTime())) return "—";
2559
+ return new Intl.DateTimeFormat("hu-HU", {
2560
+ dateStyle: "short",
2561
+ timeStyle: "short"
2562
+ }).format(date);
2563
+ }
2564
+ const config$7 = defineRouteConfig({
2565
+ label: "Jogi dokumentumok",
2566
+ icon: Newspaper,
2567
+ rank: 40
2468
2568
  });
2469
- const adminBase$4 = (__BASE__ || "/app").replace(/\/+$/, "");
2470
- const links = [
2471
- { label: "Production readiness", description: "Élesítési blokkolók: infrastruktúra, commerce, security, legal, e-mail és SEO.", href: `${adminBase$4}/system-monitoring/readiness` },
2472
- { label: "Integrációs műveletek", description: "Retry, reconciliation és külső API műveletek kezelése.", href: `${adminBase$4}/system-monitoring/operations` },
2473
- { label: "Integrációk állapota", description: "Provider állapotok, konfigurációk és hibák áttekintése.", href: `${adminBase$4}/system-monitoring/health` },
2474
- { label: "Audit napló", description: "Core és integrációs admin események visszakeresése.", href: `${adminBase$4}/system-monitoring/audit` }
2475
- ];
2476
- const SystemMonitoringPage = () => /* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
2477
- /* @__PURE__ */ jsxs("div", { className: "border-b px-6 py-5", children: [
2478
- /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Rendszerfelügyelet" }),
2479
- /* @__PURE__ */ jsx(Text, { className: "mt-1 text-ui-fg-subtle", children: "Technikai állapotok, élesítési feltételek, külső műveletek és audit események." })
2480
- ] }),
2481
- /* @__PURE__ */ jsx("div", { className: "grid gap-4 p-6 md:grid-cols-2 xl:grid-cols-4", children: links.map((item) => /* @__PURE__ */ jsxs("a", { href: item.href, className: "rounded-lg border p-5 hover:bg-ui-bg-subtle", children: [
2482
- /* @__PURE__ */ jsx(Heading, { level: "h2", children: item.label }),
2483
- /* @__PURE__ */ jsx(Text, { className: "mt-1 text-ui-fg-subtle", children: item.description })
2484
- ] }, item.href)) })
2485
- ] });
2486
- const config$7 = defineRouteConfig({ label: "Rendszerfelügyelet" });
2487
2569
  const defaults$1 = {
2488
2570
  ARUKERESO_STOREFRONT_URL: "",
2489
2571
  ARUKERESO_PRODUCT_PATH_TEMPLATE: "/{country_code}/products/{handle}?v_id={variant_id}",
@@ -3075,197 +3157,167 @@ function normalizeEntity(value) {
3075
3157
  function normalizePage(value) {
3076
3158
  return { ...value, seo: normalizeSeo(value.seo) };
3077
3159
  }
3078
- const defaults = {
3079
- GOOGLE_MERCHANT_COUNTRY_CODE: "HU",
3080
- GOOGLE_MERCHANT_CURRENCY_CODE: "HUF",
3081
- GOOGLE_MERCHANT_STOREFRONT_URL: "",
3082
- GOOGLE_MERCHANT_PRODUCT_PATH_TEMPLATE: "/{country_code}/products/{handle}?v_id={variant_id}",
3083
- GOOGLE_MERCHANT_SALES_CHANNEL_ID: "",
3084
- GOOGLE_MERCHANT_DEFAULT_BRAND: "",
3085
- GOOGLE_MERCHANT_DEFAULT_CONDITION: "new",
3086
- GOOGLE_MERCHANT_INCLUDE_OUT_OF_STOCK: true,
3087
- GOOGLE_MERCHANT_FEED_TITLE: "",
3088
- GOOGLE_MERCHANT_FEED_DESCRIPTION: ""
3089
- };
3090
3160
  const backendUrl$6 = (__BACKEND_URL__ || "").replace(/\/+$/, "");
3091
- const apiUrl$6 = (path) => `${backendUrl$6}${path.startsWith("/") ? path : `/${path}`}`;
3092
- const GoogleMerchantPage = () => {
3093
- const [enabled, setEnabled] = useState(false);
3094
- const [draft, setDraft] = useState(defaults);
3161
+ function apiUrl$6(path) {
3162
+ return `${backendUrl$6}${path.startsWith("/") ? path : `/${path}`}`;
3163
+ }
3164
+ const CoreAuditPage = () => {
3165
+ const [logs, setLogs] = useState([]);
3166
+ const [count, setCount] = useState(0);
3167
+ const [integration, setIntegration] = useState("all");
3168
+ const [status, setStatus] = useState("all");
3169
+ const [query, setQuery] = useState("");
3095
3170
  const [loading, setLoading] = useState(true);
3096
- const [saving, setSaving] = useState(false);
3097
- const [previewing, setPreviewing] = useState(false);
3098
- const [preview, setPreview] = useState(null);
3099
- const update = (key, value) => {
3100
- setDraft((current) => ({ ...current, [key]: value }));
3101
- };
3171
+ const [loadError, setLoadError] = useState(null);
3102
3172
  const load = useCallback(async () => {
3103
3173
  setLoading(true);
3174
+ setLoadError(null);
3104
3175
  try {
3105
- const response = await fetch(apiUrl$6("/admin/integrations/google-merchant"), {
3106
- credentials: "include"
3107
- });
3108
- const data = await response.json().catch(() => ({}));
3109
- if (!response.ok || !data.integration) {
3110
- throw new Error(data.message || "A Google Merchant beállítások nem tölthetők be.");
3176
+ const params = new URLSearchParams({ limit: "100" });
3177
+ if (integration !== "all") params.set("integration", integration);
3178
+ if (status !== "all") params.set("status", status);
3179
+ const response = await fetch(
3180
+ apiUrl$6(`/admin/core-audit?${params.toString()}`),
3181
+ { credentials: "include" }
3182
+ );
3183
+ const payload = await response.json().catch(() => ({}));
3184
+ if (!response.ok) {
3185
+ throw new Error(payload.message || "Az audit napló nem tölthető be.");
3111
3186
  }
3112
- const values = data.integration.values || {};
3113
- setEnabled(Boolean(data.integration.enabled));
3114
- setDraft({
3115
- GOOGLE_MERCHANT_COUNTRY_CODE: values.GOOGLE_MERCHANT_COUNTRY_CODE || "HU",
3116
- GOOGLE_MERCHANT_CURRENCY_CODE: values.GOOGLE_MERCHANT_CURRENCY_CODE || "HUF",
3117
- GOOGLE_MERCHANT_STOREFRONT_URL: values.GOOGLE_MERCHANT_STOREFRONT_URL || "",
3118
- GOOGLE_MERCHANT_PRODUCT_PATH_TEMPLATE: values.GOOGLE_MERCHANT_PRODUCT_PATH_TEMPLATE || "/{country_code}/products/{handle}?v_id={variant_id}",
3119
- GOOGLE_MERCHANT_SALES_CHANNEL_ID: values.GOOGLE_MERCHANT_SALES_CHANNEL_ID || "",
3120
- GOOGLE_MERCHANT_DEFAULT_BRAND: values.GOOGLE_MERCHANT_DEFAULT_BRAND || "",
3121
- GOOGLE_MERCHANT_DEFAULT_CONDITION: values.GOOGLE_MERCHANT_DEFAULT_CONDITION || "new",
3122
- GOOGLE_MERCHANT_INCLUDE_OUT_OF_STOCK: values.GOOGLE_MERCHANT_INCLUDE_OUT_OF_STOCK !== "false",
3123
- GOOGLE_MERCHANT_FEED_TITLE: values.GOOGLE_MERCHANT_FEED_TITLE || "",
3124
- GOOGLE_MERCHANT_FEED_DESCRIPTION: values.GOOGLE_MERCHANT_FEED_DESCRIPTION || ""
3125
- });
3187
+ setLogs(payload.logs || []);
3188
+ setCount(payload.count || 0);
3126
3189
  } catch (error) {
3127
- toast.error(error instanceof Error ? error.message : "Betöltési hiba.");
3190
+ setLogs([]);
3191
+ setLoadError(
3192
+ error instanceof Error ? error.message : "Az audit napló nem tölthető be."
3193
+ );
3128
3194
  } finally {
3129
3195
  setLoading(false);
3130
3196
  }
3131
- }, []);
3197
+ }, [integration, status]);
3132
3198
  useEffect(() => {
3133
3199
  void load();
3134
3200
  }, [load]);
3135
- const save = async () => {
3136
- setSaving(true);
3137
- try {
3138
- const response = await fetch(apiUrl$6("/admin/integrations/google-merchant"), {
3139
- method: "POST",
3140
- credentials: "include",
3141
- headers: { "Content-Type": "application/json" },
3142
- body: JSON.stringify({ enabled, values: draft })
3143
- });
3144
- const data = await response.json().catch(() => ({}));
3145
- if (!response.ok) throw new Error(data.message || "A mentés nem sikerült.");
3146
- toast.success(data.message || "Google Merchant beállítások mentve.");
3147
- setPreview(null);
3148
- await load();
3149
- } catch (error) {
3150
- toast.error(error instanceof Error ? error.message : "A mentés nem sikerült.");
3151
- } finally {
3152
- setSaving(false);
3153
- }
3154
- };
3155
- const runPreview = async () => {
3156
- setPreviewing(true);
3157
- try {
3158
- const response = await fetch(apiUrl$6("/admin/google-merchant/preview"), {
3159
- credentials: "include"
3160
- });
3161
- const data = await response.json().catch(() => ({}));
3162
- if (!response.ok) throw new Error(data.message || "A feed nem generálható.");
3163
- setPreview(data);
3164
- toast.success("A Merchant feed ellenőrzése elkészült.");
3165
- } catch (error) {
3166
- toast.error(error instanceof Error ? error.message : "A feed nem generálható.");
3167
- } finally {
3168
- setPreviewing(false);
3169
- }
3170
- };
3171
- const feedUrl = apiUrl$6("/feeds/google-merchant.xml");
3172
- const d = preview?.diagnostics;
3201
+ const visible = useMemo(() => {
3202
+ const value = query.trim().toLowerCase();
3203
+ if (!value) return logs;
3204
+ return logs.filter(
3205
+ (log) => [
3206
+ log.action,
3207
+ log.resource_type,
3208
+ log.resource_id,
3209
+ log.integration,
3210
+ log.actor_id,
3211
+ log.summary
3212
+ ].some((item) => String(item || "").toLowerCase().includes(value))
3213
+ );
3214
+ }, [logs, query]);
3173
3215
  return /* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
3174
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-4 border-b px-6 py-4", children: [
3216
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-4 border-b px-6 py-4", children: [
3175
3217
  /* @__PURE__ */ jsxs("div", { children: [
3176
- /* @__PURE__ */ jsx(Heading, { children: "Google Merchant Center" }),
3177
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Google RSS 2.0 feed a Medusa termék-, variant-, régiós ár-, ÁFA- és készletadataiból." })
3218
+ /* @__PURE__ */ jsx(Heading, { children: "Core audit napló" }),
3219
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Admin és integrációs műveletek üzleti auditja, titkok mentése nélkül." })
3178
3220
  ] }),
3179
- /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
3180
- /* @__PURE__ */ jsx(Switch, { checked: enabled, onCheckedChange: setEnabled, disabled: loading }),
3181
- /* @__PURE__ */ jsx(Text, { children: enabled ? "Bekapcsolva" : "Kikapcsolva" })
3182
- ] })
3221
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", isLoading: loading, onClick: () => void load(), children: "Frissítés" })
3183
3222
  ] }),
3184
- /* @__PURE__ */ jsxs("div", { className: "grid gap-4 border-b px-6 py-5 md:grid-cols-2", children: [
3185
- /* @__PURE__ */ jsx(Field$1, { label: "Célország", children: /* @__PURE__ */ jsx(Input, { value: draft.GOOGLE_MERCHANT_COUNTRY_CODE, onChange: (e) => update("GOOGLE_MERCHANT_COUNTRY_CODE", e.target.value.toUpperCase()), placeholder: "HU" }) }),
3186
- /* @__PURE__ */ jsx(Field$1, { label: "Pénznem", children: /* @__PURE__ */ jsx(Input, { value: draft.GOOGLE_MERCHANT_CURRENCY_CODE, onChange: (e) => update("GOOGLE_MERCHANT_CURRENCY_CODE", e.target.value.toUpperCase()), placeholder: "HUF" }) }),
3187
- /* @__PURE__ */ jsx(Field$1, { label: "Storefront URL", children: /* @__PURE__ */ jsx(Input, { value: draft.GOOGLE_MERCHANT_STOREFRONT_URL, onChange: (e) => update("GOOGLE_MERCHANT_STOREFRONT_URL", e.target.value), placeholder: "https://shop.hu (üresen STOREFRONT_URL)" }) }),
3188
- /* @__PURE__ */ jsxs(Field$1, { label: "Termék URL sablon", children: [
3189
- /* @__PURE__ */ jsx(Input, { value: draft.GOOGLE_MERCHANT_PRODUCT_PATH_TEMPLATE, onChange: (e) => update("GOOGLE_MERCHANT_PRODUCT_PATH_TEMPLATE", e.target.value) }),
3190
- /* @__PURE__ */ jsxs(Text, { className: "text-ui-fg-muted text-xs", children: [
3191
- "Helyőrzők: ",
3192
- "{country_code}",
3193
- ", ",
3194
- "{currency_code}",
3195
- ", ",
3196
- "{handle}",
3197
- ", ",
3198
- "{variant_id}",
3199
- "."
3223
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-end gap-3 border-b px-6 py-4", children: [
3224
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
3225
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Integráció" }),
3226
+ /* @__PURE__ */ jsxs(Select, { value: integration, onValueChange: setIntegration, children: [
3227
+ /* @__PURE__ */ jsx(Select.Trigger, { className: "w-44", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
3228
+ /* @__PURE__ */ jsxs(Select.Content, { children: [
3229
+ /* @__PURE__ */ jsx(Select.Item, { value: "all", children: "Összes" }),
3230
+ [
3231
+ "stripe",
3232
+ "simplepay",
3233
+ "billingo",
3234
+ "bank-transfer",
3235
+ "foxpost",
3236
+ "gls",
3237
+ "packeta",
3238
+ "dpd",
3239
+ "mpl",
3240
+ "sendgrid",
3241
+ "fogyasztobarat"
3242
+ ].map((item) => /* @__PURE__ */ jsx(Select.Item, { value: item, children: item }, item))
3243
+ ] })
3200
3244
  ] })
3201
3245
  ] }),
3202
- /* @__PURE__ */ jsx(Field$1, { label: "Sales Channel ID", children: /* @__PURE__ */ jsx(Input, { value: draft.GOOGLE_MERCHANT_SALES_CHANNEL_ID, onChange: (e) => update("GOOGLE_MERCHANT_SALES_CHANNEL_ID", e.target.value), placeholder: "sc_... (opcionális)" }) }),
3203
- /* @__PURE__ */ jsx(Field$1, { label: "Alapértelmezett márka", children: /* @__PURE__ */ jsx(Input, { value: draft.GOOGLE_MERCHANT_DEFAULT_BRAND, onChange: (e) => update("GOOGLE_MERCHANT_DEFAULT_BRAND", e.target.value) }) }),
3204
- /* @__PURE__ */ jsx(Field$1, { label: "Alapértelmezett állapot", children: /* @__PURE__ */ jsxs("select", { className: "h-8 rounded-md border bg-ui-bg-field px-2 text-sm", value: draft.GOOGLE_MERCHANT_DEFAULT_CONDITION, onChange: (e) => update("GOOGLE_MERCHANT_DEFAULT_CONDITION", e.target.value), children: [
3205
- /* @__PURE__ */ jsx("option", { value: "new", children: "Új" }),
3206
- /* @__PURE__ */ jsx("option", { value: "refurbished", children: "Felújított" }),
3207
- /* @__PURE__ */ jsx("option", { value: "used", children: "Használt" })
3208
- ] }) }),
3209
- /* @__PURE__ */ jsx(Field$1, { label: "Készlethiányos variantok", children: /* @__PURE__ */ jsxs("div", { className: "flex h-8 items-center gap-2", children: [
3210
- /* @__PURE__ */ jsx(Switch, { checked: draft.GOOGLE_MERCHANT_INCLUDE_OUT_OF_STOCK, onCheckedChange: (value) => update("GOOGLE_MERCHANT_INCLUDE_OUT_OF_STOCK", value) }),
3211
- /* @__PURE__ */ jsx(Text, { children: draft.GOOGLE_MERCHANT_INCLUDE_OUT_OF_STOCK ? "Benne maradnak" : "Kimaradnak" })
3212
- ] }) }),
3213
- /* @__PURE__ */ jsx(Field$1, { label: "Feed neve", children: /* @__PURE__ */ jsx(Input, { value: draft.GOOGLE_MERCHANT_FEED_TITLE, onChange: (e) => update("GOOGLE_MERCHANT_FEED_TITLE", e.target.value), placeholder: "Üresen automatikus" }) }),
3214
- /* @__PURE__ */ jsx(Field$1, { label: "Feed leírása", children: /* @__PURE__ */ jsx(Input, { value: draft.GOOGLE_MERCHANT_FEED_DESCRIPTION, onChange: (e) => update("GOOGLE_MERCHANT_FEED_DESCRIPTION", e.target.value), placeholder: "Üresen automatikus" }) })
3215
- ] }),
3216
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 border-b px-6 py-4", children: [
3217
- /* @__PURE__ */ jsxs("div", { children: [
3218
- /* @__PURE__ */ jsx(Text, { className: "font-medium", children: "Publikus feed URL" }),
3219
- /* @__PURE__ */ jsx("a", { className: "break-all text-ui-fg-interactive hover:underline", href: feedUrl, target: "_blank", rel: "noreferrer", children: feedUrl })
3246
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
3247
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Eredmény" }),
3248
+ /* @__PURE__ */ jsxs(Select, { value: status, onValueChange: setStatus, children: [
3249
+ /* @__PURE__ */ jsx(Select.Trigger, { className: "w-36", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
3250
+ /* @__PURE__ */ jsxs(Select.Content, { children: [
3251
+ /* @__PURE__ */ jsx(Select.Item, { value: "all", children: "Összes" }),
3252
+ /* @__PURE__ */ jsx(Select.Item, { value: "success", children: "Sikeres" }),
3253
+ /* @__PURE__ */ jsx(Select.Item, { value: "error", children: "Hiba" })
3254
+ ] })
3255
+ ] })
3220
3256
  ] }),
3221
- /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
3222
- /* @__PURE__ */ jsx(Button, { variant: "secondary", isLoading: previewing, disabled: !enabled || loading || saving || previewing, onClick: () => void runPreview(), children: "Feed ellenőrzése" }),
3223
- /* @__PURE__ */ jsx(Button, { isLoading: saving, disabled: loading || saving || previewing, onClick: () => void save(), children: "Mentés" })
3257
+ /* @__PURE__ */ jsx(
3258
+ Input,
3259
+ {
3260
+ className: "max-w-sm",
3261
+ value: query,
3262
+ onChange: (event) => setQuery(event.target.value),
3263
+ placeholder: "Keresés művelet, erőforrás, admin vagy leírás alapján"
3264
+ }
3265
+ ),
3266
+ /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
3267
+ count,
3268
+ " bejegyzés"
3224
3269
  ] })
3225
3270
  ] }),
3226
- d ? /* @__PURE__ */ jsxs(Fragment, { children: [
3227
- /* @__PURE__ */ jsxs("div", { className: "grid gap-3 border-b px-6 py-5 sm:grid-cols-2 lg:grid-cols-4", children: [
3228
- /* @__PURE__ */ jsx(Stat, { label: "Termékek", value: d.productsScanned }),
3229
- /* @__PURE__ */ jsx(Stat, { label: "Variantok", value: d.variantsScanned }),
3230
- /* @__PURE__ */ jsx(Stat, { label: "Feed tételek", value: d.itemsEmitted }),
3231
- /* @__PURE__ */ jsx(Stat, { label: "Hiányzó identifier", value: d.itemsMissingIdentifiers }),
3232
- /* @__PURE__ */ jsx(Stat, { label: "Nincs ár", value: d.skippedNoPrice }),
3233
- /* @__PURE__ */ jsx(Stat, { label: "Nincs kép", value: d.skippedNoImage }),
3234
- /* @__PURE__ */ jsx(Stat, { label: "Nincs sales channel", value: d.skippedNoSalesChannel + d.skippedNotInSalesChannel }),
3235
- /* @__PURE__ */ jsx(Stat, { label: "Érvénytelen GTIN", value: d.invalidGtinsIgnored })
3236
- ] }),
3237
- /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-left text-sm", children: [
3271
+ /* @__PURE__ */ jsxs("div", { className: "overflow-x-auto", children: [
3272
+ /* @__PURE__ */ jsxs("table", { className: "w-full text-left text-sm", children: [
3238
3273
  /* @__PURE__ */ jsx("thead", { className: "border-b bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
3239
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "ID" }),
3240
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Termék" }),
3241
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Ár" }),
3242
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Készlet" }),
3243
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Identifier" })
3274
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Idő" }),
3275
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Eredmény" }),
3276
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Művelet" }),
3277
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Erőforrás" }),
3278
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Integráció" }),
3279
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Admin / actor" }),
3280
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Leírás" })
3244
3281
  ] }) }),
3245
- /* @__PURE__ */ jsx("tbody", { children: (preview?.sample || []).map((item) => /* @__PURE__ */ jsxs("tr", { className: "border-b", children: [
3246
- /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx("code", { children: item.id }) }),
3247
- /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx("a", { href: item.link, target: "_blank", rel: "noreferrer", className: "text-ui-fg-interactive hover:underline", children: item.title }) }),
3248
- /* @__PURE__ */ jsx("td", { className: "p-4", children: item.salePrice ? `${item.salePrice} (${item.price})` : item.price }),
3249
- /* @__PURE__ */ jsx("td", { className: "p-4", children: item.availability }),
3250
- /* @__PURE__ */ jsx("td", { className: "p-4", children: item.gtin || item.mpn || item.brand || "—" })
3251
- ] }, item.id)) })
3252
- ] }) })
3253
- ] }) : null
3282
+ /* @__PURE__ */ jsx("tbody", { children: visible.map((log) => /* @__PURE__ */ jsxs("tr", { className: "border-b align-top", children: [
3283
+ /* @__PURE__ */ jsx("td", { className: "whitespace-nowrap p-4", children: formatDate$3(log.created_at) }),
3284
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx("span", { className: log.status === "error" ? "font-medium text-ui-fg-error" : "font-medium text-ui-fg-success", children: log.status === "error" ? "Hiba" : "Sikeres" }) }),
3285
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx("code", { children: log.action }) }),
3286
+ /* @__PURE__ */ jsxs("td", { className: "p-4", children: [
3287
+ /* @__PURE__ */ jsx("div", { children: log.resource_type }),
3288
+ /* @__PURE__ */ jsx("div", { className: "text-ui-fg-subtle", children: log.resource_id || "—" })
3289
+ ] }),
3290
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: log.integration || "—" }),
3291
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: log.actor_id || "system" }),
3292
+ /* @__PURE__ */ jsxs("td", { className: "max-w-xl p-4", children: [
3293
+ /* @__PURE__ */ jsx("div", { children: log.summary }),
3294
+ log.details && Object.keys(log.details).length ? /* @__PURE__ */ jsx("div", { className: "mt-1 text-ui-fg-subtle", children: Object.entries(log.details).map(([key, value]) => `${key}: ${String(value)}`).join(" · ") }) : null
3295
+ ] })
3296
+ ] }, log.id)) })
3297
+ ] }),
3298
+ loading ? /* @__PURE__ */ jsx("div", { className: "p-8 text-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Audit napló betöltése…" }) }) : null,
3299
+ !loading && loadError ? /* @__PURE__ */ jsxs("div", { className: "m-6 rounded-lg border border-ui-border-error p-4", children: [
3300
+ /* @__PURE__ */ jsx(Text, { className: "font-medium text-ui-fg-error", children: "Az audit napló nem tölthető be." }),
3301
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: loadError })
3302
+ ] }) : null,
3303
+ !loading && !loadError && !visible.length ? /* @__PURE__ */ jsx("div", { className: "p-8 text-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Nincs a szűrésnek megfelelő audit bejegyzés." }) }) : null
3304
+ ] })
3254
3305
  ] });
3255
3306
  };
3256
- function Field$1({ label, children }) {
3257
- return /* @__PURE__ */ jsxs("label", { className: "flex min-w-0 flex-col gap-1.5", children: [
3258
- /* @__PURE__ */ jsx(Text, { className: "font-medium", children: label }),
3259
- children
3260
- ] });
3261
- }
3262
- function Stat({ label, value }) {
3263
- return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border p-3", children: [
3264
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-xs", children: label }),
3265
- /* @__PURE__ */ jsx(Text, { className: "font-medium", children: value })
3266
- ] });
3307
+ function formatDate$3(value) {
3308
+ if (!value) return "—";
3309
+ const date = new Date(value);
3310
+ if (Number.isNaN(date.getTime())) return "—";
3311
+ return new Intl.DateTimeFormat("hu-HU", {
3312
+ dateStyle: "short",
3313
+ timeStyle: "short"
3314
+ }).format(date);
3267
3315
  }
3268
- const config$5 = defineRouteConfig({ label: "Google Merchant", rank: 41 });
3316
+ const config$5 = defineRouteConfig({
3317
+ label: "Audit napló",
3318
+ icon: Newspaper,
3319
+ rank: 39
3320
+ });
3269
3321
  const backendUrl$5 = (__BACKEND_URL__ || "").replace(/\/+$/, "");
3270
3322
  const adminBase$3 = (__BASE__ || "/app").replace(/\/+$/, "");
3271
3323
  function apiUrl$5(path) {
@@ -3479,314 +3531,227 @@ function ConnectionText({ integration }) {
3479
3531
  return /* @__PURE__ */ jsxs("div", { className: "max-w-sm", children: [
3480
3532
  /* @__PURE__ */ jsx("div", { children: integration.last_test_status === "ok" ? "OK" : integration.last_test_status === "error" ? "Hiba" : "Nincs hitelesítve" }),
3481
3533
  integration.last_test_message ? /* @__PURE__ */ jsx("div", { className: "text-ui-fg-subtle", children: integration.last_test_message }) : null,
3482
- integration.last_test_at ? /* @__PURE__ */ jsx("div", { className: "text-ui-fg-subtle", children: formatDate$3(integration.last_test_at) }) : null
3534
+ integration.last_test_at ? /* @__PURE__ */ jsx("div", { className: "text-ui-fg-subtle", children: formatDate$2(integration.last_test_at) }) : null
3483
3535
  ] });
3484
3536
  }
3485
3537
  function SummaryCard$1({
3486
3538
  label,
3487
3539
  value,
3488
- danger = false
3489
- }) {
3490
- return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border p-4", children: [
3491
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: label }),
3492
- /* @__PURE__ */ jsx("div", { className: danger ? "text-ui-fg-error text-2xl font-semibold" : "text-2xl font-semibold", children: value })
3493
- ] });
3494
- }
3495
- function formatDate$3(value) {
3496
- const date = new Date(value);
3497
- if (Number.isNaN(date.getTime())) return "—";
3498
- return new Intl.DateTimeFormat("hu-HU", {
3499
- dateStyle: "short",
3500
- timeStyle: "short"
3501
- }).format(date);
3502
- }
3503
- const config$4 = defineRouteConfig({
3504
- label: "Integrációk állapota",
3505
- icon: Newspaper,
3506
- rank: 38
3507
- });
3508
- const backendUrl$4 = (__BACKEND_URL__ || "").replace(/\/+$/, "");
3509
- const adminBase$2 = (__BASE__ || "/app").replace(/\/+$/, "");
3510
- const apiUrl$4 = (path) => `${backendUrl$4}${path.startsWith("/") ? path : `/${path}`}`;
3511
- const CATEGORY_LABELS = {
3512
- infrastructure: "Infrastruktúra",
3513
- security: "Biztonság",
3514
- store: "Storefront alapok",
3515
- commerce: "Kereskedelem",
3516
- communication: "Kommunikáció",
3517
- compliance: "Jogi megfelelés",
3518
- marketing: "Mérés és SEO"
3519
- };
3520
- const ProductionReadinessPage = () => {
3521
- const [report, setReport] = useState(null);
3522
- const [loading, setLoading] = useState(true);
3523
- const [error, setError] = useState(null);
3524
- const load = useCallback(async () => {
3525
- setLoading(true);
3526
- setError(null);
3527
- try {
3528
- const response = await fetch(apiUrl$4("/admin/production-readiness"), {
3529
- credentials: "include"
3530
- });
3531
- const payload = await response.json().catch(() => ({}));
3532
- if (!response.ok) {
3533
- throw new Error(payload.message || "Az élesítési ellenőrzés nem tölthető be.");
3534
- }
3535
- setReport(payload);
3536
- } catch (cause) {
3537
- setReport(null);
3538
- setError(
3539
- cause instanceof Error ? cause.message : "Az élesítési ellenőrzés nem tölthető be."
3540
- );
3541
- } finally {
3542
- setLoading(false);
3543
- }
3544
- }, []);
3545
- useEffect(() => {
3546
- void load();
3547
- }, [load]);
3548
- const groups = useMemo(() => {
3549
- const result = /* @__PURE__ */ new Map();
3550
- for (const item of report?.checks || []) {
3551
- result.set(item.category, [...result.get(item.category) || [], item]);
3552
- }
3553
- return Array.from(result.entries());
3554
- }, [report]);
3555
- return /* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
3556
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-4 border-b px-6 py-5", children: [
3557
- /* @__PURE__ */ jsxs("div", { children: [
3558
- /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Production readiness" }),
3559
- /* @__PURE__ */ jsx(Text, { className: "mt-1 text-ui-fg-subtle", children: "Élesítés előtti runtime ellenőrzés. A felület státuszokat mutat, secret értéket nem ad vissza." })
3560
- ] }),
3561
- /* @__PURE__ */ jsx(Button, { variant: "secondary", isLoading: loading, onClick: () => void load(), children: "Újraellenőrzés" })
3562
- ] }),
3563
- report ? /* @__PURE__ */ jsxs(Fragment, { children: [
3564
- /* @__PURE__ */ jsxs("div", { className: "grid gap-3 border-b p-6 sm:grid-cols-2 lg:grid-cols-4", children: [
3565
- /* @__PURE__ */ jsx(Summary, { label: "Kész", value: report.score.ready, tone: "ready" }),
3566
- /* @__PURE__ */ jsx(Summary, { label: "Figyelmeztetés", value: report.score.warning, tone: "warning" }),
3567
- /* @__PURE__ */ jsx(Summary, { label: "Blokkoló", value: report.score.blocked, tone: "blocked" }),
3568
- /* @__PURE__ */ jsxs("div", { className: "rounded-lg border p-4", children: [
3569
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Élesítési döntés" }),
3570
- /* @__PURE__ */ jsx("div", { className: report.ready ? "mt-1 text-xl font-semibold text-ui-fg-success" : "mt-1 text-xl font-semibold text-ui-fg-error", children: report.ready ? "Élesíthető" : "Még nem élesíthető" }),
3571
- /* @__PURE__ */ jsx(Text, { size: "small", className: "mt-1 text-ui-fg-subtle", children: report.environment === "production" ? "Production szabályok" : "Nem-production szabályok" })
3572
- ] })
3573
- ] }),
3574
- /* @__PURE__ */ jsx("div", { className: "border-b px-6 py-3", children: /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
3575
- "Utolsó ellenőrzés: ",
3576
- formatDate$2(report.generated_at),
3577
- ". A sárga elemek nem blokkolják az élesítést, a piros elemek igen."
3578
- ] }) }),
3579
- /* @__PURE__ */ jsx("div", { className: "space-y-6 p-6", children: groups.map(([category, checks]) => /* @__PURE__ */ jsxs("section", { className: "overflow-hidden rounded-lg border", children: [
3580
- /* @__PURE__ */ jsx("div", { className: "border-b bg-ui-bg-subtle px-4 py-3", children: /* @__PURE__ */ jsx(Heading, { level: "h2", children: CATEGORY_LABELS[category] || category }) }),
3581
- /* @__PURE__ */ jsx("div", { className: "divide-y", children: checks.map((item) => /* @__PURE__ */ jsxs("div", { className: "grid gap-3 p-4 md:grid-cols-[180px_140px_minmax(0,1fr)_auto] md:items-center", children: [
3582
- /* @__PURE__ */ jsx("strong", { children: item.label }),
3583
- /* @__PURE__ */ jsx(StatusBadge, { status: item.status }),
3584
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: item.message }),
3585
- item.action_href && item.action_label ? /* @__PURE__ */ jsx("a", { href: normalizeAdminHref(item.action_href), children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: item.action_label }) }) : /* @__PURE__ */ jsx("span", {})
3586
- ] }, item.key)) })
3587
- ] }, category)) })
3588
- ] }) : null,
3589
- loading && !report ? /* @__PURE__ */ jsx("div", { className: "p-8 text-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Élesítési feltételek ellenőrzése…" }) }) : null,
3590
- error ? /* @__PURE__ */ jsxs("div", { className: "m-6 rounded-lg border border-ui-border-error p-4", children: [
3591
- /* @__PURE__ */ jsx(Text, { className: "font-medium text-ui-fg-error", children: "Az ellenőrzés nem futott le." }),
3592
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: error })
3593
- ] }) : null
3594
- ] });
3595
- };
3596
- function StatusBadge({ status }) {
3597
- const label = status === "ready" ? "Kész" : status === "warning" ? "Figyelmeztetés" : "Blokkoló";
3598
- const className = status === "ready" ? "font-medium text-ui-fg-success" : status === "warning" ? "font-medium text-ui-fg-warning" : "font-medium text-ui-fg-error";
3599
- return /* @__PURE__ */ jsxs("span", { className, children: [
3600
- status === "ready" ? "✅" : status === "warning" ? "🟡" : "🔴",
3601
- " ",
3602
- label
3603
- ] });
3604
- }
3605
- function Summary({ label, value, tone }) {
3606
- const valueClass = tone === "ready" ? "text-ui-fg-success" : tone === "warning" ? "text-ui-fg-warning" : "text-ui-fg-error";
3540
+ danger = false
3541
+ }) {
3607
3542
  return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border p-4", children: [
3608
3543
  /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: label }),
3609
- /* @__PURE__ */ jsx("div", { className: `mt-1 text-3xl font-semibold ${valueClass}`, children: value })
3544
+ /* @__PURE__ */ jsx("div", { className: danger ? "text-ui-fg-error text-2xl font-semibold" : "text-2xl font-semibold", children: value })
3610
3545
  ] });
3611
3546
  }
3612
- function normalizeAdminHref(path) {
3613
- if (!path.startsWith("/app")) return path;
3614
- return `${adminBase$2}${path.slice(4)}`;
3615
- }
3616
3547
  function formatDate$2(value) {
3617
3548
  const date = new Date(value);
3618
3549
  if (Number.isNaN(date.getTime())) return "—";
3619
- return new Intl.DateTimeFormat("hu-HU", { dateStyle: "short", timeStyle: "medium" }).format(date);
3550
+ return new Intl.DateTimeFormat("hu-HU", {
3551
+ dateStyle: "short",
3552
+ timeStyle: "short"
3553
+ }).format(date);
3620
3554
  }
3621
- const config$3 = defineRouteConfig({
3622
- label: "Production readiness",
3623
- rank: 39
3555
+ const config$4 = defineRouteConfig({
3556
+ label: "Integrációk állapota",
3557
+ icon: Newspaper,
3558
+ rank: 38
3624
3559
  });
3625
- const backendUrl$3 = (__BACKEND_URL__ || "").replace(/\/+$/, "");
3626
- function apiUrl$3(path) {
3627
- return `${backendUrl$3}${path.startsWith("/") ? path : `/${path}`}`;
3628
- }
3629
- const CoreAuditPage = () => {
3630
- const [logs, setLogs] = useState([]);
3631
- const [count, setCount] = useState(0);
3632
- const [integration, setIntegration] = useState("all");
3633
- const [status, setStatus] = useState("all");
3634
- const [query, setQuery] = useState("");
3560
+ const defaults = {
3561
+ GOOGLE_MERCHANT_COUNTRY_CODE: "HU",
3562
+ GOOGLE_MERCHANT_CURRENCY_CODE: "HUF",
3563
+ GOOGLE_MERCHANT_STOREFRONT_URL: "",
3564
+ GOOGLE_MERCHANT_PRODUCT_PATH_TEMPLATE: "/{country_code}/products/{handle}?v_id={variant_id}",
3565
+ GOOGLE_MERCHANT_SALES_CHANNEL_ID: "",
3566
+ GOOGLE_MERCHANT_DEFAULT_BRAND: "",
3567
+ GOOGLE_MERCHANT_DEFAULT_CONDITION: "new",
3568
+ GOOGLE_MERCHANT_INCLUDE_OUT_OF_STOCK: true,
3569
+ GOOGLE_MERCHANT_FEED_TITLE: "",
3570
+ GOOGLE_MERCHANT_FEED_DESCRIPTION: ""
3571
+ };
3572
+ const backendUrl$4 = (__BACKEND_URL__ || "").replace(/\/+$/, "");
3573
+ const apiUrl$4 = (path) => `${backendUrl$4}${path.startsWith("/") ? path : `/${path}`}`;
3574
+ const GoogleMerchantPage = () => {
3575
+ const [enabled, setEnabled] = useState(false);
3576
+ const [draft, setDraft] = useState(defaults);
3635
3577
  const [loading, setLoading] = useState(true);
3636
- const [loadError, setLoadError] = useState(null);
3578
+ const [saving, setSaving] = useState(false);
3579
+ const [previewing, setPreviewing] = useState(false);
3580
+ const [preview, setPreview] = useState(null);
3581
+ const update = (key, value) => {
3582
+ setDraft((current) => ({ ...current, [key]: value }));
3583
+ };
3637
3584
  const load = useCallback(async () => {
3638
3585
  setLoading(true);
3639
- setLoadError(null);
3640
3586
  try {
3641
- const params = new URLSearchParams({ limit: "100" });
3642
- if (integration !== "all") params.set("integration", integration);
3643
- if (status !== "all") params.set("status", status);
3644
- const response = await fetch(
3645
- apiUrl$3(`/admin/core-audit?${params.toString()}`),
3646
- { credentials: "include" }
3647
- );
3648
- const payload = await response.json().catch(() => ({}));
3649
- if (!response.ok) {
3650
- throw new Error(payload.message || "Az audit napló nem tölthető be.");
3587
+ const response = await fetch(apiUrl$4("/admin/integrations/google-merchant"), {
3588
+ credentials: "include"
3589
+ });
3590
+ const data = await response.json().catch(() => ({}));
3591
+ if (!response.ok || !data.integration) {
3592
+ throw new Error(data.message || "A Google Merchant beállítások nem tölthetők be.");
3651
3593
  }
3652
- setLogs(payload.logs || []);
3653
- setCount(payload.count || 0);
3594
+ const values = data.integration.values || {};
3595
+ setEnabled(Boolean(data.integration.enabled));
3596
+ setDraft({
3597
+ GOOGLE_MERCHANT_COUNTRY_CODE: values.GOOGLE_MERCHANT_COUNTRY_CODE || "HU",
3598
+ GOOGLE_MERCHANT_CURRENCY_CODE: values.GOOGLE_MERCHANT_CURRENCY_CODE || "HUF",
3599
+ GOOGLE_MERCHANT_STOREFRONT_URL: values.GOOGLE_MERCHANT_STOREFRONT_URL || "",
3600
+ GOOGLE_MERCHANT_PRODUCT_PATH_TEMPLATE: values.GOOGLE_MERCHANT_PRODUCT_PATH_TEMPLATE || "/{country_code}/products/{handle}?v_id={variant_id}",
3601
+ GOOGLE_MERCHANT_SALES_CHANNEL_ID: values.GOOGLE_MERCHANT_SALES_CHANNEL_ID || "",
3602
+ GOOGLE_MERCHANT_DEFAULT_BRAND: values.GOOGLE_MERCHANT_DEFAULT_BRAND || "",
3603
+ GOOGLE_MERCHANT_DEFAULT_CONDITION: values.GOOGLE_MERCHANT_DEFAULT_CONDITION || "new",
3604
+ GOOGLE_MERCHANT_INCLUDE_OUT_OF_STOCK: values.GOOGLE_MERCHANT_INCLUDE_OUT_OF_STOCK !== "false",
3605
+ GOOGLE_MERCHANT_FEED_TITLE: values.GOOGLE_MERCHANT_FEED_TITLE || "",
3606
+ GOOGLE_MERCHANT_FEED_DESCRIPTION: values.GOOGLE_MERCHANT_FEED_DESCRIPTION || ""
3607
+ });
3654
3608
  } catch (error) {
3655
- setLogs([]);
3656
- setLoadError(
3657
- error instanceof Error ? error.message : "Az audit napló nem tölthető be."
3658
- );
3609
+ toast.error(error instanceof Error ? error.message : "Betöltési hiba.");
3659
3610
  } finally {
3660
3611
  setLoading(false);
3661
3612
  }
3662
- }, [integration, status]);
3613
+ }, []);
3663
3614
  useEffect(() => {
3664
3615
  void load();
3665
3616
  }, [load]);
3666
- const visible = useMemo(() => {
3667
- const value = query.trim().toLowerCase();
3668
- if (!value) return logs;
3669
- return logs.filter(
3670
- (log) => [
3671
- log.action,
3672
- log.resource_type,
3673
- log.resource_id,
3674
- log.integration,
3675
- log.actor_id,
3676
- log.summary
3677
- ].some((item) => String(item || "").toLowerCase().includes(value))
3678
- );
3679
- }, [logs, query]);
3617
+ const save = async () => {
3618
+ setSaving(true);
3619
+ try {
3620
+ const response = await fetch(apiUrl$4("/admin/integrations/google-merchant"), {
3621
+ method: "POST",
3622
+ credentials: "include",
3623
+ headers: { "Content-Type": "application/json" },
3624
+ body: JSON.stringify({ enabled, values: draft })
3625
+ });
3626
+ const data = await response.json().catch(() => ({}));
3627
+ if (!response.ok) throw new Error(data.message || "A mentés nem sikerült.");
3628
+ toast.success(data.message || "Google Merchant beállítások mentve.");
3629
+ setPreview(null);
3630
+ await load();
3631
+ } catch (error) {
3632
+ toast.error(error instanceof Error ? error.message : "A mentés nem sikerült.");
3633
+ } finally {
3634
+ setSaving(false);
3635
+ }
3636
+ };
3637
+ const runPreview = async () => {
3638
+ setPreviewing(true);
3639
+ try {
3640
+ const response = await fetch(apiUrl$4("/admin/google-merchant/preview"), {
3641
+ credentials: "include"
3642
+ });
3643
+ const data = await response.json().catch(() => ({}));
3644
+ if (!response.ok) throw new Error(data.message || "A feed nem generálható.");
3645
+ setPreview(data);
3646
+ toast.success("A Merchant feed ellenőrzése elkészült.");
3647
+ } catch (error) {
3648
+ toast.error(error instanceof Error ? error.message : "A feed nem generálható.");
3649
+ } finally {
3650
+ setPreviewing(false);
3651
+ }
3652
+ };
3653
+ const feedUrl = apiUrl$4("/feeds/google-merchant.xml");
3654
+ const d = preview?.diagnostics;
3680
3655
  return /* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
3681
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-4 border-b px-6 py-4", children: [
3656
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-4 border-b px-6 py-4", children: [
3682
3657
  /* @__PURE__ */ jsxs("div", { children: [
3683
- /* @__PURE__ */ jsx(Heading, { children: "Core audit napló" }),
3684
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Admin és integrációs műveletek üzleti auditja, titkok mentése nélkül." })
3658
+ /* @__PURE__ */ jsx(Heading, { children: "Google Merchant Center" }),
3659
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Google RSS 2.0 feed a Medusa termék-, variant-, régiós ár-, ÁFA- és készletadataiból." })
3685
3660
  ] }),
3686
- /* @__PURE__ */ jsx(Button, { variant: "secondary", isLoading: loading, onClick: () => void load(), children: "Frissítés" })
3661
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
3662
+ /* @__PURE__ */ jsx(Switch, { checked: enabled, onCheckedChange: setEnabled, disabled: loading }),
3663
+ /* @__PURE__ */ jsx(Text, { children: enabled ? "Bekapcsolva" : "Kikapcsolva" })
3664
+ ] })
3687
3665
  ] }),
3688
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-end gap-3 border-b px-6 py-4", children: [
3689
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
3690
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Integráció" }),
3691
- /* @__PURE__ */ jsxs(Select, { value: integration, onValueChange: setIntegration, children: [
3692
- /* @__PURE__ */ jsx(Select.Trigger, { className: "w-44", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
3693
- /* @__PURE__ */ jsxs(Select.Content, { children: [
3694
- /* @__PURE__ */ jsx(Select.Item, { value: "all", children: "Összes" }),
3695
- [
3696
- "stripe",
3697
- "simplepay",
3698
- "billingo",
3699
- "bank-transfer",
3700
- "foxpost",
3701
- "gls",
3702
- "packeta",
3703
- "dpd",
3704
- "mpl",
3705
- "sendgrid",
3706
- "fogyasztobarat"
3707
- ].map((item) => /* @__PURE__ */ jsx(Select.Item, { value: item, children: item }, item))
3708
- ] })
3709
- ] })
3710
- ] }),
3711
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
3712
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Eredmény" }),
3713
- /* @__PURE__ */ jsxs(Select, { value: status, onValueChange: setStatus, children: [
3714
- /* @__PURE__ */ jsx(Select.Trigger, { className: "w-36", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
3715
- /* @__PURE__ */ jsxs(Select.Content, { children: [
3716
- /* @__PURE__ */ jsx(Select.Item, { value: "all", children: "Összes" }),
3717
- /* @__PURE__ */ jsx(Select.Item, { value: "success", children: "Sikeres" }),
3718
- /* @__PURE__ */ jsx(Select.Item, { value: "error", children: "Hiba" })
3719
- ] })
3666
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-4 border-b px-6 py-5 md:grid-cols-2", children: [
3667
+ /* @__PURE__ */ jsx(Field$1, { label: "Célország", children: /* @__PURE__ */ jsx(Input, { value: draft.GOOGLE_MERCHANT_COUNTRY_CODE, onChange: (e) => update("GOOGLE_MERCHANT_COUNTRY_CODE", e.target.value.toUpperCase()), placeholder: "HU" }) }),
3668
+ /* @__PURE__ */ jsx(Field$1, { label: "Pénznem", children: /* @__PURE__ */ jsx(Input, { value: draft.GOOGLE_MERCHANT_CURRENCY_CODE, onChange: (e) => update("GOOGLE_MERCHANT_CURRENCY_CODE", e.target.value.toUpperCase()), placeholder: "HUF" }) }),
3669
+ /* @__PURE__ */ jsx(Field$1, { label: "Storefront URL", children: /* @__PURE__ */ jsx(Input, { value: draft.GOOGLE_MERCHANT_STOREFRONT_URL, onChange: (e) => update("GOOGLE_MERCHANT_STOREFRONT_URL", e.target.value), placeholder: "https://shop.hu (üresen STOREFRONT_URL)" }) }),
3670
+ /* @__PURE__ */ jsxs(Field$1, { label: "Termék URL sablon", children: [
3671
+ /* @__PURE__ */ jsx(Input, { value: draft.GOOGLE_MERCHANT_PRODUCT_PATH_TEMPLATE, onChange: (e) => update("GOOGLE_MERCHANT_PRODUCT_PATH_TEMPLATE", e.target.value) }),
3672
+ /* @__PURE__ */ jsxs(Text, { className: "text-ui-fg-muted text-xs", children: [
3673
+ "Helyőrzők: ",
3674
+ "{country_code}",
3675
+ ", ",
3676
+ "{currency_code}",
3677
+ ", ",
3678
+ "{handle}",
3679
+ ", ",
3680
+ "{variant_id}",
3681
+ "."
3720
3682
  ] })
3721
3683
  ] }),
3722
- /* @__PURE__ */ jsx(
3723
- Input,
3724
- {
3725
- className: "max-w-sm",
3726
- value: query,
3727
- onChange: (event) => setQuery(event.target.value),
3728
- placeholder: "Keresés művelet, erőforrás, admin vagy leírás alapján"
3729
- }
3730
- ),
3731
- /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
3732
- count,
3733
- " bejegyzés"
3734
- ] })
3684
+ /* @__PURE__ */ jsx(Field$1, { label: "Sales Channel ID", children: /* @__PURE__ */ jsx(Input, { value: draft.GOOGLE_MERCHANT_SALES_CHANNEL_ID, onChange: (e) => update("GOOGLE_MERCHANT_SALES_CHANNEL_ID", e.target.value), placeholder: "sc_... (opcionális)" }) }),
3685
+ /* @__PURE__ */ jsx(Field$1, { label: "Alapértelmezett márka", children: /* @__PURE__ */ jsx(Input, { value: draft.GOOGLE_MERCHANT_DEFAULT_BRAND, onChange: (e) => update("GOOGLE_MERCHANT_DEFAULT_BRAND", e.target.value) }) }),
3686
+ /* @__PURE__ */ jsx(Field$1, { label: "Alapértelmezett állapot", children: /* @__PURE__ */ jsxs("select", { className: "h-8 rounded-md border bg-ui-bg-field px-2 text-sm", value: draft.GOOGLE_MERCHANT_DEFAULT_CONDITION, onChange: (e) => update("GOOGLE_MERCHANT_DEFAULT_CONDITION", e.target.value), children: [
3687
+ /* @__PURE__ */ jsx("option", { value: "new", children: "Új" }),
3688
+ /* @__PURE__ */ jsx("option", { value: "refurbished", children: "Felújított" }),
3689
+ /* @__PURE__ */ jsx("option", { value: "used", children: "Használt" })
3690
+ ] }) }),
3691
+ /* @__PURE__ */ jsx(Field$1, { label: "Készlethiányos variantok", children: /* @__PURE__ */ jsxs("div", { className: "flex h-8 items-center gap-2", children: [
3692
+ /* @__PURE__ */ jsx(Switch, { checked: draft.GOOGLE_MERCHANT_INCLUDE_OUT_OF_STOCK, onCheckedChange: (value) => update("GOOGLE_MERCHANT_INCLUDE_OUT_OF_STOCK", value) }),
3693
+ /* @__PURE__ */ jsx(Text, { children: draft.GOOGLE_MERCHANT_INCLUDE_OUT_OF_STOCK ? "Benne maradnak" : "Kimaradnak" })
3694
+ ] }) }),
3695
+ /* @__PURE__ */ jsx(Field$1, { label: "Feed neve", children: /* @__PURE__ */ jsx(Input, { value: draft.GOOGLE_MERCHANT_FEED_TITLE, onChange: (e) => update("GOOGLE_MERCHANT_FEED_TITLE", e.target.value), placeholder: "Üresen automatikus" }) }),
3696
+ /* @__PURE__ */ jsx(Field$1, { label: "Feed leírása", children: /* @__PURE__ */ jsx(Input, { value: draft.GOOGLE_MERCHANT_FEED_DESCRIPTION, onChange: (e) => update("GOOGLE_MERCHANT_FEED_DESCRIPTION", e.target.value), placeholder: "Üresen automatikus" }) })
3735
3697
  ] }),
3736
- /* @__PURE__ */ jsxs("div", { className: "overflow-x-auto", children: [
3737
- /* @__PURE__ */ jsxs("table", { className: "w-full text-left text-sm", children: [
3738
- /* @__PURE__ */ jsx("thead", { className: "border-b bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
3739
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Idő" }),
3740
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Eredmény" }),
3741
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Művelet" }),
3742
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Erőforrás" }),
3743
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Integráció" }),
3744
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Admin / actor" }),
3745
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Leírás" })
3746
- ] }) }),
3747
- /* @__PURE__ */ jsx("tbody", { children: visible.map((log) => /* @__PURE__ */ jsxs("tr", { className: "border-b align-top", children: [
3748
- /* @__PURE__ */ jsx("td", { className: "whitespace-nowrap p-4", children: formatDate$1(log.created_at) }),
3749
- /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx("span", { className: log.status === "error" ? "font-medium text-ui-fg-error" : "font-medium text-ui-fg-success", children: log.status === "error" ? "Hiba" : "Sikeres" }) }),
3750
- /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx("code", { children: log.action }) }),
3751
- /* @__PURE__ */ jsxs("td", { className: "p-4", children: [
3752
- /* @__PURE__ */ jsx("div", { children: log.resource_type }),
3753
- /* @__PURE__ */ jsx("div", { className: "text-ui-fg-subtle", children: log.resource_id || "—" })
3754
- ] }),
3755
- /* @__PURE__ */ jsx("td", { className: "p-4", children: log.integration || "—" }),
3756
- /* @__PURE__ */ jsx("td", { className: "p-4", children: log.actor_id || "system" }),
3757
- /* @__PURE__ */ jsxs("td", { className: "max-w-xl p-4", children: [
3758
- /* @__PURE__ */ jsx("div", { children: log.summary }),
3759
- log.details && Object.keys(log.details).length ? /* @__PURE__ */ jsx("div", { className: "mt-1 text-ui-fg-subtle", children: Object.entries(log.details).map(([key, value]) => `${key}: ${String(value)}`).join(" · ") }) : null
3760
- ] })
3761
- ] }, log.id)) })
3698
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 border-b px-6 py-4", children: [
3699
+ /* @__PURE__ */ jsxs("div", { children: [
3700
+ /* @__PURE__ */ jsx(Text, { className: "font-medium", children: "Publikus feed URL" }),
3701
+ /* @__PURE__ */ jsx("a", { className: "break-all text-ui-fg-interactive hover:underline", href: feedUrl, target: "_blank", rel: "noreferrer", children: feedUrl })
3702
+ ] }),
3703
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
3704
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", isLoading: previewing, disabled: !enabled || loading || saving || previewing, onClick: () => void runPreview(), children: "Feed ellenőrzése" }),
3705
+ /* @__PURE__ */ jsx(Button, { isLoading: saving, disabled: loading || saving || previewing, onClick: () => void save(), children: "Mentés" })
3706
+ ] })
3707
+ ] }),
3708
+ d ? /* @__PURE__ */ jsxs(Fragment, { children: [
3709
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-3 border-b px-6 py-5 sm:grid-cols-2 lg:grid-cols-4", children: [
3710
+ /* @__PURE__ */ jsx(Stat, { label: "Termékek", value: d.productsScanned }),
3711
+ /* @__PURE__ */ jsx(Stat, { label: "Variantok", value: d.variantsScanned }),
3712
+ /* @__PURE__ */ jsx(Stat, { label: "Feed tételek", value: d.itemsEmitted }),
3713
+ /* @__PURE__ */ jsx(Stat, { label: "Hiányzó identifier", value: d.itemsMissingIdentifiers }),
3714
+ /* @__PURE__ */ jsx(Stat, { label: "Nincs ár", value: d.skippedNoPrice }),
3715
+ /* @__PURE__ */ jsx(Stat, { label: "Nincs kép", value: d.skippedNoImage }),
3716
+ /* @__PURE__ */ jsx(Stat, { label: "Nincs sales channel", value: d.skippedNoSalesChannel + d.skippedNotInSalesChannel }),
3717
+ /* @__PURE__ */ jsx(Stat, { label: "Érvénytelen GTIN", value: d.invalidGtinsIgnored })
3762
3718
  ] }),
3763
- loading ? /* @__PURE__ */ jsx("div", { className: "p-8 text-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Audit napló betöltése…" }) }) : null,
3764
- !loading && loadError ? /* @__PURE__ */ jsxs("div", { className: "m-6 rounded-lg border border-ui-border-error p-4", children: [
3765
- /* @__PURE__ */ jsx(Text, { className: "font-medium text-ui-fg-error", children: "Az audit napló nem tölthető be." }),
3766
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: loadError })
3767
- ] }) : null,
3768
- !loading && !loadError && !visible.length ? /* @__PURE__ */ jsx("div", { className: "p-8 text-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Nincs a szűrésnek megfelelő audit bejegyzés." }) }) : null
3769
- ] })
3719
+ /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-left text-sm", children: [
3720
+ /* @__PURE__ */ jsx("thead", { className: "border-b bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
3721
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "ID" }),
3722
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Termék" }),
3723
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Ár" }),
3724
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Készlet" }),
3725
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Identifier" })
3726
+ ] }) }),
3727
+ /* @__PURE__ */ jsx("tbody", { children: (preview?.sample || []).map((item) => /* @__PURE__ */ jsxs("tr", { className: "border-b", children: [
3728
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx("code", { children: item.id }) }),
3729
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx("a", { href: item.link, target: "_blank", rel: "noreferrer", className: "text-ui-fg-interactive hover:underline", children: item.title }) }),
3730
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: item.salePrice ? `${item.salePrice} (${item.price})` : item.price }),
3731
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: item.availability }),
3732
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: item.gtin || item.mpn || item.brand || "—" })
3733
+ ] }, item.id)) })
3734
+ ] }) })
3735
+ ] }) : null
3770
3736
  ] });
3771
3737
  };
3772
- function formatDate$1(value) {
3773
- if (!value) return "—";
3774
- const date = new Date(value);
3775
- if (Number.isNaN(date.getTime())) return "—";
3776
- return new Intl.DateTimeFormat("hu-HU", {
3777
- dateStyle: "short",
3778
- timeStyle: "short"
3779
- }).format(date);
3738
+ function Field$1({ label, children }) {
3739
+ return /* @__PURE__ */ jsxs("label", { className: "flex min-w-0 flex-col gap-1.5", children: [
3740
+ /* @__PURE__ */ jsx(Text, { className: "font-medium", children: label }),
3741
+ children
3742
+ ] });
3780
3743
  }
3781
- const config$2 = defineRouteConfig({
3782
- label: "Audit napló",
3783
- icon: Newspaper,
3784
- rank: 39
3785
- });
3786
- const backendUrl$2 = (__BACKEND_URL__ || "").replace(/\/+$/, "");
3787
- const adminBase$1 = (__BASE__ || "/app").replace(/\/+$/, "");
3788
- function apiUrl$2(path) {
3789
- return `${backendUrl$2}${path.startsWith("/") ? path : `/${path}`}`;
3744
+ function Stat({ label, value }) {
3745
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border p-3", children: [
3746
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-xs", children: label }),
3747
+ /* @__PURE__ */ jsx(Text, { className: "font-medium", children: value })
3748
+ ] });
3749
+ }
3750
+ const config$3 = defineRouteConfig({ label: "Google Merchant", rank: 41 });
3751
+ const backendUrl$3 = (__BACKEND_URL__ || "").replace(/\/+$/, "");
3752
+ const adminBase$2 = (__BASE__ || "/app").replace(/\/+$/, "");
3753
+ function apiUrl$3(path) {
3754
+ return `${backendUrl$3}${path.startsWith("/") ? path : `/${path}`}`;
3790
3755
  }
3791
3756
  const IntegrationOperationsPage = () => {
3792
3757
  const [operations, setOperations] = useState([]);
@@ -3812,7 +3777,7 @@ const IntegrationOperationsPage = () => {
3812
3777
  });
3813
3778
  if (provider !== "all") params.set("provider", provider);
3814
3779
  const response = await fetch(
3815
- apiUrl$2(`/admin/integration-operations?${params.toString()}`),
3780
+ apiUrl$3(`/admin/integration-operations?${params.toString()}`),
3816
3781
  { credentials: "include" }
3817
3782
  );
3818
3783
  const payload = await response.json().catch(() => ({}));
@@ -3880,7 +3845,7 @@ const IntegrationOperationsPage = () => {
3880
3845
  setActionLoading(operation.id);
3881
3846
  try {
3882
3847
  const response = await fetch(
3883
- apiUrl$2(`/admin/integration-operations/${operation.id}/reconcile`),
3848
+ apiUrl$3(`/admin/integration-operations/${operation.id}/reconcile`),
3884
3849
  {
3885
3850
  method: "POST",
3886
3851
  credentials: "include",
@@ -4018,7 +3983,7 @@ const IntegrationOperationsPage = () => {
4018
3983
  operation.entity_type === "order" ? /* @__PURE__ */ jsx(
4019
3984
  "a",
4020
3985
  {
4021
- href: `${adminBase$1}/orders/${operation.entity_id}`,
3986
+ href: `${adminBase$2}/orders/${operation.entity_id}`,
4022
3987
  className: "text-ui-fg-interactive",
4023
3988
  children: operation.entity_id
4024
3989
  }
@@ -4029,7 +3994,7 @@ const IntegrationOperationsPage = () => {
4029
3994
  /* @__PURE__ */ jsx("td", { className: "p-4", children: operation.attempts }),
4030
3995
  /* @__PURE__ */ jsxs("td", { className: "max-w-md p-4", children: [
4031
3996
  operation.error_summary ? /* @__PURE__ */ jsx("div", { className: "text-ui-fg-error", children: operation.error_summary }) : null,
4032
- /* @__PURE__ */ jsx("div", { className: "text-ui-fg-subtle", children: formatDate(operation.updated_at) })
3997
+ /* @__PURE__ */ jsx("div", { className: "text-ui-fg-subtle", children: formatDate$1(operation.updated_at) })
4033
3998
  ] }),
4034
3999
  /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx("div", { className: "flex min-w-52 flex-wrap gap-2", children: operation.status === "needs_reconciliation" ? /* @__PURE__ */ jsxs(Fragment, { children: [
4035
4000
  /* @__PURE__ */ jsx(
@@ -4098,7 +4063,7 @@ function providerLabel(value) {
4098
4063
  };
4099
4064
  return labels[value] || value;
4100
4065
  }
4101
- function formatDate(value) {
4066
+ function formatDate$1(value) {
4102
4067
  if (!value) return "—";
4103
4068
  const date = new Date(value);
4104
4069
  if (Number.isNaN(date.getTime())) return "—";
@@ -4107,11 +4072,128 @@ function formatDate(value) {
4107
4072
  timeStyle: "short"
4108
4073
  }).format(date);
4109
4074
  }
4110
- const config$1 = defineRouteConfig({
4075
+ const config$2 = defineRouteConfig({
4111
4076
  label: "Integrációs műveletek",
4112
4077
  icon: Newspaper,
4113
4078
  rank: 37
4114
4079
  });
4080
+ const backendUrl$2 = (__BACKEND_URL__ || "").replace(/\/+$/, "");
4081
+ const adminBase$1 = (__BASE__ || "/app").replace(/\/+$/, "");
4082
+ const apiUrl$2 = (path) => `${backendUrl$2}${path.startsWith("/") ? path : `/${path}`}`;
4083
+ const CATEGORY_LABELS = {
4084
+ infrastructure: "Infrastruktúra",
4085
+ security: "Biztonság",
4086
+ store: "Storefront alapok",
4087
+ commerce: "Kereskedelem",
4088
+ communication: "Kommunikáció",
4089
+ compliance: "Jogi megfelelés",
4090
+ marketing: "Mérés és SEO"
4091
+ };
4092
+ const ProductionReadinessPage = () => {
4093
+ const [report, setReport] = useState(null);
4094
+ const [loading, setLoading] = useState(true);
4095
+ const [error, setError] = useState(null);
4096
+ const load = useCallback(async () => {
4097
+ setLoading(true);
4098
+ setError(null);
4099
+ try {
4100
+ const response = await fetch(apiUrl$2("/admin/production-readiness"), {
4101
+ credentials: "include"
4102
+ });
4103
+ const payload = await response.json().catch(() => ({}));
4104
+ if (!response.ok) {
4105
+ throw new Error(payload.message || "Az élesítési ellenőrzés nem tölthető be.");
4106
+ }
4107
+ setReport(payload);
4108
+ } catch (cause) {
4109
+ setReport(null);
4110
+ setError(
4111
+ cause instanceof Error ? cause.message : "Az élesítési ellenőrzés nem tölthető be."
4112
+ );
4113
+ } finally {
4114
+ setLoading(false);
4115
+ }
4116
+ }, []);
4117
+ useEffect(() => {
4118
+ void load();
4119
+ }, [load]);
4120
+ const groups = useMemo(() => {
4121
+ const result = /* @__PURE__ */ new Map();
4122
+ for (const item of report?.checks || []) {
4123
+ result.set(item.category, [...result.get(item.category) || [], item]);
4124
+ }
4125
+ return Array.from(result.entries());
4126
+ }, [report]);
4127
+ return /* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
4128
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-4 border-b px-6 py-5", children: [
4129
+ /* @__PURE__ */ jsxs("div", { children: [
4130
+ /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Production readiness" }),
4131
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 text-ui-fg-subtle", children: "Élesítés előtti runtime ellenőrzés. A felület státuszokat mutat, secret értéket nem ad vissza." })
4132
+ ] }),
4133
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", isLoading: loading, onClick: () => void load(), children: "Újraellenőrzés" })
4134
+ ] }),
4135
+ report ? /* @__PURE__ */ jsxs(Fragment, { children: [
4136
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-3 border-b p-6 sm:grid-cols-2 lg:grid-cols-4", children: [
4137
+ /* @__PURE__ */ jsx(Summary, { label: "Kész", value: report.score.ready, tone: "ready" }),
4138
+ /* @__PURE__ */ jsx(Summary, { label: "Figyelmeztetés", value: report.score.warning, tone: "warning" }),
4139
+ /* @__PURE__ */ jsx(Summary, { label: "Blokkoló", value: report.score.blocked, tone: "blocked" }),
4140
+ /* @__PURE__ */ jsxs("div", { className: "rounded-lg border p-4", children: [
4141
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Élesítési döntés" }),
4142
+ /* @__PURE__ */ jsx("div", { className: report.ready ? "mt-1 text-xl font-semibold text-ui-fg-success" : "mt-1 text-xl font-semibold text-ui-fg-error", children: report.ready ? "Élesíthető" : "Még nem élesíthető" }),
4143
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "mt-1 text-ui-fg-subtle", children: report.environment === "production" ? "Production szabályok" : "Nem-production szabályok" })
4144
+ ] })
4145
+ ] }),
4146
+ /* @__PURE__ */ jsx("div", { className: "border-b px-6 py-3", children: /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
4147
+ "Utolsó ellenőrzés: ",
4148
+ formatDate(report.generated_at),
4149
+ ". A sárga elemek nem blokkolják az élesítést, a piros elemek igen."
4150
+ ] }) }),
4151
+ /* @__PURE__ */ jsx("div", { className: "space-y-6 p-6", children: groups.map(([category, checks]) => /* @__PURE__ */ jsxs("section", { className: "overflow-hidden rounded-lg border", children: [
4152
+ /* @__PURE__ */ jsx("div", { className: "border-b bg-ui-bg-subtle px-4 py-3", children: /* @__PURE__ */ jsx(Heading, { level: "h2", children: CATEGORY_LABELS[category] || category }) }),
4153
+ /* @__PURE__ */ jsx("div", { className: "divide-y", children: checks.map((item) => /* @__PURE__ */ jsxs("div", { className: "grid gap-3 p-4 md:grid-cols-[180px_140px_minmax(0,1fr)_auto] md:items-center", children: [
4154
+ /* @__PURE__ */ jsx("strong", { children: item.label }),
4155
+ /* @__PURE__ */ jsx(StatusBadge, { status: item.status }),
4156
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: item.message }),
4157
+ item.action_href && item.action_label ? /* @__PURE__ */ jsx("a", { href: normalizeAdminHref(item.action_href), children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: item.action_label }) }) : /* @__PURE__ */ jsx("span", {})
4158
+ ] }, item.key)) })
4159
+ ] }, category)) })
4160
+ ] }) : null,
4161
+ loading && !report ? /* @__PURE__ */ jsx("div", { className: "p-8 text-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Élesítési feltételek ellenőrzése…" }) }) : null,
4162
+ error ? /* @__PURE__ */ jsxs("div", { className: "m-6 rounded-lg border border-ui-border-error p-4", children: [
4163
+ /* @__PURE__ */ jsx(Text, { className: "font-medium text-ui-fg-error", children: "Az ellenőrzés nem futott le." }),
4164
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: error })
4165
+ ] }) : null
4166
+ ] });
4167
+ };
4168
+ function StatusBadge({ status }) {
4169
+ const label = status === "ready" ? "Kész" : status === "warning" ? "Figyelmeztetés" : "Blokkoló";
4170
+ const className = status === "ready" ? "font-medium text-ui-fg-success" : status === "warning" ? "font-medium text-ui-fg-warning" : "font-medium text-ui-fg-error";
4171
+ return /* @__PURE__ */ jsxs("span", { className, children: [
4172
+ status === "ready" ? "✅" : status === "warning" ? "🟡" : "🔴",
4173
+ " ",
4174
+ label
4175
+ ] });
4176
+ }
4177
+ function Summary({ label, value, tone }) {
4178
+ const valueClass = tone === "ready" ? "text-ui-fg-success" : tone === "warning" ? "text-ui-fg-warning" : "text-ui-fg-error";
4179
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border p-4", children: [
4180
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: label }),
4181
+ /* @__PURE__ */ jsx("div", { className: `mt-1 text-3xl font-semibold ${valueClass}`, children: value })
4182
+ ] });
4183
+ }
4184
+ function normalizeAdminHref(path) {
4185
+ if (!path.startsWith("/app")) return path;
4186
+ return `${adminBase$1}${path.slice(4)}`;
4187
+ }
4188
+ function formatDate(value) {
4189
+ const date = new Date(value);
4190
+ if (Number.isNaN(date.getTime())) return "—";
4191
+ return new Intl.DateTimeFormat("hu-HU", { dateStyle: "short", timeStyle: "medium" }).format(date);
4192
+ }
4193
+ const config$1 = defineRouteConfig({
4194
+ label: "Production readiness",
4195
+ rank: 39
4196
+ });
4115
4197
  const backendUrl$1 = (__BACKEND_URL__ || "").replace(/\/+$/, "");
4116
4198
  const adminBase = (__BASE__ || "/app").replace(/\/+$/, "");
4117
4199
  const apiUrl$1 = (path) => `${backendUrl$1}${path.startsWith("/") ? path : `/${path}`}`;
@@ -4281,7 +4363,7 @@ const IntegrationsPage = () => {
4281
4363
  return /* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
4282
4364
  /* @__PURE__ */ jsxs("div", { className: "border-b px-6 py-5", children: [
4283
4365
  /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Integrációk" }),
4284
- /* @__PURE__ */ jsx(Text, { className: "mt-1 text-ui-fg-subtle", children: "Külső szolgáltatások és provider kapcsolatok központi beállítása. A secret értékek nem kerülnek vissza a böngészőbe, a provider-hozzárendelés pedig továbbra is a Medusa natív felületein történik." })
4366
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 text-ui-fg-subtle", children: "Külső szolgáltatások és provider kapcsolatok központi beállítása. A secret értékek nem kerülnek vissza a böngészőbe, a provider-hozzárendelés pedig továbbra is a HSZRDM Commerce Admin natív felületein történik." })
4285
4367
  ] }),
4286
4368
  loading ? /* @__PURE__ */ jsx("div", { className: "p-6", children: /* @__PURE__ */ jsx(Text, { children: "Betöltés…" }) }) : /* @__PURE__ */ jsxs("div", { className: "grid lg:grid-cols-[320px_minmax(0,1fr)]", children: [
4287
4369
  /* @__PURE__ */ jsx("aside", { className: "border-r p-4", children: CATEGORY_ORDER.map((category) => {
@@ -4336,10 +4418,10 @@ const IntegrationsPage = () => {
4336
4418
  /* @__PURE__ */ jsx(StatusBox, { label: "Aktív", value: selected.enabled ? "Igen" : "Nem", state: selected.enabled ? "success" : "neutral" }),
4337
4419
  /* @__PURE__ */ jsx(StatusBox, { label: "Kapcsolat", value: connection.label, state: connection.state })
4338
4420
  ] }),
4339
- selected.category === "shipping" ? /* @__PURE__ */ jsx(Notice, { title: "Medusa provider hozzárendelés", children: "Mentés és backend restart után a providert a Medusa Settings → Locations & Shipping alatt rendeld locationhöz." }) : null,
4421
+ selected.category === "shipping" ? /* @__PURE__ */ jsx(Notice, { title: "HSZRDM Commerce provider hozzárendelés", children: "Mentés és backend restart után a providert a HSZRDM Commerce Admin Settings → Locations & Shipping alatt rendeld locationhöz." }) : null,
4340
4422
  selected.category === "legal" ? /* @__PURE__ */ jsx(Notice, { title: "Fogyasztó Barát EMBED", children: "Ez csak az opcionális Fogyasztó Barát embed konfigurációja. A PDF-ek és checkout elfogadások a főoldali Jogi dokumentumok menüpontban kezelhetők." }) : null,
4341
4423
  selected.category === "marketing" ? /* @__PURE__ */ jsx(Notice, { title: "Marketing feed", children: "Itt az integráció alapbeállításait módosítod. A feed előnézet, diagnosztika és publikus URL a főoldali Marketing menüpontban található." }) : null,
4342
- restartNotice ? /* @__PURE__ */ jsx(Notice, { title: "Újraindítás szükséges", children: "A beállítások elmentve. Indítsd újra a Medusa backendet az új provider-konfiguráció betöltéséhez." }) : null,
4424
+ restartNotice ? /* @__PURE__ */ jsx(Notice, { title: "Újraindítás szükséges", children: "A beállítások elmentve. Indítsd újra a HSZRDM Commerce backendet az új provider-konfiguráció betöltéséhez." }) : null,
4343
4425
  /* @__PURE__ */ jsxs("div", { children: [
4344
4426
  /* @__PURE__ */ jsx(Heading, { level: "h3", children: "Beállítások" }),
4345
4427
  /* @__PURE__ */ jsx("div", { className: "mt-4 grid gap-4 sm:grid-cols-2", children: selected.fields.map((field) => /* @__PURE__ */ jsx(
@@ -4819,28 +4901,28 @@ const routeModule = {
4819
4901
  handle: { label: config$c.label, translationNs: config$c.translationNs }
4820
4902
  },
4821
4903
  {
4822
- Component: LegalPage,
4823
- path: "/legal-documents",
4904
+ Component: MarketingPage,
4905
+ path: "/marketing",
4824
4906
  handle: { label: config$b.label, translationNs: config$b.translationNs }
4825
4907
  },
4826
4908
  {
4827
- Component: BillingPage,
4828
- path: "/billing",
4909
+ Component: ShippingPage,
4910
+ path: "/shipping",
4829
4911
  handle: { label: config$a.label, translationNs: config$a.translationNs }
4830
4912
  },
4831
4913
  {
4832
- Component: MarketingPage,
4833
- path: "/marketing",
4914
+ Component: SystemMonitoringPage,
4915
+ path: "/system-monitoring",
4834
4916
  handle: { label: config$9.label, translationNs: config$9.translationNs }
4835
4917
  },
4836
4918
  {
4837
- Component: ShippingPage,
4838
- path: "/shipping",
4919
+ Component: BillingPage,
4920
+ path: "/billing",
4839
4921
  handle: { label: config$8.label, translationNs: config$8.translationNs }
4840
4922
  },
4841
4923
  {
4842
- Component: SystemMonitoringPage,
4843
- path: "/system-monitoring",
4924
+ Component: LegalPage,
4925
+ path: "/legal-documents",
4844
4926
  handle: { label: config$7.label, translationNs: config$7.translationNs }
4845
4927
  },
4846
4928
  {
@@ -4853,8 +4935,8 @@ const routeModule = {
4853
4935
  path: "/marketing/seo"
4854
4936
  },
4855
4937
  {
4856
- Component: GoogleMerchantPage,
4857
- path: "/marketing/google-merchant",
4938
+ Component: CoreAuditPage,
4939
+ path: "/system-monitoring/audit",
4858
4940
  handle: { label: config$5.label, translationNs: config$5.translationNs }
4859
4941
  },
4860
4942
  {
@@ -4863,18 +4945,18 @@ const routeModule = {
4863
4945
  handle: { label: config$4.label, translationNs: config$4.translationNs }
4864
4946
  },
4865
4947
  {
4866
- Component: ProductionReadinessPage,
4867
- path: "/system-monitoring/readiness",
4948
+ Component: GoogleMerchantPage,
4949
+ path: "/marketing/google-merchant",
4868
4950
  handle: { label: config$3.label, translationNs: config$3.translationNs }
4869
4951
  },
4870
4952
  {
4871
- Component: CoreAuditPage,
4872
- path: "/system-monitoring/audit",
4953
+ Component: IntegrationOperationsPage,
4954
+ path: "/system-monitoring/operations",
4873
4955
  handle: { label: config$2.label, translationNs: config$2.translationNs }
4874
4956
  },
4875
4957
  {
4876
- Component: IntegrationOperationsPage,
4877
- path: "/system-monitoring/operations",
4958
+ Component: ProductionReadinessPage,
4959
+ path: "/system-monitoring/readiness",
4878
4960
  handle: { label: config$1.label, translationNs: config$1.translationNs }
4879
4961
  },
4880
4962
  {
@@ -4899,23 +4981,23 @@ const menuItemModule = {
4899
4981
  translationNs: void 0
4900
4982
  },
4901
4983
  {
4902
- label: config$a.label,
4903
- icon: config$a.icon,
4984
+ label: config$8.label,
4985
+ icon: config$8.icon,
4904
4986
  path: "/billing",
4905
4987
  nested: void 0,
4906
4988
  rank: 36,
4907
4989
  translationNs: void 0
4908
4990
  },
4909
4991
  {
4910
- label: config$b.label,
4911
- icon: config$b.icon,
4992
+ label: config$7.label,
4993
+ icon: config$7.icon,
4912
4994
  path: "/legal-documents",
4913
4995
  nested: void 0,
4914
4996
  rank: 40,
4915
4997
  translationNs: void 0
4916
4998
  },
4917
4999
  {
4918
- label: config$9.label,
5000
+ label: config$b.label,
4919
5001
  icon: void 0,
4920
5002
  path: "/marketing",
4921
5003
  nested: void 0,
@@ -4923,15 +5005,15 @@ const menuItemModule = {
4923
5005
  translationNs: void 0
4924
5006
  },
4925
5007
  {
4926
- label: config$8.label,
4927
- icon: config$8.icon,
5008
+ label: config$a.label,
5009
+ icon: config$a.icon,
4928
5010
  path: "/shipping",
4929
5011
  nested: void 0,
4930
5012
  rank: 35,
4931
5013
  translationNs: void 0
4932
5014
  },
4933
5015
  {
4934
- label: config$7.label,
5016
+ label: config$9.label,
4935
5017
  icon: void 0,
4936
5018
  path: "/system-monitoring",
4937
5019
  nested: void 0,
@@ -4939,15 +5021,15 @@ const menuItemModule = {
4939
5021
  translationNs: void 0
4940
5022
  },
4941
5023
  {
4942
- label: config$6.label,
5024
+ label: config.label,
4943
5025
  icon: void 0,
4944
- path: "/marketing/arukereso",
5026
+ path: "/settings/integrations",
4945
5027
  nested: void 0,
4946
- rank: 42,
5028
+ rank: void 0,
4947
5029
  translationNs: void 0
4948
5030
  },
4949
5031
  {
4950
- label: config$5.label,
5032
+ label: config$3.label,
4951
5033
  icon: void 0,
4952
5034
  path: "/marketing/google-merchant",
4953
5035
  nested: void 0,
@@ -4955,16 +5037,16 @@ const menuItemModule = {
4955
5037
  translationNs: void 0
4956
5038
  },
4957
5039
  {
4958
- label: config.label,
5040
+ label: config$6.label,
4959
5041
  icon: void 0,
4960
- path: "/settings/integrations",
5042
+ path: "/marketing/arukereso",
4961
5043
  nested: void 0,
4962
- rank: void 0,
5044
+ rank: 42,
4963
5045
  translationNs: void 0
4964
5046
  },
4965
5047
  {
4966
- label: config$2.label,
4967
- icon: config$2.icon,
5048
+ label: config$5.label,
5049
+ icon: config$5.icon,
4968
5050
  path: "/system-monitoring/audit",
4969
5051
  nested: void 0,
4970
5052
  rank: 39,
@@ -4979,15 +5061,15 @@ const menuItemModule = {
4979
5061
  translationNs: void 0
4980
5062
  },
4981
5063
  {
4982
- label: config$1.label,
4983
- icon: config$1.icon,
5064
+ label: config$2.label,
5065
+ icon: config$2.icon,
4984
5066
  path: "/system-monitoring/operations",
4985
5067
  nested: void 0,
4986
5068
  rank: 37,
4987
5069
  translationNs: void 0
4988
5070
  },
4989
5071
  {
4990
- label: config$3.label,
5072
+ label: config$1.label,
4991
5073
  icon: void 0,
4992
5074
  path: "/system-monitoring/readiness",
4993
5075
  nested: void 0,