@medialane/ui 0.185.0 → 0.186.0

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.
Files changed (187) hide show
  1. package/dist/components/media-wallet/action-button.cjs +54 -0
  2. package/dist/components/media-wallet/action-button.cjs.map +1 -0
  3. package/dist/components/media-wallet/action-button.d.cts +10 -0
  4. package/dist/components/media-wallet/action-button.d.ts +10 -0
  5. package/dist/components/media-wallet/action-button.js +28 -0
  6. package/dist/components/media-wallet/action-button.js.map +1 -0
  7. package/dist/components/media-wallet/action-modal.cjs +84 -0
  8. package/dist/components/media-wallet/action-modal.cjs.map +1 -0
  9. package/dist/components/media-wallet/action-modal.d.cts +20 -0
  10. package/dist/components/media-wallet/action-modal.d.ts +20 -0
  11. package/dist/components/media-wallet/action-modal.js +56 -0
  12. package/dist/components/media-wallet/action-modal.js.map +1 -0
  13. package/dist/components/media-wallet/activate-card.cjs +72 -0
  14. package/dist/components/media-wallet/activate-card.cjs.map +1 -0
  15. package/dist/components/media-wallet/activate-card.d.cts +7 -0
  16. package/dist/components/media-wallet/activate-card.d.ts +7 -0
  17. package/dist/components/media-wallet/activate-card.js +48 -0
  18. package/dist/components/media-wallet/activate-card.js.map +1 -0
  19. package/dist/components/media-wallet/address-qr.cjs +64 -0
  20. package/dist/components/media-wallet/address-qr.cjs.map +1 -0
  21. package/dist/components/media-wallet/address-qr.d.cts +8 -0
  22. package/dist/components/media-wallet/address-qr.d.ts +8 -0
  23. package/dist/components/media-wallet/address-qr.js +30 -0
  24. package/dist/components/media-wallet/address-qr.js.map +1 -0
  25. package/dist/components/media-wallet/back-button.cjs +41 -0
  26. package/dist/components/media-wallet/back-button.cjs.map +1 -0
  27. package/dist/components/media-wallet/back-button.d.cts +7 -0
  28. package/dist/components/media-wallet/back-button.d.ts +7 -0
  29. package/dist/components/media-wallet/back-button.js +17 -0
  30. package/dist/components/media-wallet/back-button.js.map +1 -0
  31. package/dist/components/media-wallet/copy-icon.cjs +49 -0
  32. package/dist/components/media-wallet/copy-icon.cjs.map +1 -0
  33. package/dist/components/media-wallet/copy-icon.d.cts +7 -0
  34. package/dist/components/media-wallet/copy-icon.d.ts +7 -0
  35. package/dist/components/media-wallet/copy-icon.js +25 -0
  36. package/dist/components/media-wallet/copy-icon.js.map +1 -0
  37. package/dist/components/media-wallet/currency-sheet.cjs +54 -0
  38. package/dist/components/media-wallet/currency-sheet.cjs.map +1 -0
  39. package/dist/components/media-wallet/currency-sheet.d.cts +12 -0
  40. package/dist/components/media-wallet/currency-sheet.d.ts +12 -0
  41. package/dist/components/media-wallet/currency-sheet.js +30 -0
  42. package/dist/components/media-wallet/currency-sheet.js.map +1 -0
  43. package/dist/components/media-wallet/media-wallet-activity.cjs +223 -0
  44. package/dist/components/media-wallet/media-wallet-activity.cjs.map +1 -0
  45. package/dist/components/media-wallet/media-wallet-activity.d.cts +12 -0
  46. package/dist/components/media-wallet/media-wallet-activity.d.ts +12 -0
  47. package/dist/components/media-wallet/media-wallet-activity.js +189 -0
  48. package/dist/components/media-wallet/media-wallet-activity.js.map +1 -0
  49. package/dist/components/media-wallet/media-wallet-header.cjs +97 -0
  50. package/dist/components/media-wallet/media-wallet-header.cjs.map +1 -0
  51. package/dist/components/media-wallet/media-wallet-header.d.cts +8 -0
  52. package/dist/components/media-wallet/media-wallet-header.d.ts +8 -0
  53. package/dist/components/media-wallet/media-wallet-header.js +63 -0
  54. package/dist/components/media-wallet/media-wallet-header.js.map +1 -0
  55. package/dist/components/media-wallet/media-wallet-home.cjs +258 -0
  56. package/dist/components/media-wallet/media-wallet-home.cjs.map +1 -0
  57. package/dist/components/media-wallet/media-wallet-home.d.cts +14 -0
  58. package/dist/components/media-wallet/media-wallet-home.d.ts +14 -0
  59. package/dist/components/media-wallet/media-wallet-home.js +224 -0
  60. package/dist/components/media-wallet/media-wallet-home.js.map +1 -0
  61. package/dist/components/media-wallet/media-wallet-overlay.cjs +137 -0
  62. package/dist/components/media-wallet/media-wallet-overlay.cjs.map +1 -0
  63. package/dist/components/media-wallet/media-wallet-overlay.d.cts +14 -0
  64. package/dist/components/media-wallet/media-wallet-overlay.d.ts +14 -0
  65. package/dist/components/media-wallet/media-wallet-overlay.js +102 -0
  66. package/dist/components/media-wallet/media-wallet-overlay.js.map +1 -0
  67. package/dist/components/media-wallet/media-wallet-send.cjs +313 -0
  68. package/dist/components/media-wallet/media-wallet-send.cjs.map +1 -0
  69. package/dist/components/media-wallet/media-wallet-send.d.cts +14 -0
  70. package/dist/components/media-wallet/media-wallet-send.d.ts +14 -0
  71. package/dist/components/media-wallet/media-wallet-send.js +289 -0
  72. package/dist/components/media-wallet/media-wallet-send.js.map +1 -0
  73. package/dist/components/media-wallet/media-wallet-token-detail.cjs +164 -0
  74. package/dist/components/media-wallet/media-wallet-token-detail.cjs.map +1 -0
  75. package/dist/components/media-wallet/media-wallet-token-detail.d.cts +13 -0
  76. package/dist/components/media-wallet/media-wallet-token-detail.d.ts +13 -0
  77. package/dist/components/media-wallet/media-wallet-token-detail.js +140 -0
  78. package/dist/components/media-wallet/media-wallet-token-detail.js.map +1 -0
  79. package/dist/components/media-wallet/media-wallet.cjs +51 -0
  80. package/dist/components/media-wallet/media-wallet.cjs.map +1 -0
  81. package/dist/components/media-wallet/media-wallet.d.cts +13 -0
  82. package/dist/components/media-wallet/media-wallet.d.ts +13 -0
  83. package/dist/components/media-wallet/media-wallet.js +27 -0
  84. package/dist/components/media-wallet/media-wallet.js.map +1 -0
  85. package/dist/components/media-wallet/nft-strip.cjs +85 -0
  86. package/dist/components/media-wallet/nft-strip.cjs.map +1 -0
  87. package/dist/components/media-wallet/nft-strip.d.cts +12 -0
  88. package/dist/components/media-wallet/nft-strip.d.ts +12 -0
  89. package/dist/components/media-wallet/nft-strip.js +51 -0
  90. package/dist/components/media-wallet/nft-strip.js.map +1 -0
  91. package/dist/components/media-wallet/quick-action.cjs +59 -0
  92. package/dist/components/media-wallet/quick-action.cjs.map +1 -0
  93. package/dist/components/media-wallet/quick-action.d.cts +12 -0
  94. package/dist/components/media-wallet/quick-action.d.ts +12 -0
  95. package/dist/components/media-wallet/quick-action.js +35 -0
  96. package/dist/components/media-wallet/quick-action.js.map +1 -0
  97. package/dist/components/media-wallet/receive-card.cjs +86 -0
  98. package/dist/components/media-wallet/receive-card.cjs.map +1 -0
  99. package/dist/components/media-wallet/receive-card.d.cts +7 -0
  100. package/dist/components/media-wallet/receive-card.d.ts +7 -0
  101. package/dist/components/media-wallet/receive-card.js +52 -0
  102. package/dist/components/media-wallet/receive-card.js.map +1 -0
  103. package/dist/components/media-wallet/section-header.cjs +32 -0
  104. package/dist/components/media-wallet/section-header.cjs.map +1 -0
  105. package/dist/components/media-wallet/section-header.d.cts +7 -0
  106. package/dist/components/media-wallet/section-header.d.ts +7 -0
  107. package/dist/components/media-wallet/section-header.js +8 -0
  108. package/dist/components/media-wallet/section-header.js.map +1 -0
  109. package/dist/components/media-wallet/success-dialog.cjs +75 -0
  110. package/dist/components/media-wallet/success-dialog.cjs.map +1 -0
  111. package/dist/components/media-wallet/success-dialog.d.cts +11 -0
  112. package/dist/components/media-wallet/success-dialog.d.ts +11 -0
  113. package/dist/components/media-wallet/success-dialog.js +51 -0
  114. package/dist/components/media-wallet/success-dialog.js.map +1 -0
  115. package/dist/components/media-wallet/types.cjs +37 -0
  116. package/dist/components/media-wallet/types.cjs.map +1 -0
  117. package/dist/components/media-wallet/types.d.cts +66 -0
  118. package/dist/components/media-wallet/types.d.ts +66 -0
  119. package/dist/components/media-wallet/types.js +12 -0
  120. package/dist/components/media-wallet/types.js.map +1 -0
  121. package/dist/components/media-wallet/wallet-activity-icon.cjs +69 -0
  122. package/dist/components/media-wallet/wallet-activity-icon.cjs.map +1 -0
  123. package/dist/components/media-wallet/wallet-activity-icon.d.cts +8 -0
  124. package/dist/components/media-wallet/wallet-activity-icon.d.ts +8 -0
  125. package/dist/components/media-wallet/wallet-activity-icon.js +45 -0
  126. package/dist/components/media-wallet/wallet-activity-icon.js.map +1 -0
  127. package/dist/index.cjs +5 -0
  128. package/dist/index.cjs.map +1 -1
  129. package/dist/index.d.cts +3 -0
  130. package/dist/index.d.ts +3 -0
  131. package/dist/index.js +3 -0
  132. package/dist/index.js.map +1 -1
  133. package/dist/utils/media-wallet/activity-feed.cjs +35 -0
  134. package/dist/utils/media-wallet/activity-feed.cjs.map +1 -0
  135. package/dist/utils/media-wallet/activity-feed.d.cts +14 -0
  136. package/dist/utils/media-wallet/activity-feed.d.ts +14 -0
  137. package/dist/utils/media-wallet/activity-feed.js +11 -0
  138. package/dist/utils/media-wallet/activity-feed.js.map +1 -0
  139. package/dist/utils/media-wallet/confetti.cjs +51 -0
  140. package/dist/utils/media-wallet/confetti.cjs.map +1 -0
  141. package/dist/utils/media-wallet/confetti.d.cts +3 -0
  142. package/dist/utils/media-wallet/confetti.d.ts +3 -0
  143. package/dist/utils/media-wallet/confetti.js +17 -0
  144. package/dist/utils/media-wallet/confetti.js.map +1 -0
  145. package/dist/utils/media-wallet/nft-items.cjs +38 -0
  146. package/dist/utils/media-wallet/nft-items.cjs.map +1 -0
  147. package/dist/utils/media-wallet/nft-items.d.cts +13 -0
  148. package/dist/utils/media-wallet/nft-items.d.ts +13 -0
  149. package/dist/utils/media-wallet/nft-items.js +14 -0
  150. package/dist/utils/media-wallet/nft-items.js.map +1 -0
  151. package/dist/utils/media-wallet/run-intent-calls.cjs +32 -0
  152. package/dist/utils/media-wallet/run-intent-calls.cjs.map +1 -0
  153. package/dist/utils/media-wallet/run-intent-calls.d.cts +16 -0
  154. package/dist/utils/media-wallet/run-intent-calls.d.ts +16 -0
  155. package/dist/utils/media-wallet/run-intent-calls.js +8 -0
  156. package/dist/utils/media-wallet/run-intent-calls.js.map +1 -0
  157. package/dist/utils/media-wallet/use-erc20-balance.cjs +75 -0
  158. package/dist/utils/media-wallet/use-erc20-balance.cjs.map +1 -0
  159. package/dist/utils/media-wallet/use-erc20-balance.d.cts +15 -0
  160. package/dist/utils/media-wallet/use-erc20-balance.d.ts +15 -0
  161. package/dist/utils/media-wallet/use-erc20-balance.js +40 -0
  162. package/dist/utils/media-wallet/use-erc20-balance.js.map +1 -0
  163. package/dist/utils/media-wallet/use-tokens-by-owner.cjs +52 -0
  164. package/dist/utils/media-wallet/use-tokens-by-owner.cjs.map +1 -0
  165. package/dist/utils/media-wallet/use-tokens-by-owner.d.cts +10 -0
  166. package/dist/utils/media-wallet/use-tokens-by-owner.d.ts +10 -0
  167. package/dist/utils/media-wallet/use-tokens-by-owner.js +18 -0
  168. package/dist/utils/media-wallet/use-tokens-by-owner.js.map +1 -0
  169. package/dist/utils/media-wallet/wallet-activity.cjs +83 -0
  170. package/dist/utils/media-wallet/wallet-activity.cjs.map +1 -0
  171. package/dist/utils/media-wallet/wallet-activity.d.cts +7 -0
  172. package/dist/utils/media-wallet/wallet-activity.d.ts +7 -0
  173. package/dist/utils/media-wallet/wallet-activity.js +57 -0
  174. package/dist/utils/media-wallet/wallet-activity.js.map +1 -0
  175. package/dist/utils/media-wallet/wallet-format.cjs +59 -0
  176. package/dist/utils/media-wallet/wallet-format.cjs.map +1 -0
  177. package/dist/utils/media-wallet/wallet-format.d.cts +9 -0
  178. package/dist/utils/media-wallet/wallet-format.d.ts +9 -0
  179. package/dist/utils/media-wallet/wallet-format.js +29 -0
  180. package/dist/utils/media-wallet/wallet-format.js.map +1 -0
  181. package/dist/utils/media-wallet/wallet-tokens.cjs +39 -0
  182. package/dist/utils/media-wallet/wallet-tokens.cjs.map +1 -0
  183. package/dist/utils/media-wallet/wallet-tokens.d.cts +10 -0
  184. package/dist/utils/media-wallet/wallet-tokens.d.ts +10 -0
  185. package/dist/utils/media-wallet/wallet-tokens.js +15 -0
  186. package/dist/utils/media-wallet/wallet-tokens.js.map +1 -0
  187. package/package.json +9 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/media-wallet/media-wallet-send.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Account, CallData, cairo, validateAndParseAddress, type Call, type ProviderInterface } from \"starknet\";\nimport { parseAmount, formatAmount } from \"@medialane/sdk\";\nimport { ActionButton } from \"../action-button.js\";\nimport { CurrencyIcon } from \"../currency-icon.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { useErc20Balance, useTokenBalance } from \"../../utils/media-wallet/use-erc20-balance.js\";\nimport { fmt, short } from \"../../utils/media-wallet/wallet-format.js\";\nimport { BackButton } from \"./back-button.js\";\nimport { TrustNote } from \"./action-button.js\";\nimport { ActionModal, BusyOverlay } from \"./action-modal.js\";\nimport { CurrencySheet } from \"./currency-sheet.js\";\nimport { WALLET_TOKENS, type WalletToken } from \"../../utils/media-wallet/wallet-tokens.js\";\nimport { SuccessDialog } from \"./success-dialog.js\";\nimport { useMediaWalletApp, type MediaWalletView } from \"./types.js\";\nimport { runIntentCalls } from \"../../utils/media-wallet/run-intent-calls.js\";\n\nfunction isValidStarknetAddress(address: string): boolean {\n try {\n validateAndParseAddress(address.trim());\n return true;\n } catch {\n return false;\n }\n}\n\nasync function estimateSendFee(provider: ProviderInterface, address: string, token: string, to: string, amountRaw: bigint) {\n const account = new Account({ provider, address, signer: \"0x1\", cairoVersion: \"1\" });\n const call: Call = {\n contractAddress: token,\n entrypoint: \"transfer\",\n calldata: CallData.compile({ recipient: to, amount: cairo.uint256(amountRaw) }),\n };\n const est = await account.estimateInvokeFee(call);\n return { feeRaw: est.overall_fee, unit: est.unit };\n}\n\nexport function MediaWalletSend({\n initialToken,\n onNavigate,\n onDone,\n}: {\n initialToken?: WalletToken;\n onNavigate: (view: MediaWalletView) => void;\n onDone: () => void;\n}) {\n const { useWalletSession, provider, getClient, useWriteAction } = useMediaWalletApp();\n const { address } = useWalletSession();\n const { run, status, reset, error } = useWriteAction();\n\n const [currency, setCurrency] = useState<WalletToken>(initialToken ?? WALLET_TOKENS[0]);\n const [pickerOpen, setPickerOpen] = useState(false);\n const strk = useTokenBalance(provider, \"STRK\", address);\n const eth = useTokenBalance(provider, \"ETH\", address);\n const usdc = useTokenBalance(provider, \"USDC\", address);\n const wbtc = useTokenBalance(provider, \"WBTC\", address);\n \n const pinnedBalancesBySymbol: Record<string, bigint | null> = {\n STRK: strk.rawBalance, ETH: eth.rawBalance, USDC: usdc.rawBalance, WBTC: wbtc.rawBalance,\n };\n const { rawBalance: currencyBalance } = useErc20Balance(provider, currency.address, address);\n\n const [to, setTo] = useState(\"\");\n const [amount, setAmount] = useState(\"\");\n const [txHash, setTxHash] = useState<string | null>(null);\n\n const [confirmOpen, setConfirmOpen] = useState(false);\n const [fee, setFee] = useState<{ raw: bigint; unit: string } | null>(null);\n const [feeError, setFeeError] = useState<string | null>(null);\n\n const recipientValid = isValidStarknetAddress(to);\n let amountRaw: bigint | null;\n try {\n amountRaw = amount.trim() ? BigInt(parseAmount(amount.trim(), currency.decimals)) : null;\n } catch {\n amountRaw = null;\n }\n const amountOverBalance = amountRaw != null && currencyBalance != null && amountRaw > currencyBalance;\n const composeReady = recipientValid && amountRaw != null && amountRaw > 0n && !amountOverBalance;\n\n const pasteRecipient = async () => {\n try {\n const text = await navigator.clipboard.readText();\n if (text) setTo(text.trim());\n } catch {\n\n }\n };\n\n const setMax = () => {\n if (currencyBalance == null) return;\n setAmount(formatAmount(currencyBalance.toString(), currency.decimals));\n };\n\n const openReview = () => {\n if (!address || !composeReady || amountRaw == null) return;\n setFeeError(null);\n setFee(null);\n setConfirmOpen(true);\n estimateSendFee(provider, address, currency.address, to.trim(), amountRaw)\n .then((f) => setFee({ raw: f.feeRaw, unit: f.unit }))\n .catch((e) => setFeeError(describeError(e, \"We couldn't estimate the network fee. Please try again.\").message));\n };\n\n const send = async () => {\n if (!composeReady || amountRaw == null) return;\n setConfirmOpen(false);\n const dest = to.trim();\n const amt = amountRaw;\n await run(async (signer) => {\n const result = await runIntentCalls(signer, () =>\n getClient().api.createTransferTokenIntent({ owner: signer.address, token: currency.address, recipient: dest, amount: amt.toString() }),\n );\n setTxHash(result.txHash);\n return result;\n });\n };\n\n return (\n <main className=\"flex flex-col gap-6 px-5 pb-8 pt-2\">\n <div className=\"flex items-center gap-3\">\n <BackButton onBack={() => onNavigate({ name: \"home\" })} />\n <h1 className=\"font-[family-name:var(--font-display)] text-2xl font-extrabold tracking-tight\">Send</h1>\n </div>\n\n {error && (\n <div className=\"rounded-2xl border border-destructive/40 bg-destructive/10 p-3 text-xs leading-relaxed\">\n <b>Something went wrong.</b> {error}\n </div>\n )}\n\n <div className=\"flex flex-col gap-3\">\n <div>\n <div className=\"flex items-center gap-2\">\n <input\n value={to}\n onChange={(e) => setTo(e.target.value)}\n placeholder=\"Recipient 0x…\"\n spellCheck={false}\n className=\"w-0 flex-1 rounded-2xl border border-border bg-foreground/[0.05] px-4 py-3 font-mono text-sm outline-none transition-colors focus:border-brand-purple\"\n />\n {to.trim() === \"\" && (\n <button\n onClick={pasteRecipient}\n className=\"shrink-0 rounded-2xl border border-border bg-foreground/[0.05] px-3 py-3 text-xs font-semibold text-muted-foreground transition-colors hover:text-foreground\"\n >\n Paste\n </button>\n )}\n </div>\n {to.trim() !== \"\" && !recipientValid && (\n <p className=\"mt-1.5 px-1 text-xs text-destructive\">Not a valid Starknet address.</p>\n )}\n </div>\n\n <div>\n <div className=\"relative\">\n <input\n value={amount}\n onChange={(e) => setAmount(e.target.value.replace(/[^0-9.]/g, \"\"))}\n placeholder=\"0.00\"\n inputMode=\"decimal\"\n className=\"w-full rounded-2xl border border-border bg-foreground/[0.05] px-4 py-3 pr-36 text-sm outline-none transition-colors focus:border-brand-purple\"\n />\n <div className=\"absolute right-2.5 top-1/2 flex -translate-y-1/2 items-center gap-1.5\">\n <button\n onClick={setMax}\n className=\"rounded-full bg-foreground/[0.06] px-2 py-1 text-[11px] font-bold text-muted-foreground transition-colors hover:text-foreground\"\n >\n MAX\n </button>\n <button\n onClick={() => setPickerOpen(true)}\n className=\"flex items-center gap-1.5 rounded-full bg-foreground/[0.06] px-2.5 py-1 text-xs font-semibold\"\n >\n <CurrencyIcon symbol={currency.symbol} size={16} /> {currency.symbol}\n </button>\n </div>\n </div>\n <div className=\"mt-1.5 flex items-center justify-between px-1\">\n <span className=\"text-xs text-muted-foreground\">\n Balance: {currencyBalance != null ? fmt(currencyBalance, currency.decimals) : \"…\"}\n </span>\n {amountOverBalance && <span className=\"text-xs text-destructive\">Amount exceeds balance.</span>}\n </div>\n </div>\n\n <ActionButton\n action=\"offer\"\n big\n onClick={openReview}\n disabled={status === \"processing\" || !composeReady}\n className=\"mt-1 w-full disabled:pointer-events-none disabled:opacity-40\"\n >\n Review Transfer\n </ActionButton>\n <TrustNote>Gas paid from your balance. Transfers are permanent and recorded onchain.</TrustNote>\n </div>\n\n {pickerOpen && (\n <CurrencySheet\n title=\"Choose currency\"\n tokens={WALLET_TOKENS}\n balances={pinnedBalancesBySymbol}\n onSelect={(t) => {\n setCurrency(t);\n setPickerOpen(false);\n }}\n onClose={() => setPickerOpen(false)}\n />\n )}\n\n {confirmOpen && (\n <ActionModal title=\"Review Transfer\" onClose={() => setConfirmOpen(false)}>\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"grid h-10 w-10 shrink-0 place-items-center rounded-full bg-foreground/[0.06]\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z\" />\n </svg>\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"font-semibold\">Send</div>\n <div className=\"truncate font-mono text-xs text-muted-foreground\">To: {short(to.trim())}</div>\n </div>\n </div>\n\n <div className=\"flex items-center gap-3 rounded-2xl bg-foreground/[0.05] p-4\">\n <CurrencyIcon symbol={currency.symbol} size={28} />\n <div className=\"min-w-0 flex-1 font-semibold\">{currency.symbol}</div>\n <div className=\"text-right font-semibold tabular-nums\">\n −{amount.trim()} {currency.symbol}\n </div>\n </div>\n\n <div className=\"flex flex-col divide-y divide-border/40 rounded-2xl bg-foreground/[0.05] px-4\">\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Amount</span>\n <span className=\"font-medium\">{amount.trim()} {currency.symbol}</span>\n </div>\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Recipient</span>\n <span className=\"font-mono font-medium\">{short(to.trim())}</span>\n </div>\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Contract</span>\n <span className=\"font-medium\">{currency.symbol}</span>\n </div>\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Call</span>\n <span className=\"font-medium underline\">transfer</span>\n </div>\n </div>\n\n <div className=\"flex items-center justify-between rounded-2xl border border-border px-4 py-3 text-sm\">\n <span className=\"text-muted-foreground\">Estimated fee</span>\n <span className=\"font-medium\">\n {feeError ? \"Unavailable\" : fee ? `${fmt(fee.raw, 18, 6)} ${fee.unit === \"FRI\" ? \"STRK\" : \"ETH\"}` : \"Estimating…\"}\n </span>\n </div>\n {feeError && <p className=\"px-1 text-xs text-destructive\">Fee estimate failed: {feeError}</p>}\n\n <div className=\"flex gap-3\">\n <button\n onClick={() => setConfirmOpen(false)}\n className=\"flex-1 rounded-2xl border border-border py-3 text-sm font-semibold text-muted-foreground transition-colors hover:text-foreground\"\n >\n Reject\n </button>\n <ActionButton action=\"offer\" big onClick={send} className=\"flex-1\">\n Confirm\n </ActionButton>\n </div>\n </div>\n </ActionModal>\n )}\n\n {status === \"processing\" && <BusyOverlay label=\"Signing & sending…\" />}\n {status === \"success\" && txHash && (\n <SuccessDialog\n title=\"Sent\"\n message={`${amount.trim()} ${currency.symbol} is on its way.`}\n txHash={txHash}\n onClose={() => {\n reset();\n onDone();\n }}\n />\n )}\n </main>\n );\n}\n"],"mappings":"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","names":["import_action_button"]}
