@superlogic/spree-pay 0.4.1 → 0.4.6

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/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
  }
@@ -698,6 +695,9 @@
698
695
  background-color: color-mix(in oklab, var(--s-warning) 10%, transparent);
699
696
  }
700
697
  }
698
+ .sl-spreepay .bg-\(--s-warning-subtle\) {
699
+ background-color: var(--s-warning-subtle);
700
+ }
701
701
  .sl-spreepay .bg-\(--secondary\) {
702
702
  background-color: var(--secondary);
703
703
  }
@@ -903,15 +903,15 @@
903
903
  .sl-spreepay .text-current {
904
904
  color: currentcolor;
905
905
  }
906
+ .sl-spreepay .text-tertiary {
907
+ color: var(--tertiary);
908
+ }
906
909
  .sl-spreepay .underline {
907
910
  text-decoration-line: underline;
908
911
  }
909
912
  .sl-spreepay .underline-offset-4 {
910
913
  text-underline-offset: 4px;
911
914
  }
912
- .sl-spreepay .opacity-50 {
913
- opacity: 50%;
914
- }
915
915
  .sl-spreepay .opacity-70 {
916
916
  opacity: 70%;
917
917
  }
@@ -1411,14 +1411,9 @@
1411
1411
  translate: var(--tw-translate-x) var(--tw-translate-y);
1412
1412
  }
1413
1413
  }
1414
- .sl-spreepay .data-\[state\=checked\]\:border-\(--primary\) {
1415
- &[data-state=checked] {
1416
- border-color: var(--primary);
1417
- }
1418
- }
1419
- .sl-spreepay .data-\[state\=checked\]\:bg-\(--primary\) {
1414
+ .sl-spreepay .data-\[state\=checked\]\:border-\(--s-brand\) {
1420
1415
  &[data-state=checked] {
1421
- background-color: var(--primary);
1416
+ border-color: var(--s-brand);
1422
1417
  }
1423
1418
  }
1424
1419
  .sl-spreepay .data-\[state\=checked\]\:bg-\(--s-brand\) {
@@ -1595,13 +1590,6 @@
1595
1590
  }
1596
1591
  }
1597
1592
  }
1598
- .sl-spreepay .dark\:data-\[state\=checked\]\:bg-\(--primary\) {
1599
- &:is(.dark *) {
1600
- &[data-state=checked] {
1601
- background-color: var(--primary);
1602
- }
1603
- }
1604
- }
1605
1593
  .sl-spreepay .\[\&_a\]\:underline {
1606
1594
  & a {
1607
1595
  text-decoration-line: underline;
@@ -1796,4 +1784,4 @@
1796
1784
  }
1797
1785
  }
1798
1786
  }
