@superlogic/spree-pay 0.4.0 → 0.4.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.
package/README.md CHANGED
@@ -110,6 +110,7 @@ type SpreePayProps = {
110
110
  currencyCode?: string; // ISO 4217 display currency (e.g. "AUD").
111
111
  foreignCurrencyAmount?: number; // Pre-fee order total in the display currency (e.g. 1280.46). Used directly as Pay button base; transaction fee is added on top.
112
112
  exchangeRate?: number; // 1 unit of currencyCode in USD (e.g. 0.65 for AUD→USD). Used to convert USD remainder when points are applied.
113
+ origin?: string; // Optional source identifier (e.g. ONE_PLATFORM)
113
114
  };
114
115
  ```
115
116
 
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Iframe3ds
3
- } from "./chunk-BGLP7QYP.js";
3
+ } from "./chunk-4ELDS4N4.js";
4
4
  import {
5
5
  InfoBanner,
6
6
  Legal,
@@ -12,7 +12,7 @@ import {
12
12
  useSpreePayRegister,
13
13
  useSpreePaymentMethod,
14
14
  useStaticConfig
15
- } from "./chunk-JUAE4572.js";
15
+ } from "./chunk-I35SE3K2.js";
16
16
 
17
17
  // src/components/CryptoComTab/CryptoComTab.tsx
18
18
  import { useCallback, useEffect } from "react";
@@ -2,7 +2,7 @@ import {
2
2
  CheckoutButton,
3
3
  PointsSwitch,
4
4
  cn as cn2
5
- } from "./chunk-STM24EZ3.js";
5
+ } from "./chunk-LXX5P2LL.js";
6
6
  import {
7
7
  Dialog,
8
8
  DialogContent,
@@ -16,7 +16,7 @@ import {
16
16
  useSpreePayConfig,
17
17
  useSpreePayRegister,
18
18
  useSpreePaymentMethod
19
- } from "./chunk-JUAE4572.js";
19
+ } from "./chunk-I35SE3K2.js";
20
20
 
21
21
  // src/components/CryptoTab/Crypto/CryptoWrapper.tsx
22
22
  import { useMemo as useMemo2 } from "react";
@@ -2,7 +2,7 @@ import {
2
2
  Dialog,
3
3
  DialogContent,
4
4
  DialogTitle
5
- } from "./chunk-JUAE4572.js";
5
+ } from "./chunk-I35SE3K2.js";
6
6
 
7
7
  // src/modals/Iframe3ds.tsx
8
8
  import { useEffect } from "react";
@@ -9,7 +9,7 @@ var PaymentType = /* @__PURE__ */ ((PaymentType2) => {
9
9
  })(PaymentType || {});
10
10
 
11
11
  // package.json
12
- var version = "0.4.0";
12
+ var version = "0.4.2";
13
13
 
14
14
  // src/utils/logger.ts
15
15
  var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
@@ -595,10 +595,20 @@ var SlapiPaymentService = {
595
595
  throw error;
596
596
  }
597
597
  },
598
- addCard: async ({ source, hash }) => {
598
+ removeCard: async ({ cardId }) => {
599
+ slapiLogger.debug("Removing card", { cardId });
600
+ try {
601
+ await slapiApi.delete(`/v1/payments/cards/${cardId}`);
602
+ slapiLogger.info("Card removed successfully", { cardId });
603
+ } catch (error) {
604
+ slapiLogger.error("Failed to remove card", error, { cardId });
605
+ throw error;
606
+ }
607
+ },
608
+ addCard: async ({ source, hash, saveCard }) => {
599
609
  slapiLogger.debug("Adding card", { hash, sourcePrefix: source.substring(0, 10) });
600
610
  try {
601
- const data = await slapiApi.post("/v1/payments/cards", { hash, source });
611
+ const data = await slapiApi.post("/v1/payments/cards", { hash, source, saveCard });
602
612
  slapiLogger.info("Card added successfully", { cardId: data.id, hash });
603
613
  return { data };
604
614
  } catch (error) {
@@ -6,7 +6,7 @@ import {
6
6
  useSpreePayEnv,
7
7
  useSpreePaymentMethod,
8
8
  useStaticConfig
9
- } from "./chunk-JUAE4572.js";
9
+ } from "./chunk-I35SE3K2.js";
10
10
 
11
11
  // src/components/common/PointsSwitch.tsx
12
12
  import { useId } from "react";
package/build/index.cjs CHANGED
@@ -68,7 +68,7 @@ var init_payments = __esm({
68
68
  var version;
69
69
  var init_package = __esm({
70
70
  "package.json"() {
71
- version = "0.4.0";
71
+ version = "0.4.2";
72
72
  }
73
73
  });
74
74
 
@@ -756,10 +756,20 @@ var init_slapi = __esm({
756
756
  throw error;
757
757
  }
758
758
  },
759
- addCard: async ({ source, hash }) => {
759
+ removeCard: async ({ cardId }) => {
760
+ slapiLogger.debug("Removing card", { cardId });
761
+ try {
762
+ await slapiApi.delete(`/v1/payments/cards/${cardId}`);
763
+ slapiLogger.info("Card removed successfully", { cardId });
764
+ } catch (error) {
765
+ slapiLogger.error("Failed to remove card", error, { cardId });
766
+ throw error;
767
+ }
768
+ },
769
+ addCard: async ({ source, hash, saveCard }) => {
760
770
  slapiLogger.debug("Adding card", { hash, sourcePrefix: source.substring(0, 10) });
761
771
  try {
762
- const data = await slapiApi.post("/v1/payments/cards", { hash, source });
772
+ const data = await slapiApi.post("/v1/payments/cards", { hash, source, saveCard });
763
773
  slapiLogger.info("Card added successfully", { cardId: data.id, hash });
764
774
  return { data };
765
775
  } catch (error) {
@@ -1994,11 +2004,11 @@ var init_useBaseTokens = __esm({
1994
2004
  });
1995
2005
 
1996
2006
  // src/modals/CryptoSelectModal.tsx
1997
- var import_react14, import_nice_modal_react5, import_jsx_runtime37, CryptoSelectModal;
2007
+ var import_react15, import_nice_modal_react5, import_jsx_runtime37, CryptoSelectModal;
1998
2008
  var init_CryptoSelectModal = __esm({
1999
2009
  "src/modals/CryptoSelectModal.tsx"() {
2000
2010
  "use strict";
2001
- import_react14 = require("react");
2011
+ import_react15 = require("react");
2002
2012
  import_nice_modal_react5 = __toESM(require("@ebay/nice-modal-react"), 1);
2003
2013
  init_input();
2004
2014
  init_separator();
@@ -2014,8 +2024,8 @@ var init_CryptoSelectModal = __esm({
2014
2024
  const { isLoading, error, erc20Balances } = useBaseERC20Token();
2015
2025
  const { isLoadingNative, nativeError, nativeBalance } = useBaseNativeToken();
2016
2026
  const { tokens, tokensIsLoading } = useBaseTokens();
2017
- const [search, setSearch] = (0, import_react14.useState)("");
2018
- const filteredCoins = (0, import_react14.useMemo)(() => {
2027
+ const [search, setSearch] = (0, import_react15.useState)("");
2028
+ const filteredCoins = (0, import_react15.useMemo)(() => {
2019
2029
  return tokens.filter(
2020
2030
  (coin) => coin.name.toLowerCase().includes(search.toLowerCase()) || coin.symbol.toLowerCase().includes(search.toLowerCase())
2021
2031
  );
@@ -2177,11 +2187,11 @@ var init_SelectedCoin = __esm({
2177
2187
  });
2178
2188
 
2179
2189
  // src/components/CryptoTab/Crypto/Crypto.tsx
2180
- var import_react15, import_wagmi4, import_jsx_runtime40, Crypto;
2190
+ var import_react16, import_wagmi4, import_jsx_runtime40, Crypto;
2181
2191
  var init_Crypto = __esm({
2182
2192
  "src/components/CryptoTab/Crypto/Crypto.tsx"() {
2183
2193
  "use strict";
2184
- import_react15 = require("react");
2194
+ import_react16 = require("react");
2185
2195
  import_wagmi4 = require("wagmi");
2186
2196
  init_SpreePayActionsContext();
2187
2197
  init_useCryptoPayment();
@@ -2200,7 +2210,7 @@ var init_Crypto = __esm({
2200
2210
  const { spreePayConfig } = useSpreePayConfig();
2201
2211
  const isWalletConnected = Boolean(address);
2202
2212
  const { register } = useSpreePayRegister();
2203
- const handlePay = (0, import_react15.useCallback)(
2213
+ const handlePay = (0, import_react16.useCallback)(
2204
2214
  async (data) => {
2205
2215
  try {
2206
2216
  const res = await cryptoPayment(data);
@@ -2214,7 +2224,7 @@ var init_Crypto = __esm({
2214
2224
  },
2215
2225
  [cryptoPayment]
2216
2226
  );
2217
- (0, import_react15.useEffect)(() => {
2227
+ (0, import_react16.useEffect)(() => {
2218
2228
  register(handlePay);
2219
2229
  }, [register, handlePay]);
2220
2230
  return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "flex flex-col items-baseline gap-4", children: [
@@ -2250,11 +2260,11 @@ function getCachedWagmiConfig(projectId, appName) {
2250
2260
  }
2251
2261
  return cfg2;
2252
2262
  }
2253
- var import_react16, import_react_query, import_nice_modal_react7, import_rainbowkit2, import_styles, import_wagmi5, import_chains, import_jsx_runtime41, queryClient, CHAINS, wagmiConfigCache, CryptoWrapper;
2263
+ var import_react17, import_react_query, import_nice_modal_react7, import_rainbowkit2, import_styles, import_wagmi5, import_chains, import_jsx_runtime41, queryClient, CHAINS, wagmiConfigCache, CryptoWrapper;
2254
2264
  var init_CryptoWrapper = __esm({
2255
2265
  "src/components/CryptoTab/Crypto/CryptoWrapper.tsx"() {
2256
2266
  "use strict";
2257
- import_react16 = require("react");
2267
+ import_react17 = require("react");
2258
2268
  import_react_query = require("@tanstack/react-query");
2259
2269
  import_nice_modal_react7 = __toESM(require("@ebay/nice-modal-react"), 1);
2260
2270
  import_rainbowkit2 = require("@rainbow-me/rainbowkit");
@@ -2269,7 +2279,7 @@ var init_CryptoWrapper = __esm({
2269
2279
  wagmiConfigCache = /* @__PURE__ */ new Map();
2270
2280
  CryptoWrapper = () => {
2271
2281
  const { spreePayConfig, configIsLoading } = useSpreePayConfig();
2272
- const wagmiConfig = (0, import_react16.useMemo)(() => {
2282
+ const wagmiConfig = (0, import_react17.useMemo)(() => {
2273
2283
  if (!spreePayConfig) return null;
2274
2284
  return getCachedWagmiConfig(spreePayConfig.rainbowProjectId, spreePayConfig.rainbowAppName);
2275
2285
  }, [spreePayConfig]);
@@ -2456,11 +2466,11 @@ var init_Checkout = __esm({
2456
2466
  });
2457
2467
 
2458
2468
  // src/components/CryptoComTab/CryptoComTab.tsx
2459
- var import_react17, import_jsx_runtime44, CryptoComTab;
2469
+ var import_react18, import_jsx_runtime44, CryptoComTab;
2460
2470
  var init_CryptoComTab = __esm({
2461
2471
  "src/components/CryptoComTab/CryptoComTab.tsx"() {
2462
2472
  "use strict";
2463
- import_react17 = require("react");
2473
+ import_react18 = require("react");
2464
2474
  init_SpreePayActionsContext();
2465
2475
  init_useCryptoComPayment();
2466
2476
  init_useSpreePayConfig();
@@ -2472,7 +2482,7 @@ var init_CryptoComTab = __esm({
2472
2482
  const { register } = useSpreePayRegister();
2473
2483
  const { cryptoComPayment } = useCryptoComPayment();
2474
2484
  const { spreePayConfig } = useSpreePayConfig();
2475
- const handlePay = (0, import_react17.useCallback)(
2485
+ const handlePay = (0, import_react18.useCallback)(
2476
2486
  async (data) => {
2477
2487
  try {
2478
2488
  const res = await cryptoComPayment(data);
@@ -2486,7 +2496,7 @@ var init_CryptoComTab = __esm({
2486
2496
  },
2487
2497
  [cryptoComPayment]
2488
2498
  );
2489
- (0, import_react17.useEffect)(() => {
2499
+ (0, import_react18.useEffect)(() => {
2490
2500
  register(handlePay);
2491
2501
  }, [register, handlePay]);
2492
2502
  return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("div", { className: "flex w-full flex-col gap-4 border-b border-b-(--border-component-specific-card) px-5 py-5 md:px-7 md:py-6", children: [
@@ -2525,15 +2535,15 @@ __export(index_exports, {
2525
2535
  module.exports = __toCommonJS(index_exports);
2526
2536
 
2527
2537
  // src/SpreePay.tsx
2528
- var import_react21 = require("react");
2538
+ var import_react22 = require("react");
2529
2539
  var import_nice_modal_react9 = __toESM(require("@ebay/nice-modal-react"), 1);
2530
2540
  var import_swr5 = require("swr");
2531
2541
 
2532
2542
  // src/SpreePayContent.tsx
2533
- var import_react18 = require("react");
2543
+ var import_react19 = require("react");
2534
2544
 
2535
2545
  // src/components/CreditCardTab/CreditCardTab.tsx
2536
- var import_react13 = require("react");
2546
+ var import_react14 = require("react");
2537
2547
  init_SpreePayActionsContext();
2538
2548
  init_StaticConfigContext();
2539
2549
 
@@ -2572,7 +2582,11 @@ var useCardPayment = () => {
2572
2582
  lastFour: card.lastFourNumbers,
2573
2583
  schema: card.schema
2574
2584
  });
2575
- const { data: cardResData } = await SlapiPaymentService.addCard({ hash, source: card.token });
2585
+ const { data: cardResData } = await SlapiPaymentService.addCard({
2586
+ hash,
2587
+ source: card.token,
2588
+ saveCard: card.saveCard
2589
+ });
2576
2590
  cardId = cardResData.id;
2577
2591
  cardPaymentLogger.info("New card added successfully", { cardId });
2578
2592
  } else {
@@ -3056,9 +3070,10 @@ var useSplitCardPayments = (mode = "web2") => {
3056
3070
  // src/hooks/useCards.ts
3057
3071
  var import_swr2 = __toESM(require("swr"), 1);
3058
3072
  init_SpreePayActionsContext();
3073
+ var URL2 = "/v1/payments/cards";
3059
3074
  var useCards = () => {
3060
3075
  const { origin } = useSpreePayEnv();
3061
- const { data, isLoading, mutate } = (0, import_swr2.default)(`/v1/payments/cards?origin=${origin}`);
3076
+ const { data, isLoading, mutate } = (0, import_swr2.default)(origin ? `${URL2}?origin=${origin}` : URL2);
3062
3077
  return {
3063
3078
  cards: data?.data.filter((c) => c.active) || [],
3064
3079
  cardsIsLoading: isLoading,
@@ -3074,7 +3089,7 @@ init_split();
3074
3089
  init_CheckoutButton();
3075
3090
 
3076
3091
  // src/components/CreditCardTab/CreditCard/CreditCard.tsx
3077
- var import_react7 = require("react");
3092
+ var import_react8 = require("react");
3078
3093
  var import_react_stripe_js2 = require("@stripe/react-stripe-js");
3079
3094
  var import_stripe_js = require("@stripe/stripe-js");
3080
3095
  init_SpreePayActionsContext();
@@ -3082,27 +3097,32 @@ init_useSpreePayConfig();
3082
3097
  init_InfoBanner();
3083
3098
 
3084
3099
  // src/components/CreditCardTab/CreditCard/CardsList.tsx
3100
+ var import_react6 = require("react");
3085
3101
  init_utils();
3102
+ init_slapi();
3086
3103
  var import_jsx_runtime12 = require("react/jsx-runtime");
3087
- var isRemoveDisabled = true;
3088
- var CardListItem = ({ card, isSelected, onSelect }) => {
3089
- const handleSelect = () => {
3090
- onSelect(card);
3091
- };
3092
- const handleRemoveCard = (e) => {
3104
+ var CardListItem = ({ card, isSelected, onSelect, onRemove }) => {
3105
+ const [isRemoving, setIsRemoving] = (0, import_react6.useState)(false);
3106
+ const removeDisabled = isSelected || isRemoving;
3107
+ const handleRemove = async (e) => {
3093
3108
  e.stopPropagation();
3094
- if (isSelected || isRemoveDisabled) return;
3109
+ setIsRemoving(true);
3110
+ try {
3111
+ await onRemove(card);
3112
+ } finally {
3113
+ setIsRemoving(false);
3114
+ }
3095
3115
  };
3096
3116
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3097
- "button",
3117
+ "div",
3098
3118
  {
3099
- type: "button",
3100
- onClick: handleSelect,
3119
+ role: "button",
3120
+ tabIndex: 0,
3121
+ onClick: () => onSelect(card),
3122
+ onKeyDown: (e) => (e.key === "Enter" || e.key === " ") && onSelect(card),
3101
3123
  className: cn(
3102
- "flex h-12 w-full overflow-hidden rounded-md border-2 border-(--b-inverse) bg-(--s-primary) hover:bg-(--s-primary-hover)",
3103
- {
3104
- "border-(--b-brand)": isSelected
3105
- }
3124
+ "flex h-12 w-full cursor-pointer overflow-hidden rounded-md border-2 border-(--b-inverse) bg-(--s-primary) hover:bg-(--s-primary-hover)",
3125
+ { "border-(--b-brand)": isSelected }
3106
3126
  ),
3107
3127
  children: [
3108
3128
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
@@ -3128,13 +3148,12 @@ var CardListItem = ({ card, isSelected, onSelect }) => {
3128
3148
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "text-(--brand-primary)", children: card.lastFourNumbers })
3129
3149
  ] }),
3130
3150
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3131
- "div",
3151
+ "button",
3132
3152
  {
3133
- onClick: handleRemoveCard,
3134
- className: cn("rounded-md p-1 text-(--tertiary) transition-all hover:bg-(--s-secondary)", {
3135
- "cursor-not-allowed opacity-50": isSelected || isRemoveDisabled
3136
- // 'cursor-pointer': !isSelected || !isRemoveDisabled,
3137
- }),
3153
+ type: "button",
3154
+ onClick: handleRemove,
3155
+ disabled: removeDisabled,
3156
+ className: "text-tertiary rounded-md p-1 transition-all hover:bg-(--s-secondary) disabled:cursor-not-allowed disabled:opacity-50",
3138
3157
  children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "currentColor", className: "size-5", viewBox: "0 0 20 20", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M6.35 16.17q-.57 0-.96-.4a1.3 1.3 0 0 1-.39-.95V4.5h-.83v-.83H7.5v-.64h5v.64h3.33v.83H15v10.32q0 .58-.39.96a1.3 1.3 0 0 1-.96.39zM14.17 4.5H5.83v10.32q0 .23.15.37.15.15.37.15h7.3q.2 0 .36-.16.15-.17.16-.36zm-6 9.17h.84v-7.5h-.84zm2.82 0h.84v-7.5h-.84z" }) })
3139
3158
  }
3140
3159
  )
@@ -3147,16 +3166,31 @@ var CardListItem = ({ card, isSelected, onSelect }) => {
3147
3166
  );
3148
3167
  };
3149
3168
  var CardsList = ({ selectedCard, setCard }) => {
3150
- const { cards, cardsIsLoading } = useCards();
3169
+ const { cards, cardsIsLoading, mutateCards } = useCards();
3170
+ const handleRemove = async (card) => {
3171
+ if ("cardId" in card) {
3172
+ await SlapiPaymentService.removeCard({ cardId: card.id });
3173
+ }
3174
+ mutateCards((data) => ({ ...data, data: (data?.data ?? []).filter((c) => c.id !== card.id) }));
3175
+ };
3151
3176
  if (cardsIsLoading) {
3152
3177
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "flex w-full flex-col", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "h-11 animate-pulse rounded-sm bg-(--s-primary)" }) });
3153
3178
  }
3154
3179
  if (cards.length === 0) return null;
3155
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "flex w-full flex-col gap-4", children: cards.map((card) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(CardListItem, { isSelected: selectedCard?.id === card.id, onSelect: setCard, card }, card.id)) });
3180
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "flex w-full flex-col gap-4", children: cards.map((card) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3181
+ CardListItem,
3182
+ {
3183
+ isSelected: selectedCard?.id === card.id,
3184
+ onSelect: setCard,
3185
+ onRemove: handleRemove,
3186
+ card
3187
+ },
3188
+ card.id
3189
+ )) });
3156
3190
  };
3157
3191
 
3158
3192
  // src/components/CreditCardTab/CreditCard/CreditCardForm.tsx
3159
- var import_react6 = require("react");
3193
+ var import_react7 = require("react");
3160
3194
  var import_react_stripe_js = require("@stripe/react-stripe-js");
3161
3195
 
3162
3196
  // src/ui/button.tsx
@@ -3239,13 +3273,14 @@ var stripeElementClasses = {
3239
3273
  focus: "border-ring ring-ring/50 ring-2"
3240
3274
  };
3241
3275
  var CreditCardForm = ({ cancel, saveCard }) => {
3242
- const [cardError, setCardError] = (0, import_react6.useState)(void 0);
3243
- const [stripeStyles, setStripeStyles] = (0, import_react6.useState)({});
3244
- const formRef = (0, import_react6.useRef)(null);
3276
+ const [cardError, setCardError] = (0, import_react7.useState)(void 0);
3277
+ const [stripeStyles, setStripeStyles] = (0, import_react7.useState)({});
3278
+ const [shouldSaveCard, setShouldSaveCard] = (0, import_react7.useState)(true);
3279
+ const formRef = (0, import_react7.useRef)(null);
3245
3280
  const elements = (0, import_react_stripe_js.useElements)();
3246
3281
  const stripe = (0, import_react_stripe_js.useStripe)();
3247
- const id = (0, import_react6.useId)();
3248
- const computeStripeStyles = (0, import_react6.useCallback)(() => {
3282
+ const id = (0, import_react7.useId)();
3283
+ const computeStripeStyles = (0, import_react7.useCallback)(() => {
3249
3284
  const formRefCurrent = formRef.current;
3250
3285
  if (typeof window === "undefined" || !formRefCurrent) return {};
3251
3286
  const container = formRefCurrent.closest(".sl-spreepay");
@@ -3266,7 +3301,7 @@ var CreditCardForm = ({ cancel, saveCard }) => {
3266
3301
  }
3267
3302
  };
3268
3303
  }, []);
3269
- (0, import_react6.useEffect)(() => {
3304
+ (0, import_react7.useEffect)(() => {
3270
3305
  setStripeStyles(computeStripeStyles());
3271
3306
  }, [computeStripeStyles]);
3272
3307
  const handleSaveCard = async () => {
@@ -3294,7 +3329,8 @@ var CreditCardForm = ({ cancel, saveCard }) => {
3294
3329
  schema: token.card?.brand,
3295
3330
  lastFourNumbers: token.card?.last4 ?? "",
3296
3331
  expireMonth: `${token.card?.exp_month}`,
3297
- expireYear: `${token.card?.exp_year}`
3332
+ expireYear: `${token.card?.exp_year}`,
3333
+ saveCard: shouldSaveCard
3298
3334
  });
3299
3335
  }
3300
3336
  }
@@ -3340,7 +3376,7 @@ var CreditCardForm = ({ cancel, saveCard }) => {
3340
3376
  cardError && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-destructive mt-1 text-sm", children: cardError })
3341
3377
  ] }),
3342
3378
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center gap-2", children: [
3343
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Checkbox, { disabled: true, checked: true, id: "saveCard" }),
3379
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Checkbox, { checked: shouldSaveCard, onCheckedChange: (v) => setShouldSaveCard(v === true), id: "saveCard" }),
3344
3380
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Label, { className: "text-sm font-medium", htmlFor: "saveCard", children: "Save card for future purchases" })
3345
3381
  ] }),
3346
3382
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex w-full justify-end gap-2", children: [
@@ -3367,17 +3403,22 @@ var CreditCardForm = ({ cancel, saveCard }) => {
3367
3403
 
3368
3404
  // src/components/CreditCardTab/CreditCard/CreditCard.tsx
3369
3405
  var import_jsx_runtime16 = require("react/jsx-runtime");
3370
- var StripeWrapper = (props) => {
3371
- const stripePromise = (0, import_react7.useMemo)(() => (0, import_stripe_js.loadStripe)(props.publicKey), [props.publicKey]);
3372
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_stripe_js2.Elements, { stripe: stripePromise, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(CreditCardForm, { cancel: props.onCancel, saveCard: props.saveNewCard }) });
3406
+ var StripeWrapper = ({ onCancel, saveNewCard, publicKey }) => {
3407
+ const stripePromise = (0, import_react8.useMemo)(() => (0, import_stripe_js.loadStripe)(publicKey), [publicKey]);
3408
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_stripe_js2.Elements, { stripe: stripePromise, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(CreditCardForm, { cancel: onCancel, saveCard: saveNewCard }) });
3373
3409
  };
3374
3410
  var CreditCard = () => {
3375
- const [showForm, setShowForm] = (0, import_react7.useState)(false);
3411
+ const [showForm, setShowForm] = (0, import_react8.useState)(false);
3376
3412
  const { selectedPaymentMethod, setSelectedPaymentMethod } = useSpreePaymentMethod();
3377
3413
  const { mutateCards } = useCards();
3378
3414
  const { spreePayConfig } = useSpreePayConfig();
3379
3415
  const setCard = (card) => {
3380
- setSelectedPaymentMethod({ ...selectedPaymentMethod, type: "CREDIT_CARD" /* CREDIT_CARD */, method: card });
3416
+ const isAlreadySelected = selectedPaymentMethod?.type === "CREDIT_CARD" /* CREDIT_CARD */ && selectedPaymentMethod.method?.id === card.id;
3417
+ setSelectedPaymentMethod({
3418
+ ...selectedPaymentMethod,
3419
+ type: "CREDIT_CARD" /* CREDIT_CARD */,
3420
+ method: isAlreadySelected ? null : card
3421
+ });
3381
3422
  };
3382
3423
  const saveNewCard = (newCard) => {
3383
3424
  mutateCards((data) => ({ ...data, data: [...data?.data ?? [], newCard] }), { revalidate: false });
@@ -3413,14 +3454,14 @@ var CreditCard = () => {
3413
3454
  };
3414
3455
 
3415
3456
  // src/components/CreditCardTab/Points/Points.tsx
3416
- var import_react12 = require("react");
3457
+ var import_react13 = require("react");
3417
3458
  init_SpreePayActionsContext();
3418
3459
  init_StaticConfigContext();
3419
3460
  init_useSpreePayConfig();
3420
3461
  init_common();
3421
3462
 
3422
3463
  // src/components/CreditCardTab/Points/SplitBlock.tsx
3423
- var import_react11 = require("react");
3464
+ var import_react12 = require("react");
3424
3465
  var import_airkit2 = require("@mocanetwork/airkit");
3425
3466
  init_SpreePayActionsContext();
3426
3467
  init_StaticConfigContext();
@@ -3430,7 +3471,7 @@ init_format();
3430
3471
  init_logger();
3431
3472
 
3432
3473
  // src/components/CreditCardTab/Points/PointsSelector.tsx
3433
- var import_react10 = require("react");
3474
+ var import_react11 = require("react");
3434
3475
  init_SpreePayActionsContext();
3435
3476
  init_StaticConfigContext();
3436
3477
  init_useSlapiBalance();
@@ -3750,10 +3791,10 @@ var Primitive = NODES.reduce((primitive, node) => {
3750
3791
  }, {});
3751
3792
 
3752
3793
  // ../../node_modules/@radix-ui/react-collection/dist/index.mjs
3753
- var import_react8 = __toESM(require("react"), 1);
3794
+ var import_react9 = __toESM(require("react"), 1);
3754
3795
  var import_react_slot3 = require("@radix-ui/react-slot");
3755
3796
  var import_jsx_runtime21 = require("react/jsx-runtime");
3756
- var import_react9 = __toESM(require("react"), 1);
3797
+ var import_react10 = __toESM(require("react"), 1);
3757
3798
  var import_react_slot4 = require("@radix-ui/react-slot");
3758
3799
  var import_jsx_runtime22 = require("react/jsx-runtime");
3759
3800
  function createCollection(name) {
@@ -3765,14 +3806,14 @@ function createCollection(name) {
3765
3806
  );
3766
3807
  const CollectionProvider = (props) => {
3767
3808
  const { scope, children } = props;
3768
- const ref = import_react8.default.useRef(null);
3769
- const itemMap = import_react8.default.useRef(/* @__PURE__ */ new Map()).current;
3809
+ const ref = import_react9.default.useRef(null);
3810
+ const itemMap = import_react9.default.useRef(/* @__PURE__ */ new Map()).current;
3770
3811
  return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(CollectionProviderImpl, { scope, itemMap, collectionRef: ref, children });
3771
3812
  };
3772
3813
  CollectionProvider.displayName = PROVIDER_NAME;
3773
3814
  const COLLECTION_SLOT_NAME = name + "CollectionSlot";
3774
3815
  const CollectionSlotImpl = (0, import_react_slot3.createSlot)(COLLECTION_SLOT_NAME);
3775
- const CollectionSlot = import_react8.default.forwardRef(
3816
+ const CollectionSlot = import_react9.default.forwardRef(
3776
3817
  (props, forwardedRef) => {
3777
3818
  const { scope, children } = props;
3778
3819
  const context = useCollectionContext(COLLECTION_SLOT_NAME, scope);
@@ -3784,13 +3825,13 @@ function createCollection(name) {
3784
3825
  const ITEM_SLOT_NAME = name + "CollectionItemSlot";
3785
3826
  const ITEM_DATA_ATTR = "data-radix-collection-item";
3786
3827
  const CollectionItemSlotImpl = (0, import_react_slot3.createSlot)(ITEM_SLOT_NAME);
3787
- const CollectionItemSlot = import_react8.default.forwardRef(
3828
+ const CollectionItemSlot = import_react9.default.forwardRef(
3788
3829
  (props, forwardedRef) => {
3789
3830
  const { scope, children, ...itemData } = props;
3790
- const ref = import_react8.default.useRef(null);
3831
+ const ref = import_react9.default.useRef(null);
3791
3832
  const composedRefs = useComposedRefs(forwardedRef, ref);
3792
3833
  const context = useCollectionContext(ITEM_SLOT_NAME, scope);
3793
- import_react8.default.useEffect(() => {
3834
+ import_react9.default.useEffect(() => {
3794
3835
  context.itemMap.set(ref, { ref, ...itemData });
3795
3836
  return () => void context.itemMap.delete(ref);
3796
3837
  });
@@ -3800,7 +3841,7 @@ function createCollection(name) {
3800
3841
  CollectionItemSlot.displayName = ITEM_SLOT_NAME;
3801
3842
  function useCollection2(scope) {
3802
3843
  const context = useCollectionContext(name + "CollectionConsumer", scope);
3803
- const getItems = import_react8.default.useCallback(() => {
3844
+ const getItems = import_react9.default.useCallback(() => {
3804
3845
  const collectionNode = context.collectionRef.current;
3805
3846
  if (!collectionNode) return [];
3806
3847
  const orderedNodes = Array.from(collectionNode.querySelectorAll(`[${ITEM_DATA_ATTR}]`));
@@ -4433,7 +4474,7 @@ var PointsSelector = (props) => {
4433
4474
  const maxByAmount = pointsConversionRatio && pointsConversionRatio > 0 ? (amount ?? 0) / pointsConversionRatio : 0;
4434
4475
  const max = Math.min(maxByAmount, balance?.availablePoints ?? 0);
4435
4476
  const step = 10;
4436
- const [splitTokens, setSplitTokens] = (0, import_react10.useState)(0);
4477
+ const [splitTokens, setSplitTokens] = (0, import_react11.useState)(0);
4437
4478
  const usdAmount = getSplitAmount(amount ?? 0, splitTokens, pointsConversionRatio);
4438
4479
  const pointsValue = String(Math.round(splitTokens));
4439
4480
  const usdWithFee = usdAmount + getTransactionFee(usdAmount, transactionFeePercentage);
@@ -4531,14 +4572,14 @@ var SplitBlock = (props) => {
4531
4572
  const { spreePayConfig } = useSpreePayConfig();
4532
4573
  const { appProps } = useStaticConfig();
4533
4574
  const { currencyCode, exchangeRate, foreignCurrencyAmount } = appProps;
4534
- const [address, setAddress] = (0, import_react11.useState)(null);
4535
- const [walletReady, setWalletReady] = (0, import_react11.useState)(false);
4575
+ const [address, setAddress] = (0, import_react12.useState)(null);
4576
+ const [walletReady, setWalletReady] = (0, import_react12.useState)(false);
4536
4577
  const { pointsConversionRatio, pointsTitle } = spreePayConfig || {};
4537
4578
  const { useWeb3Points, environment } = useSpreePayEnv();
4538
4579
  const hasForeignCurrency = !!(currencyCode && exchangeRate && foreignCurrencyAmount);
4539
4580
  const formatPointsValue = (usd) => hasForeignCurrency ? formatCurrency(usd / exchangeRate, currencyCode) : formatCurrency(usd);
4540
- const prevPointsChainRef = (0, import_react11.useRef)(spreePayConfig?.pointsChain);
4541
- const initWallet = (0, import_react11.useCallback)(
4581
+ const prevPointsChainRef = (0, import_react12.useRef)(spreePayConfig?.pointsChain);
4582
+ const initWallet = (0, import_react12.useCallback)(
4542
4583
  async (pointsChain) => {
4543
4584
  if (!pointsChain) return;
4544
4585
  try {
@@ -4561,7 +4602,7 @@ var SplitBlock = (props) => {
4561
4602
  },
4562
4603
  [onToggle, environment]
4563
4604
  );
4564
- (0, import_react11.useEffect)(() => {
4605
+ (0, import_react12.useEffect)(() => {
4565
4606
  if (!useWeb3Points) return;
4566
4607
  const pointsChainChanged = prevPointsChainRef.current !== spreePayConfig?.pointsChain;
4567
4608
  prevPointsChainRef.current = spreePayConfig?.pointsChain;
@@ -4591,8 +4632,8 @@ var SplitBlock = (props) => {
4591
4632
  // src/components/CreditCardTab/Points/Points.tsx
4592
4633
  var import_jsx_runtime27 = require("react/jsx-runtime");
4593
4634
  var Points = () => {
4594
- const [usePoints, setUsePoints] = (0, import_react12.useState)(false);
4595
- const [selectedPointsType, setSelectedPointsType] = (0, import_react12.useState)(null);
4635
+ const [usePoints, setUsePoints] = (0, import_react13.useState)(false);
4636
+ const [selectedPointsType, setSelectedPointsType] = (0, import_react13.useState)(null);
4596
4637
  const { setSelectedPaymentMethod, selectedPaymentMethod } = useSpreePaymentMethod();
4597
4638
  const { spreePayConfig } = useSpreePayConfig();
4598
4639
  const { appProps } = useStaticConfig();
@@ -4638,7 +4679,7 @@ var CreditCardTab = ({ isLoggedIn }) => {
4638
4679
  const { cardPayment } = useCardPayment();
4639
4680
  const { splitPayment } = useSplitCardPayments(isWeb3Enabled ? "web3" : "web2");
4640
4681
  const { pointsPayment } = usePointsPayment(isWeb3Enabled ? "web3" : "web2");
4641
- const handlePay = (0, import_react13.useCallback)(
4682
+ const handlePay = (0, import_react14.useCallback)(
4642
4683
  async (data) => {
4643
4684
  try {
4644
4685
  let res = null;
@@ -4677,7 +4718,7 @@ var CreditCardTab = ({ isLoggedIn }) => {
4677
4718
  mutateBalance
4678
4719
  ]
4679
4720
  );
4680
- (0, import_react13.useEffect)(() => {
4721
+ (0, import_react14.useEffect)(() => {
4681
4722
  register(handlePay);
4682
4723
  }, [register, handlePay]);
4683
4724
  return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { children: [
@@ -4762,8 +4803,8 @@ var TabButtons = (props) => {
4762
4803
  // src/SpreePayContent.tsx
4763
4804
  init_SpreePayActionsContext();
4764
4805
  var import_jsx_runtime45 = require("react/jsx-runtime");
4765
- var CryptoTab2 = (0, import_react18.lazy)(() => Promise.resolve().then(() => (init_CryptoTab2(), CryptoTab_exports)).then((module2) => ({ default: module2.CryptoTab })));
4766
- var CryptoComTab2 = (0, import_react18.lazy)(
4806
+ var CryptoTab2 = (0, import_react19.lazy)(() => Promise.resolve().then(() => (init_CryptoTab2(), CryptoTab_exports)).then((module2) => ({ default: module2.CryptoTab })));
4807
+ var CryptoComTab2 = (0, import_react19.lazy)(
4767
4808
  () => Promise.resolve().then(() => (init_CryptoComTab2(), CryptoComTab_exports)).then((module2) => ({ default: module2.CryptoComTab }))
4768
4809
  );
4769
4810
  var TabLoadingFallback = () => /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("div", { className: "flex items-center justify-center px-5 py-8 md:px-7", children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "flex flex-col items-center gap-3", children: [
@@ -4778,7 +4819,7 @@ var SpreePayContent = ({ isLoggedIn }) => {
4778
4819
  /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(TabButtons, { value: selectedPaymentMethod.type, onChange: setSelectedPaymentMethod })
4779
4820
  ] }),
4780
4821
  selectedPaymentMethod.type === "CREDIT_CARD" /* CREDIT_CARD */ && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(CreditCardTab, { isLoggedIn }),
4781
- /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_react18.Suspense, { fallback: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(TabLoadingFallback, {}), children: [
4822
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_react19.Suspense, { fallback: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(TabLoadingFallback, {}), children: [
4782
4823
  selectedPaymentMethod.type === "CRYPTO" /* CRYPTO */ && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(CryptoTab2, { isLoggedIn }),
4783
4824
  selectedPaymentMethod.type === "CDC" /* CDC */ && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(CryptoComTab2, {})
4784
4825
  ] })
@@ -4786,10 +4827,10 @@ var SpreePayContent = ({ isLoggedIn }) => {
4786
4827
  };
4787
4828
 
4788
4829
  // src/components/ErrorBoundary.tsx
4789
- var import_react19 = require("react");
4830
+ var import_react20 = require("react");
4790
4831
  init_logger();
4791
4832
  var import_jsx_runtime46 = require("react/jsx-runtime");
4792
- var ErrorBoundary = class extends import_react19.Component {
4833
+ var ErrorBoundary = class extends import_react20.Component {
4793
4834
  constructor(props) {
4794
4835
  super(props);
4795
4836
  this.state = { hasError: false, error: null };
@@ -4840,22 +4881,22 @@ init_StaticConfigContext();
4840
4881
  init_client();
4841
4882
 
4842
4883
  // src/hooks/useKeycloakSSO.ts
4843
- var import_react20 = require("react");
4884
+ var import_react21 = require("react");
4844
4885
  var import_keycloak_js = __toESM(require("keycloak-js"), 1);
4845
4886
  init_logger();
4846
4887
  var refreshAheadSeconds = 60;
4847
4888
  var keycloakLogger = logger.child("keycloak");
4848
4889
  function useKeycloakSSO(config2) {
4849
4890
  const { url, realm, clientId, ssoPageURI, enabled } = config2;
4850
- const initRef = (0, import_react20.useRef)(false);
4851
- const kcRef = (0, import_react20.useRef)(null);
4852
- const refreshTimerRef = (0, import_react20.useRef)(null);
4853
- const scheduleRefreshRef = (0, import_react20.useRef)(() => {
4891
+ const initRef = (0, import_react21.useRef)(false);
4892
+ const kcRef = (0, import_react21.useRef)(null);
4893
+ const refreshTimerRef = (0, import_react21.useRef)(null);
4894
+ const scheduleRefreshRef = (0, import_react21.useRef)(() => {
4854
4895
  });
4855
- const [error, setError] = (0, import_react20.useState)(null);
4856
- const [isChecking, setIsChecking] = (0, import_react20.useState)(enabled);
4857
- const [accessToken, setAccessToken] = (0, import_react20.useState)(null);
4858
- const scheduleRefresh = (0, import_react20.useCallback)(() => {
4896
+ const [error, setError] = (0, import_react21.useState)(null);
4897
+ const [isChecking, setIsChecking] = (0, import_react21.useState)(enabled);
4898
+ const [accessToken, setAccessToken] = (0, import_react21.useState)(null);
4899
+ const scheduleRefresh = (0, import_react21.useCallback)(() => {
4859
4900
  const kc = kcRef.current;
4860
4901
  if (!kc || !kc.tokenParsed || !kc.tokenParsed.exp) {
4861
4902
  return;
@@ -4879,10 +4920,10 @@ function useKeycloakSSO(config2) {
4879
4920
  });
4880
4921
  }, delayMs);
4881
4922
  }, []);
4882
- (0, import_react20.useEffect)(() => {
4923
+ (0, import_react21.useEffect)(() => {
4883
4924
  scheduleRefreshRef.current = scheduleRefresh;
4884
4925
  }, [scheduleRefresh]);
4885
- (0, import_react20.useEffect)(() => {
4926
+ (0, import_react21.useEffect)(() => {
4886
4927
  if (initRef.current || !enabled) return;
4887
4928
  initRef.current = true;
4888
4929
  const kc = new import_keycloak_js.default({ url, realm, clientId });
@@ -4921,14 +4962,14 @@ init_portal();
4921
4962
  init_logger();
4922
4963
  var import_jsx_runtime47 = require("react/jsx-runtime");
4923
4964
  var SpreePayInner = () => {
4924
- const [portalEl, setPortalEl] = (0, import_react21.useState)(null);
4925
- const rootRef = (0, import_react21.useCallback)((node) => {
4965
+ const [portalEl, setPortalEl] = (0, import_react22.useState)(null);
4966
+ const rootRef = (0, import_react22.useCallback)((node) => {
4926
4967
  if (!node) return;
4927
4968
  const el = node.querySelector(":scope > .sl-spreepay__portal");
4928
4969
  setPortalEl(el ?? null);
4929
4970
  }, []);
4930
4971
  const { environment, tenantId, keycloakClientId, accessToken: envAccessToken, ssoPageURI } = useSpreePayEnv();
4931
- (0, import_react21.useEffect)(() => {
4972
+ (0, import_react22.useEffect)(() => {
4932
4973
  configureLogger({ environment });
4933
4974
  logger.logVersion();
4934
4975
  }, [environment]);
@@ -4941,8 +4982,8 @@ var SpreePayInner = () => {
4941
4982
  enabled: !envAccessToken
4942
4983
  });
4943
4984
  const _accessToken = envAccessToken ?? accessToken;
4944
- const unauthenticatedFetcher = (0, import_react21.useCallback)(() => Promise.resolve(null), []);
4945
- const slapiFetcher = (0, import_react21.useMemo)(() => {
4985
+ const unauthenticatedFetcher = (0, import_react22.useCallback)(() => Promise.resolve(null), []);
4986
+ const slapiFetcher = (0, import_react22.useMemo)(() => {
4946
4987
  if (_accessToken) {
4947
4988
  return registerApi({
4948
4989
  accessToken: _accessToken,
@@ -4982,9 +5023,9 @@ var SpreePay = (props) => {
4982
5023
  };
4983
5024
 
4984
5025
  // src/hooks/useCapture3DS.ts
4985
- var import_react22 = require("react");
5026
+ var import_react23 = require("react");
4986
5027
  var useCapture3DS = (searchParams) => {
4987
- (0, import_react22.useEffect)(() => {
5028
+ (0, import_react23.useEffect)(() => {
4988
5029
  if (typeof window !== "undefined" && window.parent && searchParams?.paymentIntent) {
4989
5030
  window.parent.SP_EVENT_BUS?.emit("paymentIntent", { paymentIntent: searchParams.paymentIntent });
4990
5031
  }
package/build/index.css CHANGED
@@ -501,9 +501,6 @@
501
501
  .sl-spreepay .animate-spin {
502
502
  animation: var(--animate-spin);
503
503
  }
504
- .sl-spreepay .cursor-not-allowed {
505
- cursor: not-allowed;
506
- }
507
504
  .sl-spreepay .cursor-pointer {
508
505
  cursor: pointer;
509
506
  }
@@ -903,15 +900,15 @@
903
900
  .sl-spreepay .text-current {
904
901
  color: currentcolor;
905
902
  }
903
+ .sl-spreepay .text-tertiary {
904
+ color: var(--tertiary);
905
+ }
906
906
  .sl-spreepay .underline {
907
907
  text-decoration-line: underline;
908
908
  }
909
909
  .sl-spreepay .underline-offset-4 {
910
910
  text-underline-offset: 4px;
911
911
  }
912
- .sl-spreepay .opacity-50 {
913
- opacity: 50%;
914
- }
915
912
  .sl-spreepay .opacity-70 {
916
913
  opacity: 70%;
917
914
  }
@@ -1796,4 +1793,4 @@
1796
1793
  }
1797
1794
  }
1798
1795
  }
1799
- /*! tailwindcss v4.1.17 | MIT License | https://tailwindcss.com */
1796
+ /*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */
package/build/index.d.cts CHANGED
@@ -83,6 +83,7 @@ type Card = {
83
83
  type NewCard = Pick<Card, 'expireMonth' | 'expireYear' | 'lastFourNumbers' | 'schema' | 'active'> & {
84
84
  token: string;
85
85
  id: string;
86
+ saveCard?: boolean;
86
87
  };
87
88
  type CardPaymentMethod = {
88
89
  method: NewCard | Card | null;
package/build/index.d.ts CHANGED
@@ -83,6 +83,7 @@ type Card = {
83
83
  type NewCard = Pick<Card, 'expireMonth' | 'expireYear' | 'lastFourNumbers' | 'schema' | 'active'> & {
84
84
  token: string;
85
85
  id: string;
86
+ saveCard?: boolean;
86
87
  };
87
88
  type CardPaymentMethod = {
88
89
  method: NewCard | Card | null;
package/build/index.js CHANGED
@@ -8,10 +8,10 @@ import {
8
8
  getSplitAmount,
9
9
  getTransactionFee,
10
10
  useSlapiBalance
11
- } from "./chunk-STM24EZ3.js";
11
+ } from "./chunk-LXX5P2LL.js";
12
12
  import {
13
13
  Iframe3ds
14
- } from "./chunk-BGLP7QYP.js";
14
+ } from "./chunk-4ELDS4N4.js";
15
15
  import {
16
16
  InfoBanner,
17
17
  LogLevel,
@@ -31,10 +31,10 @@ import {
31
31
  useSpreePayRegister,
32
32
  useSpreePaymentMethod,
33
33
  useStaticConfig
34
- } from "./chunk-JUAE4572.js";
34
+ } from "./chunk-I35SE3K2.js";
35
35
 
36
36
  // src/SpreePay.tsx
37
- import { useCallback as useCallback7, useEffect as useEffect8, useMemo as useMemo7, useState as useState10 } from "react";
37
+ import { useCallback as useCallback7, useEffect as useEffect8, useMemo as useMemo7, useState as useState11 } from "react";
38
38
  import NiceModal4 from "@ebay/nice-modal-react";
39
39
  import { SWRConfig } from "swr";
40
40
 
@@ -73,7 +73,11 @@ var useCardPayment = () => {
73
73
  lastFour: card.lastFourNumbers,
74
74
  schema: card.schema
75
75
  });
76
- const { data: cardResData } = await SlapiPaymentService.addCard({ hash, source: card.token });
76
+ const { data: cardResData } = await SlapiPaymentService.addCard({
77
+ hash,
78
+ source: card.token,
79
+ saveCard: card.saveCard
80
+ });
77
81
  cardId = cardResData.id;
78
82
  cardPaymentLogger.info("New card added successfully", { cardId });
79
83
  } else {
@@ -537,9 +541,10 @@ var useSplitCardPayments = (mode = "web2") => {
537
541
 
538
542
  // src/hooks/useCards.ts
539
543
  import useSWR from "swr";
544
+ var URL = "/v1/payments/cards";
540
545
  var useCards = () => {
541
546
  const { origin } = useSpreePayEnv();
542
- const { data, isLoading, mutate } = useSWR(`/v1/payments/cards?origin=${origin}`);
547
+ const { data, isLoading, mutate } = useSWR(origin ? `${URL}?origin=${origin}` : URL);
543
548
  return {
544
549
  cards: data?.data.filter((c) => c.active) || [],
545
550
  cardsIsLoading: isLoading,
@@ -548,31 +553,35 @@ var useCards = () => {
548
553
  };
549
554
 
550
555
  // src/components/CreditCardTab/CreditCard/CreditCard.tsx
551
- import { useMemo, useState as useState2 } from "react";
556
+ import { useMemo, useState as useState3 } from "react";
552
557
  import { Elements } from "@stripe/react-stripe-js";
553
558
  import { loadStripe } from "@stripe/stripe-js";
554
559
 
555
560
  // src/components/CreditCardTab/CreditCard/CardsList.tsx
561
+ import { useState } from "react";
556
562
  import { jsx, jsxs } from "react/jsx-runtime";
557
- var isRemoveDisabled = true;
558
- var CardListItem = ({ card, isSelected, onSelect }) => {
559
- const handleSelect = () => {
560
- onSelect(card);
561
- };
562
- const handleRemoveCard = (e) => {
563
+ var CardListItem = ({ card, isSelected, onSelect, onRemove }) => {
564
+ const [isRemoving, setIsRemoving] = useState(false);
565
+ const removeDisabled = isSelected || isRemoving;
566
+ const handleRemove = async (e) => {
563
567
  e.stopPropagation();
564
- if (isSelected || isRemoveDisabled) return;
568
+ setIsRemoving(true);
569
+ try {
570
+ await onRemove(card);
571
+ } finally {
572
+ setIsRemoving(false);
573
+ }
565
574
  };
566
575
  return /* @__PURE__ */ jsxs(
567
- "button",
576
+ "div",
568
577
  {
569
- type: "button",
570
- onClick: handleSelect,
578
+ role: "button",
579
+ tabIndex: 0,
580
+ onClick: () => onSelect(card),
581
+ onKeyDown: (e) => (e.key === "Enter" || e.key === " ") && onSelect(card),
571
582
  className: cn(
572
- "flex h-12 w-full overflow-hidden rounded-md border-2 border-(--b-inverse) bg-(--s-primary) hover:bg-(--s-primary-hover)",
573
- {
574
- "border-(--b-brand)": isSelected
575
- }
583
+ "flex h-12 w-full cursor-pointer overflow-hidden rounded-md border-2 border-(--b-inverse) bg-(--s-primary) hover:bg-(--s-primary-hover)",
584
+ { "border-(--b-brand)": isSelected }
576
585
  ),
577
586
  children: [
578
587
  /* @__PURE__ */ jsx(
@@ -598,13 +607,12 @@ var CardListItem = ({ card, isSelected, onSelect }) => {
598
607
  /* @__PURE__ */ jsx("span", { className: "text-(--brand-primary)", children: card.lastFourNumbers })
599
608
  ] }),
600
609
  /* @__PURE__ */ jsx(
601
- "div",
610
+ "button",
602
611
  {
603
- onClick: handleRemoveCard,
604
- className: cn("rounded-md p-1 text-(--tertiary) transition-all hover:bg-(--s-secondary)", {
605
- "cursor-not-allowed opacity-50": isSelected || isRemoveDisabled
606
- // 'cursor-pointer': !isSelected || !isRemoveDisabled,
607
- }),
612
+ type: "button",
613
+ onClick: handleRemove,
614
+ disabled: removeDisabled,
615
+ className: "text-tertiary rounded-md p-1 transition-all hover:bg-(--s-secondary) disabled:cursor-not-allowed disabled:opacity-50",
608
616
  children: /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "currentColor", className: "size-5", viewBox: "0 0 20 20", children: /* @__PURE__ */ jsx("path", { d: "M6.35 16.17q-.57 0-.96-.4a1.3 1.3 0 0 1-.39-.95V4.5h-.83v-.83H7.5v-.64h5v.64h3.33v.83H15v10.32q0 .58-.39.96a1.3 1.3 0 0 1-.96.39zM14.17 4.5H5.83v10.32q0 .23.15.37.15.15.37.15h7.3q.2 0 .36-.16.15-.17.16-.36zm-6 9.17h.84v-7.5h-.84zm2.82 0h.84v-7.5h-.84z" }) })
609
617
  }
610
618
  )
@@ -617,16 +625,31 @@ var CardListItem = ({ card, isSelected, onSelect }) => {
617
625
  );
618
626
  };
619
627
  var CardsList = ({ selectedCard, setCard }) => {
620
- const { cards, cardsIsLoading } = useCards();
628
+ const { cards, cardsIsLoading, mutateCards } = useCards();
629
+ const handleRemove = async (card) => {
630
+ if ("cardId" in card) {
631
+ await SlapiPaymentService.removeCard({ cardId: card.id });
632
+ }
633
+ mutateCards((data) => ({ ...data, data: (data?.data ?? []).filter((c) => c.id !== card.id) }));
634
+ };
621
635
  if (cardsIsLoading) {
622
636
  return /* @__PURE__ */ jsx("div", { className: "flex w-full flex-col", children: /* @__PURE__ */ jsx("div", { className: "h-11 animate-pulse rounded-sm bg-(--s-primary)" }) });
623
637
  }
624
638
  if (cards.length === 0) return null;
625
- return /* @__PURE__ */ jsx("div", { className: "flex w-full flex-col gap-4", children: cards.map((card) => /* @__PURE__ */ jsx(CardListItem, { isSelected: selectedCard?.id === card.id, onSelect: setCard, card }, card.id)) });
639
+ return /* @__PURE__ */ jsx("div", { className: "flex w-full flex-col gap-4", children: cards.map((card) => /* @__PURE__ */ jsx(
640
+ CardListItem,
641
+ {
642
+ isSelected: selectedCard?.id === card.id,
643
+ onSelect: setCard,
644
+ onRemove: handleRemove,
645
+ card
646
+ },
647
+ card.id
648
+ )) });
626
649
  };
627
650
 
628
651
  // src/components/CreditCardTab/CreditCard/CreditCardForm.tsx
629
- import { useCallback, useEffect, useId, useRef, useState } from "react";
652
+ import { useCallback, useEffect, useId, useRef, useState as useState2 } from "react";
630
653
  import { CardCvcElement, CardExpiryElement, CardNumberElement, useElements, useStripe } from "@stripe/react-stripe-js";
631
654
 
632
655
  // src/ui/button.tsx
@@ -705,8 +728,9 @@ var stripeElementClasses = {
705
728
  focus: "border-ring ring-ring/50 ring-2"
706
729
  };
707
730
  var CreditCardForm = ({ cancel, saveCard }) => {
708
- const [cardError, setCardError] = useState(void 0);
709
- const [stripeStyles, setStripeStyles] = useState({});
731
+ const [cardError, setCardError] = useState2(void 0);
732
+ const [stripeStyles, setStripeStyles] = useState2({});
733
+ const [shouldSaveCard, setShouldSaveCard] = useState2(true);
710
734
  const formRef = useRef(null);
711
735
  const elements = useElements();
712
736
  const stripe = useStripe();
@@ -760,7 +784,8 @@ var CreditCardForm = ({ cancel, saveCard }) => {
760
784
  schema: token.card?.brand,
761
785
  lastFourNumbers: token.card?.last4 ?? "",
762
786
  expireMonth: `${token.card?.exp_month}`,
763
- expireYear: `${token.card?.exp_year}`
787
+ expireYear: `${token.card?.exp_year}`,
788
+ saveCard: shouldSaveCard
764
789
  });
765
790
  }
766
791
  }
@@ -806,7 +831,7 @@ var CreditCardForm = ({ cancel, saveCard }) => {
806
831
  cardError && /* @__PURE__ */ jsx4("p", { className: "text-destructive mt-1 text-sm", children: cardError })
807
832
  ] }),
808
833
  /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
809
- /* @__PURE__ */ jsx4(Checkbox, { disabled: true, checked: true, id: "saveCard" }),
834
+ /* @__PURE__ */ jsx4(Checkbox, { checked: shouldSaveCard, onCheckedChange: (v) => setShouldSaveCard(v === true), id: "saveCard" }),
810
835
  /* @__PURE__ */ jsx4(Label, { className: "text-sm font-medium", htmlFor: "saveCard", children: "Save card for future purchases" })
811
836
  ] }),
812
837
  /* @__PURE__ */ jsxs2("div", { className: "flex w-full justify-end gap-2", children: [
@@ -833,17 +858,22 @@ var CreditCardForm = ({ cancel, saveCard }) => {
833
858
 
834
859
  // src/components/CreditCardTab/CreditCard/CreditCard.tsx
835
860
  import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
836
- var StripeWrapper = (props) => {
837
- const stripePromise = useMemo(() => loadStripe(props.publicKey), [props.publicKey]);
838
- return /* @__PURE__ */ jsx5(Elements, { stripe: stripePromise, children: /* @__PURE__ */ jsx5(CreditCardForm, { cancel: props.onCancel, saveCard: props.saveNewCard }) });
861
+ var StripeWrapper = ({ onCancel, saveNewCard, publicKey }) => {
862
+ const stripePromise = useMemo(() => loadStripe(publicKey), [publicKey]);
863
+ return /* @__PURE__ */ jsx5(Elements, { stripe: stripePromise, children: /* @__PURE__ */ jsx5(CreditCardForm, { cancel: onCancel, saveCard: saveNewCard }) });
839
864
  };
840
865
  var CreditCard = () => {
841
- const [showForm, setShowForm] = useState2(false);
866
+ const [showForm, setShowForm] = useState3(false);
842
867
  const { selectedPaymentMethod, setSelectedPaymentMethod } = useSpreePaymentMethod();
843
868
  const { mutateCards } = useCards();
844
869
  const { spreePayConfig } = useSpreePayConfig();
845
870
  const setCard = (card) => {
846
- setSelectedPaymentMethod({ ...selectedPaymentMethod, type: "CREDIT_CARD" /* CREDIT_CARD */, method: card });
871
+ const isAlreadySelected = selectedPaymentMethod?.type === "CREDIT_CARD" /* CREDIT_CARD */ && selectedPaymentMethod.method?.id === card.id;
872
+ setSelectedPaymentMethod({
873
+ ...selectedPaymentMethod,
874
+ type: "CREDIT_CARD" /* CREDIT_CARD */,
875
+ method: isAlreadySelected ? null : card
876
+ });
847
877
  };
848
878
  const saveNewCard = (newCard) => {
849
879
  mutateCards((data) => ({ ...data, data: [...data?.data ?? [], newCard] }), { revalidate: false });
@@ -879,14 +909,14 @@ var CreditCard = () => {
879
909
  };
880
910
 
881
911
  // src/components/CreditCardTab/Points/Points.tsx
882
- import { useState as useState8 } from "react";
912
+ import { useState as useState9 } from "react";
883
913
 
884
914
  // src/components/CreditCardTab/Points/SplitBlock.tsx
885
- import { useCallback as useCallback4, useEffect as useEffect5, useRef as useRef6, useState as useState7 } from "react";
915
+ import { useCallback as useCallback4, useEffect as useEffect5, useRef as useRef6, useState as useState8 } from "react";
886
916
  import { BUILD_ENV as BUILD_ENV2 } from "@mocanetwork/airkit";
887
917
 
888
918
  // src/components/CreditCardTab/Points/PointsSelector.tsx
889
- import { useState as useState6 } from "react";
919
+ import { useState as useState7 } from "react";
890
920
 
891
921
  // src/ui/input.tsx
892
922
  import { jsx as jsx6 } from "react/jsx-runtime";
@@ -1879,7 +1909,7 @@ var PointsSelector = (props) => {
1879
1909
  const maxByAmount = pointsConversionRatio && pointsConversionRatio > 0 ? (amount ?? 0) / pointsConversionRatio : 0;
1880
1910
  const max = Math.min(maxByAmount, balance?.availablePoints ?? 0);
1881
1911
  const step = 10;
1882
- const [splitTokens, setSplitTokens] = useState6(0);
1912
+ const [splitTokens, setSplitTokens] = useState7(0);
1883
1913
  const usdAmount = getSplitAmount(amount ?? 0, splitTokens, pointsConversionRatio);
1884
1914
  const pointsValue = String(Math.round(splitTokens));
1885
1915
  const usdWithFee = usdAmount + getTransactionFee(usdAmount, transactionFeePercentage);
@@ -1977,8 +2007,8 @@ var SplitBlock = (props) => {
1977
2007
  const { spreePayConfig } = useSpreePayConfig();
1978
2008
  const { appProps } = useStaticConfig();
1979
2009
  const { currencyCode, exchangeRate, foreignCurrencyAmount } = appProps;
1980
- const [address, setAddress] = useState7(null);
1981
- const [walletReady, setWalletReady] = useState7(false);
2010
+ const [address, setAddress] = useState8(null);
2011
+ const [walletReady, setWalletReady] = useState8(false);
1982
2012
  const { pointsConversionRatio, pointsTitle } = spreePayConfig || {};
1983
2013
  const { useWeb3Points, environment } = useSpreePayEnv();
1984
2014
  const hasForeignCurrency = !!(currencyCode && exchangeRate && foreignCurrencyAmount);
@@ -2037,8 +2067,8 @@ var SplitBlock = (props) => {
2037
2067
  // src/components/CreditCardTab/Points/Points.tsx
2038
2068
  import { Fragment as Fragment3, jsx as jsx15, jsxs as jsxs8 } from "react/jsx-runtime";
2039
2069
  var Points = () => {
2040
- const [usePoints, setUsePoints] = useState8(false);
2041
- const [selectedPointsType, setSelectedPointsType] = useState8(null);
2070
+ const [usePoints, setUsePoints] = useState9(false);
2071
+ const [selectedPointsType, setSelectedPointsType] = useState9(null);
2042
2072
  const { setSelectedPaymentMethod, selectedPaymentMethod } = useSpreePaymentMethod();
2043
2073
  const { spreePayConfig } = useSpreePayConfig();
2044
2074
  const { appProps } = useStaticConfig();
@@ -2205,9 +2235,9 @@ var TabButtons = (props) => {
2205
2235
 
2206
2236
  // src/SpreePayContent.tsx
2207
2237
  import { jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
2208
- var CryptoTab = lazy(() => import("./CryptoTab-AK7WPMBJ.js").then((module) => ({ default: module.CryptoTab })));
2238
+ var CryptoTab = lazy(() => import("./CryptoTab-RY2NTNZJ.js").then((module) => ({ default: module.CryptoTab })));
2209
2239
  var CryptoComTab = lazy(
2210
- () => import("./CryptoComTab-QOGLM3EB.js").then((module) => ({ default: module.CryptoComTab }))
2240
+ () => import("./CryptoComTab-GNJ4XACU.js").then((module) => ({ default: module.CryptoComTab }))
2211
2241
  );
2212
2242
  var TabLoadingFallback = () => /* @__PURE__ */ jsx18("div", { className: "flex items-center justify-center px-5 py-8 md:px-7", children: /* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-center gap-3", children: [
2213
2243
  /* @__PURE__ */ jsx18("div", { className: "h-8 w-8 animate-spin rounded-full border-4 border-(--border-component-specific-card) border-t-(--brand-primary)" }),
@@ -2277,7 +2307,7 @@ var ErrorBoundary = class extends Component {
2277
2307
  };
2278
2308
 
2279
2309
  // src/hooks/useKeycloakSSO.ts
2280
- import { useCallback as useCallback6, useEffect as useEffect7, useRef as useRef7, useState as useState9 } from "react";
2310
+ import { useCallback as useCallback6, useEffect as useEffect7, useRef as useRef7, useState as useState10 } from "react";
2281
2311
  import Keycloak from "keycloak-js";
2282
2312
  var refreshAheadSeconds = 60;
2283
2313
  var keycloakLogger = logger.child("keycloak");
@@ -2288,9 +2318,9 @@ function useKeycloakSSO(config) {
2288
2318
  const refreshTimerRef = useRef7(null);
2289
2319
  const scheduleRefreshRef = useRef7(() => {
2290
2320
  });
2291
- const [error, setError] = useState9(null);
2292
- const [isChecking, setIsChecking] = useState9(enabled);
2293
- const [accessToken, setAccessToken] = useState9(null);
2321
+ const [error, setError] = useState10(null);
2322
+ const [isChecking, setIsChecking] = useState10(enabled);
2323
+ const [accessToken, setAccessToken] = useState10(null);
2294
2324
  const scheduleRefresh = useCallback6(() => {
2295
2325
  const kc = kcRef.current;
2296
2326
  if (!kc || !kc.tokenParsed || !kc.tokenParsed.exp) {
@@ -2354,7 +2384,7 @@ function useKeycloakSSO(config) {
2354
2384
  // src/SpreePay.tsx
2355
2385
  import { jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
2356
2386
  var SpreePayInner = () => {
2357
- const [portalEl, setPortalEl] = useState10(null);
2387
+ const [portalEl, setPortalEl] = useState11(null);
2358
2388
  const rootRef = useCallback7((node) => {
2359
2389
  if (!node) return;
2360
2390
  const el = node.querySelector(":scope > .sl-spreepay__portal");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@superlogic/spree-pay",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "Spree-pay React component and utilities",
5
5
  "private": false,
6
6
  "type": "module",
@@ -49,27 +49,27 @@
49
49
  "@rainbow-me/rainbowkit": "^2.2.9",
50
50
  "@stripe/react-stripe-js": "^3.10.0",
51
51
  "@stripe/stripe-js": "^7.9.0",
52
- "@tanstack/react-query": "^5.90.12",
52
+ "@tanstack/react-query": "^5.97.0",
53
53
  "class-variance-authority": "^0.7.0",
54
54
  "clsx": "^2.1.1",
55
- "keycloak-js": "^26.2.1",
56
- "lucide-react": "^0.556.0",
57
- "swr": "^2.3.7",
58
- "tailwind-merge": "^3.4.0",
59
- "viem": "^2.41.2",
55
+ "keycloak-js": "^26.2.3",
56
+ "lucide-react": "^1.8.0",
57
+ "swr": "^2.4.1",
58
+ "tailwind-merge": "^3.5.0",
59
+ "viem": "^2.47.11",
60
60
  "wagmi": "^2.19.5",
61
61
  "xss": "^1.0.15"
62
62
  },
63
63
  "devDependencies": {
64
64
  "@repo/eslint-config": "^1.0.0",
65
- "@tailwindcss/postcss": "^4.1.17",
65
+ "@tailwindcss/postcss": "^4.2.2",
66
66
  "@types/react": "^19",
67
67
  "@types/react-dom": "^19",
68
68
  "postcss-prefix-selector": "^2.1.1",
69
- "tailwindcss": "^4.1.17",
69
+ "tailwindcss": "^4.2.2",
70
70
  "tsup": "^8.5.1",
71
71
  "tw-animate-css": "^1.4.0",
72
- "typescript": "^5.9.3"
72
+ "typescript": "^6.0.2"
73
73
  },
74
74
  "tsup": {
75
75
  "entry": [