@hszrdm/core 1.0.1 → 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.
@@ -1770,283 +1770,400 @@ const SystemMonitoringPage = () => /* @__PURE__ */ jsxs(Container, { className:
1770
1770
  ] }, item.href)) })
1771
1771
  ] });
1772
1772
  const config$9 = defineRouteConfig({ label: "Rendszerfelügyelet" });
1773
- const defaults$1 = {
1774
- ARUKERESO_STOREFRONT_URL: "",
1775
- ARUKERESO_PRODUCT_PATH_TEMPLATE: "/{country_code}/products/{handle}?v_id={variant_id}",
1776
- ARUKERESO_SALES_CHANNEL_ID: "",
1777
- ARUKERESO_DEFAULT_MANUFACTURER: "",
1778
- ARUKERESO_USE_SKU_AS_PRODUCT_NUMBER: false,
1779
- ARUKERESO_INCLUDE_OUT_OF_STOCK: true,
1780
- ARUKERESO_DEFAULT_DELIVERY_TIME: "",
1781
- ARUKERESO_DEFAULT_DELIVERY_COST: ""
1782
- };
1783
1773
  const backendUrl$a = (__BACKEND_URL__ || "").replace(/\/+$/, "");
1784
- const apiUrl$a = (path) => `${backendUrl$a}${path.startsWith("/") ? path : `/${path}`}`;
1785
- const ArukeresoPage = () => {
1786
- const [enabled, setEnabled] = useState(false);
1787
- const [draft, setDraft] = useState(defaults$1);
1788
- const [loading, setLoading] = useState(true);
1789
- const [saving, setSaving] = useState(false);
1790
- const [previewing, setPreviewing] = useState(false);
1791
- const [preview, setPreview] = useState(null);
1792
- const update = (key, value) => {
1793
- setDraft((current) => ({ ...current, [key]: value }));
1794
- };
1774
+ const adminBase$5 = (__BASE__ || "/app").replace(/\/+$/, "");
1775
+ function apiUrl$a(path) {
1776
+ return `${backendUrl$a}${path.startsWith("/") ? path : `/${path}`}`;
1777
+ }
1778
+ const BillingPage = () => {
1779
+ const [orders, setOrders] = useState([]);
1780
+ const [configuration, setConfiguration] = useState(null);
1781
+ const [selected, setSelected] = useState([]);
1782
+ const [query, setQuery] = useState("");
1783
+ const [loading, setLoading] = useState(null);
1784
+ const [listLoading, setListLoading] = useState(true);
1785
+ const [loadError, setLoadError] = useState(null);
1795
1786
  const load = useCallback(async () => {
1796
- setLoading(true);
1787
+ setListLoading(true);
1788
+ setLoadError(null);
1797
1789
  try {
1798
- const response = await fetch(apiUrl$a("/admin/integrations/arukereso"), {
1790
+ const response = await fetch(apiUrl$a("/admin/billingo/orders"), {
1799
1791
  credentials: "include"
1800
1792
  });
1801
- const data = await response.json().catch(() => ({}));
1802
- if (!response.ok || !data.integration) {
1803
- throw new Error(data.message || "Az Árukereső beállítások nem tölthetők be.");
1793
+ const payload = await response.json().catch(() => ({}));
1794
+ if (!response.ok) {
1795
+ throw new Error(payload.message || "A számlázási lista nem tölthető be.");
1804
1796
  }
1805
- const values = data.integration.values || {};
1806
- setEnabled(Boolean(data.integration.enabled));
1807
- setDraft({
1808
- ARUKERESO_STOREFRONT_URL: values.ARUKERESO_STOREFRONT_URL || "",
1809
- ARUKERESO_PRODUCT_PATH_TEMPLATE: values.ARUKERESO_PRODUCT_PATH_TEMPLATE || "/{country_code}/products/{handle}?v_id={variant_id}",
1810
- ARUKERESO_SALES_CHANNEL_ID: values.ARUKERESO_SALES_CHANNEL_ID || "",
1811
- ARUKERESO_DEFAULT_MANUFACTURER: values.ARUKERESO_DEFAULT_MANUFACTURER || "",
1812
- ARUKERESO_USE_SKU_AS_PRODUCT_NUMBER: values.ARUKERESO_USE_SKU_AS_PRODUCT_NUMBER === "true",
1813
- ARUKERESO_INCLUDE_OUT_OF_STOCK: values.ARUKERESO_INCLUDE_OUT_OF_STOCK !== "false",
1814
- ARUKERESO_DEFAULT_DELIVERY_TIME: values.ARUKERESO_DEFAULT_DELIVERY_TIME || "",
1815
- ARUKERESO_DEFAULT_DELIVERY_COST: values.ARUKERESO_DEFAULT_DELIVERY_COST || ""
1816
- });
1797
+ const nextOrders = payload.orders || [];
1798
+ setOrders(nextOrders);
1799
+ setConfiguration(payload.configuration || null);
1800
+ setSelected(
1801
+ (current) => current.filter((id) => nextOrders.some((order) => order.id === id))
1802
+ );
1817
1803
  } catch (error) {
1818
- toast.error(error instanceof Error ? error.message : "Betöltési hiba.");
1804
+ setOrders([]);
1805
+ setLoadError(
1806
+ error instanceof Error ? error.message : "A számlázási lista nem tölthető be."
1807
+ );
1819
1808
  } finally {
1820
- setLoading(false);
1809
+ setListLoading(false);
1821
1810
  }
1822
1811
  }, []);
1823
1812
  useEffect(() => {
1824
1813
  void load();
1825
1814
  }, [load]);
1826
- const save = async () => {
1827
- setSaving(true);
1815
+ const visible = useMemo(() => {
1816
+ const value = query.trim().toLowerCase();
1817
+ if (!value) return orders;
1818
+ return orders.filter(
1819
+ (order) => [
1820
+ order.display_id,
1821
+ order.email,
1822
+ order.invoice?.invoiceNumber,
1823
+ order.invoice?.modificationInvoiceNumber
1824
+ ].some(
1825
+ (item) => String(item || "").toLowerCase().includes(value)
1826
+ )
1827
+ );
1828
+ }, [orders, query]);
1829
+ const selectedSet = useMemo(() => new Set(selected), [selected]);
1830
+ const toggle = (id) => {
1831
+ setSelected(
1832
+ (current) => current.includes(id) ? current.filter((item) => item !== id) : [...current, id]
1833
+ );
1834
+ };
1835
+ const bulkCreate = async () => {
1836
+ if (!selected.length) {
1837
+ toast.error("Jelölj ki legalább egy rendelést.");
1838
+ return;
1839
+ }
1840
+ setLoading("bulk");
1828
1841
  try {
1829
- const response = await fetch(apiUrl$a("/admin/integrations/arukereso"), {
1842
+ const response = await fetch(apiUrl$a("/admin/billingo/bulk/create"), {
1830
1843
  method: "POST",
1831
1844
  credentials: "include",
1832
1845
  headers: { "Content-Type": "application/json" },
1833
- body: JSON.stringify({ enabled, values: draft })
1846
+ body: JSON.stringify({ orderIds: selected })
1834
1847
  });
1835
- const data = await response.json().catch(() => ({}));
1836
- if (!response.ok) throw new Error(data.message || "A mentés nem sikerült.");
1837
- toast.success(data.message || "Árukereső beállítások mentve.");
1838
- setPreview(null);
1848
+ const payload = await response.json().catch(() => ({}));
1849
+ if (!response.ok && response.status !== 207) {
1850
+ throw new Error(payload.message || "A tömeges számlázás nem sikerült.");
1851
+ }
1852
+ const failed = payload.results?.filter((item) => !item.ok).length || 0;
1853
+ const created = payload.results?.filter(
1854
+ (item) => item.ok && !item.alreadyExisted
1855
+ ).length || 0;
1856
+ if (failed) {
1857
+ toast.error(`${failed} számla nem készült el; ${created} sikeres.`);
1858
+ } else {
1859
+ toast.success(`${created} új számla elkészült.`);
1860
+ }
1839
1861
  await load();
1840
1862
  } catch (error) {
1841
- toast.error(error instanceof Error ? error.message : "A mentés nem sikerült.");
1863
+ toast.error(
1864
+ error instanceof Error ? error.message : "A tömeges számlázás nem sikerült."
1865
+ );
1842
1866
  } finally {
1843
- setSaving(false);
1867
+ setLoading(null);
1844
1868
  }
1845
1869
  };
1846
- const runPreview = async () => {
1847
- setPreviewing(true);
1870
+ const action = async (order, value) => {
1871
+ if (value === "cancel" && !confirm(
1872
+ `Biztosan sztornózod a(z) ${order.invoice?.invoiceNumber || order.invoice?.documentId} számlát?`
1873
+ )) {
1874
+ return;
1875
+ }
1876
+ if (value === "modify" && !confirm(
1877
+ `Biztosan teljes jóváíró/módosító bizonylatot készítesz a(z) ${order.invoice?.invoiceNumber || order.invoice?.documentId} számlához? Ez a teljes számla összegét jóváírja.`
1878
+ )) {
1879
+ return;
1880
+ }
1881
+ setLoading(`${order.id}:${value}`);
1882
+ try {
1883
+ const response = await fetch(apiUrl$a(`/admin/orders/${order.id}/billingo`), {
1884
+ method: "POST",
1885
+ credentials: "include",
1886
+ headers: { "Content-Type": "application/json" },
1887
+ body: JSON.stringify({ action: value })
1888
+ });
1889
+ const payload = await response.json().catch(() => ({}));
1890
+ if (!response.ok) {
1891
+ throw new Error(payload.message || "A Billingo művelet nem sikerült.");
1892
+ }
1893
+ const messages = {
1894
+ create: "A számla elkészült.",
1895
+ sync: "A számla frissítve.",
1896
+ send: "A számla elküldve.",
1897
+ cancel: "A számla sztornózva.",
1898
+ modify: "A teljes jóváíró/módosító bizonylat elkészült."
1899
+ };
1900
+ toast.success(messages[value]);
1901
+ if (value === "modify" && payload.sendError) {
1902
+ toast.error(`A jóváírás elkészült, de az e-mail küldése sikertelen: ${payload.sendError}`);
1903
+ }
1904
+ await load();
1905
+ } catch (error) {
1906
+ toast.error(
1907
+ error instanceof Error ? error.message : "A Billingo művelet nem sikerült."
1908
+ );
1909
+ } finally {
1910
+ setLoading(null);
1911
+ }
1912
+ };
1913
+ const testConnection = async () => {
1914
+ setLoading("connection");
1848
1915
  try {
1849
- const response = await fetch(apiUrl$a("/admin/arukereso/preview"), {
1916
+ const response = await fetch(apiUrl$a("/admin/billingo/connection"), {
1917
+ method: "POST",
1850
1918
  credentials: "include"
1851
1919
  });
1852
- const data = await response.json().catch(() => ({}));
1853
- if (!response.ok) throw new Error(data.message || "A feed nem generálható.");
1854
- setPreview(data);
1855
- toast.success("Az Árukereső feed ellenőrzése elkészült.");
1920
+ const payload = await response.json().catch(() => ({}));
1921
+ if (!response.ok) {
1922
+ throw new Error(payload.message || "A Billingo kapcsolat nem működik.");
1923
+ }
1924
+ toast.success(payload.message || "A Billingo kapcsolat működik.");
1856
1925
  } catch (error) {
1857
- toast.error(error instanceof Error ? error.message : "A feed nem generálható.");
1926
+ toast.error(
1927
+ error instanceof Error ? error.message : "A Billingo kapcsolat nem működik."
1928
+ );
1858
1929
  } finally {
1859
- setPreviewing(false);
1930
+ setLoading(null);
1860
1931
  }
1861
1932
  };
1862
- const feedUrl = apiUrl$a("/feeds/arukereso.xml");
1863
- const d = preview?.diagnostics;
1864
1933
  return /* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
1865
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-4 border-b px-6 py-4", children: [
1934
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-4 border-b px-6 py-4", children: [
1866
1935
  /* @__PURE__ */ jsxs("div", { children: [
1867
- /* @__PURE__ */ jsx(Heading, { children: "Árukereső.hu" }),
1868
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Árukereső XML feed a Medusa termék-, variant-, HU/HUF ár-, ÁFA- és készletadataiból." })
1936
+ /* @__PURE__ */ jsx(Heading, { children: "Számlázás" }),
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." }),
1938
+ configuration?.autoInvoice ? /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
1939
+ "Az automatikus számlázás aktív",
1940
+ configuration.autoSend ? ", automatikus e-mail küldéssel" : "",
1941
+ "."
1942
+ ] }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-warning", children: "Az automatikus számlázás ki van kapcsolva." })
1869
1943
  ] }),
1870
- /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
1871
- /* @__PURE__ */ jsx(Switch, { checked: enabled, onCheckedChange: setEnabled, disabled: loading }),
1872
- /* @__PURE__ */ jsx(Text, { children: enabled ? "Bekapcsolva" : "Kikapcsolva" })
1873
- ] })
1874
- ] }),
1875
- /* @__PURE__ */ jsxs("div", { className: "grid gap-4 border-b px-6 py-5 md:grid-cols-2", children: [
1876
- /* @__PURE__ */ jsx(Field$4, { label: "Storefront URL", children: /* @__PURE__ */ jsx(
1877
- Input,
1878
- {
1879
- value: draft.ARUKERESO_STOREFRONT_URL,
1880
- onChange: (e) => update("ARUKERESO_STOREFRONT_URL", e.target.value),
1881
- placeholder: "https://shop.hu (üresen STOREFRONT_URL)"
1882
- }
1883
- ) }),
1884
- /* @__PURE__ */ jsxs(Field$4, { label: "Termék URL sablon", children: [
1944
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1945
+ /* @__PURE__ */ jsxs(Text, { children: [
1946
+ selected.length,
1947
+ " kijelölve"
1948
+ ] }),
1885
1949
  /* @__PURE__ */ jsx(
1886
- Input,
1950
+ Button,
1887
1951
  {
1888
- value: draft.ARUKERESO_PRODUCT_PATH_TEMPLATE,
1889
- onChange: (e) => update("ARUKERESO_PRODUCT_PATH_TEMPLATE", e.target.value)
1952
+ variant: "secondary",
1953
+ isLoading: loading === "connection",
1954
+ onClick: () => void testConnection(),
1955
+ children: "Kapcsolat tesztelése"
1890
1956
  }
1891
- ),
1892
- /* @__PURE__ */ jsxs(Text, { className: "text-ui-fg-muted text-xs", children: [
1893
- "Helyőrzők: ",
1894
- "{country_code}",
1895
- ", ",
1896
- "{currency_code}",
1897
- ", ",
1898
- "{handle}",
1899
- ", ",
1900
- "{variant_id}",
1901
- "."
1902
- ] })
1903
- ] }),
1904
- /* @__PURE__ */ jsx(Field$4, { label: "Sales Channel ID", children: /* @__PURE__ */ jsx(
1957
+ )
1958
+ ] })
1959
+ ] }),
1960
+ configuration && !configuration.configured ? /* @__PURE__ */ jsxs("div", { className: "border-b border-ui-border-error bg-ui-bg-base px-6 py-4", children: [
1961
+ /* @__PURE__ */ jsx(Text, { className: "font-medium text-ui-fg-error", children: "A Billingo még nincs teljesen beállítva." }),
1962
+ /* @__PURE__ */ jsxs(Text, { className: "text-ui-fg-subtle", children: [
1963
+ "Hiányzik: ",
1964
+ [
1965
+ !configuration.apiKey && "API kulcs",
1966
+ !configuration.documentBlockId && "számlatömb azonosító"
1967
+ ].filter(Boolean).join(", "),
1968
+ ". Állítsd be a Settings → Integrációk → Billingo oldalon, majd indítsd újra a backendet."
1969
+ ] })
1970
+ ] }) : null,
1971
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3 border-b px-6 py-4", children: [
1972
+ /* @__PURE__ */ jsx(
1905
1973
  Input,
1906
1974
  {
1907
- value: draft.ARUKERESO_SALES_CHANNEL_ID,
1908
- onChange: (e) => update("ARUKERESO_SALES_CHANNEL_ID", e.target.value),
1909
- placeholder: "sc_... (opcionális)"
1975
+ className: "max-w-sm",
1976
+ value: query,
1977
+ onChange: (event) => setQuery(event.target.value),
1978
+ placeholder: "Rendelés, e-mail vagy számlaszám keresése"
1910
1979
  }
1911
- ) }),
1912
- /* @__PURE__ */ jsx(Field$4, { label: "Alapértelmezett gyártó", children: /* @__PURE__ */ jsx(
1913
- Input,
1914
- {
1915
- value: draft.ARUKERESO_DEFAULT_MANUFACTURER,
1916
- onChange: (e) => update("ARUKERESO_DEFAULT_MANUFACTURER", e.target.value),
1917
- placeholder: "Csak ha minden termékre tényleg igaz"
1918
- }
1919
- ) }),
1920
- /* @__PURE__ */ jsx(Field$4, { label: "SKU mint gyártói cikkszám", children: /* @__PURE__ */ jsxs("div", { className: "flex h-8 items-center gap-2", children: [
1921
- /* @__PURE__ */ jsx(
1922
- Switch,
1923
- {
1924
- checked: draft.ARUKERESO_USE_SKU_AS_PRODUCT_NUMBER,
1925
- onCheckedChange: (value) => update("ARUKERESO_USE_SKU_AS_PRODUCT_NUMBER", value)
1926
- }
1927
- ),
1928
- /* @__PURE__ */ jsx(Text, { children: draft.ARUKERESO_USE_SKU_AS_PRODUCT_NUMBER ? "Igen" : "Nem" })
1929
- ] }) }),
1930
- /* @__PURE__ */ jsx(Field$4, { label: "Készlethiányos termékek", children: /* @__PURE__ */ jsxs("div", { className: "flex h-8 items-center gap-2", children: [
1931
- /* @__PURE__ */ jsx(
1932
- Switch,
1933
- {
1934
- checked: draft.ARUKERESO_INCLUDE_OUT_OF_STOCK,
1935
- onCheckedChange: (value) => update("ARUKERESO_INCLUDE_OUT_OF_STOCK", value)
1936
- }
1937
- ),
1938
- /* @__PURE__ */ jsx(Text, { children: draft.ARUKERESO_INCLUDE_OUT_OF_STOCK ? "DeliveryTime=NO" : "Kimaradnak" })
1939
- ] }) }),
1940
- /* @__PURE__ */ jsx(Field$4, { label: "Alap szállítási idő", children: /* @__PURE__ */ jsx(
1941
- Input,
1980
+ ),
1981
+ /* @__PURE__ */ jsx(
1982
+ Button,
1942
1983
  {
1943
- value: draft.ARUKERESO_DEFAULT_DELIVERY_TIME,
1944
- onChange: (e) => update("ARUKERESO_DEFAULT_DELIVERY_TIME", e.target.value),
1945
- placeholder: "1 vagy 3"
1984
+ disabled: Boolean(loading) || !configuration?.configured,
1985
+ isLoading: loading === "bulk",
1986
+ onClick: () => void bulkCreate(),
1987
+ children: "Kijelöltek számlázása"
1946
1988
  }
1947
- ) }),
1948
- /* @__PURE__ */ jsx(Field$4, { label: "Alap szállítási költség", children: /* @__PURE__ */ jsx(
1949
- Input,
1989
+ ),
1990
+ /* @__PURE__ */ jsx(
1991
+ Button,
1950
1992
  {
1951
- value: draft.ARUKERESO_DEFAULT_DELIVERY_COST,
1952
- onChange: (e) => update("ARUKERESO_DEFAULT_DELIVERY_COST", e.target.value),
1953
- placeholder: "1990 vagy FREE"
1993
+ variant: "secondary",
1994
+ disabled: Boolean(loading),
1995
+ onClick: () => void load(),
1996
+ children: "Frissítés"
1954
1997
  }
1955
- ) })
1956
- ] }),
1957
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 border-b px-6 py-4", children: [
1958
- /* @__PURE__ */ jsxs("div", { children: [
1959
- /* @__PURE__ */ jsx(Text, { className: "font-medium", children: "Publikus feed URL" }),
1960
- /* @__PURE__ */ jsx("a", { className: "break-all text-ui-fg-interactive hover:underline", href: feedUrl, target: "_blank", rel: "noreferrer", children: feedUrl })
1961
- ] }),
1962
- /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
1963
- /* @__PURE__ */ jsx(
1964
- Button,
1965
- {
1966
- variant: "secondary",
1967
- isLoading: previewing,
1968
- disabled: !enabled || loading || saving || previewing,
1969
- onClick: () => void runPreview(),
1970
- children: "Feed ellenőrzése"
1971
- }
1972
- ),
1973
- /* @__PURE__ */ jsx(
1974
- Button,
1975
- {
1976
- isLoading: saving,
1977
- disabled: loading || saving || previewing,
1978
- onClick: () => void save(),
1979
- children: "Mentés"
1980
- }
1981
- )
1982
- ] })
1998
+ )
1983
1999
  ] }),