1799
- /*! tailwindcss v4.1.17 | MIT License | https://tailwindcss.com */
1787
+ /*! 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-FKAVWVFL.js";
12
12
  import {
13
13
  Iframe3ds
14
- } from "./chunk-IDYBXJWP.js";
14
+ } from "./chunk-7I6EBCSI.js";
15
15
  import {
16
16
  InfoBanner,
17
17
  LogLevel,
@@ -23,6 +23,7 @@ import {
23
23
  StaticConfigProvider,
24
24
  cn,
25
25
  configureLogger,
26
+ isNewCard,
26
27
  logger,
27
28
  registerApi,
28
29
  useSpreePay,
@@ -31,10 +32,10 @@ import {
31
32
  useSpreePayRegister,
32
33
  useSpreePaymentMethod,
33
34
  useStaticConfig
34
- } from "./chunk-5GHGAP6Z.js";
35
+ } from "./chunk-AGTOSFMT.js";
35
36
 
36
37
  // src/SpreePay.tsx
37
- import { useCallback as useCallback7, useEffect as useEffect8, useMemo as useMemo7, useState as useState10 } from "react";
38
+ import { useCallback as useCallback8, useEffect as useEffect8, useMemo as useMemo9, useState as useState11 } from "react";
38
39
  import NiceModal4 from "@ebay/nice-modal-react";
39
40
  import { SWRConfig } from "swr";
40
41
 
@@ -42,7 +43,7 @@ import { SWRConfig } from "swr";
42
43
  import { Suspense, lazy } from "react";
43
44
 
44
45
  // src/components/CreditCardTab/CreditCardTab.tsx
45
- import { useCallback as useCallback5, useEffect as useEffect6 } from "react";
46
+ import { useCallback as useCallback6, useEffect as useEffect6 } from "react";
46
47
 
47
48
  // src/hooks/payments/useCardPayment.ts
48
49
  import NiceModal from "@ebay/nice-modal-react";
@@ -73,7 +74,11 @@ var useCardPayment = () => {
73
74
  lastFour: card.lastFourNumbers,
74
75
  schema: card.schema
75
76
  });
76
- const { data: cardResData } = await SlapiPaymentService.addCard({ hash, source: card.token });
77
+ const { data: cardResData } = await SlapiPaymentService.addCard({
78
+ hash,
79
+ source: card.token,
80
+ saveCard: card.saveCard
81
+ });
77
82
  cardId = cardResData.id;
78
83
  cardPaymentLogger.info("New card added successfully", { cardId });
79
84
  } else {
@@ -536,44 +541,50 @@ var useSplitCardPayments = (mode = "web2") => {
536
541
  };
537
542
 
538
543
  // src/hooks/useCards.ts
544
+ import { useMemo } from "react";
539
545
  import useSWR from "swr";
540
546
  var URL = "/v1/payments/cards";
541
547
  var useCards = () => {
542
548
  const { origin } = useSpreePayEnv();
543
549
  const { data, isLoading, mutate } = useSWR(origin ? `${URL}?origin=${origin}` : URL);
550
+ const cards = useMemo(() => data?.data.filter((c) => c.active) ?? [], [data]);
544
551
  return {
545
- cards: data?.data.filter((c) => c.active) || [],
552
+ cards,
546
553
  cardsIsLoading: isLoading,
547
554
  mutateCards: mutate
548
555
  };
549
556
  };
550
557
 
551
558
  // src/components/CreditCardTab/CreditCard/CreditCard.tsx
552
- import { useMemo, useState as useState2 } from "react";
559
+ import { useCallback as useCallback2, useMemo as useMemo3, useState as useState3 } from "react";
553
560
  import { Elements } from "@stripe/react-stripe-js";
554
561
  import { loadStripe } from "@stripe/stripe-js";
555
562
 
556
563
  // src/components/CreditCardTab/CreditCard/CardsList.tsx
564
+ import { useMemo as useMemo2, useState } from "react";
557
565
  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) => {
566
+ var CardListItem = ({ card, isSelected, onSelect, onRemove }) => {
567
+ const [isRemoving, setIsRemoving] = useState(false);
568
+ const removeDisabled = isSelected || isRemoving;
569
+ const handleRemove = async (e) => {
564
570
  e.stopPropagation();
565
- if (isSelected || isRemoveDisabled) return;
571
+ setIsRemoving(true);
572
+ try {
573
+ await onRemove(card);
574
+ } finally {
575
+ setIsRemoving(false);
576
+ }
566
577
  };
567
578
  return /* @__PURE__ */ jsxs(
568
- "button",
579
+ "div",
569
580
  {
570
- type: "button",
571
- onClick: handleSelect,
581
+ role: "button",
582
+ tabIndex: 0,
583
+ onClick: () => onSelect(card),
584
+ onKeyDown: (e) => (e.key === "Enter" || e.key === " ") && onSelect(card),
572
585
  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
- }
586
+ "flex h-12 w-full cursor-pointer overflow-hidden rounded-md border-2 border-(--b-inverse) bg-(--s-primary) hover:bg-(--s-primary-hover)",
587
+ { "border-(--b-brand)": isSelected }
577
588
  ),
578
589
  children: [
579
590
  /* @__PURE__ */ jsx(
@@ -599,13 +610,12 @@ var CardListItem = ({ card, isSelected, onSelect }) => {
599
610
  /* @__PURE__ */ jsx("span", { className: "text-(--brand-primary)", children: card.lastFourNumbers })
600
611
  ] }),
601
612
  /* @__PURE__ */ jsx(
602
- "div",
613
+ "button",
603
614
  {
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
- }),
615
+ type: "button",
616
+ onClick: handleRemove,
617
+ disabled: removeDisabled,
618
+ className: "text-tertiary rounded-md p-1 transition-all hover:bg-(--s-secondary) disabled:cursor-not-allowed disabled:opacity-50",
609
619
  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
