@moneymq/react 0.2.0 → 0.2.1

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
@@ -395,7 +395,7 @@ function MoneyMQProvider({
395
395
  }
396
396
 
397
397
  // src/pay-button.tsx
398
- import { forwardRef, useEffect as useEffect3, useState as useState5 } from "react";
398
+ import React5, { forwardRef, useEffect as useEffect3, useState as useState5 } from "react";
399
399
 
400
400
  // src/payment-modal.tsx
401
401
  import { useCallback as useCallback3, useState as useState4 } from "react";
@@ -481,8 +481,9 @@ async function makeRequestWith402Handling(url, method, body, secretKeyHex, rpcUr
481
481
  }
482
482
  return data;
483
483
  }
484
- async function createSandboxPayment(apiUrl, rpcUrl, amount, currency, recipient, senderAddress, secretKeyHex, productName) {
484
+ async function createSandboxPayment(apiUrl, rpcUrl, amount, currency, recipient, senderAddress, secretKeyHex, lineItems) {
485
485
  console.log("[MoneyMQ] Creating sandbox payment...", { amount, currency, recipient, senderAddress });
486
+ const description = lineItems && lineItems.length > 0 ? `Purchase - ${lineItems.map((item) => item.product.name).join(", ")}` : "Payment";
486
487
  const paymentIntent = await makeRequestWith402Handling(
487
488
  `${apiUrl}/catalog/v1/payment_intents`,
488
489
  "POST",
@@ -491,7 +492,7 @@ async function createSandboxPayment(apiUrl, rpcUrl, amount, currency, recipient,
491
492
  // Convert to cents (Stripe-style)
492
493
  currency: currency.toLowerCase(),
493
494
  customer: senderAddress,
494
- description: productName ? `Purchase - ${productName}` : "Payment",
495
+ description,
495
496
  metadata: {
496
497
  sender_address: senderAddress,
497
498
  recipient_address: recipient
@@ -522,7 +523,7 @@ function PaymentModal({
522
523
  amount,
523
524
  currency,
524
525
  recipient,
525
- productName,
526
+ lineItems,
526
527
  onSuccess,
527
528
  onError,
528
529
  accentColor = "#ec4899"
@@ -620,7 +621,7 @@ function PaymentModal({
620
621
  recipient,
621
622
  senderAddress,
622
623
  secretKeyHex,
623
- productName
624
+ lineItems
624
625
  );
625
626
  setIsSending(false);
626
627
  onSuccess?.(paymentId);
@@ -668,7 +669,7 @@ function PaymentModal({
668
669
  setIsSending(false);
669
670
  onError?.(err instanceof Error ? err : new Error(String(err)));
670
671
  }
671
- }, [publicKey, recipient, amount, currency, onSuccess, onError, onClose, selectedPaymentMethod, client.config.endpoint, productName]);
672
+ }, [publicKey, recipient, amount, currency, onSuccess, onError, onClose, selectedPaymentMethod, client.config.endpoint, lineItems]);
672
673
  const canPay = (connected && publicKey || selectedPaymentMethod?.type === "sandbox_account") && recipient && !isSending;
673
674
  if (!visible) return null;
674
675
  const WalletIcon = () => /* @__PURE__ */ jsxs3("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", children: [
@@ -1157,7 +1158,38 @@ function PaymentModal({
1157
1158
  },
1158
1159
  children: [
1159
1160
  /* @__PURE__ */ jsxs3("div", { style: { marginBottom: "1rem" }, children: [
1160
- /* @__PURE__ */ jsx4("div", { style: { fontSize: "0.875rem", color: "#8e8e93", marginBottom: "0.25rem" }, children: productName ? `Pay ${productName}` : "Total" }),
1161
+ lineItems && lineItems.length > 0 && /* @__PURE__ */ jsx4("div", { style: { marginBottom: "0.75rem" }, children: lineItems.map((item, index) => /* @__PURE__ */ jsxs3(
1162
+ "div",
1163
+ {
1164
+ style: {
1165
+ display: "flex",
1166
+ justifyContent: "space-between",
1167
+ alignItems: "center",
1168
+ padding: "0.5rem 0",
1169
+ borderBottom: index < lineItems.length - 1 ? "1px solid #3a3a3c" : "none"
1170
+ },
1171
+ children: [
1172
+ /* @__PURE__ */ jsxs3("div", { style: { flex: 1 }, children: [
1173
+ /* @__PURE__ */ jsx4("div", { style: { fontSize: "0.875rem", color: "#fff", fontWeight: 500 }, children: item.product.name }),
1174
+ item.quantity > 1 && /* @__PURE__ */ jsxs3("div", { style: { fontSize: "0.75rem", color: "#8e8e93" }, children: [
1175
+ "Qty: ",
1176
+ item.quantity,
1177
+ " \xD7 ",
1178
+ (item.price.unit_amount / 100).toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 }),
1179
+ " ",
1180
+ item.price.currency.toUpperCase()
1181
+ ] })
1182
+ ] }),
1183
+ /* @__PURE__ */ jsxs3("div", { style: { fontSize: "0.875rem", color: "#fff", fontWeight: 500 }, children: [
1184
+ item.subtotal.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 }),
1185
+ " ",
1186
+ item.price.currency.toUpperCase()
1187
+ ] })
1188
+ ]
1189
+ },
1190
+ item.product.id + "-" + index
1191
+ )) }),
1192
+ /* @__PURE__ */ jsx4("div", { style: { fontSize: "0.875rem", color: "#8e8e93", marginBottom: "0.25rem" }, children: "Total" }),
1161
1193
  /* @__PURE__ */ jsxs3("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
1162
1194
  /* @__PURE__ */ jsxs3("div", { style: { display: "flex", alignItems: "baseline", gap: "0.375rem" }, children: [
1163
1195
  /* @__PURE__ */ jsx4("span", { style: { fontSize: "2rem", fontWeight: 600, color: "#fff" }, children: amount.toLocaleString(void 0, { minimumFractionDigits: 2, maximumFractionDigits: 2 }) }),
@@ -1326,9 +1358,7 @@ var outlineStyle = {
1326
1358
  };
1327
1359
  var PayButton = forwardRef(
1328
1360
  function PayButton2({
1329
- priceId,
1330
- price: priceObject,
1331
- product: productObject,
1361
+ basket,
1332
1362
  onSuccess,
1333
1363
  onError,
1334
1364
  variant = "solid",
@@ -1338,18 +1368,35 @@ var PayButton = forwardRef(
1338
1368
  const client = useMoneyMQ();
1339
1369
  const [isModalOpen, setIsModalOpen] = useState5(false);
1340
1370
  const [isHovered, setIsHovered] = useState5(false);
1341
- const hasPriceObject = priceObject !== void 0;
1342
- const [isLoading, setIsLoading] = useState5(!hasPriceObject);
1371
+ const [isLoading, setIsLoading] = useState5(true);
1343
1372
  const [error, setError] = useState5(null);
1344
- const [amount, setAmount] = useState5(hasPriceObject ? priceObject.unit_amount / 100 : 0);
1345
- const [currency, setCurrency] = useState5(hasPriceObject ? priceObject.currency.toUpperCase() : "USDC");
1346
1373
  const [recipient, setRecipient] = useState5("");
1347
- const [productName, setProductName] = useState5(productObject?.name);
1374
+ const { totalAmount, currency, lineItems } = React5.useMemo(() => {
1375
+ if (!basket || basket.length === 0) {
1376
+ return { totalAmount: 0, currency: "USDC", lineItems: [] };
1377
+ }
1378
+ const baseCurrency = basket[0].price.currency.toUpperCase();
1379
+ const items = basket.map((item) => ({
1380
+ product: item.product,
1381
+ price: item.price,
1382
+ quantity: item.quantity ?? 1,
1383
+ subtotal: item.price.unit_amount / 100 * (item.quantity ?? 1)
1384
+ }));
1385
+ const total = items.reduce((sum, item) => sum + item.subtotal, 0);
1386
+ return {
1387
+ totalAmount: total,
1388
+ currency: baseCurrency,
1389
+ lineItems: items
1390
+ };
1391
+ }, [basket]);
1348
1392
  useEffect3(() => {
1349
1393
  async function fetchPaymentDetails() {
1350
1394
  setIsLoading(true);
1351
1395
  setError(null);
1352
1396
  try {
1397
+ if (!basket || basket.length === 0) {
1398
+ throw new Error("Basket is empty");
1399
+ }
1353
1400
  const apiUrl = client.config.endpoint;
1354
1401
  const configResponse = await fetch(`${apiUrl}/config`);
1355
1402
  if (!configResponse.ok) {
@@ -1359,42 +1406,6 @@ var PayButton = forwardRef(
1359
1406
  if (config.x402?.payoutAccount?.address) {
1360
1407
  setRecipient(config.x402.payoutAccount.address);
1361
1408
  }
1362
- if (hasPriceObject) {
1363
- setAmount(priceObject.unit_amount / 100);
1364
- setCurrency(priceObject.currency.toUpperCase());
1365
- if (productObject) {
1366
- setProductName(productObject.name);
1367
- } else if (priceObject.product) {
1368
- try {
1369
- const productResponse = await fetch(`${apiUrl}/catalog/v1/products/${priceObject.product}`);
1370
- if (productResponse.ok) {
1371
- const product = await productResponse.json();
1372
- setProductName(product.name);
1373
- }
1374
- } catch {
1375
- }
1376
- }
1377
- } else if (priceId) {
1378
- const priceResponse = await fetch(`${apiUrl}/catalog/v1/prices/${priceId}`);
1379
- if (!priceResponse.ok) {
1380
- throw new Error(`Failed to fetch price: ${priceResponse.status}`);
1381
- }
1382
- const price = await priceResponse.json();
1383
- setAmount(price.unit_amount / 100);
1384
- setCurrency(price.currency.toUpperCase());
1385
- if (price.product) {
1386
- try {
1387
- const productResponse = await fetch(`${apiUrl}/catalog/v1/products/${price.product}`);
1388
- if (productResponse.ok) {
1389
- const product = await productResponse.json();
1390
- setProductName(product.name);
1391
- }
1392
- } catch {
1393
- }
1394
- }
1395
- } else {
1396
- throw new Error("Either priceId or price object is required");
1397
- }
1398
1409
  } catch (err) {
1399
1410
  console.error("[PayButton] Error fetching payment details:", err);
1400
1411
  const errorMessage = err instanceof Error ? err.message : "Failed to load payment details";
@@ -1405,7 +1416,7 @@ var PayButton = forwardRef(
1405
1416
  }
1406
1417
  }
1407
1418
  fetchPaymentDetails();
1408
- }, [priceId, priceObject, productObject, client.config.endpoint, onError, hasPriceObject]);
1419
+ }, [basket, client.config.endpoint, onError]);
1409
1420
  const handleClick = () => {
1410
1421
  if (!isLoading && !error) {
1411
1422
  setIsModalOpen(true);
@@ -1414,7 +1425,7 @@ var PayButton = forwardRef(
1414
1425
  const handlePaymentSuccess = (signature) => {
1415
1426
  const payment = {
1416
1427
  id: `pay_${Date.now()}`,
1417
- amount,
1428
+ amount: totalAmount,
1418
1429
  currency,
1419
1430
  status: "completed",
1420
1431
  signature
@@ -1450,10 +1461,10 @@ var PayButton = forwardRef(
1450
1461
  {
1451
1462
  visible: isModalOpen,
1452
1463
  onClose: () => setIsModalOpen(false),
1453
- amount,
1464
+ amount: totalAmount,
1454
1465
  currency,
1455
1466
  recipient,
1456
- productName,
1467
+ lineItems,
1457
1468
  onSuccess: handlePaymentSuccess,
1458
1469
  onError: handlePaymentError
1459
1470
  }