1984
- d ? /* @__PURE__ */ jsxs(Fragment, { children: [
1985
- /* @__PURE__ */ jsxs("div", { className: "grid gap-3 border-b px-6 py-5 sm:grid-cols-2 lg:grid-cols-4", children: [
1986
- /* @__PURE__ */ jsx(Stat$1, { label: "Termékek", value: d.productsScanned }),
1987
- /* @__PURE__ */ jsx(Stat$1, { label: "Variantok", value: d.variantsScanned }),
1988
- /* @__PURE__ */ jsx(Stat$1, { label: "Feed tételek", value: d.itemsEmitted }),
1989
- /* @__PURE__ */ jsx(Stat$1, { label: "Nincs gyártó", value: d.skippedNoManufacturer }),
1990
- /* @__PURE__ */ jsx(Stat$1, { label: "Nincs kategória", value: d.skippedNoCategory }),
1991
- /* @__PURE__ */ jsx(Stat$1, { label: "Nincs ár", value: d.skippedNoPrice }),
1992
- /* @__PURE__ */ jsx(Stat$1, { label: "Nincs ProductNumber", value: d.itemsMissingProductNumber }),
1993
- /* @__PURE__ */ jsx(Stat$1, { label: "Nincs kép", value: d.itemsMissingImage }),
1994
- /* @__PURE__ */ jsx(Stat$1, { label: "Készlethiány miatt kimaradt", value: d.skippedOutOfStock }),
1995
- /* @__PURE__ */ jsx(Stat$1, { label: "Sales channel hiba", value: d.skippedNoSalesChannel + d.skippedNotInSalesChannel }),
1996
- /* @__PURE__ */ jsx(Stat$1, { label: "Hibás delivery time", value: d.invalidDeliveryTime }),
1997
- /* @__PURE__ */ jsx(Stat$1, { label: "Hibás delivery cost", value: d.invalidDeliveryCost })
1998
- ] }),
1999
- /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-left text-sm", children: [
2000
+ /* @__PURE__ */ jsxs("div", { className: "overflow-x-auto", children: [
2001
+ /* @__PURE__ */ jsxs("table", { className: "w-full text-left text-sm", children: [
2000
2002
  /* @__PURE__ */ jsx("thead", { className: "border-b bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
2001
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Identifier" }),
2002
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Termék" }),
2003
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Gyártó" }),
2004
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Kategória" }),
2005
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Bruttó / nettó" }),
2006
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Szállítás" })
2003
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: /* @__PURE__ */ jsx(
2004
+ Checkbox,
2005
+ {
2006
+ checked: visible.length > 0 && visible.every((order) => selectedSet.has(order.id)),
2007
+ onCheckedChange: () => setSelected(
2008
+ visible.every((order) => selectedSet.has(order.id)) ? selected.filter(
2009
+ (id) => !visible.some((order) => order.id === id)
2010
+ ) : [
2011
+ .../* @__PURE__ */ new Set([
2012
+ ...selected,
2013
+ ...visible.map((order) => order.id)
2014
+ ])
2015
+ ]
2016
+ )
2017
+ }
2018
+ ) }),
2019
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Rendelés" }),
2020
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Fizetés" }),
2021
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Számla" }),
2022
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Billingo státusz" }),
2023
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Műveletek" })
2007
2024
  ] }) }),
2008
- /* @__PURE__ */ jsx("tbody", { children: (preview?.sample || []).map((item) => /* @__PURE__ */ jsxs("tr", { className: "border-b", children: [
2009
- /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx("code", { children: item.identifier }) }),
2010
- /* @__PURE__ */ jsxs("td", { className: "p-4", children: [
2011
- /* @__PURE__ */ jsx("a", { href: item.productUrl, target: "_blank", rel: "noreferrer", className: "text-ui-fg-interactive hover:underline", children: item.name }),
2012
- item.productNumber ? /* @__PURE__ */ jsxs("div", { className: "text-ui-fg-muted text-xs", children: [
2013
- "PN: ",
2014
- item.productNumber
2015
- ] }) : null
2016
- ] }),
2017
- /* @__PURE__ */ jsx("td", { className: "p-4", children: item.manufacturer }),
2018
- /* @__PURE__ */ jsx("td", { className: "p-4", children: item.category }),
2019
- /* @__PURE__ */ jsxs("td", { className: "p-4", children: [
2020
- item.price,
2021
- " / ",
2022
- item.netPrice,
2023
- " HUF"
2024
- ] }),
2025
- /* @__PURE__ */ jsxs("td", { className: "p-4", children: [
2026
- item.deliveryTime || "—",
2027
- " · ",
2028
- item.deliveryCost || "—"
2029
- ] })
2030
- ] }, item.identifier)) })
2031
- ] }) })
2032
- ] }) : null
2025
+ /* @__PURE__ */ jsx("tbody", { children: visible.map((order) => {
2026
+ const invoice = order.invoice;
2027
+ const last = order.operations?.at(-1);
2028
+ const modified = Boolean(invoice?.modificationDocumentId);
2029
+ return /* @__PURE__ */ jsxs("tr", { className: "border-b align-top", children: [
2030
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx(
2031
+ Checkbox,
2032
+ {
2033
+ checked: selectedSet.has(order.id),
2034
+ onCheckedChange: () => toggle(order.id)
2035
+ }
2036
+ ) }),
2037
+ /* @__PURE__ */ jsxs("td", { className: "p-4", children: [
2038
+ /* @__PURE__ */ jsxs(
2039
+ "a",
2040
+ {
2041
+ className: "text-ui-fg-interactive",
2042
+ href: `${adminBase$5}/orders/${order.id}`,
2043
+ children: [
2044
+ "#",
2045
+ order.display_id ?? order.id
2046
+ ]
2047
+ }
2048
+ ),
2049
+ /* @__PURE__ */ jsx("div", { className: "text-ui-fg-subtle", children: order.email || "—" }),
2050
+ /* @__PURE__ */ jsx("div", { children: formatMoney(order.total, order.currency_code) })
2051
+ ] }),
2052
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: order.payment_status === "captured" ? "Fizetve" : order.payment_status === "refunded" ? "Visszatérítve" : order.payment_status === "partially_refunded" ? "Részben visszatérítve" : order.payment_status || "—" }),
2053
+ /* @__PURE__ */ jsxs("td", { className: "p-4", children: [
2054
+ /* @__PURE__ */ jsx("strong", { children: invoice?.invoiceNumber || (invoice ? `#${invoice.documentId}` : "Még nincs") }),
2055
+ invoice?.cancelled ? /* @__PURE__ */ jsx("div", { className: "text-ui-fg-error", children: "Sztornózva" }) : null,
2056
+ modified ? /* @__PURE__ */ jsxs("div", { className: "text-ui-fg-interactive", children: [
2057
+ "Jóváírva: ",
2058
+ invoice?.modificationInvoiceNumber || `#${invoice?.modificationDocumentId}`
2059
+ ] }) : null,
2060
+ last?.status === "failed" ? /* @__PURE__ */ jsx("div", { className: "max-w-xs text-ui-fg-error", children: last.message }) : null
2061
+ ] }),
2062
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: invoice ? /* @__PURE__ */ jsxs(Fragment, { children: [
2063
+ /* @__PURE__ */ jsx("div", { children: invoice.paymentStatus || "—" }),
2064
+ /* @__PURE__ */ jsxs("div", { className: "text-ui-fg-subtle", children: [
2065
+ "NAV: ",
2066
+ invoice.onlineSzamlaStatus || "—"
2067
+ ] }),
2068
+ /* @__PURE__ */ jsxs("div", { className: "text-ui-fg-subtle", children: [
2069
+ "E-mail: ",
2070
+ invoice.notificationStatus || "—"
2071
+ ] })
2072
+ ] }) : "—" }),
2073
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx("div", { className: "flex max-w-lg flex-wrap gap-2", children: !invoice ? /* @__PURE__ */ jsx(
2074
+ Button,
2075
+ {
2076
+ size: "small",
2077
+ disabled: !configuration?.configured || Boolean(loading),
2078
+ isLoading: loading === `${order.id}:create`,
2079
+ onClick: () => void action(order, "create"),
2080
+ children: "Számla készítése"
2081
+ }
2082
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
2083
+ /* @__PURE__ */ jsx(
2084
+ Button,
2085
+ {
2086
+ size: "small",
2087
+ variant: "secondary",
2088
+ disabled: Boolean(loading),
2089
+ isLoading: loading === `${order.id}:sync`,
2090
+ onClick: () => void action(order, "sync"),
2091
+ children: "Frissítés"
2092
+ }
2093
+ ),
2094
+ /* @__PURE__ */ jsx(
2095
+ "a",
2096
+ {
2097
+ href: apiUrl$a(`/admin/orders/${order.id}/billingo/pdf`),
2098
+ target: "_blank",
2099
+ rel: "noreferrer",
2100
+ children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "PDF" })
2101
+ }
2102
+ ),
2103
+ /* @__PURE__ */ jsx(
2104
+ Button,
2105
+ {
2106
+ size: "small",
2107
+ variant: "secondary",
2108
+ disabled: Boolean(loading) || invoice.cancelled,
2109
+ isLoading: loading === `${order.id}:send`,
2110
+ onClick: () => void action(order, "send"),
2111
+ children: "E-mail"
2112
+ }
2113
+ ),
2114
+ /* @__PURE__ */ jsx(
2115
+ Button,
2116
+ {
2117
+ size: "small",
2118
+ variant: "secondary",
2119
+ disabled: Boolean(loading) || invoice.cancelled || modified,
2120
+ isLoading: loading === `${order.id}:modify`,
2121
+ onClick: () => void action(order, "modify"),
2122
+ children: "Teljes jóváírás"
2123
+ }
2124
+ ),
2125
+ /* @__PURE__ */ jsx(
2126
+ Button,
2127
+ {
2128
+ size: "small",
2129
+ variant: "danger",
2130
+ disabled: Boolean(loading) || invoice.cancelled || modified,
2131
+ isLoading: loading === `${order.id}:cancel`,
2132
+ onClick: () => void action(order, "cancel"),
2133
+ children: "Sztornó"
2134
+ }
2135
+ )
2136
+ ] }) }) })
2137
+ ] }, order.id);
2138
+ }) })
2139
+ ] }),
2140
+ listLoading ? /* @__PURE__ */ jsx("div", { className: "p-8 text-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Számlázási rendelések betöltése…" }) }) : null,
2141
+ !listLoading && loadError ? /* @__PURE__ */ jsxs("div", { className: "m-6 flex items-center justify-between gap-4 rounded-lg border border-ui-border-error p-4", children: [
2142
+ /* @__PURE__ */ jsxs("div", { children: [
2143
+ /* @__PURE__ */ jsx(Text, { className: "font-medium text-ui-fg-error", children: "Betöltési hiba." }),
2144
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: loadError })
2145
+ ] }),
2146
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => void load(), children: "Újrapróbálás" })
2147
+ ] }) : null,
2148
+ !listLoading && !loadError && !visible.length ? /* @__PURE__ */ jsx("div", { className: "p-8 text-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Nincs megjeleníthető rendelés." }) }) : null
2149
+ ] })
2033
2150
  ] });
2034
2151
  };
2035
- function Field$4({ label, children }) {
2036
- return /* @__PURE__ */ jsxs("label", { className: "flex min-w-0 flex-col gap-1.5", children: [
2037
- /* @__PURE__ */ jsx(Text, { className: "font-medium", children: label }),
2038
- children
2039
- ] });
2040
- }
2041
- function Stat$1({ label, value }) {
2042
- return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border p-3", children: [
2043
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-xs", children: label }),
2044
- /* @__PURE__ */ jsx(Text, { className: "font-medium", children: value })
2045
- ] });
2152
+ function formatMoney(value, currency) {
2153
+ if (typeof value !== "number") return "—";
2154
+ return new Intl.NumberFormat("hu-HU", {
2155
+ style: "currency",
2156
+ currency: (currency || "HUF").toUpperCase(),
2157
+ maximumFractionDigits: currency?.toUpperCase() === "HUF" ? 0 : 2
2158
+ }).format(value);
2046
2159
  }
2047
- const config$8 = defineRouteConfig({ label: "Árukereső", rank: 42 });
2160
+ const config$8 = defineRouteConfig({
2161
+ label: "Számlázás",
2162
+ icon: Newspaper,
2163
+ rank: 36
2164
+ });
2048
2165
  const backendUrl$9 = (__BACKEND_URL__ || "").replace(/\/+$/, "");
2049
- const adminBase$5 = (__BASE__ || "/app").replace(/\/+$/, "");
2166
+ const adminBase$4 = (__BASE__ || "/app").replace(/\/+$/, "");
2050
2167
  const apiUrl$9 = (path) => `${backendUrl$9}${path.startsWith("/") ? path : `/${path}`}`;
2051
2168
  const LegalPage = () => {
2052
2169
  const [documents, setDocuments] = useState([]);
@@ -2201,7 +2318,7 @@ const LegalPage = () => {
2201
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." })
2202
2319
  ] }),
2203
2320
  /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
2204
- /* @__PURE__ */ jsx("a", { href: `${adminBase$5}/settings/integrations`, children: /* @__PURE__ */ jsx(Button, { variant: "secondary", children: "Fogyasztó Barát embed" }) }),
2321
+ /* @__PURE__ */ jsx("a", { href: `${adminBase$4}/settings/integrations`, children: /* @__PURE__ */ jsx(Button, { variant: "secondary", children: "Fogyasztó Barát embed" }) }),
2205
2322
  /* @__PURE__ */ jsx(
2206
2323
  Button,
2207
2324
  {
@@ -2222,7 +2339,7 @@ const LegalPage = () => {
2222
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." })
2223
2340
  ] }),