620
  }
611
621
  )
@@ -617,17 +627,35 @@ var CardListItem = ({ card, isSelected, onSelect }) => {
617
627
  }
618
628
  );
619
629
  };
620
- var CardsList = ({ selectedCard, setCard }) => {
621
- const { cards, cardsIsLoading } = useCards();
630
+ var CardsList = ({ selectedCard, setCard, newCards, onRemoveNewCard }) => {
631
+ const { cards, cardsIsLoading, mutateCards } = useCards();
632
+ const allCards = useMemo2(() => [...cards, ...newCards], [cards, newCards]);
633
+ const handleRemove = async (card) => {
634
+ if (isNewCard(card)) {
635
+ onRemoveNewCard(card);
636
+ } else {
637
+ await SlapiPaymentService.removeCard({ cardId: card.id });
638
+ mutateCards((data) => ({ ...data, data: (data?.data ?? []).filter((c) => c.id !== card.id) }));
639
+ }
640
+ };
622
641
  if (cardsIsLoading) {
623
642
  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
643
  }
625
- 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)) });
644
+ if (allCards.length === 0) return null;
645
+ return /* @__PURE__ */ jsx("div", { className: "flex w-full flex-col gap-4", children: allCards.map((card) => /* @__PURE__ */ jsx(
646
+ CardListItem,
647
+ {
648
+ isSelected: selectedCard?.id === card.id,
649
+ onSelect: setCard,
650
+ onRemove: handleRemove,
651
+ card
652
+ },
653
+ card.id
654
+ )) });
627
655
  };
628
656
 
629
657
  // src/components/CreditCardTab/CreditCard/CreditCardForm.tsx
630
- import { useCallback, useEffect, useId, useRef, useState } from "react";
658
+ import { useCallback, useEffect, useRef, useState as useState2 } from "react";
631
659
  import { CardCvcElement, CardExpiryElement, CardNumberElement, useElements, useStripe } from "@stripe/react-stripe-js";
632
660
 
633
661
  // src/ui/button.tsx
@@ -681,7 +709,7 @@ function Checkbox({ className, ...props }) {
681
709
  {
682
710
  "data-slot": "checkbox",
683
711
  className: cn(
684
- "peer border-input dark:bg-input/30 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-sm border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:border-(--primary) data-[state=checked]:bg-(--primary) data-[state=checked]:text-(--inverse) dark:data-[state=checked]:bg-(--primary)",
712
+ "peer border-input dark:bg-input/30 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-sm border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:border-(--s-brand) data-[state=checked]:bg-(--s-brand) data-[state=checked]:text-(--inverse)",
685
713
  className
686
714
  ),
687
715
  ...props,
@@ -706,12 +734,13 @@ var stripeElementClasses = {
706
734
  focus: "border-ring ring-ring/50 ring-2"
707
735
  };
708
736
  var CreditCardForm = ({ cancel, saveCard }) => {
709
- const [cardError, setCardError] = useState(void 0);
710
- const [stripeStyles, setStripeStyles] = useState({});
737
+ const [cardError, setCardError] = useState2(void 0);
738
+ const [stripeStyles, setStripeStyles] = useState2({});
739
+ const [shouldSaveCard, setShouldSaveCard] = useState2(true);
711
740
  const formRef = useRef(null);
712
741
  const elements = useElements();
713
742
  const stripe = useStripe();
714
- const id = useId();
743
+ const [id] = useState2(() => crypto.randomUUID());
715
744
  const computeStripeStyles = useCallback(() => {
716
745
  const formRefCurrent = formRef.current;
717
746
  if (typeof window === "undefined" || !formRefCurrent) return {};
@@ -761,7 +790,8 @@ var CreditCardForm = ({ cancel, saveCard }) => {
761
790
  schema: token.card?.brand,
762
791
  lastFourNumbers: token.card?.last4 ?? "",
763
792
  expireMonth: `${token.card?.exp_month}`,
764
- expireYear: `${token.card?.exp_year}`
793
+ expireYear: `${token.card?.exp_year}`,
794
+ saveCard: shouldSaveCard
765
795
  });
766
796
  }
767
797
  }
@@ -807,7 +837,7 @@ var CreditCardForm = ({ cancel, saveCard }) => {
807
837
  cardError && /* @__PURE__ */ jsx4("p", { className: "text-destructive mt-1 text-sm", children: cardError })
808
838
  ] }),
