@superlogic/spree-pay 0.4.1 → 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.
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Iframe3ds
3
- } from "./chunk-IDYBXJWP.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-5GHGAP6Z.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-W43ZCY4N.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-5GHGAP6Z.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-5GHGAP6Z.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.1";
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-5GHGAP6Z.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.1";
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 {
@@ -3075,7 +3089,7 @@ init_split();
3075
3089
  init_CheckoutButton();
3076
3090
 
3077
3091
  // src/components/CreditCardTab/CreditCard/CreditCard.tsx
3078
- var import_react7 = require("react");
3092
+ var import_react8 = require("react");
3079
3093
  var import_react_stripe_js2 = require("@stripe/react-stripe-js");
3080
3094
  var import_stripe_js = require("@stripe/stripe-js");
3081
3095
  init_SpreePayActionsContext();
@@ -3083,27 +3097,32 @@ init_useSpreePayConfig();
3083
3097
  init_InfoBanner();
3084
3098
 
3085
3099
  // src/components/CreditCardTab/CreditCard/CardsList.tsx
3100
+ var import_react6 = require("react");
3086
3101
  init_utils();
3102
+ init_slapi();
3087
3103
  var import_jsx_runtime12 = require("react/jsx-runtime");
3088
- var isRemoveDisabled = true;
3089
- var CardListItem = ({ card, isSelected, onSelect }) => {
3090
- const handleSelect = () => {
3091
- onSelect(card);
3092
- };
3093
- 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) => {
3094
3108
  e.stopPropagation();
3095
- if (isSelected || isRemoveDisabled) return;
3109
+ setIsRemoving(true);
3110
+ try {
3111
+ await onRemove(card);
3112
+ } finally {
3113
+ setIsRemoving(false);
3114
+ }
3096
3115
  };
3097
3116
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
3098
- "button",
3117
+ "div",
3099
3118
  {
3100
- type: "button",
3101
- onClick: handleSelect,
3119
+ role: "button",
3120
+ tabIndex: 0,
3121
+ onClick: () => onSelect(card),
3122
+ onKeyDown: (e) => (e.key === "Enter" || e.key === " ") && onSelect(card),
3102
3123
  className: cn(
3103
- "flex h-12 w-full overflow-hidden rounded-md border-2 border-(--b-inverse) bg-(--s-primary) hover:bg-(--s-primary-hover)",
3104
- {
3105
- "border-(--b-brand)": isSelected
3106
- }
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 }
3107
3126
  ),
3108
3127
  children: [
3109
3128
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
@@ -3129,13 +3148,12 @@ var CardListItem = ({ card, isSelected, onSelect }) => {
3129
3148
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "text-(--brand-primary)", children: card.lastFourNumbers })
3130
3149
  ] }),
3131
3150
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
3132
- "div",
3151
+ "button",
3133
3152
  {
3134
- onClick: handleRemoveCard,
3135
- className: cn("rounded-md p-1 text-(--tertiary) transition-all hover:bg-(--s-secondary)", {
3136
- "cursor-not-allowed opacity-50": isSelected || isRemoveDisabled
3137
- // 'cursor-pointer': !isSelected || !isRemoveDisabled,
3138
- }),
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",
3139
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" }) })
3140
3158
  }
3141
3159
  )
@@ -3148,16 +3166,31 @@ var CardListItem = ({ card, isSelected, onSelect }) => {
3148
3166
  );
3149
3167
  };
3150
3168
  var CardsList = ({ selectedCard, setCard }) => {
3151
- 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
+ };
3152
3176
  if (cardsIsLoading) {
3153
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)" }) });
3154
3178
  }
3155
3179
  if (cards.length === 0) return null;
3156
- 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
+ )) });
3157
3190
  };
3158
3191
 
3159
3192
  // src/components/CreditCardTab/CreditCard/CreditCardForm.tsx
3160
- var import_react6 = require("react");
3193
+ var import_react7 = require("react");
3161
3194
  var import_react_stripe_js = require("@stripe/react-stripe-js");
3162
3195
 
3163
3196
  // src/ui/button.tsx
@@ -3240,13 +3273,14 @@ var stripeElementClasses = {
3240
3273
  focus: "border-ring ring-ring/50 ring-2"
3241
3274
  };
3242
3275
  var CreditCardForm = ({ cancel, saveCard }) => {
3243
- const [cardError, setCardError] = (0, import_react6.useState)(void 0);
3244
- const [stripeStyles, setStripeStyles] = (0, import_react6.useState)({});
3245
- 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);
3246
3280
  const elements = (0, import_react_stripe_js.useElements)();
3247
3281
  const stripe = (0, import_react_stripe_js.useStripe)();