2224
2341
  /* @__PURE__ */ jsxs("div", { className: "grid gap-4 border-b px-6 py-5 md:grid-cols-2", children: [
2225
- /* @__PURE__ */ jsx(Field$3, { label: "Dokumentum neve", children: /* @__PURE__ */ jsx(
2342
+ /* @__PURE__ */ jsx(Field$4, { label: "Dokumentum neve", children: /* @__PURE__ */ jsx(
2226
2343
  Input,
2227
2344
  {
2228
2345
  value: title,
@@ -2230,7 +2347,7 @@ const LegalPage = () => {
2230
2347
  placeholder: "Általános Szerződési Feltételek"
2231
2348
  }
2232
2349
  ) }),
2233
- /* @__PURE__ */ jsx(Field$3, { label: "Kulcs", children: /* @__PURE__ */ jsx(
2350
+ /* @__PURE__ */ jsx(Field$4, { label: "Kulcs", children: /* @__PURE__ */ jsx(
2234
2351
  Input,
2235
2352
  {
2236
2353
  value: key,
@@ -2238,7 +2355,7 @@ const LegalPage = () => {
2238
2355
  placeholder: "terms"
2239
2356
  }
2240
2357
  ) }),
2241
- /* @__PURE__ */ jsx(Field$3, { label: "Típus", children: /* @__PURE__ */ jsxs(
2358
+ /* @__PURE__ */ jsx(Field$4, { label: "Típus", children: /* @__PURE__ */ jsxs(
2242
2359
  "select",
2243
2360
  {
2244
2361
  className: "h-8 rounded-md border bg-ui-bg-field px-2 text-sm",
@@ -2252,7 +2369,7 @@ const LegalPage = () => {
2252
2369
  ]
2253
2370
  }
2254
2371
  ) }),
2255
- /* @__PURE__ */ jsxs(Field$3, { label: "PDF fájl (max. 5 MB)", children: [
2372
+ /* @__PURE__ */ jsxs(Field$4, { label: "PDF fájl (max. 5 MB)", children: [
2256
2373
  /* @__PURE__ */ jsx(
2257
2374
  "input",
2258
2375
  {
@@ -2393,7 +2510,7 @@ const LegalPage = () => {
2393
2510
  "a",
2394
2511
  {
2395
2512
  className: "text-ui-fg-interactive",
2396
- href: `${adminBase$5}/orders/${consent.orderId}`,
2513
+ href: `${adminBase$4}/orders/${consent.orderId}`,
2397
2514
  children: consent.orderId
2398
2515
  }
2399
2516
  ) : "Még nincs rendelés" }),
@@ -2403,7 +2520,7 @@ const LegalPage = () => {
2403
2520
  ] }) })
2404
2521
  ] }) });
2405
2522
  };
2406
- function Field$3({
2523
+ function Field$4({
2407
2524
  label,
2408
2525
  children
2409
2526
  }) {
@@ -2449,398 +2566,281 @@ const config$7 = defineRouteConfig({
2449
2566
  icon: Newspaper,
2450
2567
  rank: 40
2451
2568
  });
2569
+ const defaults$1 = {
2570
+ ARUKERESO_STOREFRONT_URL: "",
2571
+ ARUKERESO_PRODUCT_PATH_TEMPLATE: "/{country_code}/products/{handle}?v_id={variant_id}",
2572
+ ARUKERESO_SALES_CHANNEL_ID: "",
2573
+ ARUKERESO_DEFAULT_MANUFACTURER: "",
2574
+ ARUKERESO_USE_SKU_AS_PRODUCT_NUMBER: false,
2575
+ ARUKERESO_INCLUDE_OUT_OF_STOCK: true,
2576
+ ARUKERESO_DEFAULT_DELIVERY_TIME: "",
2577
+ ARUKERESO_DEFAULT_DELIVERY_COST: ""
2578
+ };
2452
2579
  const backendUrl$8 = (__BACKEND_URL__ || "").replace(/\/+$/, "");
2453
- const adminBase$4 = (__BASE__ || "/app").replace(/\/+$/, "");
2454
- function apiUrl$8(path) {
2455
- return `${backendUrl$8}${path.startsWith("/") ? path : `/${path}`}`;
2456
- }
2457
- const BillingPage = () => {
2458
- const [orders, setOrders] = useState([]);
2459
- const [configuration, setConfiguration] = useState(null);
2460
- const [selected, setSelected] = useState([]);
2461
- const [query, setQuery] = useState("");
2462
- const [loading, setLoading] = useState(null);
2463
- const [listLoading, setListLoading] = useState(true);
2464
- const [loadError, setLoadError] = useState(null);
2580
+ const apiUrl$8 = (path) => `${backendUrl$8}${path.startsWith("/") ? path : `/${path}`}`;
2581
+ const ArukeresoPage = () => {
2582
+ const [enabled, setEnabled] = useState(false);
2583
+ const [draft, setDraft] = useState(defaults$1);
2584
+ const [loading, setLoading] = useState(true);
2585
+ const [saving, setSaving] = useState(false);
2586
+ const [previewing, setPreviewing] = useState(false);
2587
+ const [preview, setPreview] = useState(null);
2588
+ const update = (key, value) => {
2589
+ setDraft((current) => ({ ...current, [key]: value }));
2590
+ };
2465
2591
  const load = useCallback(async () => {
2466
- setListLoading(true);
2467
- setLoadError(null);
2592
+ setLoading(true);
2468
2593
  try {
2469
- const response = await fetch(apiUrl$8("/admin/billingo/orders"), {
2594
+ const response = await fetch(apiUrl$8("/admin/integrations/arukereso"), {
2470
2595
  credentials: "include"
2471
2596
  });
2472
- const payload = await response.json().catch(() => ({}));
2473
- if (!response.ok) {
2474
- throw new Error(payload.message || "A számlázási lista nem tölthető be.");
2597
+ const data = await response.json().catch(() => ({}));
2598
+ if (!response.ok || !data.integration) {
2599
+ throw new Error(data.message || "Az Árukereső beállítások nem tölthetők be.");
2475
2600
  }
2476
- const nextOrders = payload.orders || [];
2477
- setOrders(nextOrders);
2478
- setConfiguration(payload.configuration || null);
2479
- setSelected(
2480
- (current) => current.filter((id) => nextOrders.some((order) => order.id === id))
2481
- );
2601
+ const values = data.integration.values || {};
2602
+ setEnabled(Boolean(data.integration.enabled));
2603
+ setDraft({
2604
+ ARUKERESO_STOREFRONT_URL: values.ARUKERESO_STOREFRONT_URL || "",
2605
+ ARUKERESO_PRODUCT_PATH_TEMPLATE: values.ARUKERESO_PRODUCT_PATH_TEMPLATE || "/{country_code}/products/{handle}?v_id={variant_id}",
2606
+ ARUKERESO_SALES_CHANNEL_ID: values.ARUKERESO_SALES_CHANNEL_ID || "",
2607
+ ARUKERESO_DEFAULT_MANUFACTURER: values.ARUKERESO_DEFAULT_MANUFACTURER || "",
2608
+ ARUKERESO_USE_SKU_AS_PRODUCT_NUMBER: values.ARUKERESO_USE_SKU_AS_PRODUCT_NUMBER === "true",
2609
+ ARUKERESO_INCLUDE_OUT_OF_STOCK: values.ARUKERESO_INCLUDE_OUT_OF_STOCK !== "false",
2610
+ ARUKERESO_DEFAULT_DELIVERY_TIME: values.ARUKERESO_DEFAULT_DELIVERY_TIME || "",
2611
+ ARUKERESO_DEFAULT_DELIVERY_COST: values.ARUKERESO_DEFAULT_DELIVERY_COST || ""
2612
+ });
2482
2613
  } catch (error) {
2483
- setOrders([]);
2484
- setLoadError(
2485
- error instanceof Error ? error.message : "A számlázási lista nem tölthető be."
2486
- );
2614
+ toast.error(error instanceof Error ? error.message : "Betöltési hiba.");
2487
2615
  } finally {
2488
- setListLoading(false);
2616
+ setLoading(false);
2489
2617
  }
2490
2618
  }, []);
2491
2619
  useEffect(() => {
2492
2620
  void load();
2493
2621
  }, [load]);
2494
- const visible = useMemo(() => {
2495
- const value = query.trim().toLowerCase();
2496
- if (!value) return orders;
2497
- return orders.filter(
2498
- (order) => [
2499
- order.display_id,
2500
- order.email,
2501
- order.invoice?.invoiceNumber,
2502
- order.invoice?.modificationInvoiceNumber
2503
- ].some(
2504
- (item) => String(item || "").toLowerCase().includes(value)
2505
- )
2506
- );
2507
- }, [orders, query]);
2508
- const selectedSet = useMemo(() => new Set(selected), [selected]);
2509
- const toggle = (id) => {
2510
- setSelected(
2511
- (current) => current.includes(id) ? current.filter((item) => item !== id) : [...current, id]
2512
- );
2513
- };
2514
- const bulkCreate = async () => {
2515
- if (!selected.length) {
2516
- toast.error("Jelölj ki legalább egy rendelést.");
2517
- return;
2518
- }
2519
- setLoading("bulk");
2520
- try {
2521
- const response = await fetch(apiUrl$8("/admin/billingo/bulk/create"), {
2522
- method: "POST",
2523
- credentials: "include",
2524
- headers: { "Content-Type": "application/json" },
2525
- body: JSON.stringify({ orderIds: selected })
2526
- });
2527
- const payload = await response.json().catch(() => ({}));
2528
- if (!response.ok && response.status !== 207) {
2529
- throw new Error(payload.message || "A tömeges számlázás nem sikerült.");
2530
- }
2531
- const failed = payload.results?.filter((item) => !item.ok).length || 0;
2532
- const created = payload.results?.filter(
2533
- (item) => item.ok && !item.alreadyExisted
2534
- ).length || 0;
2535
- if (failed) {
2536
- toast.error(`${failed} számla nem készült el; ${created} sikeres.`);
2537
- } else {
2538
- toast.success(`${created} új számla elkészült.`);
2539
- }
2540
- await load();
2541
- } catch (error) {
2542
- toast.error(
2543
- error instanceof Error ? error.message : "A tömeges számlázás nem sikerült."
2544
- );
2545
- } finally {
2546
- setLoading(null);
2547
- }
2548
- };
2549
- const action = async (order, value) => {
2550
- if (value === "cancel" && !confirm(
2551
- `Biztosan sztornózod a(z) ${order.invoice?.invoiceNumber || order.invoice?.documentId} számlát?`
2552
- )) {
2553
- return;
2554
- }
2555
- if (value === "modify" && !confirm(
2556
- `Biztosan teljes jóváíró/módosító bizonylatot készítesz a(z) ${order.invoice?.invoiceNumber || order.invoice?.documentId} számlához? Ez a teljes számla összegét jóváírja.`
2557
- )) {
2558
- return;
2559
- }
2560
- setLoading(`${order.id}:${value}`);
2622
+ const save = async () => {
2623
+ setSaving(true);
2561
2624
  try {
2562
- const response = await fetch(apiUrl$8(`/admin/orders/${order.id}/billingo`), {
2625
+ const response = await fetch(apiUrl$8("/admin/integrations/arukereso"), {
2563
2626
  method: "POST",
2564
2627
  credentials: "include",
2565
2628
  headers: { "Content-Type": "application/json" },
2566
- body: JSON.stringify({ action: value })
2629
+ body: JSON.stringify({ enabled, values: draft })
2567
2630
  });
2568
- const payload = await response.json().catch(() => ({}));
2569
- if (!response.ok) {
2570
- throw new Error(payload.message || "A Billingo művelet nem sikerült.");
2571
- }
2572
- const messages = {
2573
- create: "A számla elkészült.",
2574
- sync: "A számla frissítve.",
2575
- send: "A számla elküldve.",
2576
- cancel: "A számla sztornózva.",
2577
- modify: "A teljes jóváíró/módosító bizonylat elkészült."
2578
- };
2579
- toast.success(messages[value]);
2580
- if (value === "modify" && payload.sendError) {
2581
- toast.error(`A jóváírás elkészült, de az e-mail küldése sikertelen: ${payload.sendError}`);
2582
- }
2631
+ const data = await response.json().catch(() => ({}));
2632
+ if (!response.ok) throw new Error(data.message || "A mentés nem sikerült.");
2633
+ toast.success(data.message || "Árukereső beállítások mentve.");
2634
+ setPreview(null);
2583
2635
  await load();
2584
2636
  } catch (error) {
2585
- toast.error(
2586
- error instanceof Error ? error.message : "A Billingo művelet nem sikerült."
2587
- );
2637
+ toast.error(error instanceof Error ? error.message : "A mentés nem sikerült.");
2588
2638
  } finally {
2589
- setLoading(null);
2639
+ setSaving(false);
2590
2640
  }
2591
2641
  };
2592
- const testConnection = async () => {
2593
- setLoading("connection");
2642
+ const runPreview = async () => {
2643
+ setPreviewing(true);
2594
2644
  try {
2595
- const response = await fetch(apiUrl$8("/admin/billingo/connection"), {
2596
- method: "POST",
2645
+ const response = await fetch(apiUrl$8("/admin/arukereso/preview"), {
2597
2646
  credentials: "include"
2598
2647
  });
2599
- const payload = await response.json().catch(() => ({}));
2600
- if (!response.ok) {
2601
- throw new Error(payload.message || "A Billingo kapcsolat nem működik.");
2602
- }
2603
- toast.success(payload.message || "A Billingo kapcsolat működik.");
2648
+ const data = await response.json().catch(() => ({}));
2649
+ if (!response.ok) throw new Error(data.message || "A feed nem generálható.");
2650
+ setPreview(data);
2651
+ toast.success("Az Árukereső feed ellenőrzése elkészült.");
2604
2652
  } catch (error) {
2605
- toast.error(
2606
- error instanceof Error ? error.message : "A Billingo kapcsolat nem működik."
2607
- );
2653
+ toast.error(error instanceof Error ? error.message : "A feed nem generálható.");
2608
2654
  } finally {
2609
- setLoading(null);
2655
+ setPreviewing(false);
2610
2656
  }
2611
2657
  };
2658
+ const feedUrl = apiUrl$8("/feeds/arukereso.xml");
2659
+ const d = preview?.diagnostics;
2612
2660
  return /* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
2613
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-4 border-b px-6 py-4", children: [
2661
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-4 border-b px-6 py-4", children: [
2614
2662
  /* @__PURE__ */ jsxs("div", { children: [
2615
- /* @__PURE__ */ jsx(Heading, { children: "Számlázás" }),
2616
- /* @__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." }),
2617
- configuration?.autoInvoice ? /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
2618
- "Az automatikus számlázás aktív",
2619
- configuration.autoSend ? ", automatikus e-mail küldéssel" : "",
2620
- "."
2621
- ] }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-warning", children: "Az automatikus számlázás ki van kapcsolva." })
2663
+ /* @__PURE__ */ jsx(Heading, { children: "Árukereső.hu" }),
2664
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Árukereső XML feed a Medusa termék-, variant-, HU/HUF ár-, ÁFA- és készletadataiból." })
2622
2665
  ] }),
2623
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2624
- /* @__PURE__ */ jsxs(Text, { children: [
2625
- selected.length,
2626
- " kijelölve"
2627
- ] }),
2666
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
2667
+ /* @__PURE__ */ jsx(Switch, { checked: enabled, onCheckedChange: setEnabled, disabled: loading }),
2668
+ /* @__PURE__ */ jsx(Text, { children: enabled ? "Bekapcsolva" : "Kikapcsolva" })
2669
+ ] })
2670
+ ] }),
2671
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-4 border-b px-6 py-5 md:grid-cols-2", children: [
2672
+ /* @__PURE__ */ jsx(Field$3, { label: "Storefront URL", children: /* @__PURE__ */ jsx(
2673
+ Input,
2674
+ {
2675
+ value: draft.ARUKERESO_STOREFRONT_URL,
2676
+ onChange: (e) => update("ARUKERESO_STOREFRONT_URL", e.target.value),
2677
+ placeholder: "https://shop.hu (üresen STOREFRONT_URL)"
2678
+ }
2679
+ ) }),
2680
+ /* @__PURE__ */ jsxs(Field$3, { label: "Termék URL sablon", children: [
2628
2681
  /* @__PURE__ */ jsx(
2629
- Button,
2682
+ Input,
2630
2683
  {
2631
- variant: "secondary",
2632
- isLoading: loading === "connection",
2633
- onClick: () => void testConnection(),
2634
- children: "Kapcsolat tesztelése"
2684
+ value: draft.ARUKERESO_PRODUCT_PATH_TEMPLATE,
2685
+ onChange: (e) => update("ARUKERESO_PRODUCT_PATH_TEMPLATE", e.target.value)
2635
2686
  }
2636
- )
2637
- ] })
2638
- ] }),
2639
- configuration && !configuration.configured ? /* @__PURE__ */ jsxs("div", { className: "border-b border-ui-border-error bg-ui-bg-base px-6 py-4", children: [
2640
- /* @__PURE__ */ jsx(Text, { className: "font-medium text-ui-fg-error", children: "A Billingo még nincs teljesen beállítva." }),
2641
- /* @__PURE__ */ jsxs(Text, { className: "text-ui-fg-subtle", children: [
2642
- "Hiányzik: ",
2643
- [
2644
- !configuration.apiKey && "API kulcs",
2645
- !configuration.documentBlockId && "számlatömb azonosító"
2646
- ].filter(Boolean).join(", "),
2647
- ". Állítsd be a Settings → Integrációk → Billingo oldalon, majd indítsd újra a backendet."
2648
- ] })
2649
- ] }) : null,
2650
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3 border-b px-6 py-4", children: [
2651
- /* @__PURE__ */ jsx(
2687
+ ),
2688
+ /* @__PURE__ */ jsxs(Text, { className: "text-ui-fg-muted text-xs", children: [
2689
+ "Helyőrzők: ",
2690
+ "{country_code}",
2691
+ ", ",
2692
+ "{currency_code}",
2693
+ ", ",
2694
+ "{handle}",
2695
+ ", ",
2696
+ "{variant_id}",
2697
+ "."
2698
+ ] })
2699
+ ] }),
2700
+ /* @__PURE__ */ jsx(Field$3, { label: "Sales Channel ID", children: /* @__PURE__ */ jsx(
2652
2701
  Input,
2653
2702
  {
2654
- className: "max-w-sm",
2655
- value: query,
2656
- onChange: (event) => setQuery(event.target.value),
2657
- placeholder: "Rendelés, e-mail vagy számlaszám keresése"
2703
+ value: draft.ARUKERESO_SALES_CHANNEL_ID,
2704
+ onChange: (e) => update("ARUKERESO_SALES_CHANNEL_ID", e.target.value),
2705
+ placeholder: "sc_... (opcionális)"
2658
2706
  }
2659
- ),
2660
- /* @__PURE__ */ jsx(
2661
- Button,
2707
+ ) }),
2708
+ /* @__PURE__ */ jsx(Field$3, { label: "Alapértelmezett gyártó", children: /* @__PURE__ */ jsx(
2709
+ Input,
2662
2710
  {
2663
- disabled: Boolean(loading) || !configuration?.configured,
2664
- isLoading: loading === "bulk",
2665
- onClick: () => void bulkCreate(),
2666
- children: "Kijelöltek számlázása"
2711
+ value: draft.ARUKERESO_DEFAULT_MANUFACTURER,
2712
+ onChange: (e) => update("ARUKERESO_DEFAULT_MANUFACTURER", e.target.value),
2713
+ placeholder: "Csak ha minden termékre tényleg igaz"
2667
2714
  }
2668
- ),
2669
- /* @__PURE__ */ jsx(
2670
- Button,
2715
+ ) }),
2716
+ /* @__PURE__ */ jsx(Field$3, { label: "SKU mint gyártói cikkszám", children: /* @__PURE__ */ jsxs("div", { className: "flex h-8 items-center gap-2", children: [
2717
+ /* @__PURE__ */ jsx(
2718
+ Switch,
2719
+ {
2720
+ checked: draft.ARUKERESO_USE_SKU_AS_PRODUCT_NUMBER,
2721
+ onCheckedChange: (value) => update("ARUKERESO_USE_SKU_AS_PRODUCT_NUMBER", value)
2722
+ }
2723
+ ),
2724
+ /* @__PURE__ */ jsx(Text, { children: draft.ARUKERESO_USE_SKU_AS_PRODUCT_NUMBER ? "Igen" : "Nem" })
2725
+ ] }) }),
2726
+ /* @__PURE__ */ jsx(Field$3, { label: "Készlethiányos termékek", children: /* @__PURE__ */ jsxs("div", { className: "flex h-8 items-center gap-2", children: [
2727
+ /* @__PURE__ */ jsx(
2728
+ Switch,
2729
+ {
2730
+ checked: draft.ARUKERESO_INCLUDE_OUT_OF_STOCK,
2731
+ onCheckedChange: (value) => update("ARUKERESO_INCLUDE_OUT_OF_STOCK", value)
2732
+ }
2733
+ ),
2734
+ /* @__PURE__ */ jsx(Text, { children: draft.ARUKERESO_INCLUDE_OUT_OF_STOCK ? "DeliveryTime=NO" : "Kimaradnak" })
2735
+ ] }) }),
2736
+ /* @__PURE__ */ jsx(Field$3, { label: "Alap szállítási idő", children: /* @__PURE__ */ jsx(
2737
+ Input,
2671
2738
  {
2672
- variant: "secondary",
2673
- disabled: Boolean(loading),
2674
- onClick: () => void load(),
2675
- children: "Frissítés"
2739
+ value: draft.ARUKERESO_DEFAULT_DELIVERY_TIME,
2740
+ onChange: (e) => update("ARUKERESO_DEFAULT_DELIVERY_TIME", e.target.value),
2741
+ placeholder: "1 vagy 3"
2676
2742
  }
2677
- )
2743
+ ) }),
2744
+ /* @__PURE__ */ jsx(Field$3, { label: "Alap szállítási költség", children: /* @__PURE__ */ jsx(
2745
+ Input,
2746
+ {
2747
+ value: draft.ARUKERESO_DEFAULT_DELIVERY_COST,
2748
+ onChange: (e) => update("ARUKERESO_DEFAULT_DELIVERY_COST", e.target.value),
2749
+ placeholder: "1990 vagy FREE"
2750
+ }
2751
+ ) })
2678
2752
  ] }),
2679
- /* @__PURE__ */ jsxs("div", { className: "overflow-x-auto", children: [
2680
- /* @__PURE__ */ jsxs("table", { className: "w-full text-left text-sm", children: [
2681
- /* @__PURE__ */ jsx("thead", { className: "border-b bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
2682
- /* @__PURE__ */ jsx("th", { className: "p-4", children: /* @__PURE__ */ jsx(
2683
- Checkbox,
2684
- {
2685
- checked: visible.length > 0 && visible.every((order) => selectedSet.has(order.id)),
2686
- onCheckedChange: () => setSelected(
2687
- visible.every((order) => selectedSet.has(order.id)) ? selected.filter(
2688
- (id) => !visible.some((order) => order.id === id)
2689
- ) : [
2690
- .../* @__PURE__ */ new Set([
2691
- ...selected,
2692
- ...visible.map((order) => order.id)
2693
- ])
2694
- ]
2695
- )
2696
- }
2697
- ) }),
2698
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Rendelés" }),
2699
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Fizetés" }),
2700
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Számla" }),
2701
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Billingo státusz" }),
2702
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Műveletek" })
2703
- ] }) }),
2704
- /* @__PURE__ */ jsx("tbody", { children: visible.map((order) => {
2705
- const invoice = order.invoice;
2706
- const last = order.operations?.at(-1);
2707
- const modified = Boolean(invoice?.modificationDocumentId);
2708
- return /* @__PURE__ */ jsxs("tr", { className: "border-b align-top", children: [
2709
- /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx(
2710
- Checkbox,
2711
- {
2712
- checked: selectedSet.has(order.id),
2713
- onCheckedChange: () => toggle(order.id)
2714
- }
2715
- ) }),
2716
- /* @__PURE__ */ jsxs("td", { className: "p-4", children: [
2717
- /* @__PURE__ */ jsxs(
2718
- "a",
2719
- {
2720
- className: "text-ui-fg-interactive",
2721
- href: `${adminBase$4}/orders/${order.id}`,
2722
- children: [
2723
- "#",
2724
- order.display_id ?? order.id
2725
- ]
2726
- }
2727
- ),
2728
- /* @__PURE__ */ jsx("div", { className: "text-ui-fg-subtle", children: order.email || "—" }),
2729
- /* @__PURE__ */ jsx("div", { children: formatMoney(order.total, order.currency_code) })
2730
- ] }),
2731
- /* @__PURE__ */ jsx("td", { className: "p-4", children: order.payment_status === "captured" ? "Fizetve" : order.payment_status === "refunded" ? "Visszatérítve" : order.payment_status === "partially_refunded" ? "Részben visszatérítve" : order.payment_status || "—" }),
2732
- /* @__PURE__ */ jsxs("td", { className: "p-4", children: [
2733
- /* @__PURE__ */ jsx("strong", { children: invoice?.invoiceNumber || (invoice ? `#${invoice.documentId}` : "Még nincs") }),
2734
- invoice?.cancelled ? /* @__PURE__ */ jsx("div", { className: "text-ui-fg-error", children: "Sztornózva" }) : null,
2735
- modified ? /* @__PURE__ */ jsxs("div", { className: "text-ui-fg-interactive", children: [
2736
- "Jóváírva: ",
2737
- invoice?.modificationInvoiceNumber || `#${invoice?.modificationDocumentId}`
2738
- ] }) : null,
2739
- last?.status === "failed" ? /* @__PURE__ */ jsx("div", { className: "max-w-xs text-ui-fg-error", children: last.message }) : null
2740
- ] }),
2741
- /* @__PURE__ */ jsx("td", { className: "p-4", children: invoice ? /* @__PURE__ */ jsxs(Fragment, { children: [
2742
- /* @__PURE__ */ jsx("div", { children: invoice.paymentStatus || "—" }),
2743
- /* @__PURE__ */ jsxs("div", { className: "text-ui-fg-subtle", children: [
2744
- "NAV: ",
2745
- invoice.onlineSzamlaStatus || "—"
2746
- ] }),
2747
- /* @__PURE__ */ jsxs("div", { className: "text-ui-fg-subtle", children: [
2748
- "E-mail: ",
2749
- invoice.notificationStatus || "—"
2750
- ] })
2751
- ] }) : "—" }),
2752
- /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx("div", { className: "flex max-w-lg flex-wrap gap-2", children: !invoice ? /* @__PURE__ */ jsx(
2753
- Button,
2754
- {
2755
- size: "small",
2756
- disabled: !configuration?.configured || Boolean(loading),
2757
- isLoading: loading === `${order.id}:create`,
2758
- onClick: () => void action(order, "create"),
2759
- children: "Számla készítése"
2760
- }
2761
- ) : /* @__PURE__ */ jsxs(Fragment, { children: [
2762
- /* @__PURE__ */ jsx(
2763
- Button,
2764
- {
2765
- size: "small",
2766
- variant: "secondary",
2767
- disabled: Boolean(loading),
2768
- isLoading: loading === `${order.id}:sync`,
2769
- onClick: () => void action(order, "sync"),
2770
- children: "Frissítés"
2771
- }
2772
- ),
2773
- /* @__PURE__ */ jsx(
2774
- "a",
2775
- {
2776
- href: apiUrl$8(`/admin/orders/${order.id}/billingo/pdf`),
2777
- target: "_blank",
2778
- rel: "noreferrer",
2779
- children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: "PDF" })
2780
- }
2781
- ),
2782
- /* @__PURE__ */ jsx(
2783
- Button,
2784
- {
2785
- size: "small",
2786
- variant: "secondary",
2787
- disabled: Boolean(loading) || invoice.cancelled,
2788
- isLoading: loading === `${order.id}:send`,
2789
- onClick: () => void action(order, "send"),
2790
- children: "E-mail"
2791
- }
2792
- ),
2793
- /* @__PURE__ */ jsx(
2794
- Button,
2795
- {
2796
- size: "small",
2797
- variant: "secondary",
2798
- disabled: Boolean(loading) || invoice.cancelled || modified,
2799
- isLoading: loading === `${order.id}:modify`,
2800
- onClick: () => void action(order, "modify"),
2801
- children: "Teljes jóváírás"
2802
- }
2803
- ),
2804
- /* @__PURE__ */ jsx(
2805
- Button,
2806
- {
2807
- size: "small",
2808
- variant: "danger",
2809
- disabled: Boolean(loading) || invoice.cancelled || modified,
2810
- isLoading: loading === `${order.id}:cancel`,
2811
- onClick: () => void action(order, "cancel"),
2812
- children: "Sztornó"
2813
- }
2814
- )
2815
- ] }) }) })
2816
- ] }, order.id);
2817
- }) })
2753
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 border-b px-6 py-4", children: [
2754
+ /* @__PURE__ */ jsxs("div", { children: [
2755
+ /* @__PURE__ */ jsx(Text, { className: "font-medium", children: "Publikus feed URL" }),
2756
+ /* @__PURE__ */ jsx("a", { className: "break-all text-ui-fg-interactive hover:underline", href: feedUrl, target: "_blank", rel: "noreferrer", children: feedUrl })
2757
+ ] }),
2758
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
2759
+ /* @__PURE__ */ jsx(
2760
+ Button,
2761
+ {
2762
+ variant: "secondary",
2763
+ isLoading: previewing,
2764
+ disabled: !enabled || loading || saving || previewing,
2765
+ onClick: () => void runPreview(),
2766
+ children: "Feed ellenőrzése"
2767
+ }
2768
+ ),
2769
+ /* @__PURE__ */ jsx(
2770
+ Button,
2771
+ {
2772
+ isLoading: saving,
2773
+ disabled: loading || saving || previewing,
2774
+ onClick: () => void save(),
2775
+ children: "Mentés"
2776
+ }
2777
+ )
2778
+ ] })
2779
+ ] }),
2780
+ d ? /* @__PURE__ */ jsxs(Fragment, { children: [
2781
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-3 border-b px-6 py-5 sm:grid-cols-2 lg:grid-cols-4", children: [
2782
+ /* @__PURE__ */ jsx(Stat$1, { label: "Termékek", value: d.productsScanned }),
2783
+ /* @__PURE__ */ jsx(Stat$1, { label: "Variantok", value: d.variantsScanned }),
2784
+ /* @__PURE__ */ jsx(Stat$1, { label: "Feed tételek", value: d.itemsEmitted }),
2785
+ /* @__PURE__ */ jsx(Stat$1, { label: "Nincs gyártó", value: d.skippedNoManufacturer }),
2786
+ /* @__PURE__ */ jsx(Stat$1, { label: "Nincs kategória", value: d.skippedNoCategory }),
2787
+ /* @__PURE__ */ jsx(Stat$1, { label: "Nincs ár", value: d.skippedNoPrice }),
2788
+ /* @__PURE__ */ jsx(Stat$1, { label: "Nincs ProductNumber", value: d.itemsMissingProductNumber }),
2789
+ /* @__PURE__ */ jsx(Stat$1, { label: "Nincs kép", value: d.itemsMissingImage }),
2790
+ /* @__PURE__ */ jsx(Stat$1, { label: "Készlethiány miatt kimaradt", value: d.skippedOutOfStock }),
2791
+ /* @__PURE__ */ jsx(Stat$1, { label: "Sales channel hiba", value: d.skippedNoSalesChannel + d.skippedNotInSalesChannel }),
2792
+ /* @__PURE__ */ jsx(Stat$1, { label: "Hibás delivery time", value: d.invalidDeliveryTime }),
2793
+ /* @__PURE__ */ jsx(Stat$1, { label: "Hibás delivery cost", value: d.invalidDeliveryCost })
2818
2794
  ] }),
