@pollar/react 0.10.1-rc.2 → 0.10.1-rc.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1033,11 +1033,62 @@ var PollarModalFooter = () => {
1033
1033
  /* @__PURE__ */ jsx("span", { className: "pollar-footer-name", children: "Pollar" }),
1034
1034
  /* @__PURE__ */ jsxs("span", { className: "pollar-footer-version", children: [
1035
1035
  "v",
1036
- "0.10.1-rc.2"
1036
+ "0.10.1-rc.4"
1037
1037
  ] })
1038
1038
  ] })
1039
1039
  ] });
1040
1040
  };
1041
+ function CopyButton({ value, label = "Copy", className }) {
1042
+ const [copied, setCopied] = useState(false);
1043
+ const timerRef = useRef(null);
1044
+ useEffect(() => {
1045
+ return () => {
1046
+ if (timerRef.current !== null) clearTimeout(timerRef.current);
1047
+ };
1048
+ }, []);
1049
+ function handleCopy(e) {
1050
+ e.stopPropagation();
1051
+ if (!value || !navigator.clipboard) return;
1052
+ void navigator.clipboard.writeText(value).then(() => {
1053
+ setCopied(true);
1054
+ if (timerRef.current !== null) clearTimeout(timerRef.current);
1055
+ timerRef.current = setTimeout(() => {
1056
+ setCopied(false);
1057
+ timerRef.current = null;
1058
+ }, 1500);
1059
+ });
1060
+ }
1061
+ return /* @__PURE__ */ jsx(
1062
+ "button",
1063
+ {
1064
+ type: "button",
1065
+ className: `pollar-copy-btn${className ? ` ${className}` : ""}`,
1066
+ onClick: handleCopy,
1067
+ "aria-label": copied ? "Copied" : label,
1068
+ children: copied ? /* @__PURE__ */ jsx("svg", { width: "13", height: "13", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx(
1069
+ "path",
1070
+ {
1071
+ d: "M3.5 7l2.5 2.5 4.5-5",
1072
+ stroke: "currentColor",
1073
+ strokeWidth: "1.5",
1074
+ strokeLinecap: "round",
1075
+ strokeLinejoin: "round"
1076
+ }
1077
+ ) }) : /* @__PURE__ */ jsxs("svg", { width: "13", height: "13", viewBox: "0 0 13 13", fill: "none", "aria-hidden": true, children: [
1078
+ /* @__PURE__ */ jsx("rect", { x: "4", y: "4", width: "8", height: "8", rx: "1.5", stroke: "currentColor", strokeWidth: "1.5" }),
1079
+ /* @__PURE__ */ jsx(
1080
+ "path",
1081
+ {
1082
+ d: "M3 9H2a1 1 0 01-1-1V2a1 1 0 011-1h6a1 1 0 011 1v1",
1083
+ stroke: "currentColor",
1084
+ strokeWidth: "1.5",
1085
+ strokeLinecap: "round"
1086
+ }
1087
+ )
1088
+ ] })
1089
+ }
1090
+ );
1091
+ }
1041
1092
  function ModalStatusBanner({ message, status, onCancel, onRetry }) {
1042
1093
  if (!message && status === "NONE") {
1043
1094
  return /* @__PURE__ */ jsx("div", { className: "pollar-status" });
@@ -2504,8 +2555,8 @@ function RampWidgetTemplate({
2504
2555
  amount,
2505
2556
  currency,
2506
2557
  country,
2507
- email,
2508
- fullName,
2558
+ requiredFields,
2559
+ fieldValues,
2509
2560
  countries,
2510
2561
  countriesLoading,
2511
2562
  refreshing,
@@ -2521,8 +2572,7 @@ function RampWidgetTemplate({
2521
2572
  errorMsg,
2522
2573
  onDirectionChange,
2523
2574
  onAmountChange,
2524
- onEmailChange,
2525
- onFullNameChange,
2575
+ onFieldChange,
2526
2576
  onCountryChange,
2527
2577
  onFindRoute,
2528
2578
  onSelectQuote,
@@ -2673,33 +2723,19 @@ function RampWidgetTemplate({
2673
2723
  /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onClose, children: "Cancel" })
2674
2724
  ] }),
2675
2725
  step === "contact" && /* @__PURE__ */ jsxs(Fragment, { children: [
2676
- /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-field", children: [
2677
- /* @__PURE__ */ jsx("label", { className: "pollar-ramp-label", children: "Full name" }),
2726
+ requiredFields.map((f) => /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-field", children: [
2727
+ /* @__PURE__ */ jsx("label", { className: "pollar-ramp-label", children: f.label }),
2678
2728
  /* @__PURE__ */ jsx(
2679
2729
  "input",
2680
2730
  {
2681
- type: "text",
2731
+ type: f.type,
2682
2732
  className: "pollar-ramp-input",
2683
- placeholder: "Jane Doe",
2684
- value: fullName,
2685
- onChange: (e) => onFullNameChange(e.target.value)
2686
- }
2687
- )
2688
- ] }),
2689
- /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-field", children: [
2690
- /* @__PURE__ */ jsx("label", { className: "pollar-ramp-label", children: "Email" }),
2691
- /* @__PURE__ */ jsx(
2692
- "input",
2693
- {
2694
- type: "email",
2695
- className: "pollar-ramp-input",
2696
- placeholder: "jane@example.com",
2697
- value: email,
2698
- autoComplete: "email",
2699
- onChange: (e) => onEmailChange(e.target.value)
2733
+ value: fieldValues[f.key] ?? "",
2734
+ autoComplete: f.type === "email" ? "email" : "off",
2735
+ onChange: (e) => onFieldChange(f.key, e.target.value)
2700
2736
  }
2701
2737
  )
2702
- ] }),
2738
+ ] }, f.key)),
2703
2739
  /* @__PURE__ */ jsxs("div", { className: "pollar-modal-actions", children: [
2704
2740
  /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onRetry, children: "Back" }),
2705
2741
  /* @__PURE__ */ jsx(
@@ -2707,7 +2743,7 @@ function RampWidgetTemplate({
2707
2743
  {
2708
2744
  type: "button",
2709
2745
  className: "pollar-btn-primary",
2710
- disabled: !fullName.trim() || !email.trim() || isLoading,
2746
+ disabled: requiredFields.some((f) => !(fieldValues[f.key] ?? "").trim()) || isLoading,
2711
2747
  onClick: onContactContinue,
2712
2748
  children: isLoading ? "Starting\u2026" : "Continue"
2713
2749
  }
@@ -2753,6 +2789,9 @@ function RampWidgetTemplate({
2753
2789
  ] });
2754
2790
  }
2755
2791
  var TERMINAL = ["completed", "failed"];
2792
+ function requiredFieldsOf(quote) {
2793
+ return quote.requiredFields ?? [];
2794
+ }
2756
2795
  function RampWidget({ onClose }) {
2757
2796
  const { getClient, signTx, wallet, styles } = usePollar();
2758
2797
  const walletAddress = wallet?.address ?? "";
@@ -2763,8 +2802,8 @@ function RampWidget({ onClose }) {
2763
2802
  const [amount, setAmount] = useState("");
2764
2803
  const [currency, setCurrency] = useState("");
2765
2804
  const [country, setCountry] = useState("");
2766
- const [email, setEmail] = useState("");
2767
- const [fullName, setFullName] = useState("");
2805
+ const [fieldValues, setFieldValues] = useState({});
2806
+ const setFieldValue = (key, value) => setFieldValues((v) => ({ ...v, [key]: value }));
2768
2807
  const [countries, setCountries] = useState([]);
2769
2808
  const [countriesLoading, setCountriesLoading] = useState(true);
2770
2809
  const [refreshing, setRefreshing] = useState(false);
@@ -2911,8 +2950,9 @@ function RampWidget({ onClose }) {
2911
2950
  function handleSelectQuote(quote) {
2912
2951
  setSelectedQuote(quote);
2913
2952
  setErrorMsg(null);
2914
- const requiresContact = quote.requiresContact ?? false;
2915
- if (requiresContact && (!email.trim() || !fullName.trim())) {
2953
+ const fields = requiredFieldsOf(quote);
2954
+ const missing = fields.some((f) => !(fieldValues[f.key] ?? "").trim());
2955
+ if (fields.length > 0 && missing) {
2916
2956
  setStep("contact");
2917
2957
  return;
2918
2958
  }
@@ -2925,15 +2965,14 @@ function RampWidget({ onClose }) {
2925
2965
  setIsLoading(true);
2926
2966
  setErrorMsg(null);
2927
2967
  try {
2928
- const base = {
2929
- quoteId: quote.quoteId,
2930
- amount: Number(amount),
2931
- currency,
2932
- country,
2933
- ...email.trim() ? { email: email.trim() } : {},
2934
- ...fullName.trim() ? { fullName: fullName.trim() } : {},
2935
- ...walletAddress ? { walletAddress } : {}
2936
- };
2968
+ const base = { quoteId: quote.quoteId, amount: Number(amount), currency, country };
2969
+ if (walletAddress) base.walletAddress = walletAddress;
2970
+ for (const f of requiredFieldsOf(quote)) {
2971
+ const val = (fieldValues[f.key] ?? "").trim();
2972
+ if (!val) continue;
2973
+ if (f.bankType) base.bankDetails = { type: f.bankType, value: val };
2974
+ else base[f.key] = val;
2975
+ }
2937
2976
  const result = direction === "onramp" ? await client.createOnRamp(base) : await client.createOffRamp(base);
2938
2977
  await applyResult(result);
2939
2978
  } catch (e) {
@@ -2978,8 +3017,8 @@ function RampWidget({ onClose }) {
2978
3017
  amount,
2979
3018
  currency,
2980
3019
  country,
2981
- email,
2982
- fullName,
3020
+ requiredFields: selectedQuote ? requiredFieldsOf(selectedQuote) : [],
3021
+ fieldValues,
2983
3022
  countries,
2984
3023
  countriesLoading,
2985
3024
  refreshing,
@@ -2995,8 +3034,7 @@ function RampWidget({ onClose }) {
2995
3034
  errorMsg,
2996
3035
  onDirectionChange: setDirection,
2997
3036
  onAmountChange: setAmount,
2998
- onEmailChange: setEmail,
2999
- onFullNameChange: setFullName,
3037
+ onFieldChange: setFieldValue,
3000
3038
  onCountryChange: handleCountryChange,
3001
3039
  onFindRoute: handleFindRoute,
3002
3040
  onSelectQuote: handleSelectQuote,
@@ -4648,6 +4686,7 @@ function TxHistoryModalTemplate({
4648
4686
  txHistory.step === "loaded" && records.length === 0 && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: "No transactions yet." }),
4649
4687
  records.map((record) => {
4650
4688
  const explorerUrl = `https://stellar.expert/explorer/${record.network === "testnet" ? "testnet" : "public"}/tx/${record.hash}`;
4689
+ const destination = typeof record.details?.destination === "string" ? record.details.destination : void 0;
4651
4690
  return /* @__PURE__ */ jsxs("div", { className: "pollar-hist-item", children: [
4652
4691
  /* @__PURE__ */ jsx("span", { className: "pollar-hist-item-summary", children: record.summary }),
4653
4692
  /* @__PURE__ */ jsx(StatusBadge, { status: record.status }),
@@ -4666,6 +4705,10 @@ function TxHistoryModalTemplate({
4666
4705
  "\xB7 ",
4667
4706
  formatDate(record.createdAt)
4668
4707
  ] }),
4708
+ destination && /* @__PURE__ */ jsxs(Fragment, { children: [
4709
+ /* @__PURE__ */ jsx("span", { children: "\xB7" }),
4710
+ /* @__PURE__ */ jsx(CopyButton, { value: destination, label: "Copy wallet address", className: "pollar-copy-btn-sm" })
4711
+ ] }),
4669
4712
  /* @__PURE__ */ jsx("span", { children: "\xB7" }),
4670
4713
  /* @__PURE__ */ jsxs(
4671
4714
  "a",
@@ -4754,7 +4797,7 @@ function TxHistoryModal({ onClose }) {
4754
4797
  }
4755
4798
  function formatBalance2(balance) {
4756
4799
  const n = parseFloat(balance);
4757
- return isNaN(n) ? balance : n.toLocaleString(void 0, { maximumFractionDigits: 7 });
4800
+ return isNaN(n) ? balance : n.toLocaleString(void 0, { minimumFractionDigits: 7, maximumFractionDigits: 7 });
4758
4801
  }
4759
4802
  function cropAddress2(address) {
4760
4803
  if (address.length <= 16) return address;
@@ -4763,7 +4806,13 @@ function cropAddress2(address) {
4763
4806
  function BalanceItem({ record }) {
4764
4807
  const balanceDiffers = record.balance !== record.available;
4765
4808
  return /* @__PURE__ */ jsxs("div", { className: "pollar-bal-item", children: [
4766
- /* @__PURE__ */ jsx("span", { className: "pollar-bal-asset", children: record.code }),
4809
+ /* @__PURE__ */ jsxs("div", { className: "pollar-bal-asset-info", children: [
4810
+ /* @__PURE__ */ jsx("span", { className: "pollar-bal-asset", children: record.code }),
4811
+ record.issuer && /* @__PURE__ */ jsxs("span", { className: "pollar-bal-issuer", children: [
4812
+ /* @__PURE__ */ jsx("span", { className: "pollar-bal-issuer-addr", children: cropAddress2(record.issuer) }),
4813
+ /* @__PURE__ */ jsx(CopyButton, { value: record.issuer, label: "Copy issuer address", className: "pollar-copy-btn-sm" })
4814
+ ] })
4815
+ ] }),
4767
4816
  /* @__PURE__ */ jsxs("div", { className: "pollar-bal-amounts", children: [
4768
4817
  /* @__PURE__ */ jsx("span", { className: "pollar-bal-amount", children: formatBalance2(record.balance) }),
4769
4818
  balanceDiffers && /* @__PURE__ */ jsxs("span", { className: "pollar-bal-available", children: [
@@ -4826,7 +4875,10 @@ function WalletBalanceModalTemplate({
4826
4875
  /* @__PURE__ */ jsx("button", { className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
4827
4876
  ] })
4828
4877
  ] }),
4829
- walletAddress && /* @__PURE__ */ jsx("div", { className: "pollar-bal-address", children: cropAddress2(walletAddress) }),
4878
+ walletAddress && /* @__PURE__ */ jsxs("div", { className: "pollar-bal-address-row", children: [
4879
+ /* @__PURE__ */ jsx("span", { className: "pollar-bal-address", children: cropAddress2(walletAddress) }),
4880
+ /* @__PURE__ */ jsx(CopyButton, { value: walletAddress, label: "Copy wallet address" })
4881
+ ] }),
4830
4882
  isLoading && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: "Loading\u2026" }),
4831
4883
  walletBalance.step === "error" && /* @__PURE__ */ jsx("div", { className: "pollar-modal-error", children: walletBalance.message }),
4832
4884
  data && !data.exists && /* @__PURE__ */ jsxs("div", { className: "pollar-modal-empty", children: [