809
839
  /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
810
- /* @__PURE__ */ jsx4(Checkbox, { disabled: true, checked: true, id: "saveCard" }),
840
+ /* @__PURE__ */ jsx4(Checkbox, { checked: shouldSaveCard, onCheckedChange: (v) => setShouldSaveCard(v === true), id: "saveCard" }),
811
841
  /* @__PURE__ */ jsx4(Label, { className: "text-sm font-medium", htmlFor: "saveCard", children: "Save card for future purchases" })
812
842
  ] }),
813
843
  /* @__PURE__ */ jsxs2("div", { className: "flex w-full justify-end gap-2", children: [
@@ -834,23 +864,31 @@ var CreditCardForm = ({ cancel, saveCard }) => {
834
864
 
835
865
  // src/components/CreditCardTab/CreditCard/CreditCard.tsx
836
866
  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 }) });
867
+ var StripeWrapper = ({ onCancel, saveNewCard, publicKey }) => {
868
+ const stripePromise = useMemo3(() => loadStripe(publicKey), [publicKey]);
869
+ return /* @__PURE__ */ jsx5(Elements, { stripe: stripePromise, children: /* @__PURE__ */ jsx5(CreditCardForm, { cancel: onCancel, saveCard: saveNewCard }) });
840
870
  };