3248
- const id = (0, import_react6.useId)();
3249
- const computeStripeStyles = (0, import_react6.useCallback)(() => {
3282
+ const id = (0, import_react7.useId)();
3283
+ const computeStripeStyles = (0, import_react7.useCallback)(() => {
3250
3284
  const formRefCurrent = formRef.current;
3251
3285
  if (typeof window === "undefined" || !formRefCurrent) return {};
3252
3286
  const container = formRefCurrent.closest(".sl-spreepay");
@@ -3267,7 +3301,7 @@ var CreditCardForm = ({ cancel, saveCard }) => {
3267
3301
  }
3268
3302
  };
3269
3303
  }, []);
3270
- (0, import_react6.useEffect)(() => {
3304
+ (0, import_react7.useEffect)(() => {
3271
3305
  setStripeStyles(computeStripeStyles());
3272
3306
  }, [computeStripeStyles]);
3273
3307
  const handleSaveCard = async () => {
@@ -3295,7 +3329,8 @@ var CreditCardForm = ({ cancel, saveCard }) => {
3295
3329
  schema: token.card?.brand,
3296
3330
  lastFourNumbers: token.card?.last4 ?? "",
3297
3331
  expireMonth: `${token.card?.exp_month}`,
3298
- expireYear: `${token.card?.exp_year}`
3332
+ expireYear: `${token.card?.exp_year}`,
3333
+ saveCard: shouldSaveCard
3299
3334
  });
3300
3335
  }
3301
3336
  }
@@ -3341,7 +3376,7 @@ var CreditCardForm = ({ cancel, saveCard }) => {
3341
3376
  cardError && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-destructive mt-1 text-sm", children: cardError })
3342
3377
  ] }),