@@ -0,0 +1,14 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { WalletToken } from '../../utils/media-wallet/wallet-tokens.cjs';
3
+ import { MediaWalletView } from './types.cjs';
4
+ import 'react';
5
+ import 'starknet';
6
+ import '@medialane/sdk/starknet';
7
+
8
+ declare function MediaWalletSend({ initialToken, onNavigate, onDone, }: {
9
+ initialToken?: WalletToken;
10
+ onNavigate: (view: MediaWalletView) => void;
11
+ onDone: () => void;
12
+ }): react_jsx_runtime.JSX.Element;
13
+
14
+ export { MediaWalletSend };
@@ -0,0 +1,14 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { WalletToken } from '../../utils/media-wallet/wallet-tokens.js';
3
+ import { MediaWalletView } from './types.js';
4
+ import 'react';
5
+ import 'starknet';
6
+ import '@medialane/sdk/starknet';
7
+
8
+ declare function MediaWalletSend({ initialToken, onNavigate, onDone, }: {
9
+ initialToken?: WalletToken;
10
+ onNavigate: (view: MediaWalletView) => void;
11
+ onDone: () => void;
12
+ }): react_jsx_runtime.JSX.Element;
13
+
14
+ export { MediaWalletSend };
@@ -0,0 +1,289 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useState } from "react";
4
+ import { Account, CallData, cairo, validateAndParseAddress } from "starknet";
5
+ import { parseAmount, formatAmount } from "@medialane/sdk";
6
+ import { ActionButton } from "../action-button.js";
7
+ import { CurrencyIcon } from "../currency-icon.js";
8
+ import { describeError } from "../../utils/describe-error.js";
9
+ import { useErc20Balance, useTokenBalance } from "../../utils/media-wallet/use-erc20-balance.js";
10
+ import { fmt, short } from "../../utils/media-wallet/wallet-format.js";
11
+ import { BackButton } from "./back-button.js";
12
+ import { TrustNote } from "./action-button.js";
13
+ import { ActionModal, BusyOverlay } from "./action-modal.js";
14
+ import { CurrencySheet } from "./currency-sheet.js";
15
+ import { WALLET_TOKENS } from "../../utils/media-wallet/wallet-tokens.js";
16
+ import { SuccessDialog } from "./success-dialog.js";
17
+ import { useMediaWalletApp } from "./types.js";
18
+ import { runIntentCalls } from "../../utils/media-wallet/run-intent-calls.js";
19
+ function isValidStarknetAddress(address) {
20
+ try {
21
+ validateAndParseAddress(address.trim());
22
+ return true;
23
+ } catch {
24
+ return false;
25
+ }
26
+ }
27
+ async function estimateSendFee(provider, address, token, to, amountRaw) {
28
+ const account = new Account({ provider, address, signer: "0x1", cairoVersion: "1" });
29
+ const call = {
30
+ contractAddress: token,
31
+ entrypoint: "transfer",
32
+ calldata: CallData.compile({ recipient: to, amount: cairo.uint256(amountRaw) })
33
+ };
34
+ const est = await account.estimateInvokeFee(call);
35
+ return { feeRaw: est.overall_fee, unit: est.unit };
36
+ }
37
+ function MediaWalletSend({
38
+ initialToken,
39
+ onNavigate,
40
+ onDone
41
+ }) {
42
+ const { useWalletSession, provider, getClient, useWriteAction } = useMediaWalletApp();
43
+ const { address } = useWalletSession();
44
+ const { run, status, reset, error } = useWriteAction();
45
+ const [currency, setCurrency] = useState(initialToken ?? WALLET_TOKENS[0]);
46
+ const [pickerOpen, setPickerOpen] = useState(false);
47
+ const strk = useTokenBalance(provider, "STRK", address);
48
+ const eth = useTokenBalance(provider, "ETH", address);
49
+ const usdc = useTokenBalance(provider, "USDC", address);
50
+ const wbtc = useTokenBalance(provider, "WBTC", address);
51
+ const pinnedBalancesBySymbol = {
52
+ STRK: strk.rawBalance,
53
+ ETH: eth.rawBalance,
54
+ USDC: usdc.rawBalance,
55
+ WBTC: wbtc.rawBalance
56
+ };
57
+ const { rawBalance: currencyBalance } = useErc20Balance(provider, currency.address, address);
58
+ const [to, setTo] = useState("");
59
+ const [amount, setAmount] = useState("");
60
+ const [txHash, setTxHash] = useState(null);
61
+ const [confirmOpen, setConfirmOpen] = useState(false);
62
+ const [fee, setFee] = useState(null);
63
+ const [feeError, setFeeError] = useState(null);
64
+ const recipientValid = isValidStarknetAddress(to);
65
+ let amountRaw;
66
+ try {
67
+ amountRaw = amount.trim() ? BigInt(parseAmount(amount.trim(), currency.decimals)) : null;
68
+ } catch {
69
+ amountRaw = null;
70
+ }
71
+ const amountOverBalance = amountRaw != null && currencyBalance != null && amountRaw > currencyBalance;
72
+ const composeReady = recipientValid && amountRaw != null && amountRaw > 0n && !amountOverBalance;
73
+ const pasteRecipient = async () => {
74
+ try {
75
+ const text = await navigator.clipboard.readText();
76
+ if (text) setTo(text.trim());
77
+ } catch {
78
+ }
79
+ };
80
+ const setMax = () => {
81
+ if (currencyBalance == null) return;
82
+ setAmount(formatAmount(currencyBalance.toString(), currency.decimals));
83
+ };
84
+ const openReview = () => {
85
+ if (!address || !composeReady || amountRaw == null) return;
86
+ setFeeError(null);
87
+ setFee(null);
88
+ setConfirmOpen(true);
89
+ estimateSendFee(provider, address, currency.address, to.trim(), amountRaw).then((f) => setFee({ raw: f.feeRaw, unit: f.unit })).catch((e) => setFeeError(describeError(e, "We couldn't estimate the network fee. Please try again.").message));
90
+ };
91
+ const send = async () => {
92
+ if (!composeReady || amountRaw == null) return;
93
+ setConfirmOpen(false);
94
+ const dest = to.trim();
95
+ const amt = amountRaw;
96
+ await run(async (signer) => {
97
+ const result = await runIntentCalls(
98
+ signer,
99
+ () => getClient().api.createTransferTokenIntent({ owner: signer.address, token: currency.address, recipient: dest, amount: amt.toString() })
100
+ );
101
+ setTxHash(result.txHash);
102
+ return result;
103
+ });
104
+ };
105
+ return /* @__PURE__ */ jsxs("main", { className: "flex flex-col gap-6 px-5 pb-8 pt-2", children: [
106
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
107
+ /* @__PURE__ */ jsx(BackButton, { onBack: () => onNavigate({ name: "home" }) }),
108
+ /* @__PURE__ */ jsx("h1", { className: "font-[family-name:var(--font-display)] text-2xl font-extrabold tracking-tight", children: "Send" })
109
+ ] }),
110
+ error && /* @__PURE__ */ jsxs("div", { className: "rounded-2xl border border-destructive/40 bg-destructive/10 p-3 text-xs leading-relaxed", children: [
111
+ /* @__PURE__ */ jsx("b", { children: "Something went wrong." }),
112
+ " ",
113
+ error
114
+ ] }),
115
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
116
+ /* @__PURE__ */ jsxs("div", { children: [
117
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
118
+ /* @__PURE__ */ jsx(
119
+ "input",
120
+ {
121
+ value: to,
122
+ onChange: (e) => setTo(e.target.value),
123
+ placeholder: "Recipient 0x\u2026",
124
+ spellCheck: false,
125
+ className: "w-0 flex-1 rounded-2xl border border-border bg-foreground/[0.05] px-4 py-3 font-mono text-sm outline-none transition-colors focus:border-brand-purple"
126
+ }
127
+ ),
128
+ to.trim() === "" && /* @__PURE__ */ jsx(
129
+ "button",
130
+ {
131
+ onClick: pasteRecipient,
132
+ className: "shrink-0 rounded-2xl border border-border bg-foreground/[0.05] px-3 py-3 text-xs font-semibold text-muted-foreground transition-colors hover:text-foreground",
133
+ children: "Paste"
134
+ }
135
+ )
136
+ ] }),
137
+ to.trim() !== "" && !recipientValid && /* @__PURE__ */ jsx("p", { className: "mt-1.5 px-1 text-xs text-destructive", children: "Not a valid Starknet address." })
138
+ ] }),
139
+ /* @__PURE__ */ jsxs("div", { children: [
140
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
141
+ /* @__PURE__ */ jsx(
142
+ "input",
143
+ {
144
+ value: amount,
145
+ onChange: (e) => setAmount(e.target.value.replace(/[^0-9.]/g, "")),
146
+ placeholder: "0.00",
147
+ inputMode: "decimal",
148
+ className: "w-full rounded-2xl border border-border bg-foreground/[0.05] px-4 py-3 pr-36 text-sm outline-none transition-colors focus:border-brand-purple"
149
+ }
150
+ ),
151
+ /* @__PURE__ */ jsxs("div", { className: "absolute right-2.5 top-1/2 flex -translate-y-1/2 items-center gap-1.5", children: [
152
+ /* @__PURE__ */ jsx(
153
+ "button",
154
+ {
155
+ onClick: setMax,
156
+ className: "rounded-full bg-foreground/[0.06] px-2 py-1 text-[11px] font-bold text-muted-foreground transition-colors hover:text-foreground",
157
+ children: "MAX"
158
+ }
159
+ ),
160
+ /* @__PURE__ */ jsxs(
161
+ "button",
162
+ {
163
+ onClick: () => setPickerOpen(true),
164
+ className: "flex items-center gap-1.5 rounded-full bg-foreground/[0.06] px-2.5 py-1 text-xs font-semibold",
165
+ children: [
166
+ /* @__PURE__ */ jsx(CurrencyIcon, { symbol: currency.symbol, size: 16 }),
167
+ " ",
168
+ currency.symbol
169
+ ]
170
+ }
171
+ )
172
+ ] })
173
+ ] }),
174
+ /* @__PURE__ */ jsxs("div", { className: "mt-1.5 flex items-center justify-between px-1", children: [
175
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
176
+ "Balance: ",
177
+ currencyBalance != null ? fmt(currencyBalance, currency.decimals) : "\u2026"
178
+ ] }),
179
+ amountOverBalance && /* @__PURE__ */ jsx("span", { className: "text-xs text-destructive", children: "Amount exceeds balance." })
180
+ ] })
181
+ ] }),
182
+ /* @__PURE__ */ jsx(
183
+ ActionButton,
184
+ {
185
+ action: "offer",
186
+ big: true,
187
+ onClick: openReview,
188
+ disabled: status === "processing" || !composeReady,
189
+ className: "mt-1 w-full disabled:pointer-events-none disabled:opacity-40",
190
+ children: "Review Transfer"
191
+ }
192
+ ),
193
+ /* @__PURE__ */ jsx(TrustNote, { children: "Gas paid from your balance. Transfers are permanent and recorded onchain." })
194
+ ] }),
195
+ pickerOpen && /* @__PURE__ */ jsx(
196
+ CurrencySheet,
197
+ {
198
+ title: "Choose currency",
199
+ tokens: WALLET_TOKENS,
200
+ balances: pinnedBalancesBySymbol,
201
+ onSelect: (t) => {
202
+ setCurrency(t);
203
+ setPickerOpen(false);
204
+ },
205
+ onClose: () => setPickerOpen(false)
206
+ }
207
+ ),
208
+ confirmOpen && /* @__PURE__ */ jsx(ActionModal, { title: "Review Transfer", onClose: () => setConfirmOpen(false), children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
209
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
210
+ /* @__PURE__ */ jsx("div", { className: "grid h-10 w-10 shrink-0 place-items-center rounded-full bg-foreground/[0.06]", children: /* @__PURE__ */ jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z" }) }) }),
211
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
212
+ /* @__PURE__ */ jsx("div", { className: "font-semibold", children: "Send" }),
213
+ /* @__PURE__ */ jsxs("div", { className: "truncate font-mono text-xs text-muted-foreground", children: [
214
+ "To: ",
215
+ short(to.trim())
216
+ ] })
217
+ ] })
218
+ ] }),
219
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 rounded-2xl bg-foreground/[0.05] p-4", children: [
220
+ /* @__PURE__ */ jsx(CurrencyIcon, { symbol: currency.symbol, size: 28 }),
221
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1 font-semibold", children: currency.symbol }),
222
+ /* @__PURE__ */ jsxs("div", { className: "text-right font-semibold tabular-nums", children: [
223
+ "\u2212",
224
+ amount.trim(),
225
+ " ",
226
+ currency.symbol
227
+ ] })
228
+ ] }),
229
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col divide-y divide-border/40 rounded-2xl bg-foreground/[0.05] px-4", children: [
230
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-3 text-sm", children: [
231
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Amount" }),
232
+ /* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
233
+ amount.trim(),
234
+ " ",
235
+ currency.symbol
236
+ ] })
237
+ ] }),
238
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-3 text-sm", children: [
239
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Recipient" }),
240
+ /* @__PURE__ */ jsx("span", { className: "font-mono font-medium", children: short(to.trim()) })
241
+ ] }),
242
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-3 text-sm", children: [
243
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Contract" }),
244
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: currency.symbol })
245
+ ] }),
246
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-3 text-sm", children: [
247
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Call" }),
248
+ /* @__PURE__ */ jsx("span", { className: "font-medium underline", children: "transfer" })
249
+ ] })
250
+ ] }),
251
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between rounded-2xl border border-border px-4 py-3 text-sm", children: [
252
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Estimated fee" }),
253
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: feeError ? "Unavailable" : fee ? `${fmt(fee.raw, 18, 6)} ${fee.unit === "FRI" ? "STRK" : "ETH"}` : "Estimating\u2026" })
254
+ ] }),
255
+ feeError && /* @__PURE__ */ jsxs("p", { className: "px-1 text-xs text-destructive", children: [
256
+ "Fee estimate failed: ",
257
+ feeError
258
+ ] }),
259
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-3", children: [
260
+ /* @__PURE__ */ jsx(
261
+ "button",
262
+ {
263
+ onClick: () => setConfirmOpen(false),
264
+ className: "flex-1 rounded-2xl border border-border py-3 text-sm font-semibold text-muted-foreground transition-colors hover:text-foreground",
265
+ children: "Reject"
266
+ }
267
+ ),
268
+ /* @__PURE__ */ jsx(ActionButton, { action: "offer", big: true, onClick: send, className: "flex-1", children: "Confirm" })
269
+ ] })
270
+ ] }) }),
271
+ status === "processing" && /* @__PURE__ */ jsx(BusyOverlay, { label: "Signing & sending\u2026" }),
272
+ status === "success" && txHash && /* @__PURE__ */ jsx(
273
+ SuccessDialog,
274
+ {
275
+ title: "Sent",
276
+ message: `${amount.trim()} ${currency.symbol} is on its way.`,
277
+ txHash,
278
+ onClose: () => {
279
+ reset();
280
+ onDone();
281
+ }
282
+ }
283
+ )
284
+ ] });
285
+ }
286
+ export {
287
+ MediaWalletSend
288
+ };
289
+ //# sourceMappingURL=media-wallet-send.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/media-wallet/media-wallet-send.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Account, CallData, cairo, validateAndParseAddress, type Call, type ProviderInterface } from \"starknet\";\nimport { parseAmount, formatAmount } from \"@medialane/sdk\";\nimport { ActionButton } from \"../action-button.js\";\nimport { CurrencyIcon } from \"../currency-icon.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { useErc20Balance, useTokenBalance } from \"../../utils/media-wallet/use-erc20-balance.js\";\nimport { fmt, short } from \"../../utils/media-wallet/wallet-format.js\";\nimport { BackButton } from \"./back-button.js\";\nimport { TrustNote } from \"./action-button.js\";\nimport { ActionModal, BusyOverlay } from \"./action-modal.js\";\nimport { CurrencySheet } from \"./currency-sheet.js\";\nimport { WALLET_TOKENS, type WalletToken } from \"../../utils/media-wallet/wallet-tokens.js\";\nimport { SuccessDialog } from \"./success-dialog.js\";\nimport { useMediaWalletApp, type MediaWalletView } from \"./types.js\";\nimport { runIntentCalls } from \"../../utils/media-wallet/run-intent-calls.js\";\n\nfunction isValidStarknetAddress(address: string): boolean {\n try {\n validateAndParseAddress(address.trim());\n return true;\n } catch {\n return false;\n }\n}\n\nasync function estimateSendFee(provider: ProviderInterface, address: string, token: string, to: string, amountRaw: bigint) {\n const account = new Account({ provider, address, signer: \"0x1\", cairoVersion: \"1\" });\n const call: Call = {\n contractAddress: token,\n entrypoint: \"transfer\",\n calldata: CallData.compile({ recipient: to, amount: cairo.uint256(amountRaw) }),\n };\n const est = await account.estimateInvokeFee(call);\n return { feeRaw: est.overall_fee, unit: est.unit };\n}\n\nexport function MediaWalletSend({\n initialToken,\n onNavigate,\n onDone,\n}: {\n initialToken?: WalletToken;\n onNavigate: (view: MediaWalletView) => void;\n onDone: () => void;\n}) {\n const { useWalletSession, provider, getClient, useWriteAction } = useMediaWalletApp();\n const { address } = useWalletSession();\n const { run, status, reset, error } = useWriteAction();\n\n const [currency, setCurrency] = useState<WalletToken>(initialToken ?? WALLET_TOKENS[0]);\n const [pickerOpen, setPickerOpen] = useState(false);\n const strk = useTokenBalance(provider, \"STRK\", address);\n const eth = useTokenBalance(provider, \"ETH\", address);\n const usdc = useTokenBalance(provider, \"USDC\", address);\n const wbtc = useTokenBalance(provider, \"WBTC\", address);\n \n const pinnedBalancesBySymbol: Record<string, bigint | null> = {\n STRK: strk.rawBalance, ETH: eth.rawBalance, USDC: usdc.rawBalance, WBTC: wbtc.rawBalance,\n };\n const { rawBalance: currencyBalance } = useErc20Balance(provider, currency.address, address);\n\n const [to, setTo] = useState(\"\");\n const [amount, setAmount] = useState(\"\");\n const [txHash, setTxHash] = useState<string | null>(null);\n\n const [confirmOpen, setConfirmOpen] = useState(false);\n const [fee, setFee] = useState<{ raw: bigint; unit: string } | null>(null);\n const [feeError, setFeeError] = useState<string | null>(null);\n\n const recipientValid = isValidStarknetAddress(to);\n let amountRaw: bigint | null;\n try {\n amountRaw = amount.trim() ? BigInt(parseAmount(amount.trim(), currency.decimals)) : null;\n } catch {\n amountRaw = null;\n }\n const amountOverBalance = amountRaw != null && currencyBalance != null && amountRaw > currencyBalance;\n const composeReady = recipientValid && amountRaw != null && amountRaw > 0n && !amountOverBalance;\n\n const pasteRecipient = async () => {\n try {\n const text = await navigator.clipboard.readText();\n if (text) setTo(text.trim());\n } catch {\n\n }\n };\n\n const setMax = () => {\n if (currencyBalance == null) return;\n setAmount(formatAmount(currencyBalance.toString(), currency.decimals));\n };\n\n const openReview = () => {\n if (!address || !composeReady || amountRaw == null) return;\n setFeeError(null);\n setFee(null);\n setConfirmOpen(true);\n estimateSendFee(provider, address, currency.address, to.trim(), amountRaw)\n .then((f) => setFee({ raw: f.feeRaw, unit: f.unit }))\n .catch((e) => setFeeError(describeError(e, \"We couldn't estimate the network fee. Please try again.\").message));\n };\n\n const send = async () => {\n if (!composeReady || amountRaw == null) return;\n setConfirmOpen(false);\n const dest = to.trim();\n const amt = amountRaw;\n await run(async (signer) => {\n const result = await runIntentCalls(signer, () =>\n getClient().api.createTransferTokenIntent({ owner: signer.address, token: currency.address, recipient: dest, amount: amt.toString() }),\n );\n setTxHash(result.txHash);\n return result;\n });\n };\n\n return (\n <main className=\"flex flex-col gap-6 px-5 pb-8 pt-2\">\n <div className=\"flex items-center gap-3\">\n <BackButton onBack={() => onNavigate({ name: \"home\" })} />\n <h1 className=\"font-[family-name:var(--font-display)] text-2xl font-extrabold tracking-tight\">Send</h1>\n </div>\n\n {error && (\n <div className=\"rounded-2xl border border-destructive/40 bg-destructive/10 p-3 text-xs leading-relaxed\">\n <b>Something went wrong.</b> {error}\n </div>\n )}\n\n <div className=\"flex flex-col gap-3\">\n <div>\n <div className=\"flex items-center gap-2\">\n <input\n value={to}\n onChange={(e) => setTo(e.target.value)}\n placeholder=\"Recipient 0x…\"\n spellCheck={false}\n className=\"w-0 flex-1 rounded-2xl border border-border bg-foreground/[0.05] px-4 py-3 font-mono text-sm outline-none transition-colors focus:border-brand-purple\"\n />\n {to.trim() === \"\" && (\n <button\n onClick={pasteRecipient}\n className=\"shrink-0 rounded-2xl border border-border bg-foreground/[0.05] px-3 py-3 text-xs font-semibold text-muted-foreground transition-colors hover:text-foreground\"\n >\n Paste\n </button>\n )}\n </div>\n {to.trim() !== \"\" && !recipientValid && (\n <p className=\"mt-1.5 px-1 text-xs text-destructive\">Not a valid Starknet address.</p>\n )}\n </div>\n\n <div>\n <div className=\"relative\">\n <input\n value={amount}\n onChange={(e) => setAmount(e.target.value.replace(/[^0-9.]/g, \"\"))}\n placeholder=\"0.00\"\n inputMode=\"decimal\"\n className=\"w-full rounded-2xl border border-border bg-foreground/[0.05] px-4 py-3 pr-36 text-sm outline-none transition-colors focus:border-brand-purple\"\n />\n <div className=\"absolute right-2.5 top-1/2 flex -translate-y-1/2 items-center gap-1.5\">\n <button\n onClick={setMax}\n className=\"rounded-full bg-foreground/[0.06] px-2 py-1 text-[11px] font-bold text-muted-foreground transition-colors hover:text-foreground\"\n >\n MAX\n </button>\n <button\n onClick={() => setPickerOpen(true)}\n className=\"flex items-center gap-1.5 rounded-full bg-foreground/[0.06] px-2.5 py-1 text-xs font-semibold\"\n >\n <CurrencyIcon symbol={currency.symbol} size={16} /> {currency.symbol}\n </button>\n </div>\n </div>\n <div className=\"mt-1.5 flex items-center justify-between px-1\">\n <span className=\"text-xs text-muted-foreground\">\n Balance: {currencyBalance != null ? fmt(currencyBalance, currency.decimals) : \"…\"}\n </span>\n {amountOverBalance && <span className=\"text-xs text-destructive\">Amount exceeds balance.</span>}\n </div>\n </div>\n\n <ActionButton\n action=\"offer\"\n big\n onClick={openReview}\n disabled={status === \"processing\" || !composeReady}\n className=\"mt-1 w-full disabled:pointer-events-none disabled:opacity-40\"\n >\n Review Transfer\n </ActionButton>\n <TrustNote>Gas paid from your balance. Transfers are permanent and recorded onchain.</TrustNote>\n </div>\n\n {pickerOpen && (\n <CurrencySheet\n title=\"Choose currency\"\n tokens={WALLET_TOKENS}\n balances={pinnedBalancesBySymbol}\n onSelect={(t) => {\n setCurrency(t);\n setPickerOpen(false);\n }}\n onClose={() => setPickerOpen(false)}\n />\n )}\n\n {confirmOpen && (\n <ActionModal title=\"Review Transfer\" onClose={() => setConfirmOpen(false)}>\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"grid h-10 w-10 shrink-0 place-items-center rounded-full bg-foreground/[0.06]\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z\" />\n </svg>\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"font-semibold\">Send</div>\n <div className=\"truncate font-mono text-xs text-muted-foreground\">To: {short(to.trim())}</div>\n </div>\n </div>\n\n <div className=\"flex items-center gap-3 rounded-2xl bg-foreground/[0.05] p-4\">\n <CurrencyIcon symbol={currency.symbol} size={28} />\n <div className=\"min-w-0 flex-1 font-semibold\">{currency.symbol}</div>\n <div className=\"text-right font-semibold tabular-nums\">\n −{amount.trim()} {currency.symbol}\n </div>\n </div>\n\n <div className=\"flex flex-col divide-y divide-border/40 rounded-2xl bg-foreground/[0.05] px-4\">\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Amount</span>\n <span className=\"font-medium\">{amount.trim()} {currency.symbol}</span>\n </div>\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Recipient</span>\n <span className=\"font-mono font-medium\">{short(to.trim())}</span>\n </div>\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Contract</span>\n <span className=\"font-medium\">{currency.symbol}</span>\n </div>\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Call</span>\n <span className=\"font-medium underline\">transfer</span>\n </div>\n </div>\n\n <div className=\"flex items-center justify-between rounded-2xl border border-border px-4 py-3 text-sm\">\n <span className=\"text-muted-foreground\">Estimated fee</span>\n <span className=\"font-medium\">\n {feeError ? \"Unavailable\" : fee ? `${fmt(fee.raw, 18, 6)} ${fee.unit === \"FRI\" ? \"STRK\" : \"ETH\"}` : \"Estimating…\"}\n </span>\n </div>\n {feeError && <p className=\"px-1 text-xs text-destructive\">Fee estimate failed: {feeError}</p>}\n\n <div className=\"flex gap-3\">\n <button\n onClick={() => setConfirmOpen(false)}\n className=\"flex-1 rounded-2xl border border-border py-3 text-sm font-semibold text-muted-foreground transition-colors hover:text-foreground\"\n >\n Reject\n </button>\n <ActionButton action=\"offer\" big onClick={send} className=\"flex-1\">\n Confirm\n </ActionButton>\n </div>\n </div>\n </ActionModal>\n )}\n\n {status === \"processing\" && <BusyOverlay label=\"Signing & sending…\" />}\n {status === \"success\" && txHash && (\n <SuccessDialog\n title=\"Sent\"\n message={`${amount.trim()} ${currency.symbol} is on its way.`}\n txHash={txHash}\n onClose={() => {\n reset();\n onDone();\n }}\n />\n )}\n </main>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+ "use client";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+ var media_wallet_token_detail_exports = {};
21
+ __export(media_wallet_token_detail_exports, {
22
+ MediaWalletTokenDetail: () => MediaWalletTokenDetail
23
+ });
24
+ module.exports = __toCommonJS(media_wallet_token_detail_exports);
25
+ var import_jsx_runtime = require("react/jsx-runtime");
26
+ var import_react = require("react");
27
+ var import_currency_icon = require("../currency-icon.js");
28
+ var import_sdk = require("@medialane/sdk");
29
+ var import_use_erc20_balance = require("../../utils/media-wallet/use-erc20-balance.js");
30
+ var import_wallet_format = require("../../utils/media-wallet/wallet-format.js");
31
+ var import_wallet_activity = require("../../utils/media-wallet/wallet-activity.js");
32
+ var import_back_button = require("./back-button.js");
33
+ var import_quick_action = require("./quick-action.js");
34
+ var import_section_header = require("./section-header.js");
35
+ var import_wallet_activity_icon = require("./wallet-activity-icon.js");
36
+ var import_use_usd_prices = require("../../utils/use-usd-prices.js");
37
+ var import_types = require("./types.js");
38
+ function MediaWalletTokenDetail({
39
+ token,
40
+ onNavigate
41
+ }) {
42
+ const { useWalletSession, provider, explorerUrl } = (0, import_types.useMediaWalletApp)();
43
+ const { address: walletAddress } = useWalletSession();
44
+ const { rawBalance: bal } = (0, import_use_erc20_balance.useErc20Balance)(provider, token.address, walletAddress);
45
+ const usdPrices = (0, import_use_usd_prices.useUsdPrices)();
46
+ const price = (0, import_use_usd_prices.usdPriceFor)(usdPrices, token.symbol) ?? null;
47
+ const voyager = (0, import_react.useMemo)(() => (0, import_wallet_format.explorerTokenUrl)(explorerUrl, token.address), [explorerUrl, token.address]);
48
+ const heldValue = bal != null && price != null ? (0, import_wallet_format.rawToNumber)(bal, token.decimals) * price : null;
49
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("main", { className: "flex flex-col gap-6 px-5 pb-8 pt-2", children: [
50
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-3", children: [
51
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_back_button.BackButton, { onBack: () => onNavigate({ name: "home" }) }),
52
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-3", children: [
53
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "grid h-11 w-11 shrink-0 place-items-center overflow-hidden rounded-full bg-foreground/[0.06]", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_currency_icon.CurrencyIcon, { symbol: token.symbol, size: 26 }) }),
54
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
55
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "font-[family-name:var(--font-display)] text-lg font-bold leading-none", children: token.name }),
56
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mt-0.5 text-xs text-muted-foreground", children: token.symbol })
57
+ ] })
58
+ ] })
59
+ ] }),
60
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "py-2 text-center", children: [
61
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "font-[family-name:var(--font-display)] text-5xl font-extrabold tracking-tight tabular-nums", children: bal === void 0 ? "\u2026" : bal === null ? "\u2014" : (0, import_wallet_format.fmt)(bal, token.decimals, 6) }),
62
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mt-2 text-sm text-muted-foreground", children: [
63
+ token.symbol,
64
+ " \xB7 ",
65
+ heldValue != null ? (0, import_wallet_format.fmtUsd)(heldValue) : "\u2014"
66
+ ] }),
67
+ price != null && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mt-0.5 text-xs text-muted-foreground", children: [
68
+ (0, import_wallet_format.fmtUsd)(price),
69
+ " per ",
70
+ token.symbol
71
+ ] })
72
+ ] }),
73
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
74
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
75
+ import_quick_action.QuickAction,
76
+ {
77
+ label: "Send",
78
+ action: "offer",
79
+ onClick: () => onNavigate({ name: "send", token }),
80
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.3", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 19V5M5 12l7-7 7 7" }) })
81
+ }
82
+ ),
83
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
84
+ import_quick_action.QuickAction,
85
+ {
86
+ label: "Receive",
87
+ action: "buy",
88
+ onClick: () => onNavigate({ name: "home" }),
89
+ icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.3", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 5v14M19 12l-7 7-7-7" }) })
90
+ }
91
+ )
92
+ ] }),
93
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TokenActivity, { tokenAddress: token.address, walletAddress }),
94
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { children: [
95
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_section_header.SectionHeader, { title: "Details" }),
96
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mt-2 flex flex-col divide-y divide-border/40 rounded-2xl bg-card/40 px-4 backdrop-blur-sm", children: [
97
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
98
+ InfoRow,
99
+ {
100
+ label: "Network",
101
+ value: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "flex items-center gap-2", children: [
102
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "grid h-6 w-6 shrink-0 place-items-center rounded-full bg-foreground/[0.06]", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_currency_icon.CurrencyIcon, { symbol: "STRK", size: 14 }) }),
103
+ "Starknet"
104
+ ] })
105
+ }
106
+ ),
107
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(InfoRow, { label: "Standard", value: "ERC-20" }),
108
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
109
+ InfoRow,
110
+ {
111
+ label: "Contract",
112
+ value: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("a", { href: voyager, target: "_blank", rel: "noopener noreferrer", className: "font-mono text-brand-blue hover:underline", children: [
113
+ (0, import_wallet_format.short)(token.address),
114
+ " \u2197"
115
+ ] })
116
+ }
117
+ )
118
+ ] })
119
+ ] })
120
+ ] });
121
+ }
122
+ function TokenActivity({ tokenAddress, walletAddress }) {
123
+ const { getClient } = (0, import_types.useMediaWalletApp)();
124
+ const [items, setItems] = (0, import_react.useState)(null);
125
+ const [error, setError] = (0, import_react.useState)(false);
126
+ (0, import_react.useEffect)(() => {
127
+ if (!walletAddress) return;
128
+ const normalizedToken = (0, import_sdk.normalizeAddress)("STARKNET", tokenAddress);
129
+ getClient().api.getWalletActivity(walletAddress).then((res) => {
130
+ const filtered = res.data.filter((a) => (a.type === "SEND" || a.type === "RECEIVE") && a.tokenAddress && (0, import_sdk.normalizeAddress)("STARKNET", a.tokenAddress) === normalizedToken).slice(0, 5);
131
+ setItems(filtered);
132
+ }).catch(() => setError(true));
133
+ }, [walletAddress, tokenAddress, getClient]);
134
+ if (error || items && items.length === 0) return null;
135
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { children: [
136
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_section_header.SectionHeader, { title: "Activity" }),
137
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mt-2", children: items === null ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex flex-col gap-2", children: [0, 1].map((i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-16 animate-pulse rounded-2xl bg-foreground/[0.04]" }, i)) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex flex-col gap-2", children: items.map((a) => {
138
+ const subtitle = (0, import_wallet_activity.walletActivitySubtitle)(a);
139
+ const amount = (0, import_wallet_activity.walletActivityAmount)(a);
140
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-3 rounded-2xl bg-card/40 px-4 py-3 backdrop-blur-sm", children: [
141
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_wallet_activity_icon.WalletActivityIcon, { a }),
142
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "min-w-0 flex-1", children: [
143
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "text-sm font-semibold", children: (0, import_wallet_activity.walletActivityTitle)(a) }),
144
+ subtitle && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "truncate text-xs text-muted-foreground", children: subtitle })
145
+ ] }),
146
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "shrink-0 text-right", children: [
147
+ amount && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "text-sm font-semibold tabular-nums", children: amount }),
148
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "text-xs text-muted-foreground", children: (0, import_wallet_format.when)(a.timestamp) })
149
+ ] })
150
+ ] }, a.id);
151
+ }) }) })
152
+ ] });
153
+ }
154
+ function InfoRow({ label, value }) {
155
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between py-3 text-sm", children: [
156
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-muted-foreground", children: label }),
157
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "font-medium", children: value })
158
+ ] });
159
+ }
160
+ // Annotate the CommonJS export names for ESM import in node:
161
+ 0 && (module.exports = {
162
+ MediaWalletTokenDetail
163
+ });
164
+ //# sourceMappingURL=media-wallet-token-detail.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/media-wallet/media-wallet-token-detail.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useState } from \"react\";\nimport type { ApiWalletActivity } from \"@medialane/sdk\";\nimport { CurrencyIcon } from \"../currency-icon.js\";\nimport { normalizeAddress } from \"@medialane/sdk\";\nimport { useErc20Balance } from \"../../utils/media-wallet/use-erc20-balance.js\";\nimport { fmt, fmtUsd, rawToNumber, short, when, explorerTokenUrl } from \"../../utils/media-wallet/wallet-format.js\";\nimport { walletActivityTitle, walletActivitySubtitle, walletActivityAmount } from \"../../utils/media-wallet/wallet-activity.js\";\nimport { BackButton } from \"./back-button.js\";\nimport { QuickAction } from \"./quick-action.js\";\nimport { SectionHeader } from \"./section-header.js\";\nimport { WalletActivityIcon } from \"./wallet-activity-icon.js\";\nimport { useUsdPrices, usdPriceFor } from \"../../utils/use-usd-prices.js\";\nimport type { WalletToken } from \"../../utils/media-wallet/wallet-tokens.js\";\nimport { useMediaWalletApp, type MediaWalletView } from \"./types.js\";\n\nexport function MediaWalletTokenDetail({\n token,\n onNavigate,\n}: {\n token: WalletToken;\n onNavigate: (view: MediaWalletView) => void;\n}) {\n const { useWalletSession, provider, explorerUrl } = useMediaWalletApp();\n const { address: walletAddress } = useWalletSession();\n const { rawBalance: bal } = useErc20Balance(provider, token.address, walletAddress);\n const usdPrices = useUsdPrices();\n const price = usdPriceFor(usdPrices, token.symbol) ?? null;\n\n const voyager = useMemo(() => explorerTokenUrl(explorerUrl, token.address), [explorerUrl, token.address]);\n const heldValue = bal != null && price != null ? rawToNumber(bal, token.decimals) * price : null;\n\n return (\n <main className=\"flex flex-col gap-6 px-5 pb-8 pt-2\">\n <div className=\"flex items-center gap-3\">\n <BackButton onBack={() => onNavigate({ name: \"home\" })} />\n <div className=\"flex items-center gap-3\">\n <div className=\"grid h-11 w-11 shrink-0 place-items-center overflow-hidden rounded-full bg-foreground/[0.06]\">\n <CurrencyIcon symbol={token.symbol} size={26} />\n </div>\n <div>\n <div className=\"font-[family-name:var(--font-display)] text-lg font-bold leading-none\">{token.name}</div>\n <div className=\"mt-0.5 text-xs text-muted-foreground\">{token.symbol}</div>\n </div>\n </div>\n </div>\n\n <section className=\"py-2 text-center\">\n <div className=\"font-[family-name:var(--font-display)] text-5xl font-extrabold tracking-tight tabular-nums\">\n {bal === undefined ? \"…\" : bal === null ? \"—\" : fmt(bal, token.decimals, 6)}\n </div>\n <div className=\"mt-2 text-sm text-muted-foreground\">\n {token.symbol}\n {\" · \"}\n {heldValue != null ? fmtUsd(heldValue) : \"—\"}\n </div>\n {price != null && <div className=\"mt-0.5 text-xs text-muted-foreground\">{fmtUsd(price)} per {token.symbol}</div>}\n </section>\n\n <div className=\"grid grid-cols-2 gap-2\">\n <QuickAction\n label=\"Send\"\n action=\"offer\"\n onClick={() => onNavigate({ name: \"send\", token })}\n icon={<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.3\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M12 19V5M5 12l7-7 7 7\" /></svg>}\n />\n <QuickAction\n label=\"Receive\"\n action=\"buy\"\n onClick={() => onNavigate({ name: \"home\" })}\n icon={<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.3\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M12 5v14M19 12l-7 7-7-7\" /></svg>}\n />\n </div>\n\n <TokenActivity tokenAddress={token.address} walletAddress={walletAddress} />\n\n <section>\n <SectionHeader title=\"Details\" />\n <div className=\"mt-2 flex flex-col divide-y divide-border/40 rounded-2xl bg-card/40 px-4 backdrop-blur-sm\">\n <InfoRow\n label=\"Network\"\n value={\n <span className=\"flex items-center gap-2\">\n <span className=\"grid h-6 w-6 shrink-0 place-items-center rounded-full bg-foreground/[0.06]\">\n <CurrencyIcon symbol=\"STRK\" size={14} />\n </span>\n Starknet\n </span>\n }\n />\n <InfoRow label=\"Standard\" value=\"ERC-20\" />\n <InfoRow\n label=\"Contract\"\n value={\n <a href={voyager} target=\"_blank\" rel=\"noopener noreferrer\" className=\"font-mono text-brand-blue hover:underline\">\n {short(token.address)} ↗\n </a>\n }\n />\n </div>\n </section>\n </main>\n );\n}\n\nfunction TokenActivity({ tokenAddress, walletAddress }: { tokenAddress: string; walletAddress: string | null }) {\n const { getClient } = useMediaWalletApp();\n const [items, setItems] = useState<ApiWalletActivity[] | null>(null);\n const [error, setError] = useState(false);\n\n useEffect(() => {\n if (!walletAddress) return;\n const normalizedToken = normalizeAddress(\"STARKNET\", tokenAddress);\n getClient()\n .api.getWalletActivity(walletAddress)\n .then((res) => {\n const filtered = res.data\n .filter((a) => (a.type === \"SEND\" || a.type === \"RECEIVE\") && a.tokenAddress && normalizeAddress(\"STARKNET\", a.tokenAddress) === normalizedToken)\n .slice(0, 5);\n setItems(filtered);\n })\n .catch(() => setError(true));\n }, [walletAddress, tokenAddress, getClient]);\n\n if (error || (items && items.length === 0)) return null;\n\n return (\n <section>\n <SectionHeader title=\"Activity\" />\n <div className=\"mt-2\">\n {items === null ? (\n <div className=\"flex flex-col gap-2\">\n {[0, 1].map((i) => (\n <div key={i} className=\"h-16 animate-pulse rounded-2xl bg-foreground/[0.04]\" />\n ))}\n </div>\n ) : (\n <div className=\"flex flex-col gap-2\">\n {items.map((a) => {\n const subtitle = walletActivitySubtitle(a);\n const amount = walletActivityAmount(a);\n return (\n <div key={a.id} className=\"flex items-center gap-3 rounded-2xl bg-card/40 px-4 py-3 backdrop-blur-sm\">\n <WalletActivityIcon a={a} />\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-sm font-semibold\">{walletActivityTitle(a)}</div>\n {subtitle && <div className=\"truncate text-xs text-muted-foreground\">{subtitle}</div>}\n </div>\n <div className=\"shrink-0 text-right\">\n {amount && <div className=\"text-sm font-semibold tabular-nums\">{amount}</div>}\n <div className=\"text-xs text-muted-foreground\">{when(a.timestamp)}</div>\n </div>\n </div>\n );\n })}\n </div>\n )}\n </div>\n </section>\n );\n}\n\nfunction InfoRow({ label, value }: { label: string; value: React.ReactNode }) {\n return (\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">{label}</span>\n <span className=\"font-medium\">{value}</span>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,13 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { WalletToken } from '../../utils/media-wallet/wallet-tokens.cjs';
3
+ import { MediaWalletView } from './types.cjs';
4
+ import 'react';
5
+ import 'starknet';
6
+ import '@medialane/sdk/starknet';
7
+
8
+ declare function MediaWalletTokenDetail({ token, onNavigate, }: {
9
+ token: WalletToken;
10
+ onNavigate: (view: MediaWalletView) => void;
11
+ }): react_jsx_runtime.JSX.Element;
12
+
13
+ export { MediaWalletTokenDetail };