2819
- listLoading ? /* @__PURE__ */ jsx("div", { className: "p-8 text-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Számlázási rendelések betöltése…" }) }) : null,
2820
- !listLoading && loadError ? /* @__PURE__ */ jsxs("div", { className: "m-6 flex items-center justify-between gap-4 rounded-lg border border-ui-border-error p-4", children: [
2821
- /* @__PURE__ */ jsxs("div", { children: [
2822
- /* @__PURE__ */ jsx(Text, { className: "font-medium text-ui-fg-error", children: "Betöltési hiba." }),
2823
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: loadError })
2824
- ] }),
2825
- /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => void load(), children: "Újrapróbálás" })
2826
- ] }) : null,
2827
- !listLoading && !loadError && !visible.length ? /* @__PURE__ */ jsx("div", { className: "p-8 text-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Nincs megjeleníthető rendelés." }) }) : null
2828
- ] })
2795
+ /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-left text-sm", children: [
2796
+ /* @__PURE__ */ jsx("thead", { className: "border-b bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
2797
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Identifier" }),
2798
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Termék" }),
2799
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Gyártó" }),
2800
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Kategória" }),
2801
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Bruttó / nettó" }),
2802
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Szállítás" })
2803
+ ] }) }),
2804
+ /* @__PURE__ */ jsx("tbody", { children: (preview?.sample || []).map((item) => /* @__PURE__ */ jsxs("tr", { className: "border-b", children: [
2805
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx("code", { children: item.identifier }) }),
2806
+ /* @__PURE__ */ jsxs("td", { className: "p-4", children: [
2807
+ /* @__PURE__ */ jsx("a", { href: item.productUrl, target: "_blank", rel: "noreferrer", className: "text-ui-fg-interactive hover:underline", children: item.name }),
2808
+ item.productNumber ? /* @__PURE__ */ jsxs("div", { className: "text-ui-fg-muted text-xs", children: [
2809
+ "PN: ",
2810
+ item.productNumber
2811
+ ] }) : null
2812
+ ] }),
2813
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: item.manufacturer }),
2814
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: item.category }),
2815
+ /* @__PURE__ */ jsxs("td", { className: "p-4", children: [
2816
+ item.price,
2817
+ " / ",
2818
+ item.netPrice,
2819
+ " HUF"
2820
+ ] }),
2821
+ /* @__PURE__ */ jsxs("td", { className: "p-4", children: [
2822
+ item.deliveryTime || "—",
2823
+ " · ",
2824
+ item.deliveryCost || "—"
2825
+ ] })
2826
+ ] }, item.identifier)) })
2827
+ ] }) })
2828
+ ] }) : null
2829
2829
  ] });
2830
2830
  };