3343
3378
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex items-center gap-2", children: [
3344
- /* @__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" }),
3345
3380
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Label, { className: "text-sm font-medium", htmlFor: "saveCard", children: "Save card for future purchases" })
3346
3381
  ] }),
3347
3382
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex w-full justify-end gap-2", children: [
@@ -3368,17 +3403,22 @@ var CreditCardForm = ({ cancel, saveCard }) => {
3368
3403
 
3369
3404
  // src/components/CreditCardTab/CreditCard/CreditCard.tsx
3370
3405
  var import_jsx_runtime16 = require("react/jsx-runtime");
3371
- var StripeWrapper = (props) => {
3372
- const stripePromise = (0, import_react7.useMemo)(() => (0, import_stripe_js.loadStripe)(props.publicKey), [props.publicKey]);
3373
- 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 }) });
3374
3409
  };
3375
3410
  var CreditCard = () => {
3376
- const [showForm, setShowForm] = (0, import_react7.useState)(false);
3411
+ const [showForm, setShowForm] = (0, import_react8.useState)(false);
3377
3412
  const { selectedPaymentMethod, setSelectedPaymentMethod } = useSpreePaymentMethod();
3378
3413
  const { mutateCards } = useCards();
3379
3414
  const { spreePayConfig } = useSpreePayConfig();
3380
3415
  const setCard = (card) => {
3381
- 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
+ });
3382
3422
  };
3383
3423
  const saveNewCard = (newCard) => {
3384
3424
  mutateCards((data) => ({ ...data, data: [...data?.data ?? [], newCard] }), { revalidate: false });
@@ -3414,14 +3454,14 @@ var CreditCard = () => {
3414
3454
  };
3415
3455
 
3416
3456
  // src/components/CreditCardTab/Points/Points.tsx
3417
- var import_react12 = require("react");
3457
+ var import_react13 = require("react");
3418
3458
  init_SpreePayActionsContext();
3419
3459
  init_StaticConfigContext();
3420
3460
  init_useSpreePayConfig();
3421
3461
  init_common();
3422
3462
 
3423
3463
  // src/components/CreditCardTab/Points/SplitBlock.tsx
3424
- var import_react11 = require("react");
3464
+ var import_react12 = require("react");
3425
3465
  var import_airkit2 = require("@mocanetwork/airkit");
3426
3466
  init_SpreePayActionsContext();
3427
3467
  init_StaticConfigContext();
@@ -3431,7 +3471,7 @@ init_format();
3431
3471
  init_logger();
3432
3472
 
3433
3473
  // src/components/CreditCardTab/Points/PointsSelector.tsx
3434
- var import_react10 = require("react");
3474
+ var import_react11 = require("react");
3435
3475
  init_SpreePayActionsContext();
3436
3476
  init_StaticConfigContext();
3437
3477
  init_useSlapiBalance();
@@ -3751,10 +3791,10 @@ var Primitive = NODES.reduce((primitive, node) => {
3751
3791
  }, {});
3752
3792
 
3753
3793
  // ../../node_modules/@radix-ui/react-collection/dist/index.mjs
3754
- var import_react8 = __toESM(require("react"), 1);
3794
+ var import_react9 = __toESM(require("react"), 1);
3755
3795
  var import_react_slot3 = require("@radix-ui/react-slot");
3756
3796
  var import_jsx_runtime21 = require("react/jsx-runtime");
3757
- var import_react9 = __toESM(require("react"), 1);
3797
+ var import_react10 = __toESM(require("react"), 1);
3758
3798
  var import_react_slot4 = require("@radix-ui/react-slot");
3759
3799
  var import_jsx_runtime22 = require("react/jsx-runtime");
3760
3800
  function createCollection(name) {
@@ -3766,14 +3806,14 @@ function createCollection(name) {
3766
3806
  );
3767
3807
  const CollectionProvider = (props) => {
3768
3808
  const { scope, children } = props;
3769
- const ref = import_react8.default.useRef(null);
3770
- 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;
3771
3811
  return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(CollectionProviderImpl, { scope, itemMap, collectionRef: ref, children });
3772
3812
  };
3773
3813
  CollectionProvider.displayName = PROVIDER_NAME;
3774
3814
  const COLLECTION_SLOT_NAME = name + "CollectionSlot";
3775
3815
  const CollectionSlotImpl = (0, import_react_slot3.createSlot)(COLLECTION_SLOT_NAME);
3776
- const CollectionSlot = import_react8.default.forwardRef(
3816
+ const CollectionSlot = import_react9.default.forwardRef(
3777
3817
  (props, forwardedRef) => {
3778
3818
  const { scope, children } = props;
3779
3819
  const context = useCollectionContext(COLLECTION_SLOT_NAME, scope);
@@ -3785,13 +3825,13 @@ function createCollection(name) {
3785
3825
  const ITEM_SLOT_NAME = name + "CollectionItemSlot";
3786
3826
  const ITEM_DATA_ATTR = "data-radix-collection-item";
3787
3827
  const CollectionItemSlotImpl = (0, import_react_slot3.createSlot)(ITEM_SLOT_NAME);
3788
- const CollectionItemSlot = import_react8.default.forwardRef(
3828
+ const CollectionItemSlot = import_react9.default.forwardRef(
3789
3829
  (props, forwardedRef) => {
3790
3830
  const { scope, children, ...itemData } = props;
3791
- const ref = import_react8.default.useRef(null);
3831
+ const ref = import_react9.default.useRef(null);
3792
3832
  const composedRefs = useComposedRefs(forwardedRef, ref);
3793
3833
  const context = useCollectionContext(ITEM_SLOT_NAME, scope);
3794
- import_react8.default.useEffect(() => {
3834
+ import_react9.default.useEffect(() => {
3795
3835
  context.itemMap.set(ref, { ref, ...itemData });
3796
3836
  return () => void context.itemMap.delete(ref);
3797
3837
  });
@@ -3801,7 +3841,7 @@ function createCollection(name) {
3801
3841
  CollectionItemSlot.displayName = ITEM_SLOT_NAME;
3802
3842
  function useCollection2(scope) {
3803
3843
  const context = useCollectionContext(name + "CollectionConsumer", scope);
3804
- const getItems = import_react8.default.useCallback(() => {
3844
+ const getItems = import_react9.default.useCallback(() => {
3805
3845
  const collectionNode = context.collectionRef.current;
3806
3846
  if (!collectionNode) return [];
3807
3847
  const orderedNodes = Array.from(collectionNode.querySelectorAll(`[${ITEM_DATA_ATTR}]`));
@@ -4434,7 +4474,7 @@ var PointsSelector = (props) => {
4434
4474
  const maxByAmount = pointsConversionRatio && pointsConversionRatio > 0 ? (amount ?? 0) / pointsConversionRatio : 0;
4435
4475
  const max = Math.min(maxByAmount, balance?.availablePoints ?? 0);
4436
4476
  const step = 10;
4437
- const [splitTokens, setSplitTokens] = (0, import_react10.useState)(0);
4477
+ const [splitTokens, setSplitTokens] = (0, import_react11.useState)(0);
4438
4478
  const usdAmount = getSplitAmount(amount ?? 0, splitTokens, pointsConversionRatio);
4439
4479
  const pointsValue = String(Math.round(splitTokens));
4440
4480
  const usdWithFee = usdAmount + getTransactionFee(usdAmount, transactionFeePercentage);
@@ -4532,14 +4572,14 @@ var SplitBlock = (props) => {
4532
4572
  const { spreePayConfig } = useSpreePayConfig();
4533
4573
  const { appProps } = useStaticConfig();
4534
4574
  const { currencyCode, exchangeRate, foreignCurrencyAmount } = appProps;
4535
- const [address, setAddress] = (0, import_react11.useState)(null);
4536
- 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);
4537
4577
  const { pointsConversionRatio, pointsTitle } = spreePayConfig || {};
4538
4578
  const { useWeb3Points, environment } = useSpreePayEnv();
4539
4579
  const hasForeignCurrency = !!(currencyCode && exchangeRate && foreignCurrencyAmount);
4540
4580
  const formatPointsValue = (usd) => hasForeignCurrency ? formatCurrency(usd / exchangeRate, currencyCode) : formatCurrency(usd);
4541
- const prevPointsChainRef = (0, import_react11.useRef)(spreePayConfig?.pointsChain);
4542
- const initWallet = (0, import_react11.useCallback)(
4581
+ const prevPointsChainRef = (0, import_react12.useRef)(spreePayConfig?.pointsChain);
4582
+ const initWallet = (0, import_react12.useCallback)(
4543
4583
  async (pointsChain) => {
4544
4584
  if (!pointsChain) return;
4545
4585
  try {
@@ -4562,7 +4602,7 @@ var SplitBlock = (props) => {
4562
4602
  },
4563
4603
  [onToggle, environment]
4564
4604
  );
4565
- (0, import_react11.useEffect)(() => {
4605
+ (0, import_react12.useEffect)(() => {
4566
4606
  if (!useWeb3Points) return;
4567
4607
  const pointsChainChanged = prevPointsChainRef.current !== spreePayConfig?.pointsChain;
4568
4608
  prevPointsChainRef.current = spreePayConfig?.pointsChain;
@@ -4592,8 +4632,8 @@ var SplitBlock = (props) => {
4592
4632
  // src/components/CreditCardTab/Points/Points.tsx
4593
4633
  var import_jsx_runtime27 = require("react/jsx-runtime");
4594
4634
  var Points = () => {
4595
- const [usePoints, setUsePoints] = (0, import_react12.useState)(false);
4596
- 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);
4597
4637
  const { setSelectedPaymentMethod, selectedPaymentMethod } = useSpreePaymentMethod();
4598
4638
  const { spreePayConfig } = useSpreePayConfig();
4599
4639
  const { appProps } = useStaticConfig();
@@ -4639,7 +4679,7 @@ var CreditCardTab = ({ isLoggedIn }) => {
4639
4679
  const { cardPayment } = useCardPayment();
4640
4680
  const { splitPayment } = useSplitCardPayments(isWeb3Enabled ? "web3" : "web2");
4641
4681
  const { pointsPayment } = usePointsPayment(isWeb3Enabled ? "web3" : "web2");
4642
- const handlePay = (0, import_react13.useCallback)(
4682
+ const handlePay = (0, import_react14.useCallback)(
4643
4683
  async (data) => {
4644
4684
  try {
4645
4685
  let res = null;
@@ -4678,7 +4718,7 @@ var CreditCardTab = ({ isLoggedIn }) => {
4678
4718
  mutateBalance
4679
4719
  ]
4680
4720
  );
4681
- (0, import_react13.useEffect)(() => {
4721
+ (0, import_react14.useEffect)(() => {
4682
4722
  register(handlePay);
4683
4723
  }, [register, handlePay]);
4684
4724
  return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { children: [
@@ -4763,8 +4803,8 @@ var TabButtons = (props) => {
4763
4803
  // src/SpreePayContent.tsx
4764
4804
  init_SpreePayActionsContext();
4765
4805
  var import_jsx_runtime45 = require("react/jsx-runtime");
4766
- var CryptoTab2 = (0, import_react18.lazy)(() => Promise.resolve().then(() => (init_CryptoTab2(), CryptoTab_exports)).then((module2) => ({ default: module2.CryptoTab })));
4767
- 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)(
4768
4808
  () => Promise.resolve().then(() => (init_CryptoComTab2(), CryptoComTab_exports)).then((module2) => ({ default: module2.CryptoComTab }))
4769
4809
  );
4770
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: [
@@ -4779,7 +4819,7 @@ var SpreePayContent = ({ isLoggedIn }) => {
4779
4819
  /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(TabButtons, { value: selectedPaymentMethod.type, onChange: setSelectedPaymentMethod })
4780
4820
  ] }),
4781
4821
  selectedPaymentMethod.type === "CREDIT_CARD" /* CREDIT_CARD */ && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(CreditCardTab, { isLoggedIn }),