841
871
  var CreditCard = () => {
842
- const [showForm, setShowForm] = useState2(false);
872
+ const [showForm, setShowForm] = useState3(false);
873
+ const [newCards, setNewCards] = useState3([]);
843
874
  const { selectedPaymentMethod, setSelectedPaymentMethod } = useSpreePaymentMethod();
844
- const { mutateCards } = useCards();
845
875
  const { spreePayConfig } = useSpreePayConfig();
846
876
  const setCard = (card) => {
847
- setSelectedPaymentMethod({ ...selectedPaymentMethod, type: "CREDIT_CARD" /* CREDIT_CARD */, method: card });
877
+ const isAlreadySelected = selectedPaymentMethod?.type === "CREDIT_CARD" /* CREDIT_CARD */ && selectedPaymentMethod.method?.id === card.id;
878
+ setSelectedPaymentMethod({
879
+ ...selectedPaymentMethod,
880
+ type: "CREDIT_CARD" /* CREDIT_CARD */,
881
+ method: isAlreadySelected ? null : card
882
+ });
848
883
  };
849
884
  const saveNewCard = (newCard) => {
850
- mutateCards((data) => ({ ...data, data: [...data?.data ?? [], newCard] }), { revalidate: false });
885
+ setNewCards((prev) => [...prev, newCard]);
851
886
  setCard(newCard);
852
887
  setShowForm(false);
853
888
  };
889
+ const removeNewCard = useCallback2((card) => {
890
+ setNewCards((prev) => prev.filter((c) => c.id !== card.id));
891
+ }, []);
854
892
  const handleCancel = () => {
855
893
  setShowForm(false);
856
894
  };
@@ -861,7 +899,9 @@ var CreditCard = () => {
861
899
  CardsList,
862
900
  {
863
901
  selectedCard: selectedPaymentMethod?.type === "CREDIT_CARD" /* CREDIT_CARD */ ? selectedPaymentMethod.method : null,
864
- setCard
902
+ setCard,
903
+ newCards,
904
+ onRemoveNewCard: removeNewCard
865
905
  }
866
906
  ),
867
907
  spreePayConfig?.creditCard.infoMessage && /* @__PURE__ */ jsx5(InfoBanner, { message: spreePayConfig.creditCard.infoMessage }),
@@ -880,14 +920,14 @@ var CreditCard = () => {
880
920
  };
881
921
 
882
922
  // src/components/CreditCardTab/Points/Points.tsx
883
- import { useState as useState8 } from "react";
923
+ import { useState as useState9 } from "react";
884
924
 
885
925
  // src/components/CreditCardTab/Points/SplitBlock.tsx
886
- import { useCallback as useCallback4, useEffect as useEffect5, useRef as useRef6, useState as useState7 } from "react";
926
+ import { useCallback as useCallback5, useEffect as useEffect5, useRef as useRef6, useState as useState8 } from "react";
887
927
  import { BUILD_ENV as BUILD_ENV2 } from "@mocanetwork/airkit";
888
928
 
889
929
  // src/components/CreditCardTab/Points/PointsSelector.tsx
890
- import { useState as useState6 } from "react";
930
+ import { useState as useState7 } from "react";
891
931
 
892
932
  // src/ui/input.tsx
893
933
  import { jsx as jsx6 } from "react/jsx-runtime";
@@ -1880,7 +1920,7 @@ var PointsSelector = (props) => {
1880
1920
  const maxByAmount = pointsConversionRatio && pointsConversionRatio > 0 ? (amount ?? 0) / pointsConversionRatio : 0;
1881
1921
  const max = Math.min(maxByAmount, balance?.availablePoints ?? 0);
1882
1922
  const step = 10;
1883
- const [splitTokens, setSplitTokens] = useState6(0);
1923
+ const [splitTokens, setSplitTokens] = useState7(0);
1884
1924
  const usdAmount = getSplitAmount(amount ?? 0, splitTokens, pointsConversionRatio);
1885
1925
  const pointsValue = String(Math.round(splitTokens));
1886
1926
  const usdWithFee = usdAmount + getTransactionFee(usdAmount, transactionFeePercentage);
@@ -1978,14 +2018,14 @@ var SplitBlock = (props) => {
1978
2018
  const { spreePayConfig } = useSpreePayConfig();
1979
2019
  const { appProps } = useStaticConfig();
1980
2020
  const { currencyCode, exchangeRate, foreignCurrencyAmount } = appProps;
1981
- const [address, setAddress] = useState7(null);
1982
- const [walletReady, setWalletReady] = useState7(false);
2021
+ const [address, setAddress] = useState8(null);
2022
+ const [walletReady, setWalletReady] = useState8(false);
1983
2023
  const { pointsConversionRatio, pointsTitle } = spreePayConfig || {};
1984
2024
  const { useWeb3Points, environment } = useSpreePayEnv();
1985
2025
  const hasForeignCurrency = !!(currencyCode && exchangeRate && foreignCurrencyAmount);
1986
2026
  const formatPointsValue = (usd) => hasForeignCurrency ? formatCurrency(usd / exchangeRate, currencyCode) : formatCurrency(usd);
1987
2027
  const prevPointsChainRef = useRef6(spreePayConfig?.pointsChain);
1988
- const initWallet = useCallback4(
2028
+ const initWallet = useCallback5(
1989
2029
  async (pointsChain) => {
1990
2030
  if (!pointsChain) return;
1991
2031
  try {
@@ -2038,8 +2078,8 @@ var SplitBlock = (props) => {
2038
2078
  // src/components/CreditCardTab/Points/Points.tsx
2039
2079
  import { Fragment as Fragment3, jsx as jsx15, jsxs as jsxs8 } from "react/jsx-runtime";
2040
2080
  var Points = () => {
2041
- const [usePoints, setUsePoints] = useState8(false);
2042
- const [selectedPointsType, setSelectedPointsType] = useState8(null);
2081
+ const [usePoints, setUsePoints] = useState9(false);
2082
+ const [selectedPointsType, setSelectedPointsType] = useState9(null);
2043
2083
  const { setSelectedPaymentMethod, selectedPaymentMethod } = useSpreePaymentMethod();
2044
2084
  const { spreePayConfig } = useSpreePayConfig();
2045
2085
  const { appProps } = useStaticConfig();
@@ -2085,7 +2125,7 @@ var CreditCardTab = ({ isLoggedIn }) => {
2085
2125
  const { cardPayment } = useCardPayment();
2086
2126
  const { splitPayment } = useSplitCardPayments(isWeb3Enabled ? "web3" : "web2");
2087
2127
  const { pointsPayment } = usePointsPayment(isWeb3Enabled ? "web3" : "web2");
2088
- const handlePay = useCallback5(
2128
+ const handlePay = useCallback6(
2089
2129
  async (data) => {
2090
2130
  try {
2091
2131
  let res = null;
@@ -2206,9 +2246,9 @@ var TabButtons = (props) => {
2206
2246
 
2207
2247
  // src/SpreePayContent.tsx
2208
2248
  import { jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
2209
- var CryptoTab = lazy(() => import("./CryptoTab-ZABUPHVT.js").then((module) => ({ default: module.CryptoTab })));
2249
+ var CryptoTab = lazy(() => import("./CryptoTab-7EG23TQW.js").then((module) => ({ default: module.CryptoTab })));
2210
2250
  var CryptoComTab = lazy(
2211
- () => import("./CryptoComTab-PW3NRWJL.js").then((module) => ({ default: module.CryptoComTab }))
2251
+ () => import("./CryptoComTab-5662XFNI.js").then((module) => ({ default: module.CryptoComTab }))
2212
2252
  );
2213
2253
  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
2254
  /* @__PURE__ */ jsx18("div", { className: "h-8 w-8 animate-spin rounded-full border-4 border-(--border-component-specific-card) border-t-(--brand-primary)" }),
@@ -2250,8 +2290,8 @@ var ErrorBoundary = class extends Component {
2250
2290
  if (this.props.fallback) {
2251
2291
  return this.props.fallback;
2252
2292
  }
2253
- return /* @__PURE__ */ jsxs12("div", { className: "flex w-full flex-col items-center justify-center rounded-3xl border border-(--b-inverse) bg-(--s-primary) p-8", children: [
2254
- /* @__PURE__ */ jsx19("div", { className: "mb-4 flex size-12 items-center justify-center rounded-full bg-(--s-secondary)", children: /* @__PURE__ */ jsxs12(
2293
+ return /* @__PURE__ */ jsx19("div", { className: cn("sl-spreepay", this.props.className), children: /* @__PURE__ */ jsxs12("div", { className: "flex w-full flex-col items-center justify-center rounded-3xl border border-(--border-component-specific-card) bg-(--surface-component-specific-card-default-card) p-8 shadow-[0_6.25px_25px_0_var(--shadow-component-specific-card)]", children: [
2294
+ /* @__PURE__ */ jsx19("div", { className: "mb-4 flex size-12 items-center justify-center rounded-full bg-(--s-warning-subtle)", children: /* @__PURE__ */ jsxs12(
2255
2295
  "svg",
2256
2296
  {
2257
2297
  xmlns: "http://www.w3.org/2000/svg",
@@ -2269,16 +2309,16 @@ var ErrorBoundary = class extends Component {
2269
2309
  ]
2270
2310
  }
2271
2311
  ) }),
2272
- /* @__PURE__ */ jsx19("h3", { className: "mb-2 text-lg font-semibold text-(--primary)", children: "Payment Widget Error" }),
2273
- /* @__PURE__ */ jsx19("p", { className: "text-center text-sm text-(--secondary)", children: "Something went wrong loading the payment widget. Please refresh the page and try again." })
2274
- ] });
2312
+ /* @__PURE__ */ jsx19("h3", { className: "mb-2 text-lg font-semibold text-(--brand-primary)", children: "Payment Widget Error" }),
2313
+ /* @__PURE__ */ jsx19("p", { className: "text-center text-sm text-(--text-tertiary)", children: "Something went wrong loading the payment widget. Please refresh the page and try again." })
2314
+ ] }) });
2275
2315
  }
2276
2316
  return this.props.children;
2277
2317
  }
2278
2318
  };
2279
2319
 
2280
2320
  // src/hooks/useKeycloakSSO.ts
2281
- import { useCallback as useCallback6, useEffect as useEffect7, useRef as useRef7, useState as useState9 } from "react";
2321
+ import { useCallback as useCallback7, useEffect as useEffect7, useRef as useRef7, useState as useState10 } from "react";
2282
2322
  import Keycloak from "keycloak-js";
2283
2323
  var refreshAheadSeconds = 60;
2284
2324
  var keycloakLogger = logger.child("keycloak");
@@ -2289,10 +2329,10 @@ function useKeycloakSSO(config) {
2289
2329
  const refreshTimerRef = useRef7(null);
2290
2330
  const scheduleRefreshRef = useRef7(() => {
2291
2331
  });
2292
- const [error, setError] = useState9(null);
2293
- const [isChecking, setIsChecking] = useState9(enabled);
2294
- const [accessToken, setAccessToken] = useState9(null);
2295
- const scheduleRefresh = useCallback6(() => {
2332
+ const [error, setError] = useState10(null);
2333
+ const [isChecking, setIsChecking] = useState10(enabled);
2334
+ const [accessToken, setAccessToken] = useState10(null);
2335
+ const scheduleRefresh = useCallback7(() => {
2296
2336
  const kc = kcRef.current;
2297
2337
  if (!kc || !kc.tokenParsed || !kc.tokenParsed.exp) {
2298
2338
  return;
@@ -2352,11 +2392,22 @@ function useKeycloakSSO(config) {
2352
2392
  return { isChecking, accessToken, error };
2353
2393
  }
2354
2394
 
2395
+ // src/utils/token.ts
2396
+ import { jwtDecode } from "jwt-decode";
2397
+ var isTokenExpired = (token) => {
2398
+ try {
2399
+ const { exp } = jwtDecode(token);
2400
+ return typeof exp === "number" && exp < Math.floor(Date.now() / 1e3);
2401
+ } catch {
2402
+ return true;
2403
+ }
2404
+ };
2405
+
2355
2406
  // src/SpreePay.tsx
2356
2407
  import { jsx as jsx20, jsxs as jsxs13 } from "react/jsx-runtime";
2357
2408
  var SpreePayInner = () => {
2358
- const [portalEl, setPortalEl] = useState10(null);
2359
- const rootRef = useCallback7((node) => {
2409
+ const [portalEl, setPortalEl] = useState11(null);
2410
+ const rootRef = useCallback8((node) => {
2360
2411
  if (!node) return;
2361
2412
  const el = node.querySelector(":scope > .sl-spreepay__portal");
2362
2413
  setPortalEl(el ?? null);
@@ -2367,16 +2418,17 @@ var SpreePayInner = () => {
2367
2418
  logger.logVersion();
2368
2419
  }, [environment]);
2369
2420
  const { staticConfig, appProps } = useStaticConfig();
2421
+ const envTokenValid = Boolean(envAccessToken && !isTokenExpired(envAccessToken));
2370
2422
  const { isChecking, accessToken } = useKeycloakSSO({
2371
2423
  realm: tenantId,
2372
2424
  url: staticConfig.keycloakUrl,
2373
2425
  clientId: keycloakClientId ?? "oneof-next",
2374
2426
  ssoPageURI,
2375
- enabled: !envAccessToken
2427
+ enabled: !envTokenValid
2376
2428
  });
2377
- const _accessToken = envAccessToken ?? accessToken;
2378
- const unauthenticatedFetcher = useCallback7(() => Promise.resolve(null), []);
2379
- const slapiFetcher = useMemo7(() => {
2429
+ const _accessToken = envTokenValid ? envAccessToken : accessToken;
2430
+ const unauthenticatedFetcher = useCallback8(() => Promise.resolve(null), []);
2431
+ const slapiFetcher = useMemo9(() => {
2380
2432
  if (_accessToken) {
2381
2433
  return registerApi({
2382
2434
  accessToken: _accessToken,
@@ -2412,7 +2464,7 @@ var SpreePayInner = () => {
2412
2464
  ] });
2413
2465
  };
2414
2466
  var SpreePay = (props) => {
2415
- return /* @__PURE__ */ jsx20(ErrorBoundary, { children: /* @__PURE__ */ jsx20(StaticConfigProvider, { props, children: /* @__PURE__ */ jsx20(SpreePayInner, {}) }) });
2467
+ return /* @__PURE__ */ jsx20(ErrorBoundary, { className: props.className, children: /* @__PURE__ */ jsx20(StaticConfigProvider, { props, children: /* @__PURE__ */ jsx20(SpreePayInner, {}) }) });
2416
2468
  };
2417
2469
 
2418
2470
  // src/hooks/useCapture3DS.ts
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.6",
4
4
  "description": "Spree-pay React component and utilities",
5
5
  "private": false,
6
6
  "type": "module",
@@ -18,7 +18,8 @@
18
18
  "require": "./build/index.cjs",
19
19
  "default": "./build/index.js"
20
20
  },
21
- "./styles.css": "./build/index.css"
21
+ "./styles.css": "./build/index.css",
22
+ "./bridge.css": "./src/styles/bridge.css"
22
23
  },
23
24
  "files": [
24
25
  "build",
@@ -49,27 +50,28 @@
49
50
  "@rainbow-me/rainbowkit": "^2.2.9",
50
51
  "@stripe/react-stripe-js": "^3.10.0",
51
52
  "@stripe/stripe-js": "^7.9.0",
52
- "@tanstack/react-query": "^5.90.12",
53
+ "@tanstack/react-query": "^5.97.0",
53
54
  "class-variance-authority": "^0.7.0",
54
55
  "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",
56
+ "jwt-decode": "^4.0.0",
57
+ "keycloak-js": "^26.2.3",
58
+ "lucide-react": "^1.8.0",
59
+ "swr": "^2.4.1",
60
+ "tailwind-merge": "^3.5.0",
61
+ "viem": "^2.47.11",
60
62
  "wagmi": "^2.19.5",
61
63
  "xss": "^1.0.15"
62
64
  },
63
65
  "devDependencies": {
64
66
  "@repo/eslint-config": "^1.0.0",
65
- "@tailwindcss/postcss": "^4.1.17",
67
+ "@tailwindcss/postcss": "^4.2.2",
66
68
  "@types/react": "^19",
67
69
  "@types/react-dom": "^19",
68
70
  "postcss-prefix-selector": "^2.1.1",
69
- "tailwindcss": "^4.1.17",
71
+ "tailwindcss": "^4.2.2",
70
72
  "tsup": "^8.5.1",
71
73
  "tw-animate-css": "^1.4.0",
72
- "typescript": "^5.9.3"
74
+ "typescript": "^6.0.2"
73
75
  },
74
76
  "tsup": {
75
77
  "entry": [
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Spree-pay CSS variable bridge — live-tickets context only.
3
+ *
4
+ * Exposes legacy short-name CSS variables that spree-pay TSX components
5
+ * still reference, mapped to the current Figma token names. This file is
6
+ * imported by apps/live-tickets/src/theme/globals.css so the host app's
7
+ * tenant *.figma.css tokens are available under the old names.
8
+ *
9
+ * NOT used in standalone mode — the standalone build gets default values
10
+ * from packages/spree-pay/src/styles/globals.css instead.
11
+ */
12
+ :root {
13
+ /* text / icons */
14
+ --primary: var(--color-text-icons-primary-default);
15
+ --secondary: var(--color-text-icons-secondary-default);
16
+ --tertiary: var(--color-text-icons-tertiary-default);
17
+ --text-tertiary: var(--color-text-icons-tertiary-default); /* pre-existing alias bug */
18
+ --brand-primary: var(--color-text-icons-brand-default);
19
+ --accent: var(--color-text-icons-accent-default);
20
+ --inverse: var(--color-text-icons-inverse-default);
21
+ --disabled: var(--color-text-icons-primary-disabled);
22
+ --positive: var(--color-feedback-success);
23
+ --warning: var(--color-feedback-attention);
24
+ --negative: var(--color-feedback-error);
25
+
26
+ /* surface */
27
+ --s-default: var(--color-surface-layer-page);
28
+ --s-primary: var(--color-surface-container-subtle);
29
+ --s-primary-hover: var(--color-component-list-row-subtle-hover);
30
+ --s-secondary: var(--color-component-table-header);
31
+ --s-tertiary: var(--color-control-tertiary-bg-default);
32
+ --s-brand: var(--color-surface-container-brand);
33
+ --s-brand-hover: var(--color-control-primary-bg-hover);
34
+ --s-disabled: var(--color-component-bg-disabled);
35
+ --s-warning: var(--color-feedback-attention);
36
+
37
+ /* border */
38
+ --b-primary: var(--color-border-subtle);
39
+ --b-secondary: var(--color-border-default);
40
+ --b-tertiary: var(--color-component-divider-default);
41
+ --b-brand: var(--color-control-primary-border-default);
42
+ --b-inverse: var(--color-border-inverse);
43
+
44
+ /* overlay / component-specific */
45
+ --overlay: var(--color-surface-layer-backdrop);
46
+ --border-component-specific-card: var(--color-component-divider-subtle);
47
+ --surface-component-specific-card-default-card: var(--color-surface-layer-card);
48
+ --shadow-component-specific-card: var(--color-effect-shadow-card);
49
+
50
+ /* Crypto.com brand colors — same across all tenants */
51
+ --crypto-pay-bg: #00307d;
52
+ --crypto-pay-bg-hover: #002655;
53
+ }