2831
- function formatMoney(value, currency) {
2832
- if (typeof value !== "number") return "—";
2833
- return new Intl.NumberFormat("hu-HU", {
2834
- style: "currency",
2835
- currency: (currency || "HUF").toUpperCase(),
2836
- maximumFractionDigits: currency?.toUpperCase() === "HUF" ? 0 : 2
2837
- }).format(value);
2831
+ function Field$3({ label, children }) {
2832
+ return /* @__PURE__ */ jsxs("label", { className: "flex min-w-0 flex-col gap-1.5", children: [
2833
+ /* @__PURE__ */ jsx(Text, { className: "font-medium", children: label }),
2834
+ children
2835
+ ] });
2838
2836
  }
2839
- const config$6 = defineRouteConfig({
2840
- label: "Számlázás",
2841
- icon: Newspaper,
2842
- rank: 36
2843
- });
2837
+ function Stat$1({ label, value }) {
2838
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border p-3", children: [
2839
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-xs", children: label }),
2840
+ /* @__PURE__ */ jsx(Text, { className: "font-medium", children: value })
2841
+ ] });
2842
+ }
2843
+ const config$6 = defineRouteConfig({ label: "Árukereső", rank: 42 });
2844
2844
  const EMPTY_SEO = {
2845
2845
  title: "",
2846
2846
  description: "",
@@ -3106,251 +3106,60 @@ ${selectedPage.path}`)) return;
3106
3106
  /* @__PURE__ */ jsx(Text, { className: "mt-2 text-ui-fg-subtle", children: previewDescription })
3107
3107
  ] }),
3108
3108
  /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2 border-t pt-5", children: [
3109
- /* @__PURE__ */ jsx(Button, { isLoading: saving, disabled: saving || deleting || mode === "page" && !pagePath.trim(), onClick: () => void save(), children: "Mentés" }),
3110
- /* @__PURE__ */ jsx(Button, { variant: "secondary", disabled: saving || deleting, onClick: () => setForm({ ...EMPTY_SEO }), children: "SEO felülírások ürítése" }),
3111
- mode === "page" && selectedPage ? /* @__PURE__ */ jsx(Button, { className: "ml-auto", variant: "secondary", isLoading: deleting, disabled: saving || deleting, onClick: () => void removePage(), children: "Oldal törlése" }) : null
3112
- ] })
3113
- ] }) : /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Válassz egy elemet a SEO szerkesztéséhez." }) })
3114
- ] })
3115
- ] });
3116
- };
3117
- const ModeButton = ({ active, onClick, children }) => /* @__PURE__ */ jsx(Button, { size: "small", variant: active ? "primary" : "secondary", onClick, children });
3118
- const ListButton = ({ active, title, subtitle, onClick }) => /* @__PURE__ */ jsxs("button", { type: "button", onClick, className: `mb-2 w-full rounded-lg border p-3 text-left transition-colors hover:bg-ui-bg-subtle ${active ? "bg-ui-bg-subtle" : "bg-ui-bg-base"}`, children: [
3119
- /* @__PURE__ */ jsx("div", { className: "truncate font-medium", children: title }),
3120
- /* @__PURE__ */ jsx("div", { className: "mt-1 truncate text-xs text-ui-fg-subtle", children: subtitle })
3121
- ] });
3122
- const Field$2 = ({ label, help, children }) => /* @__PURE__ */ jsxs("label", { className: "flex min-w-0 flex-col gap-1.5", children: [
3123
- /* @__PURE__ */ jsx(Text, { className: "font-medium", children: label }),
3124
- children,
3125
- help ? /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-muted", children: help }) : null
3126
- ] });
3127
- const Counter = ({ value, recommended }) => {
3128
- const length = value.length;
3129
- return /* @__PURE__ */ jsxs(Text, { className: `text-xs ${length > recommended ? "text-ui-fg-warning" : "text-ui-fg-muted"}`, children: [
3130
- length,
3131
- " karakter",
3132
- length > recommended ? ` · ajánlott maximum kb. ${recommended}` : ""
3133
- ] });
3134
- };
3135
- const ToggleCard = ({ label, description, checked, onCheckedChange }) => /* @__PURE__ */ jsxs("label", { className: "flex items-start justify-between gap-4 rounded-lg border p-4", children: [
3136
- /* @__PURE__ */ jsxs("div", { children: [
3137
- /* @__PURE__ */ jsx(Text, { className: "font-medium", children: label }),
3138
- /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle", children: description })
3139
- ] }),
3140
- /* @__PURE__ */ jsx(Switch, { checked, onCheckedChange })
3141
- ] });
3142
- function normalizeSeo(value) {
3143
- return {
3144
- title: value?.title || "",
3145
- description: value?.description || "",
3146
- canonical: value?.canonical || "",
3147
- noindex: Boolean(value?.noindex),
3148
- nofollow: Boolean(value?.nofollow),
3149
- ogTitle: value?.ogTitle || "",
3150
- ogDescription: value?.ogDescription || "",
3151
- ogImage: value?.ogImage || ""
3152
- };
3153
- }
3154
- function normalizeEntity(value) {
3155
- return { ...value, seo: normalizeSeo(value.seo) };
3156
- }
3157
- function normalizePage(value) {
3158
- return { ...value, seo: normalizeSeo(value.seo) };
3159
- }
3160
- const defaults = {
3161
- GOOGLE_MERCHANT_COUNTRY_CODE: "HU",
3162
- GOOGLE_MERCHANT_CURRENCY_CODE: "HUF",
3163
- GOOGLE_MERCHANT_STOREFRONT_URL: "",
3164
- GOOGLE_MERCHANT_PRODUCT_PATH_TEMPLATE: "/{country_code}/products/{handle}?v_id={variant_id}",
3165
- GOOGLE_MERCHANT_SALES_CHANNEL_ID: "",
3166
- GOOGLE_MERCHANT_DEFAULT_BRAND: "",
3167
- GOOGLE_MERCHANT_DEFAULT_CONDITION: "new",
3168
- GOOGLE_MERCHANT_INCLUDE_OUT_OF_STOCK: true,
3169
- GOOGLE_MERCHANT_FEED_TITLE: "",
3170
- GOOGLE_MERCHANT_FEED_DESCRIPTION: ""
3171
- };
3172
- const backendUrl$6 = (__BACKEND_URL__ || "").replace(/\/+$/, "");
3173
- const apiUrl$6 = (path) => `${backendUrl$6}${path.startsWith("/") ? path : `/${path}`}`;
3174
- const GoogleMerchantPage = () => {
3175
- const [enabled, setEnabled] = useState(false);
3176
- const [draft, setDraft] = useState(defaults);
3177
- const [loading, setLoading] = useState(true);
3178
- const [saving, setSaving] = useState(false);
3179
- const [previewing, setPreviewing] = useState(false);
3180
- const [preview, setPreview] = useState(null);
3181
- const update = (key, value) => {
3182
- setDraft((current) => ({ ...current, [key]: value }));
3183
- };
3184
- const load = useCallback(async () => {
3185
- setLoading(true);
3186
- try {
3187
- const response = await fetch(apiUrl$6("/admin/integrations/google-merchant"), {
3188
- credentials: "include"
3189
- });
3190
- const data = await response.json().catch(() => ({}));
3191
- if (!response.ok || !data.integration) {
3192
- throw new Error(data.message || "A Google Merchant beállítások nem tölthetők be.");
3193
- }
3194
- const values = data.integration.values || {};
3195
- setEnabled(Boolean(data.integration.enabled));
3196
- setDraft({
3197
- GOOGLE_MERCHANT_COUNTRY_CODE: values.GOOGLE_MERCHANT_COUNTRY_CODE || "HU",
3198
- GOOGLE_MERCHANT_CURRENCY_CODE: values.GOOGLE_MERCHANT_CURRENCY_CODE || "HUF",
3199
- GOOGLE_MERCHANT_STOREFRONT_URL: values.GOOGLE_MERCHANT_STOREFRONT_URL || "",
3200
- GOOGLE_MERCHANT_PRODUCT_PATH_TEMPLATE: values.GOOGLE_MERCHANT_PRODUCT_PATH_TEMPLATE || "/{country_code}/products/{handle}?v_id={variant_id}",
3201
- GOOGLE_MERCHANT_SALES_CHANNEL_ID: values.GOOGLE_MERCHANT_SALES_CHANNEL_ID || "",
3202
- GOOGLE_MERCHANT_DEFAULT_BRAND: values.GOOGLE_MERCHANT_DEFAULT_BRAND || "",
3203
- GOOGLE_MERCHANT_DEFAULT_CONDITION: values.GOOGLE_MERCHANT_DEFAULT_CONDITION || "new",
3204
- GOOGLE_MERCHANT_INCLUDE_OUT_OF_STOCK: values.GOOGLE_MERCHANT_INCLUDE_OUT_OF_STOCK !== "false",
3205
- GOOGLE_MERCHANT_FEED_TITLE: values.GOOGLE_MERCHANT_FEED_TITLE || "",
3206
- GOOGLE_MERCHANT_FEED_DESCRIPTION: values.GOOGLE_MERCHANT_FEED_DESCRIPTION || ""
3207
- });
3208
- } catch (error) {
3209
- toast.error(error instanceof Error ? error.message : "Betöltési hiba.");
3210
- } finally {
3211
- setLoading(false);
3212
- }
3213
- }, []);
3214
- useEffect(() => {
3215
- void load();
3216
- }, [load]);
3217
- const save = async () => {
3218
- setSaving(true);
3219
- try {
3220
- const response = await fetch(apiUrl$6("/admin/integrations/google-merchant"), {
3221
- method: "POST",
3222
- credentials: "include",
3223
- headers: { "Content-Type": "application/json" },
3224
- body: JSON.stringify({ enabled, values: draft })
3225
- });
3226
- const data = await response.json().catch(() => ({}));
3227
- if (!response.ok) throw new Error(data.message || "A mentés nem sikerült.");
3228
- toast.success(data.message || "Google Merchant beállítások mentve.");
3229
- setPreview(null);
3230
- await load();
3231
- } catch (error) {
3232
- toast.error(error instanceof Error ? error.message : "A mentés nem sikerült.");
3233
- } finally {
3234
- setSaving(false);
3235
- }
3236
- };
3237
- const runPreview = async () => {
3238
- setPreviewing(true);
3239
- try {
3240
- const response = await fetch(apiUrl$6("/admin/google-merchant/preview"), {
3241
- credentials: "include"
3242
- });
3243
- const data = await response.json().catch(() => ({}));
3244
- if (!response.ok) throw new Error(data.message || "A feed nem generálható.");
3245
- setPreview(data);
3246
- toast.success("A Merchant feed ellenőrzése elkészült.");
3247
- } catch (error) {
3248
- toast.error(error instanceof Error ? error.message : "A feed nem generálható.");
3249
- } finally {
3250
- setPreviewing(false);
3251
- }
3252
- };
3253
- const feedUrl = apiUrl$6("/feeds/google-merchant.xml");
3254
- const d = preview?.diagnostics;
3255
- return /* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
3256
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-4 border-b px-6 py-4", children: [
3257
- /* @__PURE__ */ jsxs("div", { children: [
3258
- /* @__PURE__ */ jsx(Heading, { children: "Google Merchant Center" }),
3259
- /* @__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." })
3260
- ] }),
3261
- /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
3262
- /* @__PURE__ */ jsx(Switch, { checked: enabled, onCheckedChange: setEnabled, disabled: loading }),
3263
- /* @__PURE__ */ jsx(Text, { children: enabled ? "Bekapcsolva" : "Kikapcsolva" })
3264
- ] })
3265
- ] }),
3266
- /* @__PURE__ */ jsxs("div", { className: "grid gap-4 border-b px-6 py-5 md:grid-cols-2", children: [
3267
- /* @__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" }) }),
3268
- /* @__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" }) }),
3269
- /* @__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)" }) }),
3270
- /* @__PURE__ */ jsxs(Field$1, { label: "Termék URL sablon", children: [
3271
- /* @__PURE__ */ jsx(Input, { value: draft.GOOGLE_MERCHANT_PRODUCT_PATH_TEMPLATE, onChange: (e) => update("GOOGLE_MERCHANT_PRODUCT_PATH_TEMPLATE", e.target.value) }),
3272
- /* @__PURE__ */ jsxs(Text, { className: "text-ui-fg-muted text-xs", children: [
3273
- "Helyőrzők: ",
3274
- "{country_code}",
3275
- ", ",
3276
- "{currency_code}",
3277
- ", ",
3278
- "{handle}",
3279
- ", ",
3280
- "{variant_id}",
3281
- "."
3109
+ /* @__PURE__ */ jsx(Button, { isLoading: saving, disabled: saving || deleting || mode === "page" && !pagePath.trim(), onClick: () => void save(), children: "Mentés" }),
3110
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", disabled: saving || deleting, onClick: () => setForm({ ...EMPTY_SEO }), children: "SEO felülírások ürítése" }),
3111
+ mode === "page" && selectedPage ? /* @__PURE__ */ jsx(Button, { className: "ml-auto", variant: "secondary", isLoading: deleting, disabled: saving || deleting, onClick: () => void removePage(), children: "Oldal törlése" }) : null
3282
3112
  ] })
3283
- ] }),
3284
- /* @__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)" }) }),
3285
- /* @__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) }) }),
3286
- /* @__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: [
3287
- /* @__PURE__ */ jsx("option", { value: "new", children: "Új" }),
3288
- /* @__PURE__ */ jsx("option", { value: "refurbished", children: "Felújított" }),
3289
- /* @__PURE__ */ jsx("option", { value: "used", children: "Használt" })
3290
- ] }) }),
3291
- /* @__PURE__ */ jsx(Field$1, { label: "Készlethiányos variantok", children: /* @__PURE__ */ jsxs("div", { className: "flex h-8 items-center gap-2", children: [
3292
- /* @__PURE__ */ jsx(Switch, { checked: draft.GOOGLE_MERCHANT_INCLUDE_OUT_OF_STOCK, onCheckedChange: (value) => update("GOOGLE_MERCHANT_INCLUDE_OUT_OF_STOCK", value) }),
3293
- /* @__PURE__ */ jsx(Text, { children: draft.GOOGLE_MERCHANT_INCLUDE_OUT_OF_STOCK ? "Benne maradnak" : "Kimaradnak" })
3294
- ] }) }),
3295
- /* @__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" }) }),
3296
- /* @__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" }) })
3297
- ] }),
3298
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 border-b px-6 py-4", children: [
3299
- /* @__PURE__ */ jsxs("div", { children: [
3300
- /* @__PURE__ */ jsx(Text, { className: "font-medium", children: "Publikus feed URL" }),
3301
- /* @__PURE__ */ jsx("a", { className: "break-all text-ui-fg-interactive hover:underline", href: feedUrl, target: "_blank", rel: "noreferrer", children: feedUrl })
3302
- ] }),
3303
- /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
3304
- /* @__PURE__ */ jsx(Button, { variant: "secondary", isLoading: previewing, disabled: !enabled || loading || saving || previewing, onClick: () => void runPreview(), children: "Feed ellenőrzése" }),
3305
- /* @__PURE__ */ jsx(Button, { isLoading: saving, disabled: loading || saving || previewing, onClick: () => void save(), children: "Mentés" })
3306
- ] })
3307
- ] }),
3308
- d ? /* @__PURE__ */ jsxs(Fragment, { children: [
3309
- /* @__PURE__ */ jsxs("div", { className: "grid gap-3 border-b px-6 py-5 sm:grid-cols-2 lg:grid-cols-4", children: [
3310
- /* @__PURE__ */ jsx(Stat, { label: "Termékek", value: d.productsScanned }),
3311
- /* @__PURE__ */ jsx(Stat, { label: "Variantok", value: d.variantsScanned }),
3312
- /* @__PURE__ */ jsx(Stat, { label: "Feed tételek", value: d.itemsEmitted }),
3313
- /* @__PURE__ */ jsx(Stat, { label: "Hiányzó identifier", value: d.itemsMissingIdentifiers }),
3314
- /* @__PURE__ */ jsx(Stat, { label: "Nincs ár", value: d.skippedNoPrice }),
3315
- /* @__PURE__ */ jsx(Stat, { label: "Nincs kép", value: d.skippedNoImage }),
3316
- /* @__PURE__ */ jsx(Stat, { label: "Nincs sales channel", value: d.skippedNoSalesChannel + d.skippedNotInSalesChannel }),
3317
- /* @__PURE__ */ jsx(Stat, { label: "Érvénytelen GTIN", value: d.invalidGtinsIgnored })
3318
- ] }),
3319
- /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-left text-sm", children: [
3320
- /* @__PURE__ */ jsx("thead", { className: "border-b bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
3321
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "ID" }),
3322
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Termék" }),
3323
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Ár" }),
3324
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Készlet" }),
3325
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Identifier" })
3326
- ] }) }),
3327
- /* @__PURE__ */ jsx("tbody", { children: (preview?.sample || []).map((item) => /* @__PURE__ */ jsxs("tr", { className: "border-b", children: [
3328
- /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx("code", { children: item.id }) }),
3329
- /* @__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 }) }),
3330
- /* @__PURE__ */ jsx("td", { className: "p-4", children: item.salePrice ? `${item.salePrice} (${item.price})` : item.price }),
3331
- /* @__PURE__ */ jsx("td", { className: "p-4", children: item.availability }),
3332
- /* @__PURE__ */ jsx("td", { className: "p-4", children: item.gtin || item.mpn || item.brand || "—" })
3333
- ] }, item.id)) })
3334
- ] }) })
3335
- ] }) : null
3113
+ ] }) : /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Válassz egy elemet a SEO szerkesztéséhez." }) })
3114
+ ] })
3336
3115
  ] });
3337
3116
  };
3338
- function Field$1({ label, children }) {
3339
- return /* @__PURE__ */ jsxs("label", { className: "flex min-w-0 flex-col gap-1.5", children: [
3340
- /* @__PURE__ */ jsx(Text, { className: "font-medium", children: label }),
3341
- children
3117
+ const ModeButton = ({ active, onClick, children }) => /* @__PURE__ */ jsx(Button, { size: "small", variant: active ? "primary" : "secondary", onClick, children });
3118
+ const ListButton = ({ active, title, subtitle, onClick }) => /* @__PURE__ */ jsxs("button", { type: "button", onClick, className: `mb-2 w-full rounded-lg border p-3 text-left transition-colors hover:bg-ui-bg-subtle ${active ? "bg-ui-bg-subtle" : "bg-ui-bg-base"}`, children: [
3119
+ /* @__PURE__ */ jsx("div", { className: "truncate font-medium", children: title }),
3120
+ /* @__PURE__ */ jsx("div", { className: "mt-1 truncate text-xs text-ui-fg-subtle", children: subtitle })
3121
+ ] });
3122
+ const Field$2 = ({ label, help, children }) => /* @__PURE__ */ jsxs("label", { className: "flex min-w-0 flex-col gap-1.5", children: [
3123
+ /* @__PURE__ */ jsx(Text, { className: "font-medium", children: label }),
3124
+ children,
3125
+ help ? /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-muted", children: help }) : null
3126
+ ] });
3127
+ const Counter = ({ value, recommended }) => {
3128
+ const length = value.length;
3129
+ return /* @__PURE__ */ jsxs(Text, { className: `text-xs ${length > recommended ? "text-ui-fg-warning" : "text-ui-fg-muted"}`, children: [
3130
+ length,
3131
+ " karakter",
3132
+ length > recommended ? ` · ajánlott maximum kb. ${recommended}` : ""
3342
3133
  ] });
3134
+ };
3135
+ const ToggleCard = ({ label, description, checked, onCheckedChange }) => /* @__PURE__ */ jsxs("label", { className: "flex items-start justify-between gap-4 rounded-lg border p-4", children: [
3136
+ /* @__PURE__ */ jsxs("div", { children: [
3137
+ /* @__PURE__ */ jsx(Text, { className: "font-medium", children: label }),
3138
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle", children: description })
3139
+ ] }),
3140
+ /* @__PURE__ */ jsx(Switch, { checked, onCheckedChange })
3141
+ ] });
3142
+ function normalizeSeo(value) {
3143
+ return {
3144
+ title: value?.title || "",
3145
+ description: value?.description || "",
3146
+ canonical: value?.canonical || "",
3147
+ noindex: Boolean(value?.noindex),
3148
+ nofollow: Boolean(value?.nofollow),
3149
+ ogTitle: value?.ogTitle || "",
3150
+ ogDescription: value?.ogDescription || "",
3151
+ ogImage: value?.ogImage || ""
3152
+ };
3343
3153
  }
3344
- function Stat({ label, value }) {
3345
- return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border p-3", children: [
3346
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted text-xs", children: label }),
3347
- /* @__PURE__ */ jsx(Text, { className: "font-medium", children: value })
3348
- ] });
3154
+ function normalizeEntity(value) {
3155
+ return { ...value, seo: normalizeSeo(value.seo) };
3349
3156
  }
3350
- const config$5 = defineRouteConfig({ label: "Google Merchant", rank: 41 });
3351
- const backendUrl$5 = (__BACKEND_URL__ || "").replace(/\/+$/, "");
3352
- function apiUrl$5(path) {
3353
- return `${backendUrl$5}${path.startsWith("/") ? path : `/${path}`}`;
3157
+ function normalizePage(value) {
3158
+ return { ...value, seo: normalizeSeo(value.seo) };
3159
+ }
3160
+ const backendUrl$6 = (__BACKEND_URL__ || "").replace(/\/+$/, "");
3161
+ function apiUrl$6(path) {
3162
+ return `${backendUrl$6}${path.startsWith("/") ? path : `/${path}`}`;
3354
3163
  }
3355
3164
  const CoreAuditPage = () => {
3356
3165
  const [logs, setLogs] = useState([]);
@@ -3368,7 +3177,7 @@ const CoreAuditPage = () => {
3368
3177
  if (integration !== "all") params.set("integration", integration);
3369
3178
  if (status !== "all") params.set("status", status);
3370
3179
  const response = await fetch(
3371
- apiUrl$5(`/admin/core-audit?${params.toString()}`),
3180
+ apiUrl$6(`/admin/core-audit?${params.toString()}`),
3372
3181
  { credentials: "include" }
3373
3182
  );
3374
3183
  const payload = await response.json().catch(() => ({}));
@@ -3504,15 +3313,15 @@ function formatDate$3(value) {
3504
3313
  timeStyle: "short"
3505
3314
  }).format(date);
3506
3315
  }
3507
- const config$4 = defineRouteConfig({
3316
+ const config$5 = defineRouteConfig({
3508
3317
  label: "Audit napló",
3509
3318
  icon: Newspaper,
3510
3319
  rank: 39
3511
3320
  });
3512
- const backendUrl$4 = (__BACKEND_URL__ || "").replace(/\/+$/, "");
3321
+ const backendUrl$5 = (__BACKEND_URL__ || "").replace(/\/+$/, "");
3513
3322
  const adminBase$3 = (__BASE__ || "/app").replace(/\/+$/, "");
3514
- function apiUrl$4(path) {
3515
- return `${backendUrl$4}${path.startsWith("/") ? path : `/${path}`}`;
3323
+ function apiUrl$5(path) {
3324
+ return `${backendUrl$5}${path.startsWith("/") ? path : `/${path}`}`;
3516
3325
  }
3517
3326
  const IntegrationHealthPage = () => {
3518
3327
  const [integrations, setIntegrations] = useState([]);
@@ -3525,8 +3334,8 @@ const IntegrationHealthPage = () => {
3525
3334
  setLoadError(null);
3526
3335
  try {
3527
3336
  const [integrationsResponse, operationsResponse] = await Promise.all([
3528
- fetch(apiUrl$4("/admin/integrations"), { credentials: "include" }),
3529
- fetch(apiUrl$4("/admin/integration-operations?status=problems&limit=100"), {
3337
+ fetch(apiUrl$5("/admin/integrations"), { credentials: "include" }),
3338
+ fetch(apiUrl$5("/admin/integration-operations?status=problems&limit=100"), {
3530
3339
  credentials: "include"
3531
3340
  })
3532
3341
  ]);
@@ -3590,7 +3399,7 @@ const IntegrationHealthPage = () => {
3590
3399
  setTesting(integration.key);
3591
3400
  try {
3592
3401
  const response = await fetch(
3593
- apiUrl$4(`/admin/integrations/${integration.key}/test`),
3402
+ apiUrl$5(`/admin/integrations/${integration.key}/test`),
3594
3403
  {
3595
3404
  method: "POST",
3596
3405
  credentials: "include"
@@ -3738,206 +3547,66 @@ function SummaryCard$1({
3738
3547
  function formatDate$2(value) {
3739
3548
  const date = new Date(value);
3740
3549
  if (Number.isNaN(date.getTime())) return "—";
3741
- return new Intl.DateTimeFormat("hu-HU", {
3742
- dateStyle: "short",
3743
- timeStyle: "short"
3744
- }).format(date);
3745
- }
3746
- const config$3 = defineRouteConfig({
3747
- label: "Integrációk állapota",
3748
- icon: Newspaper,
3749
- rank: 38
3750
- });
3751
- const backendUrl$3 = (__BACKEND_URL__ || "").replace(/\/+$/, "");
3752
- const adminBase$2 = (__BASE__ || "/app").replace(/\/+$/, "");
3753
- const apiUrl$3 = (path) => `${backendUrl$3}${path.startsWith("/") ? path : `/${path}`}`;
3754
- const CATEGORY_LABELS = {
3755
- infrastructure: "Infrastruktúra",
3756
- security: "Biztonság",
3757
- store: "Storefront alapok",
3758
- commerce: "Kereskedelem",
3759
- communication: "Kommunikáció",
3760
- compliance: "Jogi megfelelés",
3761
- marketing: "Mérés és SEO"
3762
- };
3763
- const ProductionReadinessPage = () => {
3764
- const [report, setReport] = useState(null);
3765
- const [loading, setLoading] = useState(true);
3766
- const [error, setError] = useState(null);
3767
- const load = useCallback(async () => {
3768
- setLoading(true);
3769
- setError(null);
3770
- try {
3771
- const response = await fetch(apiUrl$3("/admin/production-readiness"), {
3772
- credentials: "include"
3773
- });
3774
- const payload = await response.json().catch(() => ({}));
3775
- if (!response.ok) {
3776
- throw new Error(payload.message || "Az élesítési ellenőrzés nem tölthető be.");
3777
- }
3778
- setReport(payload);
3779
- } catch (cause) {
3780
- setReport(null);
3781
- setError(
3782
- cause instanceof Error ? cause.message : "Az élesítési ellenőrzés nem tölthető be."
3783
- );
3784
- } finally {
3785
- setLoading(false);
3786
- }
3787
- }, []);
3788
- useEffect(() => {
3789
- void load();
3790
- }, [load]);
3791
- const groups = useMemo(() => {
3792
- const result = /* @__PURE__ */ new Map();
3793
- for (const item of report?.checks || []) {
3794
- result.set(item.category, [...result.get(item.category) || [], item]);
3795
- }
3796
- return Array.from(result.entries());
3797
- }, [report]);
3798
- return /* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
3799
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-4 border-b px-6 py-5", children: [
3800
- /* @__PURE__ */ jsxs("div", { children: [
3801
- /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Production readiness" }),
3802
- /* @__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." })
3803
- ] }),
3804
- /* @__PURE__ */ jsx(Button, { variant: "secondary", isLoading: loading, onClick: () => void load(), children: "Újraellenőrzés" })
3805
- ] }),
3806
- report ? /* @__PURE__ */ jsxs(Fragment, { children: [
3807
- /* @__PURE__ */ jsxs("div", { className: "grid gap-3 border-b p-6 sm:grid-cols-2 lg:grid-cols-4", children: [
3808
- /* @__PURE__ */ jsx(Summary, { label: "Kész", value: report.score.ready, tone: "ready" }),
3809
- /* @__PURE__ */ jsx(Summary, { label: "Figyelmeztetés", value: report.score.warning, tone: "warning" }),
3810
- /* @__PURE__ */ jsx(Summary, { label: "Blokkoló", value: report.score.blocked, tone: "blocked" }),
3811
- /* @__PURE__ */ jsxs("div", { className: "rounded-lg border p-4", children: [
3812
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Élesítési döntés" }),
3813
- /* @__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ő" }),
3814
- /* @__PURE__ */ jsx(Text, { size: "small", className: "mt-1 text-ui-fg-subtle", children: report.environment === "production" ? "Production szabályok" : "Nem-production szabályok" })
3815
- ] })
3816
- ] }),
3817
- /* @__PURE__ */ jsx("div", { className: "border-b px-6 py-3", children: /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
3818
- "Utolsó ellenőrzés: ",
3819
- formatDate$1(report.generated_at),
3820
- ". A sárga elemek nem blokkolják az élesítést, a piros elemek igen."
3821
- ] }) }),
3822
- /* @__PURE__ */ jsx("div", { className: "space-y-6 p-6", children: groups.map(([category, checks]) => /* @__PURE__ */ jsxs("section", { className: "overflow-hidden rounded-lg border", children: [
3823
- /* @__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 }) }),
3824
- /* @__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: [
3825
- /* @__PURE__ */ jsx("strong", { children: item.label }),
3826
- /* @__PURE__ */ jsx(StatusBadge, { status: item.status }),
3827
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: item.message }),
3828
- 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", {})
3829
- ] }, item.key)) })
3830
- ] }, category)) })
3831
- ] }) : null,
3832
- 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,
3833
- error ? /* @__PURE__ */ jsxs("div", { className: "m-6 rounded-lg border border-ui-border-error p-4", children: [
3834
- /* @__PURE__ */ jsx(Text, { className: "font-medium text-ui-fg-error", children: "Az ellenőrzés nem futott le." }),
3835
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: error })
3836
- ] }) : null
3837
- ] });
3838
- };
3839
- function StatusBadge({ status }) {
3840
- const label = status === "ready" ? "Kész" : status === "warning" ? "Figyelmeztetés" : "Blokkoló";
3841
- const className = status === "ready" ? "font-medium text-ui-fg-success" : status === "warning" ? "font-medium text-ui-fg-warning" : "font-medium text-ui-fg-error";
3842
- return /* @__PURE__ */ jsxs("span", { className, children: [
3843
- status === "ready" ? "✅" : status === "warning" ? "🟡" : "🔴",
3844
- " ",
3845
- label
3846
- ] });
3847
- }
3848
- function Summary({ label, value, tone }) {
3849
- const valueClass = tone === "ready" ? "text-ui-fg-success" : tone === "warning" ? "text-ui-fg-warning" : "text-ui-fg-error";
3850
- return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border p-4", children: [
3851
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: label }),
3852
- /* @__PURE__ */ jsx("div", { className: `mt-1 text-3xl font-semibold ${valueClass}`, children: value })
3853
- ] });
3854
- }
3855
- function normalizeAdminHref(path) {
3856
- if (!path.startsWith("/app")) return path;
3857
- return `${adminBase$2}${path.slice(4)}`;
3858
- }
3859
- function formatDate$1(value) {
3860
- const date = new Date(value);
3861
- if (Number.isNaN(date.getTime())) return "—";
3862
- return new Intl.DateTimeFormat("hu-HU", { dateStyle: "short", timeStyle: "medium" }).format(date);
3863
- }
3864
- const config$2 = defineRouteConfig({
3865
- label: "Production readiness",
3866
- rank: 39
3867
- });
3868
- const backendUrl$2 = (__BACKEND_URL__ || "").replace(/\/+$/, "");
3869
- const adminBase$1 = (__BASE__ || "/app").replace(/\/+$/, "");
3870
- const apiUrl$2 = (path) => `${backendUrl$2}${path.startsWith("/") ? path : `/${path}`}`;
3871
- const CATEGORY_ORDER = [
3872
- "payment",
3873
- "invoicing",
3874
- "shipping",
3875
- "notification",
3876
- "legal",
3877
- "marketing"
3878
- ];
3879
- const CATEGORY_LABEL = {
3880
- payment: "Fizetés",
3881
- invoicing: "Számlázás",
3882
- shipping: "Szállítás",
3883
- notification: "Értesítés",
3884
- legal: "Jogi integráció",
3885
- marketing: "Marketing"
3550
+ return new Intl.DateTimeFormat("hu-HU", {
3551
+ dateStyle: "short",
3552
+ timeStyle: "short"
3553
+ }).format(date);
3554
+ }
3555
+ const config$4 = defineRouteConfig({
3556
+ label: "Integrációk állapota",
3557
+ icon: Newspaper,
3558
+ rank: 38
3559
+ });
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: ""
3886
3571
  };
3887
- const IntegrationsPage = () => {
3888
- const [items, setItems] = useState([]);
3889
- const [selectedKey, setSelectedKey] = useState(null);
3890
- const [draft, setDraft] = useState({});
3891
- const [clearSecrets, setClearSecrets] = useState([]);
3572
+ const backendUrl$4 = (__BACKEND_URL__ || "").replace(/\/+$/, "");
3573
+ const apiUrl$4 = (path) => `${backendUrl$4}${path.startsWith("/") ? path : `/${path}`}`;
3574
+ const GoogleMerchantPage = () => {
3892
3575
  const [enabled, setEnabled] = useState(false);
3576
+ const [draft, setDraft] = useState(defaults);
3893
3577
  const [loading, setLoading] = useState(true);
3894
3578
  const [saving, setSaving] = useState(false);
3895
- const [testing, setTesting] = useState(false);
3896
- const [restartNotice, setRestartNotice] = useState(false);
3897
- const visibleItems = useMemo(
3898
- () => items.filter((item) => CATEGORY_ORDER.includes(item.category)),
3899
- [items]
3900
- );
3901
- const selected = useMemo(
3902
- () => visibleItems.find((item) => item.key === selectedKey) || null,
3903
- [visibleItems, selectedKey]
3904
- );
3905
- const hasUnsavedChanges = useMemo(() => {
3906
- if (!selected) return false;
3907
- if (enabled !== selected.enabled || clearSecrets.length > 0) return true;
3908
- return selected.fields.some((field) => {
3909
- const value = draft[field.name];
3910
- if (field.type === "secret") {
3911
- return Boolean(String(value || "").trim());
3912
- }
3913
- if (field.type === "boolean") {
3914
- return Boolean(value) !== (selected.values[field.name] === "true");
3915
- }
3916
- return String(value || "").trim() !== String(selected.values[field.name] || "").trim();
3917
- });
3918
- }, [selected, enabled, draft, clearSecrets]);
3579
+ const [previewing, setPreviewing] = useState(false);
3580
+ const [preview, setPreview] = useState(null);
3581
+ const update = (key, value) => {
3582
+ setDraft((current) => ({ ...current, [key]: value }));
3583
+ };
3919
3584
  const load = useCallback(async () => {
3920
3585
  setLoading(true);
3921
3586
  try {
3922
- const response = await fetch(apiUrl$2("/admin/integrations"), {
3587
+ const response = await fetch(apiUrl$4("/admin/integrations/google-merchant"), {
3923
3588
  credentials: "include"
3924
3589
  });
3925
3590
  const data = await response.json().catch(() => ({}));
3926
- if (!response.ok) {
3927
- throw new Error(data.message || "Az integrációk nem tölthetők be.");
3591
+ if (!response.ok || !data.integration) {
3592
+ throw new Error(data.message || "A Google Merchant beállítások nem tölthetők be.");
3928
3593
  }
3929
- const integrations = data.integrations || [];
3930
- setItems(integrations);
3931
- const eligible = integrations.filter(
3932
- (item) => CATEGORY_ORDER.includes(item.category)
3933
- );
3934
- setSelectedKey(
3935
- (current) => current && eligible.some((item) => item.key === current) ? current : eligible[0]?.key || null
3936
- );
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
+ });
3937
3608
  } catch (error) {
3938
- toast.error(
3939
- error instanceof Error ? error.message : "Az integrációk nem tölthetők be."
3940
- );
3609
+ toast.error(error instanceof Error ? error.message : "Betöltési hiba.");
3941
3610
  } finally {
3942
3611
  setLoading(false);
3943
3612
  }
@@ -3945,641 +3614,972 @@ const IntegrationsPage = () => {
3945
3614
  useEffect(() => {
3946
3615
  void load();
3947
3616
  }, [load]);
3948
- useEffect(() => {
3949
- if (!selected) return;
3950
- const next = {};
3951
- for (const field of selected.fields) {
3952
- if (field.type === "secret") next[field.name] = "";
3953
- else if (field.type === "boolean") {
3954
- next[field.name] = selected.values[field.name] === "true";
3955
- } else {
3956
- next[field.name] = selected.values[field.name] || "";
3957
- }
3958
- }
3959
- setDraft(next);
3960
- setClearSecrets([]);
3961
- setEnabled(selected.enabled);
3962
- setRestartNotice(false);
3963
- }, [selected?.key, selected?.values, selected?.enabled]);
3964
3617
  const save = async () => {
3965
- if (!selected) return;
3966
3618
  setSaving(true);
3967
3619
  try {
3968
- const values = {};
3969
- for (const field of selected.fields) {
3970
- const value = draft[field.name];
3971
- if (field.type === "secret" && !String(value || "").trim()) continue;
3972
- values[field.name] = value;
3973
- }
3974
- const response = await fetch(apiUrl$2(`/admin/integrations/${selected.key}`), {
3620
+ const response = await fetch(apiUrl$4("/admin/integrations/google-merchant"), {
3975
3621
  method: "POST",
3976
3622
  credentials: "include",
3977
3623
  headers: { "Content-Type": "application/json" },
3978
- body: JSON.stringify({
3979
- enabled,
3980
- values,
3981
- clear_secrets: clearSecrets
3982
- })
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;
3655
+ return /* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
3656
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-4 border-b px-6 py-4", children: [
3657
+ /* @__PURE__ */ jsxs("div", { children: [
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." })
3660
+ ] }),
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
+ ] })
3665
+ ] }),
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
+ "."
3682
+ ] })
3683
+ ] }),
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" }) })
3697
+ ] }),
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 })
3718
+ ] }),
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
3736
+ ] });
3737
+ };
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
+ ] });
3743
+ }
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}`}`;
3755
+ }
3756
+ const IntegrationOperationsPage = () => {
3757
+ const [operations, setOperations] = useState([]);
3758
+ const [summary, setSummary] = useState({
3759
+ failed: 0,
3760
+ needsReconciliation: 0,
3761
+ processing: 0
3762
+ });
3763
+ const [count, setCount] = useState(0);
3764
+ const [status, setStatus] = useState("problems");
3765
+ const [provider, setProvider] = useState("all");
3766
+ const [query, setQuery] = useState("");
3767
+ const [loading, setLoading] = useState(false);
3768
+ const [actionLoading, setActionLoading] = useState(null);
3769
+ const [loadError, setLoadError] = useState(null);
3770
+ const load = useCallback(async () => {
3771
+ setLoading(true);
3772
+ setLoadError(null);
3773
+ try {
3774
+ const params = new URLSearchParams({
3775
+ limit: "100",
3776
+ status
3983
3777
  });
3984
- const data = await response.json().catch(() => ({}));
3778
+ if (provider !== "all") params.set("provider", provider);
3779
+ const response = await fetch(
3780
+ apiUrl$3(`/admin/integration-operations?${params.toString()}`),
3781
+ { credentials: "include" }
3782
+ );
3783
+ const payload = await response.json().catch(() => ({}));
3985
3784
  if (!response.ok) {
3986
- throw new Error(data.message || "A mentés nem sikerült.");
3785
+ throw new Error(
3786
+ payload.message || "Az integrációs műveletek nem tölthetők be."
3787
+ );
3987
3788
  }
3988
- if (data.integration) replaceIntegration(data.integration);
3989
- setClearSecrets([]);
3990
- setRestartNotice(Boolean(data.integration?.restart_required));
3991
- toast.success(data.message || "Beállítások mentve.");
3789
+ setOperations(payload.operations || []);
3790
+ setCount(payload.count || 0);
3791
+ setSummary(
3792
+ payload.summary || {
3793
+ failed: 0,
3794
+ needsReconciliation: 0,
3795
+ processing: 0
3796
+ }
3797
+ );
3992
3798
  } catch (error) {
3993
- toast.error(error instanceof Error ? error.message : "A mentés nem sikerült.");
3799
+ setOperations([]);
3800
+ setLoadError(
3801
+ error instanceof Error ? error.message : "Az integrációs műveletek nem tölthetők be."
3802
+ );
3994
3803
  } finally {
3995
- setSaving(false);
3804
+ setLoading(false);
3996
3805
  }
3997
- };
3998
- const test = async () => {
3999
- if (!selected || hasUnsavedChanges) return;
4000
- setTesting(true);
4001
- try {
4002
- const response = await fetch(apiUrl$2(`/admin/integrations/${selected.key}/test`), {
4003
- method: "POST",
4004
- credentials: "include"
4005
- });
4006
- const data = await response.json().catch(() => ({}));
4007
- if (data.integration) replaceIntegration(data.integration);
4008
- if (!response.ok || !data.ok) {
4009
- throw new Error(data.message || "A kapcsolat tesztelése nem sikerült.");
3806
+ }, [provider, status]);
3807
+ useEffect(() => {
3808
+ void load();
3809
+ }, [load]);
3810
+ const visible = useMemo(() => {
3811
+ const value = query.trim().toLowerCase();
3812
+ if (!value) return operations;
3813
+ return operations.filter(
3814
+ (operation) => [
3815
+ operation.provider,
3816
+ operation.operation_type,
3817
+ operation.entity_type,
3818
+ operation.entity_id,
3819
+ operation.external_id,
3820
+ operation.error_summary
3821
+ ].some(
3822
+ (item) => String(item || "").toLowerCase().includes(value)
3823
+ )
3824
+ );
3825
+ }, [operations, query]);
3826
+ const reconcile = async (operation, decision) => {
3827
+ const confirmed = confirm(
3828
+ decision === "confirmed_succeeded" ? "Megerősíted, hogy a külső szolgáltatónál ez a művelet valóban sikeresen megtörtént?" : "Megerősíted, hogy a külső szolgáltatónál ez a művelet biztosan NEM történt meg? Ez engedélyezi a normál művelet későbbi újrapróbálását."
3829
+ );
3830
+ if (!confirmed) return;
3831
+ let externalId = operation.external_id || void 0;
3832
+ if (decision === "confirmed_succeeded" && !externalId) {
3833
+ externalId = prompt(
3834
+ "Add meg a külső szolgáltató azonosítóját (pl. Billingo document ID vagy shipment ID):"
3835
+ )?.trim() || void 0;
3836
+ if (!externalId) {
3837
+ toast.error("A sikeres lezáráshoz külső azonosító szükséges.");
3838
+ return;
4010
3839
  }
4011
- if (data.verified) {
4012
- toast.success(data.message || "Kapcsolat ellenőrizve.");
4013
- } else {
4014
- toast.success(data.message || "Részleges ellenőrzés sikeres.");
3840
+ }
3841
+ const note = prompt(
3842
+ "Opcionális megjegyzés az egyeztetéshez:",
3843
+ ""
3844
+ )?.trim();
3845
+ setActionLoading(operation.id);
3846
+ try {
3847
+ const response = await fetch(
3848
+ apiUrl$3(`/admin/integration-operations/${operation.id}/reconcile`),
3849
+ {
3850
+ method: "POST",
3851
+ credentials: "include",
3852
+ headers: { "Content-Type": "application/json" },
3853
+ body: JSON.stringify({ decision, externalId, note })
3854
+ }
3855
+ );
3856
+ const payload = await response.json().catch(() => ({}));
3857
+ if (!response.ok) {
3858
+ throw new Error(
3859
+ payload.message || "Az egyeztetés lezárása nem sikerült."
3860
+ );
4015
3861
  }
3862
+ toast.success(
3863
+ decision === "confirmed_succeeded" ? "A művelet sikeresként lezárva." : "A művelet újrapróbálhatóvá téve."
3864
+ );
3865
+ await load();
4016
3866
  } catch (error) {
4017
3867
  toast.error(
4018
- error instanceof Error ? error.message : "A kapcsolat tesztelése nem sikerült."
3868
+ error instanceof Error ? error.message : "Az egyeztetés lezárása nem sikerült."
4019
3869
  );
4020
- void load();
4021
3870
  } finally {
4022
- setTesting(false);
3871
+ setActionLoading(null);
4023
3872
  }
4024
3873
  };
4025
- const replaceIntegration = (integration) => {
4026
- setItems(
4027
- (current) => current.map(
4028
- (item) => item.key === integration.key ? integration : item
4029
- )
4030
- );
4031
- };
4032
- const detailHref = selected ? detailPageForIntegration(selected.key) : null;
4033
- const connection = selected ? connectionPresentation(selected) : null;
4034
3874
  return /* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
4035
- /* @__PURE__ */ jsxs("div", { className: "border-b px-6 py-5", children: [
4036
- /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Integrációk" }),
4037
- /* @__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." })
3875
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-4 border-b px-6 py-4", children: [
3876
+ /* @__PURE__ */ jsxs("div", { children: [
3877
+ /* @__PURE__ */ jsx(Heading, { children: "Integrációs műveletek" }),
3878
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Külső API műveletek, hibák és kézi reconciliation kezelése." })
3879
+ ] }),
3880
+ /* @__PURE__ */ jsx(
3881
+ Button,
3882
+ {
3883
+ variant: "secondary",
3884
+ isLoading: loading,
3885
+ onClick: () => void load(),
3886
+ children: "Frissítés"
3887
+ }
3888
+ )
4038
3889
  ] }),
4039
- 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: [
4040
- /* @__PURE__ */ jsx("aside", { className: "border-r p-4", children: CATEGORY_ORDER.map((category) => {
4041
- const categoryItems = visibleItems.filter(
4042
- (item) => item.category === category
4043
- );
4044
- if (!categoryItems.length) return null;
4045
- return /* @__PURE__ */ jsxs("div", { className: "mb-6 last:mb-0", children: [
4046
- /* @__PURE__ */ jsx(Text, { className: "mb-2 px-1 text-xs font-medium uppercase tracking-wide text-ui-fg-muted", children: CATEGORY_LABEL[category] }),
4047
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: categoryItems.map((item) => {
4048
- const itemConnection = connectionPresentation(item);
4049
- return /* @__PURE__ */ jsxs(
4050
- "button",
4051
- {
4052
- type: "button",
4053
- onClick: () => setSelectedKey(item.key),
4054
- className: `rounded-lg border p-3 text-left transition-colors hover:bg-ui-bg-subtle ${selectedKey === item.key ? "bg-ui-bg-subtle" : "bg-ui-bg-base"}`,
4055
- children: [
4056
- /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
4057
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: item.label }),
4058
- /* @__PURE__ */ jsx("span", { className: item.enabled ? "text-xs font-medium text-ui-fg-success" : "text-xs text-ui-fg-muted", children: item.enabled ? "Aktív" : "Kikapcsolva" })
4059
- ] }),
4060
- /* @__PURE__ */ jsxs("div", { className: "mt-1 text-xs text-ui-fg-subtle", children: [
4061
- item.configured ? "Konfigurálva" : "Beállítás szükséges",
4062
- " · ",
4063
- itemConnection.label
4064
- ] })
4065
- ]
4066
- },
4067
- item.key
4068
- );
4069
- }) })
4070
- ] }, category);
4071
- }) }),
4072
- /* @__PURE__ */ jsx("main", { className: "min-w-0 p-6", children: selected && connection ? /* @__PURE__ */ jsxs("div", { className: "flex max-w-4xl flex-col gap-6", children: [
4073
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-4", children: [
4074
- /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
4075
- /* @__PURE__ */ jsx(Heading, { level: "h2", children: selected.label }),
4076
- /* @__PURE__ */ jsx(Text, { className: "mt-1 text-ui-fg-subtle", children: selected.description })
3890
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-3 border-b px-6 py-4 md:grid-cols-3", children: [
3891
+ /* @__PURE__ */ jsx(
3892
+ SummaryCard,
3893
+ {
3894
+ label: "Egyeztetést igényel",
3895
+ value: summary.needsReconciliation,
3896
+ danger: summary.needsReconciliation > 0
3897
+ }
3898
+ ),
3899
+ /* @__PURE__ */ jsx(
3900
+ SummaryCard,
3901
+ {
3902
+ label: "Sikertelen",
3903
+ value: summary.failed,
3904
+ danger: summary.failed > 0
3905
+ }
3906
+ ),
3907
+ /* @__PURE__ */ jsx(SummaryCard, { label: "Folyamatban", value: summary.processing })
3908
+ ] }),
3909
+ summary.needsReconciliation > 0 ? /* @__PURE__ */ jsxs("div", { className: "border-b border-ui-border-warning bg-ui-bg-base px-6 py-4", children: [
3910
+ /* @__PURE__ */ jsxs(Text, { className: "font-medium text-ui-fg-warning", children: [
3911
+ summary.needsReconciliation,
3912
+ " műveletnél nem dönthető el automatikusan, hogy a külső szolgáltató végrehajtotta-e a kérést."
3913
+ ] }),
3914
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Ellenőrizd a szolgáltatónál, majd csak ezután jelöld sikeresnek vagy újrapróbálhatónak. Így elkerülhető a duplikált számla, csomag vagy fizetés." })
3915
+ ] }) : null,
3916
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-end gap-3 border-b px-6 py-4", children: [
3917
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
3918
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Státusz" }),
3919
+ /* @__PURE__ */ jsxs(Select, { value: status, onValueChange: setStatus, children: [
3920
+ /* @__PURE__ */ jsx(Select.Trigger, { className: "w-52", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
3921
+ /* @__PURE__ */ jsxs(Select.Content, { children: [
3922
+ /* @__PURE__ */ jsx(Select.Item, { value: "problems", children: "Hibák + egyeztetés" }),
3923
+ /* @__PURE__ */ jsx(Select.Item, { value: "needs_reconciliation", children: "Egyeztetést igényel" }),
3924
+ /* @__PURE__ */ jsx(Select.Item, { value: "failed", children: "Sikertelen" }),
3925
+ /* @__PURE__ */ jsx(Select.Item, { value: "processing", children: "Folyamatban" }),
3926
+ /* @__PURE__ */ jsx(Select.Item, { value: "pending", children: "Várakozik" }),
3927
+ /* @__PURE__ */ jsx(Select.Item, { value: "succeeded", children: "Sikeres" }),
3928
+ /* @__PURE__ */ jsx(Select.Item, { value: "all", children: "Összes" })
3929
+ ] })
3930
+ ] })
3931
+ ] }),
3932
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
3933
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Provider" }),
3934
+ /* @__PURE__ */ jsxs(Select, { value: provider, onValueChange: setProvider, children: [
3935
+ /* @__PURE__ */ jsx(Select.Trigger, { className: "w-44", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
3936
+ /* @__PURE__ */ jsxs(Select.Content, { children: [
3937
+ /* @__PURE__ */ jsx(Select.Item, { value: "all", children: "Összes" }),
3938
+ [
3939
+ "stripe",
3940
+ "simplepay",
3941
+ "billingo",
3942
+ "foxpost",
3943
+ "gls",
3944
+ "packeta",
3945
+ "dpd",
3946
+ "mpl"
3947
+ ].map((item) => /* @__PURE__ */ jsx(Select.Item, { value: item, children: providerLabel(item) }, item))
3948
+ ] })
3949
+ ] })
3950
+ ] }),
3951
+ /* @__PURE__ */ jsx(
3952
+ Input,
3953
+ {
3954
+ className: "max-w-sm",
3955
+ value: query,
3956
+ onChange: (event) => setQuery(event.target.value),
3957
+ placeholder: "Keresés művelet, rendelés, külső ID vagy hiba alapján"
3958
+ }
3959
+ ),
3960
+ /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
3961
+ count,
3962
+ " találat"
3963
+ ] })
3964
+ ] }),
3965
+ /* @__PURE__ */ jsxs("div", { className: "overflow-x-auto", children: [
3966
+ /* @__PURE__ */ jsxs("table", { className: "w-full text-left text-sm", children: [
3967
+ /* @__PURE__ */ jsx("thead", { className: "border-b bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
3968
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Státusz" }),
3969
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Provider / művelet" }),
3970
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Entitás" }),
3971
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Külső ID" }),
3972
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Próbálkozás" }),
3973
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Hiba / idő" }),
3974
+ /* @__PURE__ */ jsx("th", { className: "p-4", children: "Műveletek" })
3975
+ ] }) }),
3976
+ /* @__PURE__ */ jsx("tbody", { children: visible.map((operation) => /* @__PURE__ */ jsxs("tr", { className: "border-b align-top", children: [
3977
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx(StatusText, { status: operation.status }) }),
3978
+ /* @__PURE__ */ jsxs("td", { className: "p-4", children: [
3979
+ /* @__PURE__ */ jsx("strong", { children: providerLabel(operation.provider) }),
3980
+ /* @__PURE__ */ jsx("div", { className: "text-ui-fg-subtle", children: operation.operation_type })
4077
3981
  ] }),
4078
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-end gap-1", children: [
4079
- /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
4080
- /* @__PURE__ */ jsx(Switch, { checked: enabled, onCheckedChange: setEnabled }),
4081
- /* @__PURE__ */ jsx(Text, { children: enabled ? "Bekapcsolva" : "Kikapcsolva" })
4082
- ] }),
4083
- hasUnsavedChanges ? /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-warning", children: "Nem mentett módosítások" }) : null
4084
- ] })
4085
- ] }),
4086
- /* @__PURE__ */ jsxs("div", { className: "grid gap-3 sm:grid-cols-2 xl:grid-cols-4", children: [
4087
- /* @__PURE__ */ jsx(StatusBox, { label: "Telepítve", value: selected.installed ? "Igen" : "Nem", state: selected.installed ? "success" : "neutral" }),
4088
- /* @__PURE__ */ jsx(StatusBox, { label: "Konfigurálva", value: selected.configured ? "Igen" : "Nem", state: selected.configured ? "success" : "neutral" }),
4089
- /* @__PURE__ */ jsx(StatusBox, { label: "Aktív", value: selected.enabled ? "Igen" : "Nem", state: selected.enabled ? "success" : "neutral" }),
4090
- /* @__PURE__ */ jsx(StatusBox, { label: "Kapcsolat", value: connection.label, state: connection.state })
4091
- ] }),
4092
- 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,
4093
- 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,
4094
- 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,
4095
- 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,
4096
- /* @__PURE__ */ jsxs("div", { children: [
4097
- /* @__PURE__ */ jsx(Heading, { level: "h3", children: "Beállítások" }),
4098
- /* @__PURE__ */ jsx("div", { className: "mt-4 grid gap-4 sm:grid-cols-2", children: selected.fields.map((field) => /* @__PURE__ */ jsx(
4099
- FieldEditor,
4100
- {
4101
- field,
4102
- value: draft[field.name],
4103
- hasSecret: Boolean(selected.secrets[field.name]),
4104
- clearPending: clearSecrets.includes(field.name),
4105
- onChange: (value) => {
4106
- setDraft((current) => ({ ...current, [field.name]: value }));
4107
- if (field.type === "secret" && String(value || "").trim()) {
4108
- setClearSecrets(
4109
- (current) => current.filter((name) => name !== field.name)
4110
- );
4111
- }
4112
- },
4113
- onClearSecret: () => {
4114
- setDraft((current) => ({ ...current, [field.name]: "" }));
4115
- setClearSecrets(
4116
- (current) => current.includes(field.name) ? current : [...current, field.name]
4117
- );
4118
- },
4119
- onRestoreSecret: () => setClearSecrets(
4120
- (current) => current.filter((name) => name !== field.name)
4121
- )
4122
- },
4123
- field.name
4124
- )) })
4125
- ] }),
4126
- selected.last_test_message ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border p-4", children: [
4127
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
4128
- /* @__PURE__ */ jsx(Text, { className: "font-medium", children: "Utolsó kapcsolat-teszt" }),
4129
- /* @__PURE__ */ jsx(Text, { className: connectionTextClass(connection.state), children: connection.label })
3982
+ /* @__PURE__ */ jsxs("td", { className: "p-4", children: [
3983
+ operation.entity_type === "order" ? /* @__PURE__ */ jsx(
3984
+ "a",
3985
+ {
3986
+ href: `${adminBase$2}/orders/${operation.entity_id}`,
3987
+ className: "text-ui-fg-interactive",
3988
+ children: operation.entity_id
3989
+ }
3990
+ ) : /* @__PURE__ */ jsx("span", { children: operation.entity_id }),
3991
+ /* @__PURE__ */ jsx("div", { className: "text-ui-fg-subtle", children: operation.entity_type })
4130
3992
  ] }),
4131
- /* @__PURE__ */ jsx(Text, { className: "mt-1 text-ui-fg-subtle", children: selected.last_test_message }),
4132
- selected.last_test_at ? /* @__PURE__ */ jsx(Text, { className: "mt-1 text-xs text-ui-fg-muted", children: new Date(selected.last_test_at).toLocaleString("hu-HU") }) : null
4133
- ] }) : null,
4134
- /* @__PURE__ */ jsxs("div", { className: "border-t pt-5", children: [
4135
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
3993
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: operation.external_id || "—" }),
3994
+ /* @__PURE__ */ jsx("td", { className: "p-4", children: operation.attempts }),
3995
+ /* @__PURE__ */ jsxs("td", { className: "max-w-md p-4", children: [
3996
+ operation.error_summary ? /* @__PURE__ */ jsx("div", { className: "text-ui-fg-error", children: operation.error_summary }) : null,
3997
+ /* @__PURE__ */ jsx("div", { className: "text-ui-fg-subtle", children: formatDate$1(operation.updated_at) })
3998
+ ] }),
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: [
4136
4000
  /* @__PURE__ */ jsx(
4137
4001
  Button,
4138
4002
  {
4139
- isLoading: saving,
4140
- disabled: saving || testing || !hasUnsavedChanges,
4141
- onClick: () => void save(),
4142
- children: "Mentés"
4003
+ size: "small",
4004
+ disabled: Boolean(actionLoading),
4005
+ isLoading: actionLoading === operation.id,
4006
+ onClick: () => void reconcile(operation, "confirmed_succeeded"),
4007
+ children: "Megtörtént"
4143
4008
  }
4144
4009
  ),
4145
4010
  /* @__PURE__ */ jsx(
4146
4011
  Button,
4147
4012
  {
4013
+ size: "small",
4148
4014
  variant: "secondary",
4149
- isLoading: testing,
4150
- disabled: saving || testing || hasUnsavedChanges || !selected.configured || !selected.enabled,
4151
- onClick: () => void test(),
4152
- children: "Kapcsolat tesztelése"
4015
+ disabled: Boolean(actionLoading),
4016
+ onClick: () => void reconcile(operation, "confirmed_not_executed"),
4017
+ children: "Nem történt meg"
4153
4018
  }
4154
- ),
4155
- detailHref ? /* @__PURE__ */ jsx("a", { href: detailHref, className: "ml-auto", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", children: "Részletes nézet" }) }) : null
4156
- ] }),
4157
- hasUnsavedChanges ? /* @__PURE__ */ jsx(Text, { className: "mt-2 text-xs text-ui-fg-warning", children: "A kapcsolat-teszt mindig a mentett konfigurációt használja. Mentsd a módosításokat a teszt előtt." }) : !selected.enabled ? /* @__PURE__ */ jsx(Text, { className: "mt-2 text-xs text-ui-fg-muted", children: "Kapcsolat-teszt csak bekapcsolt integráción futtatható." }) : !selected.configured ? /* @__PURE__ */ jsx(Text, { className: "mt-2 text-xs text-ui-fg-muted", children: "Töltsd ki a kötelező mezőket és mentsd az integrációt a teszteléshez." }) : null
4158
- ] })
4159
- ] }) : /* @__PURE__ */ jsx(Text, { children: "Nincs kiválasztott integráció." }) })
4019
+ )
4020
+ ] }) : operation.status === "failed" ? /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "A normál rendelési művelet újraindítható." }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "—" }) }) })
4021
+ ] }, operation.id)) })
4022
+ ] }),
4023
+ loading ? /* @__PURE__ */ jsx("div", { className: "p-8 text-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Műveletek betöltése…" }) }) : null,
4024
+ !loading && loadError ? /* @__PURE__ */ jsxs("div", { className: "m-6 rounded-lg border border-ui-border-error p-4", children: [
4025
+ /* @__PURE__ */ jsx(Text, { className: "font-medium text-ui-fg-error", children: "Az integrációs műveletek nem tölthetők be." }),
4026
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: loadError })
4027
+ ] }) : null,
4028
+ !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ő integrációs művelet." }) }) : null
4160
4029
  ] })
4161
4030
  ] });
4162
4031
  };
4163
- function Notice({ title, children }) {
4164
- return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-ui-bg-subtle p-4", children: [
4165
- /* @__PURE__ */ jsx(Text, { className: "font-medium", children: title }),
4166
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children })
4167
- ] });
4168
- }
4169
- function FieldEditor({
4170
- field,
4032
+ function SummaryCard({
4033
+ label,
4171
4034
  value,
4172
- hasSecret,
4173
- clearPending,
4174
- onChange,
4175
- onClearSecret,
4176
- onRestoreSecret
4035
+ danger = false
4177
4036
  }) {
4178
- return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [
4179
- /* @__PURE__ */ jsxs(Text, { className: "font-medium", children: [
4180
- field.label,
4181
- field.required ? " *" : ""
4182
- ] }),
4183
- field.type === "boolean" ? /* @__PURE__ */ jsxs("div", { className: "flex h-8 items-center gap-2", children: [
4184
- /* @__PURE__ */ jsx(Switch, { checked: Boolean(value), onCheckedChange: onChange }),
4185
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: value ? "Igen" : "Nem" })
4186
- ] }) : field.type === "select" ? /* @__PURE__ */ jsxs(
4187
- "select",
4188
- {
4189
- className: "h-8 rounded-md border bg-ui-bg-field px-2 text-sm",
4190
- value: String(value || ""),
4191
- onChange: (event) => onChange(event.target.value),
4192
- children: [
4193
- /* @__PURE__ */ jsx("option", { value: "", children: "—" }),
4194
- (field.options || []).map((option) => /* @__PURE__ */ jsx("option", { value: option.value, children: option.label }, option.value))
4195
- ]
4196
- }
4197
- ) : /* @__PURE__ */ jsx(
4198
- Input,
4199
- {
4200
- type: field.type === "secret" ? "password" : field.type === "number" ? "number" : "text",
4201
- value: String(value || ""),
4202
- placeholder: field.type === "secret" && hasSecret && !clearPending ? "•••••••• (beállítva – hagyd üresen a megtartáshoz)" : field.help,
4203
- onChange: (event) => onChange(event.target.value)
4037
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border p-4", children: [
4038
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: label }),
4039
+ /* @__PURE__ */ jsx("div", { className: danger ? "text-ui-fg-error text-2xl font-semibold" : "text-2xl font-semibold", children: value })
4040
+ ] });
4041
+ }
4042
+ function StatusText({ status }) {
4043
+ const labels = {
4044
+ pending: "Várakozik",
4045
+ processing: "Folyamatban",
4046
+ succeeded: "Sikeres",
4047
+ failed: "Sikertelen",
4048
+ needs_reconciliation: "Egyeztetést igényel"
4049
+ };
4050
+ const className = status === "failed" || status === "needs_reconciliation" ? "font-medium text-ui-fg-error" : status === "succeeded" ? "font-medium text-ui-fg-success" : "font-medium";
4051
+ return /* @__PURE__ */ jsx("span", { className, children: labels[status] });
4052
+ }
4053
+ function providerLabel(value) {
4054
+ const labels = {
4055
+ stripe: "Stripe",
4056
+ simplepay: "SimplePay",
4057
+ billingo: "Billingo",
4058
+ foxpost: "FOXPOST",
4059
+ gls: "GLS",
4060
+ packeta: "Packeta",
4061
+ dpd: "DPD",
4062
+ mpl: "MPL"
4063
+ };
4064
+ return labels[value] || value;
4065
+ }
4066
+ function formatDate$1(value) {
4067
+ if (!value) return "—";
4068
+ const date = new Date(value);
4069
+ if (Number.isNaN(date.getTime())) return "—";
4070
+ return new Intl.DateTimeFormat("hu-HU", {
4071
+ dateStyle: "short",
4072
+ timeStyle: "short"
4073
+ }).format(date);
4074
+ }
4075
+ const config$2 = defineRouteConfig({
4076
+ label: "Integrációs műveletek",
4077
+ icon: Newspaper,
4078
+ rank: 37
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.");
4204
4106
  }
4205
- ),
4206
- field.type === "secret" && hasSecret ? /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
4207
- /* @__PURE__ */ jsx(Text, { className: `text-xs ${clearPending ? "text-ui-fg-error" : "text-ui-fg-muted"}`, children: clearPending ? "A mentett titok a következő mentéskor törlődik." : "Titkos érték beállítva." }),
4208
- /* @__PURE__ */ jsx(
4209
- "button",
4210
- {
4211
- type: "button",
4212
- className: "shrink-0 text-xs font-medium text-ui-fg-interactive hover:underline",
4213
- onClick: clearPending ? onRestoreSecret : onClearSecret,
4214
- children: clearPending ? "Törlés visszavonása" : "Titok törlése"
4215
- }
4216
- )
4217
- ] }) : field.help ? /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-muted", children: field.help }) : null
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
4218
4166
  ] });
4219
- }
4220
- function StatusBox({
4221
- label,
4222
- value,
4223
- state
4224
- }) {
4225
- return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border p-3", children: [
4226
- /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-muted", children: label }),
4227
- /* @__PURE__ */ jsx(Text, { className: connectionTextClass(state), children: value })
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
4228
4175
  ] });
4229
4176
  }
4230
- function detailPageForIntegration(key) {
4231
- if (key === "google-merchant") return `${adminBase$1}/marketing/google-merchant`;
4232
- if (key === "arukereso") return `${adminBase$1}/marketing/arukereso`;
4233
- return null;
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
+ ] });
4234
4183
  }
4235
- function connectionPresentation(item) {
4236
- if (item.last_test_status === "ok") {
4237
- return { label: "Ellenőrizve", state: "success" };
4238
- }
4239
- if (item.last_test_status === "error") {
4240
- return { label: "Hiba", state: "error" };
4241
- }
4242
- if (item.last_test_at) {
4243
- return { label: "Részleges ellenőrzés", state: "warning" };
4244
- }
4245
- return { label: "Nem ellenőrzött", state: "neutral" };
4184
+ function normalizeAdminHref(path) {
4185
+ if (!path.startsWith("/app")) return path;
4186
+ return `${adminBase$1}${path.slice(4)}`;
4246
4187
  }
4247
- function connectionTextClass(state) {
4248
- if (state === "success") return "font-medium text-ui-fg-success";
4249
- if (state === "warning") return "font-medium text-ui-fg-warning";
4250
- if (state === "error") return "font-medium text-ui-fg-error";
4251
- return "font-medium";
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);
4252
4192
  }
4253
- const config$1 = defineRouteConfig({ label: "Integrációk" });
4193
+ const config$1 = defineRouteConfig({
4194
+ label: "Production readiness",
4195
+ rank: 39
4196
+ });
4254
4197
  const backendUrl$1 = (__BACKEND_URL__ || "").replace(/\/+$/, "");
4255
4198
  const adminBase = (__BASE__ || "/app").replace(/\/+$/, "");
4256
- function apiUrl$1(path) {
4257
- return `${backendUrl$1}${path.startsWith("/") ? path : `/${path}`}`;
4258
- }
4259
- const IntegrationOperationsPage = () => {
4260
- const [operations, setOperations] = useState([]);
4261
- const [summary, setSummary] = useState({
4262
- failed: 0,
4263
- needsReconciliation: 0,
4264
- processing: 0
4265
- });
4266
- const [count, setCount] = useState(0);
4267
- const [status, setStatus] = useState("problems");
4268
- const [provider, setProvider] = useState("all");
4269
- const [query, setQuery] = useState("");
4270
- const [loading, setLoading] = useState(false);
4271
- const [actionLoading, setActionLoading] = useState(null);
4272
- const [loadError, setLoadError] = useState(null);
4199
+ const apiUrl$1 = (path) => `${backendUrl$1}${path.startsWith("/") ? path : `/${path}`}`;
4200
+ const CATEGORY_ORDER = [
4201
+ "payment",
4202
+ "invoicing",
4203
+ "shipping",
4204
+ "notification",
4205
+ "legal",
4206
+ "marketing"
4207
+ ];
4208
+ const CATEGORY_LABEL = {
4209
+ payment: "Fizetés",
4210
+ invoicing: "Számlázás",
4211
+ shipping: "Szállítás",
4212
+ notification: "Értesítés",
4213
+ legal: "Jogi integráció",
4214
+ marketing: "Marketing"
4215
+ };
4216
+ const IntegrationsPage = () => {
4217
+ const [items, setItems] = useState([]);
4218
+ const [selectedKey, setSelectedKey] = useState(null);
4219
+ const [draft, setDraft] = useState({});
4220
+ const [clearSecrets, setClearSecrets] = useState([]);
4221
+ const [enabled, setEnabled] = useState(false);
4222
+ const [loading, setLoading] = useState(true);
4223
+ const [saving, setSaving] = useState(false);
4224
+ const [testing, setTesting] = useState(false);
4225
+ const [restartNotice, setRestartNotice] = useState(false);
4226
+ const visibleItems = useMemo(
4227
+ () => items.filter((item) => CATEGORY_ORDER.includes(item.category)),
4228
+ [items]
4229
+ );
4230
+ const selected = useMemo(
4231
+ () => visibleItems.find((item) => item.key === selectedKey) || null,
4232
+ [visibleItems, selectedKey]
4233
+ );
4234
+ const hasUnsavedChanges = useMemo(() => {
4235
+ if (!selected) return false;
4236
+ if (enabled !== selected.enabled || clearSecrets.length > 0) return true;
4237
+ return selected.fields.some((field) => {
4238
+ const value = draft[field.name];
4239
+ if (field.type === "secret") {
4240
+ return Boolean(String(value || "").trim());
4241
+ }
4242
+ if (field.type === "boolean") {
4243
+ return Boolean(value) !== (selected.values[field.name] === "true");
4244
+ }
4245
+ return String(value || "").trim() !== String(selected.values[field.name] || "").trim();
4246
+ });
4247
+ }, [selected, enabled, draft, clearSecrets]);
4273
4248
  const load = useCallback(async () => {
4274
4249
  setLoading(true);
4275
- setLoadError(null);
4276
4250
  try {
4277
- const params = new URLSearchParams({
4278
- limit: "100",
4279
- status
4251
+ const response = await fetch(apiUrl$1("/admin/integrations"), {
4252
+ credentials: "include"
4280
4253
  });
4281
- if (provider !== "all") params.set("provider", provider);
4282
- const response = await fetch(
4283
- apiUrl$1(`/admin/integration-operations?${params.toString()}`),
4284
- { credentials: "include" }
4285
- );
4286
- const payload = await response.json().catch(() => ({}));
4254
+ const data = await response.json().catch(() => ({}));
4287
4255
  if (!response.ok) {
4288
- throw new Error(
4289
- payload.message || "Az integrációs műveletek nem tölthetők be."
4290
- );
4256
+ throw new Error(data.message || "Az integrációk nem tölthetők be.");
4291
4257
  }
4292
- setOperations(payload.operations || []);
4293
- setCount(payload.count || 0);
4294
- setSummary(
4295
- payload.summary || {
4296
- failed: 0,
4297
- needsReconciliation: 0,
4298
- processing: 0
4299
- }
4258
+ const integrations = data.integrations || [];
4259
+ setItems(integrations);
4260
+ const eligible = integrations.filter(
4261
+ (item) => CATEGORY_ORDER.includes(item.category)
4262
+ );
4263
+ setSelectedKey(
4264
+ (current) => current && eligible.some((item) => item.key === current) ? current : eligible[0]?.key || null
4300
4265
  );
4301
4266
  } catch (error) {
4302
- setOperations([]);
4303
- setLoadError(
4304
- error instanceof Error ? error.message : "Az integrációs műveletek nem tölthetők be."
4267
+ toast.error(
4268
+ error instanceof Error ? error.message : "Az integrációk nem tölthetők be."
4305
4269
  );
4306
4270
  } finally {
4307
4271
  setLoading(false);
4308
4272
  }
4309
- }, [provider, status]);
4273
+ }, []);
4310
4274
  useEffect(() => {
4311
4275
  void load();
4312
4276
  }, [load]);
4313
- const visible = useMemo(() => {
4314
- const value = query.trim().toLowerCase();
4315
- if (!value) return operations;
4316
- return operations.filter(
4317
- (operation) => [
4318
- operation.provider,
4319
- operation.operation_type,
4320
- operation.entity_type,
4321
- operation.entity_id,
4322
- operation.external_id,
4323
- operation.error_summary
4324
- ].some(
4325
- (item) => String(item || "").toLowerCase().includes(value)
4326
- )
4327
- );
4328
- }, [operations, query]);
4329
- const reconcile = async (operation, decision) => {
4330
- const confirmed = confirm(
4331
- decision === "confirmed_succeeded" ? "Megerősíted, hogy a külső szolgáltatónál ez a művelet valóban sikeresen megtörtént?" : "Megerősíted, hogy a külső szolgáltatónál ez a művelet biztosan NEM történt meg? Ez engedélyezi a normál művelet későbbi újrapróbálását."
4332
- );
4333
- if (!confirmed) return;
4334
- let externalId = operation.external_id || void 0;
4335
- if (decision === "confirmed_succeeded" && !externalId) {
4336
- externalId = prompt(
4337
- "Add meg a külső szolgáltató azonosítóját (pl. Billingo document ID vagy shipment ID):"
4338
- )?.trim() || void 0;
4339
- if (!externalId) {
4340
- toast.error("A sikeres lezáráshoz külső azonosító szükséges.");
4341
- return;
4277
+ useEffect(() => {
4278
+ if (!selected) return;
4279
+ const next = {};
4280
+ for (const field of selected.fields) {
4281
+ if (field.type === "secret") next[field.name] = "";
4282
+ else if (field.type === "boolean") {
4283
+ next[field.name] = selected.values[field.name] === "true";
4284
+ } else {
4285
+ next[field.name] = selected.values[field.name] || "";
4286
+ }
4287
+ }
4288
+ setDraft(next);
4289
+ setClearSecrets([]);
4290
+ setEnabled(selected.enabled);
4291
+ setRestartNotice(false);
4292
+ }, [selected?.key, selected?.values, selected?.enabled]);
4293
+ const save = async () => {
4294
+ if (!selected) return;
4295
+ setSaving(true);
4296
+ try {
4297
+ const values = {};
4298
+ for (const field of selected.fields) {
4299
+ const value = draft[field.name];
4300
+ if (field.type === "secret" && !String(value || "").trim()) continue;
4301
+ values[field.name] = value;
4302
+ }
4303
+ const response = await fetch(apiUrl$1(`/admin/integrations/${selected.key}`), {
4304
+ method: "POST",
4305
+ credentials: "include",
4306
+ headers: { "Content-Type": "application/json" },
4307
+ body: JSON.stringify({
4308
+ enabled,
4309
+ values,
4310
+ clear_secrets: clearSecrets
4311
+ })
4312
+ });
4313
+ const data = await response.json().catch(() => ({}));
4314
+ if (!response.ok) {
4315
+ throw new Error(data.message || "A mentés nem sikerült.");
4342
4316
  }
4317
+ if (data.integration) replaceIntegration(data.integration);
4318
+ setClearSecrets([]);
4319
+ setRestartNotice(Boolean(data.integration?.restart_required));
4320
+ toast.success(data.message || "Beállítások mentve.");
4321
+ } catch (error) {
4322
+ toast.error(error instanceof Error ? error.message : "A mentés nem sikerült.");
4323
+ } finally {
4324
+ setSaving(false);
4343
4325
  }
4344
- const note = prompt(
4345
- "Opcionális megjegyzés az egyeztetéshez:",
4346
- ""
4347
- )?.trim();
4348
- setActionLoading(operation.id);
4326
+ };
4327
+ const test = async () => {
4328
+ if (!selected || hasUnsavedChanges) return;
4329
+ setTesting(true);
4349
4330
  try {
4350
- const response = await fetch(
4351
- apiUrl$1(`/admin/integration-operations/${operation.id}/reconcile`),
4352
- {
4353
- method: "POST",
4354
- credentials: "include",
4355
- headers: { "Content-Type": "application/json" },
4356
- body: JSON.stringify({ decision, externalId, note })
4357
- }
4358
- );
4359
- const payload = await response.json().catch(() => ({}));
4360
- if (!response.ok) {
4361
- throw new Error(
4362
- payload.message || "Az egyeztetés lezárása nem sikerült."
4363
- );
4331
+ const response = await fetch(apiUrl$1(`/admin/integrations/${selected.key}/test`), {
4332
+ method: "POST",
4333
+ credentials: "include"
4334
+ });
4335
+ const data = await response.json().catch(() => ({}));
4336
+ if (data.integration) replaceIntegration(data.integration);
4337
+ if (!response.ok || !data.ok) {
4338
+ throw new Error(data.message || "A kapcsolat tesztelése nem sikerült.");
4339
+ }
4340
+ if (data.verified) {
4341
+ toast.success(data.message || "Kapcsolat ellenőrizve.");
4342
+ } else {
4343
+ toast.success(data.message || "Részleges ellenőrzés sikeres.");
4364
4344
  }
4365
- toast.success(
4366
- decision === "confirmed_succeeded" ? "A művelet sikeresként lezárva." : "A művelet újrapróbálhatóvá téve."
4367
- );
4368
- await load();
4369
4345
  } catch (error) {
4370
4346
  toast.error(
4371
- error instanceof Error ? error.message : "Az egyeztetés lezárása nem sikerült."
4347
+ error instanceof Error ? error.message : "A kapcsolat tesztelése nem sikerült."
4372
4348
  );
4349
+ void load();
4373
4350
  } finally {
4374
- setActionLoading(null);
4351
+ setTesting(false);
4375
4352
  }
4376
4353
  };
4377
- return /* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
4378
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-4 border-b px-6 py-4", children: [
4379
- /* @__PURE__ */ jsxs("div", { children: [
4380
- /* @__PURE__ */ jsx(Heading, { children: "Integrációs műveletek" }),
4381
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Külső API műveletek, hibák és kézi reconciliation kezelése." })
4382
- ] }),
4383
- /* @__PURE__ */ jsx(
4384
- Button,
4385
- {
4386
- variant: "secondary",
4387
- isLoading: loading,
4388
- onClick: () => void load(),
4389
- children: "Frissítés"
4390
- }
4354
+ const replaceIntegration = (integration) => {
4355
+ setItems(
4356
+ (current) => current.map(
4357
+ (item) => item.key === integration.key ? integration : item
4391
4358
  )
4359
+ );
4360
+ };
4361
+ const detailHref = selected ? detailPageForIntegration(selected.key) : null;
4362
+ const connection = selected ? connectionPresentation(selected) : null;
4363
+ return /* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
4364
+ /* @__PURE__ */ jsxs("div", { className: "border-b px-6 py-5", children: [
4365
+ /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Integrációk" }),
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." })
4392
4367
  ] }),
4393
- /* @__PURE__ */ jsxs("div", { className: "grid gap-3 border-b px-6 py-4 md:grid-cols-3", children: [
4394
- /* @__PURE__ */ jsx(
4395
- SummaryCard,
4396
- {
4397
- label: "Egyeztetést igényel",
4398
- value: summary.needsReconciliation,
4399
- danger: summary.needsReconciliation > 0
4400
- }
4401
- ),
4402
- /* @__PURE__ */ jsx(
4403
- SummaryCard,
4404
- {
4405
- label: "Sikertelen",
4406
- value: summary.failed,
4407
- danger: summary.failed > 0
4408
- }
4409
- ),
4410
- /* @__PURE__ */ jsx(SummaryCard, { label: "Folyamatban", value: summary.processing })
4411
- ] }),
4412
- summary.needsReconciliation > 0 ? /* @__PURE__ */ jsxs("div", { className: "border-b border-ui-border-warning bg-ui-bg-base px-6 py-4", children: [
4413
- /* @__PURE__ */ jsxs(Text, { className: "font-medium text-ui-fg-warning", children: [
4414
- summary.needsReconciliation,
4415
- " műveletnél nem dönthető el automatikusan, hogy a külső szolgáltató végrehajtotta-e a kérést."
4416
- ] }),
4417
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Ellenőrizd a szolgáltatónál, majd csak ezután jelöld sikeresnek vagy újrapróbálhatónak. Így elkerülhető a duplikált számla, csomag vagy fizetés." })
4418
- ] }) : null,
4419
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-end gap-3 border-b px-6 py-4", children: [
4420
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
4421
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Státusz" }),
4422
- /* @__PURE__ */ jsxs(Select, { value: status, onValueChange: setStatus, children: [
4423
- /* @__PURE__ */ jsx(Select.Trigger, { className: "w-52", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
4424
- /* @__PURE__ */ jsxs(Select.Content, { children: [
4425
- /* @__PURE__ */ jsx(Select.Item, { value: "problems", children: "Hibák + egyeztetés" }),
4426
- /* @__PURE__ */ jsx(Select.Item, { value: "needs_reconciliation", children: "Egyeztetést igényel" }),
4427
- /* @__PURE__ */ jsx(Select.Item, { value: "failed", children: "Sikertelen" }),
4428
- /* @__PURE__ */ jsx(Select.Item, { value: "processing", children: "Folyamatban" }),
4429
- /* @__PURE__ */ jsx(Select.Item, { value: "pending", children: "Várakozik" }),
4430
- /* @__PURE__ */ jsx(Select.Item, { value: "succeeded", children: "Sikeres" }),
4431
- /* @__PURE__ */ jsx(Select.Item, { value: "all", children: "Összes" })
4432
- ] })
4433
- ] })
4434
- ] }),
4435
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
4436
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "Provider" }),
4437
- /* @__PURE__ */ jsxs(Select, { value: provider, onValueChange: setProvider, children: [
4438
- /* @__PURE__ */ jsx(Select.Trigger, { className: "w-44", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
4439
- /* @__PURE__ */ jsxs(Select.Content, { children: [
4440
- /* @__PURE__ */ jsx(Select.Item, { value: "all", children: "Összes" }),
4441
- [
4442
- "stripe",
4443
- "simplepay",
4444
- "billingo",
4445
- "foxpost",
4446
- "gls",
4447
- "packeta",
4448
- "dpd",
4449
- "mpl"
4450
- ].map((item) => /* @__PURE__ */ jsx(Select.Item, { value: item, children: providerLabel(item) }, item))
4451
- ] })
4452
- ] })
4453
- ] }),
4454
- /* @__PURE__ */ jsx(
4455
- Input,
4456
- {
4457
- className: "max-w-sm",
4458
- value: query,
4459
- onChange: (event) => setQuery(event.target.value),
4460
- placeholder: "Keresés művelet, rendelés, külső ID vagy hiba alapján"
4461
- }
4462
- ),
4463
- /* @__PURE__ */ jsxs(Text, { size: "small", className: "text-ui-fg-subtle", children: [
4464
- count,
4465
- " találat"
4466
- ] })
4467
- ] }),
4468
- /* @__PURE__ */ jsxs("div", { className: "overflow-x-auto", children: [
4469
- /* @__PURE__ */ jsxs("table", { className: "w-full text-left text-sm", children: [
4470
- /* @__PURE__ */ jsx("thead", { className: "border-b bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
4471
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Státusz" }),
4472
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Provider / művelet" }),
4473
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Entitás" }),
4474
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Külső ID" }),
4475
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Próbálkozás" }),
4476
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Hiba / idő" }),
4477
- /* @__PURE__ */ jsx("th", { className: "p-4", children: "Műveletek" })
4478
- ] }) }),
4479
- /* @__PURE__ */ jsx("tbody", { children: visible.map((operation) => /* @__PURE__ */ jsxs("tr", { className: "border-b align-top", children: [
4480
- /* @__PURE__ */ jsx("td", { className: "p-4", children: /* @__PURE__ */ jsx(StatusText, { status: operation.status }) }),
4481
- /* @__PURE__ */ jsxs("td", { className: "p-4", children: [
4482
- /* @__PURE__ */ jsx("strong", { children: providerLabel(operation.provider) }),
4483
- /* @__PURE__ */ jsx("div", { className: "text-ui-fg-subtle", children: operation.operation_type })
4484
- ] }),
4485
- /* @__PURE__ */ jsxs("td", { className: "p-4", children: [
4486
- operation.entity_type === "order" ? /* @__PURE__ */ jsx(
4487
- "a",
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: [
4369
+ /* @__PURE__ */ jsx("aside", { className: "border-r p-4", children: CATEGORY_ORDER.map((category) => {
4370
+ const categoryItems = visibleItems.filter(
4371
+ (item) => item.category === category
4372
+ );
4373
+ if (!categoryItems.length) return null;
4374
+ return /* @__PURE__ */ jsxs("div", { className: "mb-6 last:mb-0", children: [
4375
+ /* @__PURE__ */ jsx(Text, { className: "mb-2 px-1 text-xs font-medium uppercase tracking-wide text-ui-fg-muted", children: CATEGORY_LABEL[category] }),
4376
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: categoryItems.map((item) => {
4377
+ const itemConnection = connectionPresentation(item);
4378
+ return /* @__PURE__ */ jsxs(
4379
+ "button",
4488
4380
  {
4489
- href: `${adminBase}/orders/${operation.entity_id}`,
4490
- className: "text-ui-fg-interactive",
4491
- children: operation.entity_id
4492
- }
4493
- ) : /* @__PURE__ */ jsx("span", { children: operation.entity_id }),
4494
- /* @__PURE__ */ jsx("div", { className: "text-ui-fg-subtle", children: operation.entity_type })
4381
+ type: "button",
4382
+ onClick: () => setSelectedKey(item.key),
4383
+ className: `rounded-lg border p-3 text-left transition-colors hover:bg-ui-bg-subtle ${selectedKey === item.key ? "bg-ui-bg-subtle" : "bg-ui-bg-base"}`,
4384
+ children: [
4385
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
4386
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: item.label }),
4387
+ /* @__PURE__ */ jsx("span", { className: item.enabled ? "text-xs font-medium text-ui-fg-success" : "text-xs text-ui-fg-muted", children: item.enabled ? "Aktív" : "Kikapcsolva" })
4388
+ ] }),
4389
+ /* @__PURE__ */ jsxs("div", { className: "mt-1 text-xs text-ui-fg-subtle", children: [
4390
+ item.configured ? "Konfigurálva" : "Beállítás szükséges",
4391
+ " · ",
4392
+ itemConnection.label
4393
+ ] })
4394
+ ]
4395
+ },
4396
+ item.key
4397
+ );
4398
+ }) })
4399
+ ] }, category);
4400
+ }) }),
4401
+ /* @__PURE__ */ jsx("main", { className: "min-w-0 p-6", children: selected && connection ? /* @__PURE__ */ jsxs("div", { className: "flex max-w-4xl flex-col gap-6", children: [
4402
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-4", children: [
4403
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
4404
+ /* @__PURE__ */ jsx(Heading, { level: "h2", children: selected.label }),
4405
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 text-ui-fg-subtle", children: selected.description })
4495
4406
  ] }),
4496
- /* @__PURE__ */ jsx("td", { className: "p-4", children: operation.external_id || "—" }),
4497
- /* @__PURE__ */ jsx("td", { className: "p-4", children: operation.attempts }),
4498
- /* @__PURE__ */ jsxs("td", { className: "max-w-md p-4", children: [
4499
- operation.error_summary ? /* @__PURE__ */ jsx("div", { className: "text-ui-fg-error", children: operation.error_summary }) : null,
4500
- /* @__PURE__ */ jsx("div", { className: "text-ui-fg-subtle", children: formatDate(operation.updated_at) })
4407
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-end gap-1", children: [
4408
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
4409
+ /* @__PURE__ */ jsx(Switch, { checked: enabled, onCheckedChange: setEnabled }),
4410
+ /* @__PURE__ */ jsx(Text, { children: enabled ? "Bekapcsolva" : "Kikapcsolva" })
4411
+ ] }),
4412
+ hasUnsavedChanges ? /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-warning", children: "Nem mentett módosítások" }) : null
4413
+ ] })
4414
+ ] }),
4415
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-3 sm:grid-cols-2 xl:grid-cols-4", children: [
4416
+ /* @__PURE__ */ jsx(StatusBox, { label: "Telepítve", value: selected.installed ? "Igen" : "Nem", state: selected.installed ? "success" : "neutral" }),
4417
+ /* @__PURE__ */ jsx(StatusBox, { label: "Konfigurálva", value: selected.configured ? "Igen" : "Nem", state: selected.configured ? "success" : "neutral" }),
4418
+ /* @__PURE__ */ jsx(StatusBox, { label: "Aktív", value: selected.enabled ? "Igen" : "Nem", state: selected.enabled ? "success" : "neutral" }),
4419
+ /* @__PURE__ */ jsx(StatusBox, { label: "Kapcsolat", value: connection.label, state: connection.state })
4420
+ ] }),
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,
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,
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,
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,
4425
+ /* @__PURE__ */ jsxs("div", { children: [
4426
+ /* @__PURE__ */ jsx(Heading, { level: "h3", children: "Beállítások" }),
4427
+ /* @__PURE__ */ jsx("div", { className: "mt-4 grid gap-4 sm:grid-cols-2", children: selected.fields.map((field) => /* @__PURE__ */ jsx(
4428
+ FieldEditor,
4429
+ {
4430
+ field,
4431
+ value: draft[field.name],
4432
+ hasSecret: Boolean(selected.secrets[field.name]),
4433
+ clearPending: clearSecrets.includes(field.name),
4434
+ onChange: (value) => {
4435
+ setDraft((current) => ({ ...current, [field.name]: value }));
4436
+ if (field.type === "secret" && String(value || "").trim()) {
4437
+ setClearSecrets(
4438
+ (current) => current.filter((name) => name !== field.name)
4439
+ );
4440
+ }
4441
+ },
4442
+ onClearSecret: () => {
4443
+ setDraft((current) => ({ ...current, [field.name]: "" }));
4444
+ setClearSecrets(
4445
+ (current) => current.includes(field.name) ? current : [...current, field.name]
4446
+ );
4447
+ },
4448
+ onRestoreSecret: () => setClearSecrets(
4449
+ (current) => current.filter((name) => name !== field.name)
4450
+ )
4451
+ },
4452
+ field.name
4453
+ )) })
4454
+ ] }),
4455
+ selected.last_test_message ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border p-4", children: [
4456
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
4457
+ /* @__PURE__ */ jsx(Text, { className: "font-medium", children: "Utolsó kapcsolat-teszt" }),
4458
+ /* @__PURE__ */ jsx(Text, { className: connectionTextClass(connection.state), children: connection.label })
4501
4459
  ] }),
4502
- /* @__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: [
4460
+ /* @__PURE__ */ jsx(Text, { className: "mt-1 text-ui-fg-subtle", children: selected.last_test_message }),
4461
+ selected.last_test_at ? /* @__PURE__ */ jsx(Text, { className: "mt-1 text-xs text-ui-fg-muted", children: new Date(selected.last_test_at).toLocaleString("hu-HU") }) : null
4462
+ ] }) : null,
4463
+ /* @__PURE__ */ jsxs("div", { className: "border-t pt-5", children: [
4464
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
4503
4465
  /* @__PURE__ */ jsx(
4504
4466
  Button,
4505
4467
  {
4506
- size: "small",
4507
- disabled: Boolean(actionLoading),
4508
- isLoading: actionLoading === operation.id,
4509
- onClick: () => void reconcile(operation, "confirmed_succeeded"),
4510
- children: "Megtörtént"
4468
+ isLoading: saving,
4469
+ disabled: saving || testing || !hasUnsavedChanges,
4470
+ onClick: () => void save(),
4471
+ children: "Mentés"
4511
4472
  }
4512
4473
  ),
4513
4474
  /* @__PURE__ */ jsx(
4514
4475
  Button,
4515
4476
  {
4516
- size: "small",
4517
4477
  variant: "secondary",
4518
- disabled: Boolean(actionLoading),
4519
- onClick: () => void reconcile(operation, "confirmed_not_executed"),
4520
- children: "Nem történt meg"
4478
+ isLoading: testing,
4479
+ disabled: saving || testing || hasUnsavedChanges || !selected.configured || !selected.enabled,
4480
+ onClick: () => void test(),
4481
+ children: "Kapcsolat tesztelése"
4521
4482
  }
4522
- )
4523
- ] }) : operation.status === "failed" ? /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "A normál rendelési művelet újraindítható." }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "—" }) }) })
4524
- ] }, operation.id)) })
4525
- ] }),
4526
- loading ? /* @__PURE__ */ jsx("div", { className: "p-8 text-center", children: /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Műveletek betöltése…" }) }) : null,
4527
- !loading && loadError ? /* @__PURE__ */ jsxs("div", { className: "m-6 rounded-lg border border-ui-border-error p-4", children: [
4528
- /* @__PURE__ */ jsx(Text, { className: "font-medium text-ui-fg-error", children: "Az integrációs műveletek nem tölthetők be." }),
4529
- /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: loadError })
4530
- ] }) : null,
4531
- !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ő integrációs művelet." }) }) : null
4483
+ ),
4484
+ detailHref ? /* @__PURE__ */ jsx("a", { href: detailHref, className: "ml-auto", children: /* @__PURE__ */ jsx(Button, { variant: "secondary", children: "Részletes nézet" }) }) : null
4485
+ ] }),
4486
+ hasUnsavedChanges ? /* @__PURE__ */ jsx(Text, { className: "mt-2 text-xs text-ui-fg-warning", children: "A kapcsolat-teszt mindig a mentett konfigurációt használja. Mentsd a módosításokat a teszt előtt." }) : !selected.enabled ? /* @__PURE__ */ jsx(Text, { className: "mt-2 text-xs text-ui-fg-muted", children: "Kapcsolat-teszt csak bekapcsolt integráción futtatható." }) : !selected.configured ? /* @__PURE__ */ jsx(Text, { className: "mt-2 text-xs text-ui-fg-muted", children: "Töltsd ki a kötelező mezőket és mentsd az integrációt a teszteléshez." }) : null
4487
+ ] })
4488
+ ] }) : /* @__PURE__ */ jsx(Text, { children: "Nincs kiválasztott integráció." }) })
4532
4489
  ] })
4533
4490
  ] });
4534
4491
  };
4535
- function SummaryCard({
4492
+ function Notice({ title, children }) {
4493
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-ui-bg-subtle p-4", children: [
4494
+ /* @__PURE__ */ jsx(Text, { className: "font-medium", children: title }),
4495
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children })
4496
+ ] });
4497
+ }
4498
+ function FieldEditor({
4499
+ field,
4500
+ value,
4501
+ hasSecret,
4502
+ clearPending,
4503
+ onChange,
4504
+ onClearSecret,
4505
+ onRestoreSecret
4506
+ }) {
4507
+ return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [
4508
+ /* @__PURE__ */ jsxs(Text, { className: "font-medium", children: [
4509
+ field.label,
4510
+ field.required ? " *" : ""
4511
+ ] }),
4512
+ field.type === "boolean" ? /* @__PURE__ */ jsxs("div", { className: "flex h-8 items-center gap-2", children: [
4513
+ /* @__PURE__ */ jsx(Switch, { checked: Boolean(value), onCheckedChange: onChange }),
4514
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: value ? "Igen" : "Nem" })
4515
+ ] }) : field.type === "select" ? /* @__PURE__ */ jsxs(
4516
+ "select",
4517
+ {
4518
+ className: "h-8 rounded-md border bg-ui-bg-field px-2 text-sm",
4519
+ value: String(value || ""),
4520
+ onChange: (event) => onChange(event.target.value),
4521
+ children: [
4522
+ /* @__PURE__ */ jsx("option", { value: "", children: "—" }),
4523
+ (field.options || []).map((option) => /* @__PURE__ */ jsx("option", { value: option.value, children: option.label }, option.value))
4524
+ ]
4525
+ }
4526
+ ) : /* @__PURE__ */ jsx(
4527
+ Input,
4528
+ {
4529
+ type: field.type === "secret" ? "password" : field.type === "number" ? "number" : "text",
4530
+ value: String(value || ""),
4531
+ placeholder: field.type === "secret" && hasSecret && !clearPending ? "•••••••• (beállítva – hagyd üresen a megtartáshoz)" : field.help,
4532
+ onChange: (event) => onChange(event.target.value)
4533
+ }
4534
+ ),
4535
+ field.type === "secret" && hasSecret ? /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
4536
+ /* @__PURE__ */ jsx(Text, { className: `text-xs ${clearPending ? "text-ui-fg-error" : "text-ui-fg-muted"}`, children: clearPending ? "A mentett titok a következő mentéskor törlődik." : "Titkos érték beállítva." }),
4537
+ /* @__PURE__ */ jsx(
4538
+ "button",
4539
+ {
4540
+ type: "button",
4541
+ className: "shrink-0 text-xs font-medium text-ui-fg-interactive hover:underline",
4542
+ onClick: clearPending ? onRestoreSecret : onClearSecret,
4543
+ children: clearPending ? "Törlés visszavonása" : "Titok törlése"
4544
+ }
4545
+ )
4546
+ ] }) : field.help ? /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-muted", children: field.help }) : null
4547
+ ] });
4548
+ }
4549
+ function StatusBox({
4536
4550
  label,
4537
4551
  value,
4538
- danger = false
4552
+ state
4539
4553
  }) {
4540
- return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border p-4", children: [
4541
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: label }),
4542
- /* @__PURE__ */ jsx("div", { className: danger ? "text-ui-fg-error text-2xl font-semibold" : "text-2xl font-semibold", children: value })
4554
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border p-3", children: [
4555
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-muted", children: label }),
4556
+ /* @__PURE__ */ jsx(Text, { className: connectionTextClass(state), children: value })
4543
4557
  ] });
4544
4558
  }
4545
- function StatusText({ status }) {
4546
- const labels = {
4547
- pending: "Várakozik",
4548
- processing: "Folyamatban",
4549
- succeeded: "Sikeres",
4550
- failed: "Sikertelen",
4551
- needs_reconciliation: "Egyeztetést igényel"
4552
- };
4553
- const className = status === "failed" || status === "needs_reconciliation" ? "font-medium text-ui-fg-error" : status === "succeeded" ? "font-medium text-ui-fg-success" : "font-medium";
4554
- return /* @__PURE__ */ jsx("span", { className, children: labels[status] });
4559
+ function detailPageForIntegration(key) {
4560
+ if (key === "google-merchant") return `${adminBase}/marketing/google-merchant`;
4561
+ if (key === "arukereso") return `${adminBase}/marketing/arukereso`;
4562
+ return null;
4555
4563
  }
4556
- function providerLabel(value) {
4557
- const labels = {
4558
- stripe: "Stripe",
4559
- simplepay: "SimplePay",
4560
- billingo: "Billingo",
4561
- foxpost: "FOXPOST",
4562
- gls: "GLS",
4563
- packeta: "Packeta",
4564
- dpd: "DPD",
4565
- mpl: "MPL"
4566
- };
4567
- return labels[value] || value;
4564
+ function connectionPresentation(item) {
4565
+ if (item.last_test_status === "ok") {
4566
+ return { label: "Ellenőrizve", state: "success" };
4567
+ }
4568
+ if (item.last_test_status === "error") {
4569
+ return { label: "Hiba", state: "error" };
4570
+ }
4571
+ if (item.last_test_at) {
4572
+ return { label: "Részleges ellenőrzés", state: "warning" };
4573
+ }
4574
+ return { label: "Nem ellenőrzött", state: "neutral" };
4568
4575
  }
4569
- function formatDate(value) {
4570
- if (!value) return "—";
4571
- const date = new Date(value);
4572
- if (Number.isNaN(date.getTime())) return "—";
4573
- return new Intl.DateTimeFormat("hu-HU", {
4574
- dateStyle: "short",
4575
- timeStyle: "short"
4576
- }).format(date);
4576
+ function connectionTextClass(state) {
4577
+ if (state === "success") return "font-medium text-ui-fg-success";
4578
+ if (state === "warning") return "font-medium text-ui-fg-warning";
4579
+ if (state === "error") return "font-medium text-ui-fg-error";
4580
+ return "font-medium";
4577
4581
  }
4578
- const config = defineRouteConfig({
4579
- label: "Integrációs műveletek",
4580
- icon: Newspaper,
4581
- rank: 37
4582
- });
4582
+ const config = defineRouteConfig({ label: "Integrációk" });
4583
4583
  const EMPTY = {
4584
4584
  sourcePath: "",
4585
4585
  targetPath: "",
@@ -4916,8 +4916,8 @@ const routeModule = {
4916
4916
  handle: { label: config$9.label, translationNs: config$9.translationNs }
4917
4917
  },
4918
4918
  {
4919
- Component: ArukeresoPage,
4920
- path: "/marketing/arukereso",
4919
+ Component: BillingPage,
4920
+ path: "/billing",
4921
4921
  handle: { label: config$8.label, translationNs: config$8.translationNs }
4922
4922
  },
4923
4923
  {
@@ -4926,42 +4926,42 @@ const routeModule = {
4926
4926
  handle: { label: config$7.label, translationNs: config$7.translationNs }
4927
4927
  },
4928
4928
  {
4929
- Component: BillingPage,
4930
- path: "/billing",
4929
+ Component: ArukeresoPage,
4930
+ path: "/marketing/arukereso",
4931
4931
  handle: { label: config$6.label, translationNs: config$6.translationNs }
4932
4932
  },
4933
4933
  {
4934
4934
  Component: SeoAdminPage,
4935
4935
  path: "/marketing/seo"
4936
4936
  },
4937
- {
4938
- Component: GoogleMerchantPage,
4939
- path: "/marketing/google-merchant",
4940
- handle: { label: config$5.label, translationNs: config$5.translationNs }
4941
- },
4942
4937
  {
4943
4938
  Component: CoreAuditPage,
4944
4939
  path: "/system-monitoring/audit",
4945
- handle: { label: config$4.label, translationNs: config$4.translationNs }
4940
+ handle: { label: config$5.label, translationNs: config$5.translationNs }
4946
4941
  },
4947
4942
  {
4948
4943
  Component: IntegrationHealthPage,
4949
4944
  path: "/system-monitoring/health",
4945
+ handle: { label: config$4.label, translationNs: config$4.translationNs }
4946
+ },
4947
+ {
4948
+ Component: GoogleMerchantPage,
4949
+ path: "/marketing/google-merchant",
4950
4950
  handle: { label: config$3.label, translationNs: config$3.translationNs }
4951
4951
  },
4952
4952
  {
4953
- Component: ProductionReadinessPage,
4954
- path: "/system-monitoring/readiness",
4953
+ Component: IntegrationOperationsPage,
4954
+ path: "/system-monitoring/operations",
4955
4955
  handle: { label: config$2.label, translationNs: config$2.translationNs }
4956
4956
  },
4957
4957
  {
4958
- Component: IntegrationsPage,
4959
- path: "/settings/integrations",
4958
+ Component: ProductionReadinessPage,
4959
+ path: "/system-monitoring/readiness",
4960
4960
  handle: { label: config$1.label, translationNs: config$1.translationNs }
4961
4961
  },
4962
4962
  {
4963
- Component: IntegrationOperationsPage,
4964
- path: "/system-monitoring/operations",
4963
+ Component: IntegrationsPage,
4964
+ path: "/settings/integrations",
4965
4965
  handle: { label: config.label, translationNs: config.translationNs }
4966
4966
  },
4967
4967
  {
@@ -4981,8 +4981,8 @@ const menuItemModule = {
4981
4981
  translationNs: void 0
4982
4982
  },
4983
4983
  {
4984
- label: config$6.label,
4985
- icon: config$6.icon,
4984
+ label: config$8.label,
4985
+ icon: config$8.icon,
4986
4986
  path: "/billing",
4987
4987
  nested: void 0,
4988
4988
  rank: 36,
@@ -5004,6 +5004,14 @@ const menuItemModule = {
5004
5004
  rank: void 0,
5005
5005
  translationNs: void 0
5006
5006
  },
5007
+ {
5008
+ label: config$a.label,
5009
+ icon: config$a.icon,
5010
+ path: "/shipping",
5011
+ nested: void 0,
5012
+ rank: 35,
5013
+ translationNs: void 0
5014
+ },
5007
5015
  {
5008
5016
  label: config$9.label,
5009
5017
  icon: void 0,
@@ -5013,23 +5021,23 @@ const menuItemModule = {
5013
5021
  translationNs: void 0
5014
5022
  },
5015
5023
  {
5016
- label: config$a.label,
5017
- icon: config$a.icon,
5018
- path: "/shipping",
5024
+ label: config.label,
5025
+ icon: void 0,
5026
+ path: "/settings/integrations",
5019
5027
  nested: void 0,
5020
- rank: 35,
5028
+ rank: void 0,
5021
5029
  translationNs: void 0
5022
5030
  },
5023
5031
  {
5024
- label: config$1.label,
5032
+ label: config$3.label,
5025
5033
  icon: void 0,
5026
- path: "/settings/integrations",
5034
+ path: "/marketing/google-merchant",
5027
5035
  nested: void 0,
5028
- rank: void 0,
5036
+ rank: 41,
5029
5037
  translationNs: void 0
5030
5038
  },
5031
5039
  {
5032
- label: config$8.label,
5040
+ label: config$6.label,
5033
5041
  icon: void 0,
5034
5042
  path: "/marketing/arukereso",
5035
5043
  nested: void 0,
@@ -5038,43 +5046,35 @@ const menuItemModule = {
5038
5046
  },
5039
5047
  {
5040
5048
  label: config$5.label,
5041
- icon: void 0,
5042
- path: "/marketing/google-merchant",
5049
+ icon: config$5.icon,
5050
+ path: "/system-monitoring/audit",
5043
5051
  nested: void 0,
5044
- rank: 41,
5052
+ rank: 39,
5045
5053
  translationNs: void 0
5046
5054
  },
5047
5055
  {
5048
5056
  label: config$4.label,
5049
5057
  icon: config$4.icon,
5050
- path: "/system-monitoring/audit",
5058
+ path: "/system-monitoring/health",
5051
5059
  nested: void 0,
5052
- rank: 39,
5060
+ rank: 38,
5053
5061
  translationNs: void 0
5054
5062
  },
5055
5063
  {
5056
- label: config.label,
5057
- icon: config.icon,
5064
+ label: config$2.label,
5065
+ icon: config$2.icon,
5058
5066
  path: "/system-monitoring/operations",
5059
5067
  nested: void 0,
5060
5068
  rank: 37,
5061
5069
  translationNs: void 0
5062
5070
  },
5063
5071
  {
5064
- label: config$2.label,
5072
+ label: config$1.label,
5065
5073
  icon: void 0,
5066
5074
  path: "/system-monitoring/readiness",
5067
5075
  nested: void 0,
5068
5076
  rank: 39,
5069
5077
  translationNs: void 0
5070
- },
5071
- {
5072
- label: config$3.label,
5073
- icon: config$3.icon,
5074
- path: "/system-monitoring/health",
5075
- nested: void 0,
5076
- rank: 38,
5077
- translationNs: void 0
5078
5078
  }
5079
5079
  ]
5080
5080
  };