4782
- /* @__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: [
4783
4823
  selectedPaymentMethod.type === "CRYPTO" /* CRYPTO */ && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(CryptoTab2, { isLoggedIn }),
4784
4824
  selectedPaymentMethod.type === "CDC" /* CDC */ && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(CryptoComTab2, {})
4785
4825
  ] })
@@ -4787,10 +4827,10 @@ var SpreePayContent = ({ isLoggedIn }) => {
4787
4827
  };
4788
4828
 
4789
4829
  // src/components/ErrorBoundary.tsx
4790
- var import_react19 = require("react");
4830
+ var import_react20 = require("react");
4791
4831
  init_logger();
4792
4832
  var import_jsx_runtime46 = require("react/jsx-runtime");
4793
- var ErrorBoundary = class extends import_react19.Component {
4833
+ var ErrorBoundary = class extends import_react20.Component {
4794
4834
  constructor(props) {
4795
4835
  super(props);
4796
4836
  this.state = { hasError: false, error: null };
@@ -4841,22 +4881,22 @@ init_StaticConfigContext();
4841
4881
  init_client();
4842
4882
 
4843
4883
  // src/hooks/useKeycloakSSO.ts
4844
- var import_react20 = require("react");
4884
+ var import_react21 = require("react");
4845
4885
  var import_keycloak_js = __toESM(require("keycloak-js"), 1);
4846
4886
  init_logger();
4847
4887
  var refreshAheadSeconds = 60;
4848
4888
  var keycloakLogger = logger.child("keycloak");
4849
4889
  function useKeycloakSSO(config2) {
4850
4890
  const { url, realm, clientId, ssoPageURI, enabled } = config2;
4851
- const initRef = (0, import_react20.useRef)(false);
4852
- const kcRef = (0, import_react20.useRef)(null);
4853
- const refreshTimerRef = (0, import_react20.useRef)(null);
4854
- 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)(() => {
4855
4895
  });
4856
- const [error, setError] = (0, import_react20.useState)(null);
4857
- const [isChecking, setIsChecking] = (0, import_react20.useState)(enabled);
4858
- const [accessToken, setAccessToken] = (0, import_react20.useState)(null);
4859
- 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)(() => {
4860
4900
  const kc = kcRef.current;
4861
4901
  if (!kc || !kc.tokenParsed || !kc.tokenParsed.exp) {
4862
4902
  return;
@@ -4880,10 +4920,10 @@ function useKeycloakSSO(config2) {
4880
4920
  });
4881
4921
  }, delayMs);
4882
4922
  }, []);
