@shop-prompter/react 1.1.0 → 1.2.0

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.
package/dist/index.mjs CHANGED
@@ -650,6 +650,57 @@ var ShopPrompterService = class {
650
650
  }
651
651
  };
652
652
 
653
+ // src/translations.ts
654
+ var DEFAULT_LOCALE = "en";
655
+ var TRANSLATIONS = {
656
+ en: {
657
+ newChat: "New Chat",
658
+ welcomeToShopPrompter: "Welcome",
659
+ welcomeDescription: "I am your personal AI shopping assistant. Ask me what you would like to know!",
660
+ askMeAnything: "Ask me anything...",
661
+ thinking: "Thinking...",
662
+ feedbackError: "We are sorry, but we could not process your feedback. Please try again later.",
663
+ guestLimitReached: "We are sorry, the chat is no longer available for a guest user. Please log in to continue chatting.",
664
+ sessionExpired: "We are sorry. It looks like the session just expired. Please refresh the page to continue chatting.",
665
+ agentExperienceError: "We are sorry. The session seems to be expired, or the connection is wrongly configured. Please reload the page.",
666
+ apiKeyWarning: "API Key is only for development purposes",
667
+ configErrorTitle: "Configuration Error",
668
+ configErrorMessage: "The initialization requires certain parameters to be present\u201A. Please check your setup.",
669
+ configMissingParams: "Missing Parameters:",
670
+ configMissingToken: "- Valid token (not found)",
671
+ configMissingApiKey: "- Valid API Key. (not found)",
672
+ disclaimer: "AI content may be inaccurate.",
673
+ loadingProducts: "Loading products...",
674
+ productFetchError: "We are unable to fetch products.",
675
+ predefinedPromptDisclaimer: "Click on a prompt, to start the conversation"
676
+ },
677
+ de: {
678
+ newChat: "Neuer Chat",
679
+ welcomeToShopPrompter: "Willkommen",
680
+ welcomeDescription: "Ich bin Ihr pers\xF6nlicher KI-Einkaufsassistent. Fragen Sie mich alles \xFCber was Sie wissen m\xF6chten!",
681
+ askMeAnything: "Fragen Sie mich etwas...",
682
+ thinking: "Einen Moment...",
683
+ feedbackError: "Es tut uns leid, aber wir konnten Ihr Feedback nicht verarbeiten. Bitte versuchen Sie es sp\xE4ter erneut.",
684
+ guestLimitReached: "Es tut uns leid, der Chat steht f\xFCr Gastbenutzer nicht mehr zur Verf\xFCgung. Bitte melden Sie sich an, um weiter zu chatten.",
685
+ sessionExpired: "Es tut uns leid. Die Sitzung scheint abgelaufen zu sein. Bitte laden Sie die Seite neu, um weiter zu chatten.",
686
+ agentExperienceError: "Es tut uns leid. Die Sitzung scheint abgelaufen zu sein oder die Verbindung ist falsch konfiguriert. Bitte laden Sie die Seite neu.",
687
+ apiKeyWarning: "API Key ist nur f\xFCr Entwicklungszwecke",
688
+ configErrorTitle: "Konfigurationsfehler",
689
+ configErrorMessage: "Die Initialsierung ben\xF6tigt gewisse Parameter, die nicht vorhanden sind. Bitte \xFCberpr\xFCfen Sie Ihre Einrichtung.",
690
+ configMissingParams: "Fehlende Parameter:",
691
+ configMissingToken: "- G\xFCltiger Token (nicht gefunden)",
692
+ configMissingApiKey: "- API Key (nicht gefunden)",
693
+ disclaimer: "KI-Inhalte k\xF6nnen Fehler beinhalten.",
694
+ loadingProducts: "Produkte werden geladen...",
695
+ productFetchError: "Die Produkte konnten leider nicht geladen werden.",
696
+ predefinedPromptDisclaimer: "Klicken Sie auf einen Text, um die Unterhaltung zu starten"
697
+ }
698
+ };
699
+ function getTranslations(locale) {
700
+ const resolved = locale || DEFAULT_LOCALE;
701
+ return TRANSLATIONS[resolved] || TRANSLATIONS[DEFAULT_LOCALE];
702
+ }
703
+
653
704
  // src/thumbs-up-icon.component.jsx
