diff --git a/modules/rcart/components/folk-payment-page.ts b/modules/rcart/components/folk-payment-page.ts index 0d7a9ee..80d2ee7 100644 --- a/modules/rcart/components/folk-payment-page.ts +++ b/modules/rcart/components/folk-payment-page.ts @@ -140,10 +140,11 @@ class FolkPaymentPage extends HTMLElement { this.render(); try { + const effectiveAmount = this.getEffectiveAmount(); const res = await fetch(`${this.getApiBase()}/api/payments/${this.paymentId}/transak-session`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ email: this.cardEmail }), + body: JSON.stringify({ email: this.cardEmail, ...(effectiveAmount ? { amount: effectiveAmount } : {}) }), }); const data = await res.json(); if (!res.ok) throw new Error(data.error || 'Failed to create session'); @@ -391,16 +392,38 @@ class FolkPaymentPage extends HTMLElement { const chainNames: Record = { 8453: 'Base', 84532: 'Base Sepolia', 1: 'Ethereum' }; const chainName = chainNames[p.chainId] || `Chain ${p.chainId}`; + const isTestnet = p.chainId === 84532; const showAmountInput = p.amountEditable && p.status === 'pending'; const displayAmount = (!p.amount || p.amount === '0') && p.amountEditable ? 'Any amount' : `${p.amount} ${p.token}`; + // Derive a short recipient label from creatorDid + const recipientLabel = p.creatorDid + ? (p.creatorDid.startsWith('did:') ? p.creatorDid.split(':').pop()?.slice(0, 12) + '...' : p.creatorDid.slice(0, 16) + '...') + : p.recipientAddress.slice(0, 8) + '...' + p.recipientAddress.slice(-6); + + // Build available methods description + const methods = p.enabledMethods || { card: true, wallet: true, encryptid: true }; + const methodLabels: string[] = []; + if (methods.card) methodLabels.push('Credit Card (via Transak)'); + if (methods.wallet) methodLabels.push('External Wallet (MetaMask, etc.)'); + if (methods.encryptid) methodLabels.push('EncryptID Passkey'); + return ` + ${isTestnet ? `
+ This is a staging environment for testing credit card to stablecoin and asset-backed CRDT token transactions. Your credit card will not be charged. +
` : ''} +

Payment Request

${p.status}
+
+ You are sending a payment to ${this.esc(recipientLabel)}${p.description ? ` for ${this.esc(p.description)}` : ''}. + ${methodLabels.length > 0 ? `You can pay by: ${methodLabels.join(', ')}.` : ''} +
+
${showAmountInput ? `
@@ -417,7 +440,7 @@ class FolkPaymentPage extends HTMLElement { `}
-
${this.esc(p.description)}
+ ${p.description ? `
${this.esc(p.description)}
` : ''} ${p.paymentType === 'subscription' ? '
Subscription
' : ''} ${p.paymentType === 'payer_choice' && p.status === 'pending' ? ` @@ -633,6 +656,10 @@ class FolkPaymentPage extends HTMLElement { .payment-page { } + .staging-banner { background: rgba(251,191,36,0.12); border: 1px solid rgba(251,191,36,0.3); color: #fbbf24; border-radius: 8px; padding: 0.75rem 1rem; font-size: 0.8125rem; line-height: 1.5; margin-bottom: 1rem; text-align: center; } + .recipient-info { color: var(--rs-text-secondary); font-size: 0.875rem; line-height: 1.6; margin-bottom: 1.25rem; padding: 0.75rem 1rem; background: var(--rs-bg-surface); border-radius: 8px; border: 1px solid var(--rs-border); } + .recipient-info strong { color: var(--rs-text-primary); } + .header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem; } .title { color: var(--rs-text-primary); font-size: 1.25rem; font-weight: 700; margin: 0; } diff --git a/modules/rcart/mod.ts b/modules/rcart/mod.ts index 66bbd07..f657184 100644 --- a/modules/rcart/mod.ts +++ b/modules/rcart/mod.ts @@ -1389,7 +1389,7 @@ routes.post("/api/payments/:id/transak-session", async (c) => { if (p.status !== 'pending') return c.json({ error: "Payment is no longer pending" }, 400); if (p.enabledMethods && !p.enabledMethods.card) return c.json({ error: "Card payments are not enabled for this request" }, 400); - const { email } = await c.req.json(); + const { email, amount: overrideAmount } = await c.req.json(); if (!email) return c.json({ error: "Required: email" }, 400); const transakApiKey = getTransakApiKey(); @@ -1399,6 +1399,9 @@ routes.post("/api/payments/:id/transak-session", async (c) => { const host = new URL(c.req.url).hostname; + // Use override amount for editable-amount payments, otherwise use preset amount + const effectiveAmount = (p.amountEditable && overrideAmount) ? String(overrideAmount) : p.amount; + const widgetParams: Record = { apiKey: transakApiKey, referrerDomain: extractRootDomain(host), @@ -1407,7 +1410,7 @@ routes.post("/api/payments/:id/transak-session", async (c) => { defaultCryptoCurrency: p.token, walletAddress: p.recipientAddress, disableWalletAddressForm: 'true', - cryptoAmount: p.amount, + cryptoAmount: effectiveAmount, partnerOrderId: `pay-${paymentId}`, email, themeColor: '6366f1',