'use client' import { useState, useCallback } from 'react' import type { FundingSource, FundingSourceType } from '@/lib/types' import { initiateOnRamp } from '@/lib/api/flows-client' import TransakWidget from './TransakWidget' interface FundingSourcesPanelProps { sources: FundingSource[] onSourcesChange: (sources: FundingSource[]) => void funnelWalletAddress?: string flowId?: string funnelId?: string isDeployed: boolean } const SOURCE_TYPE_META: Record = { card: { icon: 'credit-card', label: 'Card', color: 'violet' }, crypto_wallet: { icon: 'wallet', label: 'Crypto Wallet', color: 'cyan' }, safe_treasury: { icon: 'safe', label: 'Safe Treasury', color: 'emerald' }, bank_transfer: { icon: 'bank', label: 'Bank Transfer', color: 'blue' }, } const CURRENCIES = ['USD', 'EUR', 'GBP'] const CHAIN_OPTIONS = [ { id: 1, name: 'Ethereum' }, { id: 10, name: 'Optimism' }, { id: 100, name: 'Gnosis' }, { id: 137, name: 'Polygon' }, { id: 8453, name: 'Base' }, { id: 84532, name: 'Base Sepolia' }, ] function SourceIcon({ type }: { type: FundingSourceType }) { switch (type) { case 'card': return ( ) case 'crypto_wallet': return ( ) case 'safe_treasury': return ( ) case 'bank_transfer': return ( ) } } export default function FundingSourcesPanel({ sources, onSourcesChange, funnelWalletAddress, flowId, funnelId, isDeployed, }: FundingSourcesPanelProps) { const [showTypePicker, setShowTypePicker] = useState(false) const [configType, setConfigType] = useState(null) const [transakUrl, setTransakUrl] = useState(null) const [fundingError, setFundingError] = useState(null) // Config form state const [configLabel, setConfigLabel] = useState('') const [configCurrency, setConfigCurrency] = useState('USD') const [configDefaultAmount, setConfigDefaultAmount] = useState('') const [configSafeAddress, setConfigSafeAddress] = useState('') const [configSafeChainId, setConfigSafeChainId] = useState(1) const [copied, setCopied] = useState(false) const resetConfigForm = useCallback(() => { setConfigType(null) setShowTypePicker(false) setConfigLabel('') setConfigCurrency('USD') setConfigDefaultAmount('') setConfigSafeAddress('') setConfigSafeChainId(1) }, []) const handleSelectType = useCallback((type: FundingSourceType) => { setConfigType(type) setShowTypePicker(false) // Pre-fill label setConfigLabel(SOURCE_TYPE_META[type].label) }, []) const handleSaveSource = useCallback(() => { if (!configType) return const newSource: FundingSource = { id: crypto.randomUUID(), type: configType, label: configLabel || SOURCE_TYPE_META[configType].label, enabled: true, } if (configType === 'card' || configType === 'bank_transfer') { newSource.transakConfig = { fiatCurrency: configCurrency, defaultAmount: configDefaultAmount ? parseFloat(configDefaultAmount) : undefined, } } if (configType === 'crypto_wallet') { newSource.walletAddress = funnelWalletAddress || '' } if (configType === 'safe_treasury') { newSource.safeAddress = configSafeAddress newSource.safeChainId = configSafeChainId } onSourcesChange([...sources, newSource]) resetConfigForm() }, [configType, configLabel, configCurrency, configDefaultAmount, configSafeAddress, configSafeChainId, funnelWalletAddress, sources, onSourcesChange, resetConfigForm]) const handleToggleSource = useCallback((id: string) => { onSourcesChange( sources.map((s) => (s.id === id ? { ...s, enabled: !s.enabled } : s)) ) }, [sources, onSourcesChange]) const handleDeleteSource = useCallback((id: string) => { onSourcesChange(sources.filter((s) => s.id !== id)) }, [sources, onSourcesChange]) const handleFundNow = useCallback(async (source: FundingSource) => { if (!flowId || !funnelId) return setFundingError(null) try { const amount = source.transakConfig?.defaultAmount || 100 const currency = source.transakConfig?.fiatCurrency || 'USD' const result = await initiateOnRamp(flowId, funnelId, amount, currency) if (result.widgetUrl) { setTransakUrl(result.widgetUrl) } else { setFundingError('No widget URL returned from on-ramp') } } catch (err) { setFundingError(err instanceof Error ? err.message : 'Failed to initiate on-ramp') } }, [flowId, funnelId]) const handleCopyAddress = useCallback(() => { if (funnelWalletAddress) { navigator.clipboard.writeText(funnelWalletAddress) setCopied(true) setTimeout(() => setCopied(false), 2000) } }, [funnelWalletAddress]) const cardOrBankSource = sources.find( (s) => (s.type === 'card' || s.type === 'bank_transfer') && s.enabled ) return (
{/* Source list */} {sources.length > 0 && (
{sources.map((source) => { const meta = SOURCE_TYPE_META[source.type] return (
{source.label} {meta.label} {/* Enable/disable toggle */} {/* Delete button */}
) })}
)} {/* Fund Now button (for deployed flows with card/bank source) */} {isDeployed && cardOrBankSource && ( )} {fundingError && (

{fundingError}

)} {/* Type picker */} {showTypePicker && !configType && (
{(Object.entries(SOURCE_TYPE_META) as [FundingSourceType, typeof SOURCE_TYPE_META['card']][]).map( ([type, meta]) => ( ) )}
)} {/* Config form based on selected type */} {configType && (
Configure {SOURCE_TYPE_META[configType].label}
{/* Label input (all types) */} setConfigLabel(e.target.value)} placeholder="Label..." className="w-full text-xs px-2 py-1.5 border border-slate-200 rounded mb-2 text-slate-800" /> {/* Card / Bank Transfer config */} {(configType === 'card' || configType === 'bank_transfer') && ( <> setConfigDefaultAmount(e.target.value)} placeholder="100" className="w-full text-xs px-2 py-1.5 border border-slate-200 rounded mb-2 text-slate-800" min="0" step="1" /> )} {/* Crypto Wallet config */} {configType === 'crypto_wallet' && ( <>
{funnelWalletAddress && ( )}
)} {/* Safe Treasury config */} {configType === 'safe_treasury' && ( <> setConfigSafeAddress(e.target.value)} placeholder="0x..." className="w-full text-xs px-2 py-1.5 border border-slate-200 rounded mb-2 text-slate-800 font-mono" /> )}
)} {/* Add button */} {!showTypePicker && !configType && ( )} {/* Transak Widget */} {transakUrl && ( setTransakUrl(null)} onComplete={(orderId) => { console.log('Transak order completed:', orderId) }} /> )}
) }