4883
- (0, import_react20.useEffect)(() => {
4923
+ (0, import_react21.useEffect)(() => {
4884
4924
  scheduleRefreshRef.current = scheduleRefresh;
4885
4925
  }, [scheduleRefresh]);
4886
- (0, import_react20.useEffect)(() => {
4926
+ (0, import_react21.useEffect)(() => {
4887
4927
  if (initRef.current || !enabled) return;
4888
4928
  initRef.current = true;
4889
4929
  const kc = new import_keycloak_js.default({ url, realm, clientId });
@@ -4922,14 +4962,14 @@ init_portal();
4922
4962
  init_logger();
4923
4963
  var import_jsx_runtime47 = require("react/jsx-runtime");
4924
4964
  var SpreePayInner = () => {
4925
- const [portalEl, setPortalEl] = (0, import_react21.useState)(null);
4926
- const rootRef = (0, import_react21.useCallback)((node) => {
4965
+ const [portalEl, setPortalEl] = (0, import_react22.useState)(null);
4966
+ const rootRef = (0, import_react22.useCallback)((node) => {
4927
4967
  if (!node) return;
4928
4968
  const el = node.querySelector(":scope > .sl-spreepay__portal");
4929
4969
  setPortalEl(el ?? null);
4930
4970
  }, []);
4931
4971
  const { environment, tenantId, keycloakClientId, accessToken: envAccessToken, ssoPageURI } = useSpreePayEnv();
4932
- (0, import_react21.useEffect)(() => {
4972
+ (0, import_react22.useEffect)(() => {
4933
4973
  configureLogger({ environment });
4934
4974
  logger.logVersion();
4935
4975
  }, [environment]);
@@ -4942,8 +4982,8 @@ var SpreePayInner = () => {
4942
4982
  enabled: !envAccessToken
4943
4983
  });
4944
4984
  const _accessToken = envAccessToken ?? accessToken;
4945
- const unauthenticatedFetcher = (0, import_react21.useCallback)(() => Promise.resolve(null), []);
4946
- const slapiFetcher = (0, import_react21.useMemo)(() => {
4985
+ const unauthenticatedFetcher = (0, import_react22.useCallback)(() => Promise.resolve(null), []);
4986
+ const slapiFetcher = (0, import_react22.useMemo)(() => {
4947
4987
  if (_accessToken) {
4948
4988
  return registerApi({
4949
4989
  accessToken: _accessToken,
@@ -4983,9 +5023,9 @@ var SpreePay = (props) => {
4983
5023
  };
4984
5024
 
4985
5025
  // src/hooks/useCapture3DS.ts
4986
- var import_react22 = require("react");
5026
+ var import_react23 = require("react");
4987
5027
  var useCapture3DS = (searchParams) => {
4988
- (0, import_react22.useEffect)(() => {
5028
+ (0, import_react23.useEffect)(() => {
4989
5029
  if (typeof window !== "undefined" && window.parent && searchParams?.paymentIntent) {
4990
5030
  window.parent.SP_EVENT_BUS?.emit("paymentIntent", { paymentIntent: searchParams.paymentIntent });
4991
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-W43ZCY4N.js";
11
+ } from "./chunk-LXX5P2LL.js";
12
12
  import {
13
13
  Iframe3ds
14
- } from "./chunk-IDYBXJWP.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-5GHGAP6Z.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 {
@@ -549,31 +553,35 @@ var useCards = () => {
549
553
  };
550
554
 
551
555
  // src/components/CreditCardTab/CreditCard/CreditCard.tsx
552
- import { useMemo, useState as useState2 } from "react";
556
+ import { useMemo, useState as useState3 } from "react";
553
557
  import { Elements } from "@stripe/react-stripe-js";
554
558
  import { loadStripe } from "@stripe/stripe-js";
555
559
 
556
560
  // src/components/CreditCardTab/CreditCard/CardsList.tsx
561
+ import { useState } from "react";
557
562
  import { jsx, jsxs } from "react/jsx-runtime";
558
- var isRemoveDisabled = true;
559
- var CardListItem = ({ card, isSelected, onSelect }) => {
560
- const handleSelect = () => {
561
- onSelect(card);
562
- };
563
- 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) => {
564
567
  e.stopPropagation();
565
- if (isSelected || isRemoveDisabled) return;
568
+ setIsRemoving(true);
569
+ try {
570
+ await onRemove(card);
571
+ } finally {
572
+ setIsRemoving(false);
573
+ }
566
574
  };
567
575
  return /* @__PURE__ */ jsxs(
568
- "button",
576
+ "div",
569
577
  {
570
- type: "button",
571
- onClick: handleSelect,
578
+ role: "button",
579
+ tabIndex: 0,
580
+ onClick: () => onSelect(card),
581
+ onKeyDown: (e) => (e.key === "Enter" || e.key === " ") && onSelect(card),
572
582
  className: cn(
573
- "flex h-12 w-full overflow-hidden rounded-md border-2 border-(--b-inverse) bg-(--s-primary) hover:bg-(--s-primary-hover)",
574
- {
575
- "border-(--b-brand)": isSelected
576
- }
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 }
577
585
  ),
578
586
  children: [
579
587
  /* @__PURE__ */ jsx(
@@ -599,13 +607,12 @@ var CardListItem = ({ card, isSelected, onSelect }) => {
599
607
  /* @__PURE__ */ jsx("span", { className: "text-(--brand-primary)", children: card.lastFourNumbers })
600
608
  ] }),
601
609
  /* @__PURE__ */ jsx(
602
- "div",
610
+ "button",
603
611
  {
604
- onClick: handleRemoveCard,
605
- className: cn("rounded-md p-1 text-(--tertiary) transition-all hover:bg-(--s-secondary)", {
606
- "cursor-not-allowed opacity-50": isSelected || isRemoveDisabled
607
- // 'cursor-pointer': !isSelected || !isRemoveDisabled,
608
- }),
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",
609
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" }) })
610
617
  }
611
618
  )
@@ -618,16 +625,31 @@ var CardListItem = ({ card, isSelected, onSelect }) => {
618
625
  );
619
626
  };
620
627
  var CardsList = ({ selectedCard, setCard }) => {
621
- 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
+ };
622
635
  if (cardsIsLoading) {
623
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)" }) });
624
637
  }
625
638
  if (cards.length === 0) return null;
626
- 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
+ )) });
627
649
  };
628
650
 
629
651
  // src/components/CreditCardTab/CreditCard/CreditCardForm.tsx
630
- import { useCallback, useEffect, useId, useRef, useState } from "react";
652
+ import { useCallback, useEffect, useId, useRef, useState as useState2 } from "react";
631
653
  import { CardCvcElement, CardExpiryElement, CardNumberElement, useElements, useStripe } from "@stripe/react-stripe-js";
632
654
 
633
655
  // src/ui/button.tsx
@@ -706,8 +728,9 @@ var stripeElementClasses = {
706
728
  focus: "border-ring ring-ring/50 ring-2"
707
729
  };
708
730
  var CreditCardForm = ({ cancel, saveCard }) => {
709
- const [cardError, setCardError] = useState(void 0);
710
- const [stripeStyles, setStripeStyles] = useState({});
731
+ const [cardError, setCardError] = useState2(void 0);
732
+ const [stripeStyles, setStripeStyles] = useState2({});
733
+ const [shouldSaveCard, setShouldSaveCard] = useState2(true);
711
734
  const formRef = useRef(null);
712
735
  const elements = useElements();
713
736
  const stripe = useStripe();
@@ -761,7 +784,8 @@ var CreditCardForm = ({ cancel, saveCard }) => {
761
784
  schema: token.card?.brand,
762
785
  lastFourNumbers: token.card?.last4 ?? "",
763
786
  expireMonth: `${token.card?.exp_month}`,
764
- expireYear: `${token.card?.exp_year}`
787
+ expireYear: `${token.card?.exp_year}`,
788
+ saveCard: shouldSaveCard
765
789
  });
766
790
  }
767
791
  }
@@ -807,7 +831,7 @@ var CreditCardForm = ({ cancel, saveCard }) => {
807
831
  cardError && /* @__PURE__ */ jsx4("p", { className: "text-destructive mt-1 text-sm", children: cardError })
808
832
  ] }),
809
833
  /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
810
- /* @__PURE__ */ jsx4(Checkbox, { disabled: true, checked: true, id: "saveCard" }),
834
+ /* @__PURE__ */ jsx4(Checkbox, { checked: shouldSaveCard, onCheckedChange: (v) => setShouldSaveCard(v === true), id: "saveCard" }),
811
835
  /* @__PURE__ */ jsx4(Label, { className: "text-sm font-medium", htmlFor: "saveCard", children: "Save card for future purchases" })
812
836
  ] }),
813
837
  /* @__PURE__ */ jsxs2("div", { className: "flex w-full justify-end gap-2", children: [
@@ -834,17 +858,22 @@ var CreditCardForm = ({ cancel, saveCard }) => {
834
858
 
835
859
  // src/components/CreditCardTab/CreditCard/CreditCard.tsx
836
860
  import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
837
- var StripeWrapper = (props) => {
838
- const stripePromise = useMemo(() => loadStripe(props.publicKey), [props.publicKey]);
839
- 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 }) });
840
864
  };
841
865
  var CreditCard = () => {
842
- const [showForm, setShowForm] = useState2(false);
866
+ const [showForm, setShowForm] = useState3(false);
843
867
  const { selectedPaymentMethod, setSelectedPaymentMethod } = useSpreePaymentMethod();
844
868
  const { mutateCards } = useCards();
845
869
  const { spreePayConfig } = useSpreePayConfig();
846
870
  const setCard = (card) => {
847
- 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
+ });
848
877
  };
849
878
  const saveNewCard = (newCard) => {
850
879
  mutateCards((data) => ({ ...data, data: [...data?.data ?? [], newCard] }), { revalidate: false });
@@ -880,14 +909,14 @@ var CreditCard = () => {
880
909
  };
881
910
 
882
911
  // src/components/CreditCardTab/Points/Points.tsx
883
- import { useState as useState8 } from "react";
912
+ import { useState as useState9 } from "react";
884
913
 
885
914
  // src/components/CreditCardTab/Points/SplitBlock.tsx
886
- 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";
887
916
  import { BUILD_ENV as BUILD_ENV2 } from "@mocanetwork/airkit";
888
917
 
889
918
  // src/components/CreditCardTab/Points/PointsSelector.tsx
890
- import { useState as useState6 } from "react";
919
+ import { useState as useState7 } from "react";
891
920
 
892
921
  // src/ui/input.tsx
893
922
  import { jsx as jsx6 } from "react/jsx-runtime";
@@ -1880,7 +1909,7 @@ var PointsSelector = (props) => {
1880
1909
  const maxByAmount = pointsConversionRatio && pointsConversionRatio > 0 ? (amount ?? 0) / pointsConversionRatio : 0;
1881
1910
  const max = Math.min(maxByAmount, balance?.availablePoints ?? 0);
1882
1911
  const step = 10;
1883
- const [splitTokens, setSplitTokens] = useState6(0);
1912
+ const [splitTokens, setSplitTokens] = useState7(0);
1884
1913
  const usdAmount = getSplitAmount(amount ?? 0, splitTokens, pointsConversionRatio);
1885
1914
  const pointsValue = String(Math.round(splitTokens));
1886
1915
  const usdWithFee = usdAmount + getTransactionFee(usdAmount, transactionFeePercentage);
@@ -1978,8 +2007,8 @@ var SplitBlock = (props) => {
1978
2007
  const { spreePayConfig } = useSpreePayConfig();
1979
2008
  const { appProps } = useStaticConfig();
1980
2009
  const { currencyCode, exchangeRate, foreignCurrencyAmount } = appProps;
1981
- const [address, setAddress] = useState7(null);
1982
- const [walletReady, setWalletReady] = useState7(false);
2010
+ const [address, setAddress] = useState8(null);
2011
+ const [walletReady, setWalletReady] = useState8(false);
1983
2012
  const { pointsConversionRatio, pointsTitle } = spreePayConfig || {};
1984
2013
  const { useWeb3Points, environment } = useSpreePayEnv();
1985
2014
  const hasForeignCurrency = !!(currencyCode && exchangeRate && foreignCurrencyAmount);
@@ -2038,8 +2067,8 @@ var SplitBlock = (props) => {
2038
2067
  // src/components/CreditCardTab/Points/Points.tsx
2039
2068
  import { Fragment as Fragment3, jsx as jsx15, jsxs as jsxs8 } from "react/jsx-runtime";
2040
2069
  var Points = () => {
2041
- const [usePoints, setUsePoints] = useState8(false);
2042
- const [selectedPointsType, setSelectedPointsType] = useState8(null);
2070
+ const [usePoints, setUsePoints] = useState9(false);
2071
+ const [selectedPointsType, setSelectedPointsType] = useState9(null);
2043
2072
  const { setSelectedPaymentMethod, selectedPaymentMethod } = useSpreePaymentMethod();
2044
2073
  const { spreePayConfig } = useSpreePayConfig();
2045
2074
  const { appProps } = useStaticConfig();
@@ -2206,9 +2235,9 @@ var TabButtons = (props) => {
2206
2235
 
2207
2236
  // src/SpreePayContent.tsx
2208
2237
  import { jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
2209
- var CryptoTab = lazy(() => import("./CryptoTab-ZABUPHVT.js").then((module) => ({ default: module.CryptoTab })));
2238
+ var CryptoTab = lazy(() => import("./CryptoTab-RY2NTNZJ.js").then((module) => ({ default: module.CryptoTab })));
2210
2239
  var CryptoComTab = lazy(
2211
- () => import("./CryptoComTab-PW3NRWJL.js").then((module) => ({ default: module.CryptoComTab }))
2240
+ () => import("./CryptoComTab-GNJ4XACU.js").then((module) => ({ default: module.CryptoComTab }))
2212
2241
  );
2213
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: [
2214
2243
  /* @__PURE__ */ jsx18("div", { className: "h-8 w-8 animate-spin rounded-full border-4 border-(--border-component-specific-card) border-t-(--brand-primary)" }),
@@ -2278,7 +2307,7 @@ var ErrorBoundary = class extends Component {
2278
2307
  };
2279
2308
 
2280
2309
  // src/hooks/useKeycloakSSO.ts
2281
- 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";
2282
2311
  import Keycloak from "keycloak-js";
2283
2312
  var refreshAheadSeconds = 60;
2284
2313
  var keycloakLogger = logger.child("keycloak");
@@ -2289,9 +2318,9 @@ function useKeycloakSSO(config) {
2289
2318
  const refreshTimerRef = useRef7(null);
2290
2319
  const scheduleRefreshRef = useRef7(() => {
2291
2320
  });
2292
- const [error, setError] = useState9(null);
2293
- const [isChecking, setIsChecking] = useState9(enabled);
2294
- const [accessToken, setAccessToken] = useState9(null);
2321
+ const [error, setError] = useState10(null);
2322
+ const [isChecking, setIsChecking] = useState10(enabled);
2323
+ const [accessToken, setAccessToken] = useState10(null);
2295
2324
  const scheduleRefresh = useCallback6(() => {
2296
2325
  const kc = kcRef.current;
2297
2326
  if (!kc || !kc.tokenParsed || !kc.tokenParsed.exp) {
@@ -2355,7 +2384,7 @@ function useKeycloakSSO(config) {
2355
2384
  // src/SpreePay.tsx
2356
2385
  import { jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
2357
2386
  var SpreePayInner = () => {
2358
- const [portalEl, setPortalEl] = useState10(null);
2387
+ const [portalEl, setPortalEl] = useState11(null);
2359
2388
  const rootRef = useCallback7((node) => {
2360
2389
  if (!node) return;
2361
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.1",
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": [