654
705
  import * as React from "react";
655
706
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -797,12 +848,23 @@ var styles = {
797
848
  maxWidth: "100%",
798
849
  boxSizing: "border-box",
799
850
  overflow: "hidden"
851
+ },
852
+ errorContainer: {
853
+ padding: "0.75rem",
854
+ backgroundColor: "#fef2f2",
855
+ border: "1px solid #fecaca",
856
+ color: "#dc2626",
857
+ fontSize: "0.75rem",
858
+ borderRadius: "0.5rem"
800
859
  }
801
860
  };
802
861
  function ProductCardList(props) {
803
862
  const [products, setProducts] = useState(() => []);
804
863
  const [loading, setLoading] = useState(() => false);
805
864
  const [error, setError] = useState(() => null);
865
+ function t() {
866
+ return getTranslations(props.defaultLocale);
867
+ }
806
868
  function fetchProducts() {
807
869
  let skusList = props.skus;
808
870
  if (typeof skusList === "string") {
@@ -826,13 +888,13 @@ function ProductCardList(props) {
826
888
  setLoading(false);
827
889
  }).catch((err) => {
828
890
  console.error("Failed to fetch products:", err);
829
- setError((err == null ? void 0 : err.message) || "Failed to load products");
891
+ setError(t().productFetchError);
830
892
  setLoading(false);
831
893
  });
832
894
  }
833
895
  function getProductName(product) {
834
896
  var _a;
835
- const locale = props.defaultLocale || "de";
897
+ const locale = props.defaultLocale;
836
898
  const localized = ((_a = product.localization) == null ? void 0 : _a[locale]) || Object.values(product.localization || {})[0];
837
899
  return (localized == null ? void 0 : localized.name) || product.sku;
838
900
  }
@@ -856,7 +918,7 @@ function ProductCardList(props) {
856
918
  }
857
919
  function getDynamicField(product, field) {
858
920
  var _a;
859
- const locale = props.defaultLocale || "de";
921
+ const locale = props.defaultLocale;
860
922
  const localized = ((_a = product.localization) == null ? void 0 : _a[locale]) || Object.values(product.localization || {})[0];
861
923
  if (!localized) return void 0;
862
924
  const parts = field.split(".");
@@ -888,11 +950,8 @@ function ProductCardList(props) {
888
950
  props.skus ? Array.isArray(props.skus) ? props.skus.join(",") : props.skus : ""
889
951
  ]);
890
952
  return /* @__PURE__ */ jsx3(Fragment, { children: props.skus && props.skus.length > 0 ? /* @__PURE__ */ jsx3(Fragment, { children: /* @__PURE__ */ jsxs3("div", { style: styles.wrapper, children: [
891
- loading ? /* @__PURE__ */ jsx3("div", { style: styles.statusContainer, children: /* @__PURE__ */ jsx3("span", { children: "Loading products..." }) }) : null,
892
- !loading && error ? /* @__PURE__ */ jsx3("div", { style: styles.statusContainer, children: /* @__PURE__ */ jsxs3("span", { style: styles.errorText, children: [
893
- "Error: ",
894
- error
895
- ] }) }) : null,
953
+ loading ? /* @__PURE__ */ jsx3("div", { style: styles.statusContainer, children: /* @__PURE__ */ jsx3("span", { children: t().loadingProducts }) }) : null,
954
+ !loading && error ? /* @__PURE__ */ jsx3("div", { style: styles.errorContainer, children: t().productFetchError }) : null,
896
955
  !loading && products && products.length > 0 ? /* @__PURE__ */ jsx3("div", { style: styles.productCardsContainer, children: products == null ? void 0 : products.map((product) => {
897
956
  var _a;
898
957
  return /* @__PURE__ */ jsxs3("div", { style: styles.productCard, children: [
@@ -1011,7 +1070,7 @@ var styles2 = {
1011
1070
  fontFamily: 'var(--font-space-grotesk), "Space Grotesk", sans-serif',
1012
1071
  fontWeight: 500,
1013
1072
  fontStyle: "Medium",
1014
- fontSize: "32px",
1073
+ fontSize: "28px",
1015
1074
  leadingTrim: "NONE",
1016
1075
  lineHeight: "100%",
1017
1076
  letterSpacing: "0%",
@@ -1019,7 +1078,7 @@ var styles2 = {
1019
1078
  },
1020
1079
  welcomeDescription: {
1021
1080
  color: "#4b5563",
1022
- maxWidth: "20rem",
1081
+ maxWidth: "32rem",
1023
1082
  fontFamily: 'var(--font-space-grotesk), "Space Grotesk", sans-serif',
1024
1083
  fontWeight: 400,
1025
1084
  fontStyle: "Regular",
@@ -1034,7 +1093,7 @@ var styles2 = {
1034
1093
  display: "flex",
1035
1094
  flexWrap: "wrap",
1036
1095
  justifyContent: "center",
1037
- gap: "0.5rem"
1096
+ gap: "1rem"
1038
1097
  },
1039
1098
  messageContainerUser: {
1040
1099
  display: "flex",
@@ -1179,6 +1238,13 @@ var styles2 = {
1179
1238
  textAlign: "center",
1180
1239
  marginTop: "0.75rem"
1181
1240
  },
1241
+ predefinedPromptDisclaimer: {
1242
+ fontSize: "0.75rem",
1243
+ color: "#6b7280",
1244
+ textAlign: "center",
1245
+ marginTop: "2rem",
1246
+ width: "100%"
1247
+ },
1182
1248
  backdrop: {
1183
1249
  position: "fixed",
1184
1250
  top: 0,
@@ -1333,14 +1399,6 @@ var ANIMATION_STYLES = `
1333
1399
  border-color: #d1d5db !important;
1334
1400
  }
1335
1401
  `;
1336
- var TRANSLATIONS = {
1337
- newChat: "New Chat",
1338
- welcomeToShopPrompter: "Welcome to ShopPrompter",
1339
- welcomeDescription: "I am your personal AI shopping assistant. Ask me anything about our products!",
1340
- askMeAnything: "Ask me anything...",
1341
- thinking: "Thinking...",
1342
- feedbackError: "We are sorry, but we could not process your feedback. Please try again later."
1343
- };
1344
1402
  var ICONS = {
1345
1403
  chat: "https://cdn.jsdelivr.net/gh/lucide-icons/lucide@latest/icons/message-square.svg",
1346
1404
  shopprompter: "https://cdn.jsdelivr.net/gh/lucide-icons/lucide@latest/icons/bot.svg",
@@ -1363,6 +1421,20 @@ function ShopPrompter(props) {
1363
1421
  const [backdropAnimationClass, setBackdropAnimationClass] = useState2(
1364
1422
  () => ""
1365
1423
  );
1424
+ function t() {
1425
+ return getTranslations(props.defaultLocale);
1426
+ }
1427
+ function requireClickOnPredefinedPromptVal() {
1428
+ const flag = props.requireClickOnPredefinedPrompt;
1429
+ return typeof flag === "string" ? flag !== "false" : flag != null ? flag : true;
1430
+ }
1431
+ function shouldHideInput() {
1432
+ const requireClick = requireClickOnPredefinedPromptVal();
1433
+ if (!requireClick) return false;
1434
+ if (chatMessages.length > 0) return false;
1435
+ if (prompts().length === 0) return false;
1436
+ return true;
1437
+ }
1366
1438
  function hasToken() {
1367
1439
  var _a2;
1368
1440
  const token = props.shopPrompterToken || ((_a2 = apiConfigObj == null ? void 0 : apiConfigObj()) == null ? void 0 : _a2.shopPrompterToken);
@@ -1522,7 +1594,13 @@ function ShopPrompter(props) {
1522
1594
  setIsLoading(loading);
1523
1595
  },
1524
1596
  onError: (err) => {
1525
- setError(err);
1597
+ if (err.includes("429")) {
1598
+ setError(t().guestLimitReached);
1599
+ } else if (err.includes("401") || err.includes("403")) {
1600
+ setError(t().sessionExpired);
1601
+ } else {
1602
+ setError(err);
1603
+ }
1526
1604
  },
1527
1605
  onCartOperation: (ops) => {
1528
1606
  if (props.onCartOperation) {
@@ -1659,6 +1737,10 @@ function ShopPrompter(props) {
1659
1737
  return;
1660
1738
  }
1661
1739
  const response = await (service == null ? void 0 : service.getAgentExperience());
1740
+ if (!response) {
1741
+ setError(t().agentExperienceError);
1742
+ return;
1743
+ }
1662
1744
  setAgentExperience(response);
1663
1745
  })();
1664
1746
  }
@@ -1682,7 +1764,7 @@ function ShopPrompter(props) {
1682
1764
  setError(null);
1683
1765
  service == null ? void 0 : service.sendFeedback(messageId, messageContent, targetFeedback).catch((err) => {
1684
1766
  setChatMessages(oldMessages);
1685
- setError((err == null ? void 0 : err.message) || TRANSLATIONS.feedbackError);
1767
+ setError((err == null ? void 0 : err.message) || t().feedbackError);
1686
1768
  });
1687
1769
  }
1688
1770
  function canShowFeedback(message) {
@@ -1820,7 +1902,7 @@ function ShopPrompter(props) {
1820
1902
  ) : null,
1821
1903
  (agentExperience == null ? void 0 : agentExperience.agentName) ? /* @__PURE__ */ jsx4("span", { style: styles2.headerText, children: agentExperience.agentName }) : null
1822
1904
  ] }) : /* @__PURE__ */ jsx4(Fragment2, { children: /* @__PURE__ */ jsx4("div", { style: styles2.subHeaderContainer }) }),
1823
- !hasToken() && ((_a = apiConfigObj == null ? void 0 : apiConfigObj()) == null ? void 0 : _a.apiKey) ? /* @__PURE__ */ jsx4("div", { style: styles2.warningBanner, children: "API Key is only for development purposes" }) : null,
1905
+ !hasToken() && ((_a = apiConfigObj == null ? void 0 : apiConfigObj()) == null ? void 0 : _a.apiKey) ? /* @__PURE__ */ jsx4("div", { style: styles2.warningBanner, children: t().apiKeyWarning }) : null,
1824
1906
  /* @__PURE__ */ jsxs4("div", { style: styles2.subHeaderContainer, children: [
1825
1907
  /* @__PURE__ */ jsx4(
1826
1908
  "button",
@@ -1828,7 +1910,7 @@ function ShopPrompter(props) {
1828
1910
  className: "sh-header-btn",
1829
1911
  onClick: (e) => handleNewChat(),
1830
1912
  style: styles2.headerButton,
1831
- children: TRANSLATIONS.newChat
1913
+ children: t().newChat
1832
1914
  }
1833
1915
  ),
1834
1916
  props.chatPosition === "classic-chatbot" || props.chatPosition === "right-panel" || props.chatPosition === "dialog" ? /* @__PURE__ */ jsx4(
@@ -1871,7 +1953,7 @@ function ShopPrompter(props) {
1871
1953
  ...styles2.insufficientConfigTitle,
1872
1954
  fontFamily: themeObj().fontFamily || void 0
1873
1955
  },
1874
- children: "Configuration Error"
1956
+ children: t().configErrorTitle
1875
1957
  }
1876
1958
  ),
1877
1959
  /* @__PURE__ */ jsx4(
@@ -1881,7 +1963,7 @@ function ShopPrompter(props) {
1881
1963
  ...styles2.insufficientConfigMessage,
1882
1964
  fontFamily: themeObj().fontFamily || void 0
1883
1965
  },
1884
- children: "ShopPrompter requires a secure token or API key to initialize. Please check your setup."
1966
+ children: t().configErrorMessage
1885
1967
  }
1886
1968
  ),
1887
1969
  /* @__PURE__ */ jsxs4(
@@ -1899,7 +1981,7 @@ function ShopPrompter(props) {
1899
1981
  fontWeight: 600,
1900
1982
  marginBottom: "0.25rem"
1901
1983
  },
1902
- children: "Missing Parameters:"
1984
+ children: t().configMissingParams
1903
1985
  }
1904
1986
  ),
1905
1987
  /* @__PURE__ */ jsxs4(
@@ -1919,7 +2001,7 @@ function ShopPrompter(props) {
1919
2001
  style: {
1920
2002
  color: "#ef4444"
1921
2003
  },
1922
- children: "\u2717 shopPrompterToken (not found)"
2004
+ children: t().configMissingToken
1923
2005
  }
1924
2006
  ),
1925
2007
  /* @__PURE__ */ jsx4(
@@ -1928,7 +2010,7 @@ function ShopPrompter(props) {
1928
2010
  style: {
1929
2011
  color: "#ef4444"
1930
2012
  },
1931
- children: "\u2717 apiConfig.apiKey (not found)"
2013
+ children: t().configMissingApiKey
1932
2014
  }
1933
2015
  )
1934
2016
  ]
@@ -1964,8 +2046,8 @@ function ShopPrompter(props) {
1964
2046
  alt: "ShopPrompter",
1965
2047
  src: (agentExperience == null ? void 0 : agentExperience.agentLogoUrl) ? agentExperience.agentLogoUrl : ICONS.shopprompter,
1966
2048
  style: {
1967
- width: "64px",
1968
- height: "64px",
2049
+ width: "96px",
2050
+ height: "96px",
1969
2051
  marginBottom: "24px",
1970
2052
  borderRadius: "12px",
1971
2053
  objectFit: "cover"
@@ -1979,7 +2061,9 @@ function ShopPrompter(props) {
1979
2061
  ...styles2.welcomeTitle,
1980
2062
  fontFamily: themeObj().fontFamily || styles2.welcomeTitle.fontFamily
1981
2063
  },
1982
- children: ((_b = agentExperience == null ? void 0 : agentExperience.greeting) == null ? void 0 : _b.title) || TRANSLATIONS.welcomeToShopPrompter
2064
+ dangerouslySetInnerHTML: {
2065
+ __html: ((_b = agentExperience == null ? void 0 : agentExperience.greeting) == null ? void 0 : _b.title) || t().welcomeToShopPrompter
2066
+ }
1983
2067
  }
1984
2068
  ),
1985
2069
  /* @__PURE__ */ jsx4(
@@ -1989,13 +2073,19 @@ function ShopPrompter(props) {
1989
2073
  ...styles2.welcomeDescription,
1990
2074
  fontFamily: themeObj().fontFamily || styles2.welcomeDescription.fontFamily
1991
2075
  },
1992
- children: ((_c = agentExperience == null ? void 0 : agentExperience.greeting) == null ? void 0 : _c.description) || TRANSLATIONS.welcomeDescription
2076
+ dangerouslySetInnerHTML: {
2077
+ __html: ((_c = agentExperience == null ? void 0 : agentExperience.greeting) == null ? void 0 : _c.message) || t().welcomeDescription
2078
+ }
1993
2079
  }
1994
2080
  ),
1995
2081
  /* @__PURE__ */ jsx4("div", { style: styles2.buttonContainer, children: (_d = prompts()) == null ? void 0 : _d.map((item) => /* @__PURE__ */ jsx4(
1996
2082
  "button",
1997
2083
  {
1998
- style: styles2.button,
2084
+ style: {
2085
+ ...styles2.button,
2086
+ borderColor: themeObj().actionColor || "#e5e7eb",
2087
+ outlineColor: themeObj().actionColor || void 0
2088
+ },
1999
2089
  onClick: (event) => {
2000
2090
  setInput(item.prompt);
2001
2091
  handleSend(item.prompt);
@@ -2003,7 +2093,17 @@ function ShopPrompter(props) {
2003
2093
  children: item.prompt
2004
2094
  },
2005
2095
  item.prompt
2006
- )) })
2096
+ )) }),
2097
+ requireClickOnPredefinedPromptVal() && prompts().length > 0 ? /* @__PURE__ */ jsx4(
2098
+ "div",
2099
+ {
2100
+ style: {
2101
+ ...styles2.predefinedPromptDisclaimer,
2102
+ fontFamily: themeObj().fontFamily || void 0
2103
+ },
2104
+ children: t().predefinedPromptDisclaimer
2105
+ }
2106
+ ) : null
2007
2107
  ] }) : null,
2008
2108
  !showWelcome() ? /* @__PURE__ */ jsx4(
2009
2109
  "div",
@@ -2129,7 +2229,7 @@ function ShopPrompter(props) {
2129
2229
  product_card_list_component_default,
2130
2230
  {
2131
2231
  skus: message.productSkus,
2132
- defaultLocale: props.defaultLocale,
2232
+ defaultLocale: props.defaultLocale || DEFAULT_LOCALE,
2133
2233
  showPriceIfEmpty: showPriceIfEmptyVal(),
2134
2234
  visibleFields: visibleFieldsList()
2135
2235
  }
@@ -2138,19 +2238,20 @@ function ShopPrompter(props) {
2138
2238
  ] }, message.id))
2139
2239
  }
2140
2240
  ) : null,
2141
- error ? /* @__PURE__ */ jsxs4("div", { style: styles2.errorContainer, children: [
2142
- "Error: ",
2143
- error
2144
- ] }) : null
2241
+ error ? /* @__PURE__ */ jsx4("div", { style: styles2.errorContainer, children: error }) : null
2145
2242
  ]
2146
2243
  }
2147
2244
  ),
2148
- /* @__PURE__ */ jsxs4(
2245
+ !shouldHideInput() ? /* @__PURE__ */ jsxs4(
2149
2246
  "div",
2150
2247
  {
2151
2248
  style: {
2152
2249
  ...styles2.inputSection,
2153
- backgroundColor: themeObj().mainBackgroundColor || styles2.inputSection.backgroundColor
2250
+ backgroundColor: themeObj().mainBackgroundColor || styles2.inputSection.backgroundColor,
2251
+ ...error ? {
2252
+ opacity: "0.5",
2253
+ pointerEvents: "none"
2254
+ } : {}
2154
2255
  },
2155
2256
  children: [
2156
2257
  /* @__PURE__ */ jsxs4("div", { style: styles2.inputWrapper, children: [
@@ -2160,10 +2261,11 @@ function ShopPrompter(props) {
2160
2261
  id: "shop-prompter-input",
2161
2262
  type: "text",
2162
2263
  style: styles2.input,
2163
- placeholder: (agentExperience == null ? void 0 : agentExperience.hintText) || TRANSLATIONS.askMeAnything,
2264
+ placeholder: (agentExperience == null ? void 0 : agentExperience.hintText) || t().askMeAnything,
2164
2265
  value: input,
2165
2266
  onInput: (e) => onInputChange(e),
2166
- onKeyDown: (e) => onInputKeyDown(e)
2267
+ onKeyDown: (e) => onInputKeyDown(e),
2268
+ disabled: !!error
2167
2269
  }
2168
2270
  ),
2169
2271
  /* @__PURE__ */ jsx4(
@@ -2188,10 +2290,10 @@ function ShopPrompter(props) {
2188
2290
  }
2189
2291
  )
2190
2292
  ] }),
2191
- /* @__PURE__ */ jsx4("p", { style: styles2.disclaimer, children: "AI content may be inaccurate." })
2293
+ /* @__PURE__ */ jsx4("p", { style: styles2.disclaimer, children: t().disclaimer })
2192
2294
  ]
2193
2295
  }
2194
- )
2296
+ ) : null
2195
2297
  ]
2196
2298
  }
2197
2299
  ) : null
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shop-prompter/react",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.mjs",
6
6
  "types": "dist/index.d.ts",
@@ -2,6 +2,7 @@
2
2
  import * as React from "react";
3
3
  import { useState, useEffect } from "react";
4
4
  import { productApi } from "./api/product-api";
5
+ import { getTranslations } from "./translations";
5
6
  const styles = {
6
7
  productCardsContainer: {
7
8
  marginTop: "0.75rem",
@@ -91,6 +92,14 @@ const styles = {
91
92
  boxSizing: "border-box",
92
93
  overflow: "hidden",
93
94
  },
95
+ errorContainer: {
96
+ padding: "0.75rem",
97
+ backgroundColor: "#fef2f2",
98
+ border: "1px solid #fecaca",
99
+ color: "#dc2626",
100
+ fontSize: "0.75rem",
101
+ borderRadius: "0.5rem",
102
+ },
94
103
  };
95
104
 
96
105
  function ProductCardList(props) {
@@ -100,6 +109,10 @@ function ProductCardList(props) {
100
109
 
101
110
  const [error, setError] = useState(() => null);
102
111
 
112
+ function t() {
113
+ return getTranslations(props.defaultLocale);
114
+ }
115
+
103
116
  function fetchProducts() {
104
117
  let skusList = props.skus;
105
118
  if (typeof skusList === "string") {
@@ -129,13 +142,13 @@ function ProductCardList(props) {
129
142
  })
130
143
  .catch((err) => {
131
144
  console.error("Failed to fetch products:", err);
132
- setError(err?.message || "Failed to load products");
145
+ setError(t().productFetchError);
133
146
  setLoading(false);
134
147
  });
135
148
  }
136
149
 
137
150
  function getProductName(product) {
138
- const locale = props.defaultLocale || "de";
151
+ const locale = props.defaultLocale;
139
152
  const localized =
140
153
  product.localization?.[locale] ||
141
154
  Object.values(product.localization || {})[0];
@@ -166,7 +179,7 @@ function ProductCardList(props) {
166
179
  }
167
180
 
168
181
  function getDynamicField(product, field) {
169
- const locale = props.defaultLocale || "de";
182
+ const locale = props.defaultLocale;
170
183
  const localized =
171
184
  product.localization?.[locale] ||
172
185
  Object.values(product.localization || {})[0];
@@ -215,13 +228,11 @@ function ProductCardList(props) {
215
228
  <div style={styles.wrapper}>
216
229
  {loading ? (
217
230
  <div style={styles.statusContainer}>
218
- <span>Loading products...</span>
231
+ <span>{t().loadingProducts}</span>
219
232
  </div>
220
233
  ) : null}
221
234
  {!loading && error ? (
222
- <div style={styles.statusContainer}>
223
- <span style={styles.errorText}>Error: {error}</span>
224
- </div>
235
+ <div style={styles.errorContainer}>{t().productFetchError}</div>
225
236
  ) : null}
226
237
  {!loading && products && products.length > 0 ? (
227
238
  <div style={styles.productCardsContainer}>