@medialane/ui 0.259.0 → 0.261.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.
- package/dist/components/action-button.cjs +7 -2
- package/dist/components/action-button.cjs.map +1 -1
- package/dist/components/action-button.d.cts +2 -1
- package/dist/components/action-button.d.ts +2 -1
- package/dist/components/action-button.js +7 -2
- package/dist/components/action-button.js.map +1 -1
- package/dist/components/activities-feed.cjs +5 -1
- package/dist/components/activities-feed.cjs.map +1 -1
- package/dist/components/activities-feed.js +5 -1
- package/dist/components/activities-feed.js.map +1 -1
- package/dist/components/activity-feed-shell.cjs +3 -1
- package/dist/components/activity-feed-shell.cjs.map +1 -1
- package/dist/components/activity-feed-shell.js +3 -1
- package/dist/components/activity-feed-shell.js.map +1 -1
- package/dist/components/asset-access-cards.cjs +21 -33
- package/dist/components/asset-access-cards.cjs.map +1 -1
- package/dist/components/asset-access-cards.d.cts +3 -3
- package/dist/components/asset-access-cards.d.ts +3 -3
- package/dist/components/asset-access-cards.js +20 -32
- package/dist/components/asset-access-cards.js.map +1 -1
- package/dist/components/asset-marketplace-panel.cjs +44 -41
- package/dist/components/asset-marketplace-panel.cjs.map +1 -1
- package/dist/components/asset-marketplace-panel.js +45 -42
- package/dist/components/asset-marketplace-panel.js.map +1 -1
- package/dist/components/asset-overview-content.cjs +12 -1
- package/dist/components/asset-overview-content.cjs.map +1 -1
- package/dist/components/asset-overview-content.d.cts +3 -1
- package/dist/components/asset-overview-content.d.ts +3 -1
- package/dist/components/asset-overview-content.js +13 -2
- package/dist/components/asset-overview-content.js.map +1 -1
- package/dist/components/asset-page.cjs +8 -6
- package/dist/components/asset-page.cjs.map +1 -1
- package/dist/components/asset-page.js +8 -6
- package/dist/components/asset-page.js.map +1 -1
- package/dist/components/asset-top-sections.cjs +1 -9
- package/dist/components/asset-top-sections.cjs.map +1 -1
- package/dist/components/asset-top-sections.d.cts +1 -2
- package/dist/components/asset-top-sections.d.ts +1 -2
- package/dist/components/asset-top-sections.js +1 -9
- package/dist/components/asset-top-sections.js.map +1 -1
- package/dist/components/coins-explorer.cjs +5 -1
- package/dist/components/coins-explorer.cjs.map +1 -1
- package/dist/components/coins-explorer.js +6 -2
- package/dist/components/coins-explorer.js.map +1 -1
- package/dist/components/comments-section.cjs +2 -2
- package/dist/components/comments-section.cjs.map +1 -1
- package/dist/components/comments-section.js +2 -2
- package/dist/components/comments-section.js.map +1 -1
- package/dist/components/discover-community-section.cjs +5 -1
- package/dist/components/discover-community-section.cjs.map +1 -1
- package/dist/components/discover-community-section.js +5 -1
- package/dist/components/discover-community-section.js.map +1 -1
- package/dist/components/discover-feed-section.cjs +5 -1
- package/dist/components/discover-feed-section.cjs.map +1 -1
- package/dist/components/discover-feed-section.js +5 -1
- package/dist/components/discover-feed-section.js.map +1 -1
- package/dist/components/fast-mint/success-view.cjs +2 -2
- package/dist/components/fast-mint/success-view.cjs.map +1 -1
- package/dist/components/fast-mint/success-view.js +2 -2
- package/dist/components/fast-mint/success-view.js.map +1 -1
- package/dist/components/ip-type-page.cjs +3 -2
- package/dist/components/ip-type-page.cjs.map +1 -1
- package/dist/components/ip-type-page.js +3 -2
- package/dist/components/ip-type-page.js.map +1 -1
- package/dist/components/markdown-text.cjs +53 -0
- package/dist/components/markdown-text.cjs.map +1 -0
- package/dist/components/markdown-text.d.cts +7 -0
- package/dist/components/markdown-text.d.ts +7 -0
- package/dist/components/markdown-text.js +19 -0
- package/dist/components/markdown-text.js.map +1 -0
- package/dist/components/marketplace-dialog-primitives.cjs +1 -1
- package/dist/components/marketplace-dialog-primitives.cjs.map +1 -1
- package/dist/components/marketplace-dialog-primitives.js +1 -1
- package/dist/components/marketplace-dialog-primitives.js.map +1 -1
- package/dist/components/media-wallet/media-wallet-activity.cjs +5 -1
- package/dist/components/media-wallet/media-wallet-activity.cjs.map +1 -1
- package/dist/components/media-wallet/media-wallet-activity.js +5 -1
- package/dist/components/media-wallet/media-wallet-activity.js.map +1 -1
- package/dist/components/media-wallet/media-wallet-home.cjs +3 -2
- package/dist/components/media-wallet/media-wallet-home.cjs.map +1 -1
- package/dist/components/media-wallet/media-wallet-home.js +3 -2
- package/dist/components/media-wallet/media-wallet-home.js.map +1 -1
- package/dist/components/media-wallet/media-wallet-send.cjs +5 -2
- package/dist/components/media-wallet/media-wallet-send.cjs.map +1 -1
- package/dist/components/media-wallet/media-wallet-send.js +5 -2
- package/dist/components/media-wallet/media-wallet-send.js.map +1 -1
- package/dist/components/media-wallet/success-dialog.cjs +5 -11
- package/dist/components/media-wallet/success-dialog.cjs.map +1 -1
- package/dist/components/media-wallet/success-dialog.js +5 -11
- package/dist/components/media-wallet/success-dialog.js.map +1 -1
- package/dist/components/pop-claim-button.cjs +2 -2
- package/dist/components/pop-claim-button.cjs.map +1 -1
- package/dist/components/pop-claim-button.js +2 -2
- package/dist/components/pop-claim-button.js.map +1 -1
- package/dist/components/pop-manage-page.cjs +3 -2
- package/dist/components/pop-manage-page.cjs.map +1 -1
- package/dist/components/pop-manage-page.js +3 -2
- package/dist/components/pop-manage-page.js.map +1 -1
- package/dist/components/portfolio-sponsorships.cjs +14 -7
- package/dist/components/portfolio-sponsorships.cjs.map +1 -1
- package/dist/components/portfolio-sponsorships.js +14 -7
- package/dist/components/portfolio-sponsorships.js.map +1 -1
- package/dist/components/service-collections-page.cjs +2 -2
- package/dist/components/service-collections-page.cjs.map +1 -1
- package/dist/components/service-collections-page.d.cts +2 -2
- package/dist/components/service-collections-page.d.ts +2 -2
- package/dist/components/service-collections-page.js +2 -2
- package/dist/components/service-collections-page.js.map +1 -1
- package/dist/components/sponsorship-offer-page.cjs +4 -4
- package/dist/components/sponsorship-offer-page.cjs.map +1 -1
- package/dist/components/sponsorship-offer-page.js +4 -4
- package/dist/components/sponsorship-offer-page.js.map +1 -1
- package/dist/components/transaction-success.cjs +2 -5
- package/dist/components/transaction-success.cjs.map +1 -1
- package/dist/components/transaction-success.js +3 -6
- package/dist/components/transaction-success.js.map +1 -1
- package/dist/components/transfer-collection-ownership.cjs +2 -5
- package/dist/components/transfer-collection-ownership.cjs.map +1 -1
- package/dist/components/transfer-collection-ownership.js +2 -5
- package/dist/components/transfer-collection-ownership.js.map +1 -1
- package/dist/index.cjs +3 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/empty-messages.cjs +62 -0
- package/dist/utils/empty-messages.cjs.map +1 -0
- package/dist/utils/empty-messages.d.cts +40 -0
- package/dist/utils/empty-messages.d.ts +40 -0
- package/dist/utils/empty-messages.js +38 -0
- package/dist/utils/empty-messages.js.map +1 -0
- package/dist/utils/success-messages.cjs +52 -0
- package/dist/utils/success-messages.cjs.map +1 -1
- package/dist/utils/success-messages.d.cts +27 -0
- package/dist/utils/success-messages.d.ts +27 -0
- package/dist/utils/success-messages.js +52 -0
- package/dist/utils/success-messages.js.map +1 -1
- package/package.json +3 -1
|
@@ -1 +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/run-intent-calls.js\";\nimport { useMedialaneApp } from \"../medialane-app.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, useWriteAction } = useMediaWalletApp();\n const { getClient } = useMedialaneApp();\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(\"STRK\", address);\n const eth = useTokenBalance(\"ETH\", address);\n const usdc = useTokenBalance(\"USDC\", address);\n const wbtc = useTokenBalance(\"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(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(getClient().provider, address, currency.address, to.trim(), amountRaw)\n .then((f) => setFee({ raw: f.feeRaw, unit: f.unit }))\n .catch((e) => setFeeError(describeError(e).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.intents.create(\"transfer-token\", { 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 {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-2xs 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"]}
|
|
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 { shortenAddress } from \"../../utils/address.js\";\nimport { runIntentCalls } from \"../../utils/run-intent-calls.js\";\nimport { successMessages } from \"../../utils/success-messages.js\";\nimport { useMedialaneApp } from \"../medialane-app.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, useWriteAction } = useMediaWalletApp();\n const { getClient } = useMedialaneApp();\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(\"STRK\", address);\n const eth = useTokenBalance(\"ETH\", address);\n const usdc = useTokenBalance(\"USDC\", address);\n const wbtc = useTokenBalance(\"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(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 const sentMessage = successMessages.sent({ amount: amount.trim(), symbol: currency.symbol, to: shortenAddress(to.trim()) });\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(getClient().provider, address, currency.address, to.trim(), amountRaw)\n .then((f) => setFee({ raw: f.feeRaw, unit: f.unit }))\n .catch((e) => setFeeError(describeError(e).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.intents.create(\"transfer-token\", { 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 {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-2xs 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={sentMessage.title}\n message={sentMessage.description}\n txHash={txHash}\n onClose={() => {\n reset();\n onDone();\n }}\n />\n )}\n </main>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA+HM;AA7HN,mBAAyB;AACzB,sBAAqG;AACrG,iBAA0C;AAC1C,2BAA6B;AAC7B,2BAA6B;AAC7B,4BAA8B;AAC9B,+BAAiD;AACjD,2BAA2B;AAC3B,yBAA2B;AAC3B,IAAAA,wBAA0B;AAC1B,0BAAyC;AACzC,4BAA8B;AAC9B,2BAAgD;AAChD,4BAA8B;AAC9B,mBAAwD;AACxD,qBAA+B;AAC/B,8BAA+B;AAC/B,8BAAgC;AAChC,2BAAgC;AAEhC,SAAS,uBAAuB,SAA0B;AACxD,MAAI;AACF,iDAAwB,QAAQ,KAAK,CAAC;AACtC,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAe,gBAAgB,UAA6B,SAAiB,OAAe,IAAY,WAAmB;AACzH,QAAM,UAAU,IAAI,wBAAQ,EAAE,UAAU,SAAS,QAAQ,OAAO,cAAc,IAAI,CAAC;AACnF,QAAM,OAAa;AAAA,IACjB,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU,yBAAS,QAAQ,EAAE,WAAW,IAAI,QAAQ,sBAAM,QAAQ,SAAS,EAAE,CAAC;AAAA,EAChF;AACA,QAAM,MAAM,MAAM,QAAQ,kBAAkB,IAAI;AAChD,SAAO,EAAE,QAAQ,IAAI,aAAa,MAAM,IAAI,KAAK;AACnD;AAEO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,EAAE,kBAAkB,eAAe,QAAI,gCAAkB;AAC/D,QAAM,EAAE,UAAU,QAAI,sCAAgB;AACtC,QAAM,EAAE,QAAQ,IAAI,iBAAiB;AACrC,QAAM,EAAE,KAAK,QAAQ,OAAO,MAAM,IAAI,eAAe;AAErD,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAsB,gBAAgB,mCAAc,CAAC,CAAC;AACtF,QAAM,CAAC,YAAY,aAAa,QAAI,uBAAS,KAAK;AAClD,QAAM,WAAO,0CAAgB,QAAQ,OAAO;AAC5C,QAAM,UAAM,0CAAgB,OAAO,OAAO;AAC1C,QAAM,WAAO,0CAAgB,QAAQ,OAAO;AAC5C,QAAM,WAAO,0CAAgB,QAAQ,OAAO;AAE5C,QAAM,yBAAwD;AAAA,IAC5D,MAAM,KAAK;AAAA,IAAY,KAAK,IAAI;AAAA,IAAY,MAAM,KAAK;AAAA,IAAY,MAAM,KAAK;AAAA,EAChF;AACA,QAAM,EAAE,YAAY,gBAAgB,QAAI,0CAAgB,SAAS,SAAS,OAAO;AAEjF,QAAM,CAAC,IAAI,KAAK,QAAI,uBAAS,EAAE;AAC/B,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAS,EAAE;AACvC,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAwB,IAAI;AAExD,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAS,KAAK;AACpD,QAAM,CAAC,KAAK,MAAM,QAAI,uBAA+C,IAAI;AACzE,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAwB,IAAI;AAE5D,QAAM,iBAAiB,uBAAuB,EAAE;AAChD,QAAM,cAAc,wCAAgB,KAAK,EAAE,QAAQ,OAAO,KAAK,GAAG,QAAQ,SAAS,QAAQ,QAAI,+BAAe,GAAG,KAAK,CAAC,EAAE,CAAC;AAC1H,MAAI;AACJ,MAAI;AACF,gBAAY,OAAO,KAAK,IAAI,WAAO,wBAAY,OAAO,KAAK,GAAG,SAAS,QAAQ,CAAC,IAAI;AAAA,EACtF,QAAQ;AACN,gBAAY;AAAA,EACd;AACA,QAAM,oBAAoB,aAAa,QAAQ,mBAAmB,QAAQ,YAAY;AACtF,QAAM,eAAe,kBAAkB,aAAa,QAAQ,YAAY,MAAM,CAAC;AAE/E,QAAM,iBAAiB,YAAY;AACjC,QAAI;AACF,YAAM,OAAO,MAAM,UAAU,UAAU,SAAS;AAChD,UAAI,KAAM,OAAM,KAAK,KAAK,CAAC;AAAA,IAC7B,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,QAAM,SAAS,MAAM;AACnB,QAAI,mBAAmB,KAAM;AAC7B,kBAAU,yBAAa,gBAAgB,SAAS,GAAG,SAAS,QAAQ,CAAC;AAAA,EACvE;AAEA,QAAM,aAAa,MAAM;AACvB,QAAI,CAAC,WAAW,CAAC,gBAAgB,aAAa,KAAM;AACpD,gBAAY,IAAI;AAChB,WAAO,IAAI;AACX,mBAAe,IAAI;AACnB,oBAAgB,UAAU,EAAE,UAAU,SAAS,SAAS,SAAS,GAAG,KAAK,GAAG,SAAS,EAClF,KAAK,CAAC,MAAM,OAAO,EAAE,KAAK,EAAE,QAAQ,MAAM,EAAE,KAAK,CAAC,CAAC,EACnD,MAAM,CAAC,MAAM,gBAAY,qCAAc,CAAC,EAAE,OAAO,CAAC;AAAA,EACvD;AAEA,QAAM,OAAO,YAAY;AACvB,QAAI,CAAC,gBAAgB,aAAa,KAAM;AACxC,mBAAe,KAAK;AACpB,UAAM,OAAO,GAAG,KAAK;AACrB,UAAM,MAAM;AACZ,UAAM,IAAI,OAAO,WAAW;AAC1B,YAAM,SAAS,UAAM;AAAA,QAAe;AAAA,QAAQ,MAC1C,UAAU,EAAE,IAAI,QAAQ,OAAO,kBAAkB,EAAE,OAAO,OAAO,SAAS,OAAO,SAAS,SAAS,WAAW,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;AAAA,MAC9I;AACA,gBAAU,OAAO,MAAM;AACvB,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,SACE,6CAAC,UAAK,WAAU,sCACd;AAAA,iDAAC,SAAI,WAAU,2BACb;AAAA,kDAAC,iCAAW,QAAQ,MAAM,WAAW,EAAE,MAAM,OAAO,CAAC,GAAG;AAAA,MACxD,4CAAC,QAAG,WAAU,iFAAgF,kBAAI;AAAA,OACpG;AAAA,IAEC,SACC,4CAAC,SAAI,WAAU,0FACZ,iBACH;AAAA,IAGF,6CAAC,SAAI,WAAU,uBACb;AAAA,mDAAC,SACC;AAAA,qDAAC,SAAI,WAAU,2BACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,MAAM,EAAE,OAAO,KAAK;AAAA,cACrC,aAAY;AAAA,cACZ,YAAY;AAAA,cACZ,WAAU;AAAA;AAAA,UACZ;AAAA,UACC,GAAG,KAAK,MAAM,MACb;AAAA,YAAC;AAAA;AAAA,cACC,SAAS;AAAA,cACT,WAAU;AAAA,cACX;AAAA;AAAA,UAED;AAAA,WAEJ;AAAA,QACC,GAAG,KAAK,MAAM,MAAM,CAAC,kBACpB,4CAAC,OAAE,WAAU,wCAAuC,2CAA6B;AAAA,SAErF;AAAA,MAEA,6CAAC,SACC;AAAA,qDAAC,SAAI,WAAU,YACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,UAAU,EAAE,OAAO,MAAM,QAAQ,YAAY,EAAE,CAAC;AAAA,cACjE,aAAY;AAAA,cACZ,WAAU;AAAA,cACV,WAAU;AAAA;AAAA,UACZ;AAAA,UACA,6CAAC,SAAI,WAAU,yEACb;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,SAAS;AAAA,gBACT,WAAU;AAAA,gBACX;AAAA;AAAA,YAED;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,SAAS,MAAM,cAAc,IAAI;AAAA,gBACjC,WAAU;AAAA,gBAEV;AAAA,8DAAC,qCAAa,QAAQ,SAAS,QAAQ,MAAM,IAAI;AAAA,kBAAE;AAAA,kBAAE,SAAS;AAAA;AAAA;AAAA,YAChE;AAAA,aACF;AAAA,WACF;AAAA,QACA,6CAAC,SAAI,WAAU,iDACb;AAAA,uDAAC,UAAK,WAAU,iCAAgC;AAAA;AAAA,YACpC,mBAAmB,WAAO,0BAAI,iBAAiB,SAAS,QAAQ,IAAI;AAAA,aAChF;AAAA,UACC,qBAAqB,4CAAC,UAAK,WAAU,4BAA2B,qCAAuB;AAAA,WAC1F;AAAA,SACF;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,QAAO;AAAA,UACP,KAAG;AAAA,UACH,SAAS;AAAA,UACT,UAAU,WAAW,gBAAgB,CAAC;AAAA,UACtC,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,MACA,4CAAC,mCAAU,uFAAyE;AAAA,OACtF;AAAA,IAEC,cACC;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,UAAU,CAAC,MAAM;AACf,sBAAY,CAAC;AACb,wBAAc,KAAK;AAAA,QACrB;AAAA,QACA,SAAS,MAAM,cAAc,KAAK;AAAA;AAAA,IACpC;AAAA,IAGD,eACC,4CAAC,mCAAY,OAAM,mBAAkB,SAAS,MAAM,eAAe,KAAK,GACtE,uDAAC,SAAI,WAAU,uBACb;AAAA,mDAAC,SAAI,WAAU,2BACb;AAAA,oDAAC,SAAI,WAAU,gFACb,sDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI,sDAAC,UAAK,GAAE,wCAAuC,GACjD,GACF;AAAA,QACA,6CAAC,SAAI,WAAU,kBACb;AAAA,sDAAC,SAAI,WAAU,iBAAgB,kBAAI;AAAA,UACnC,6CAAC,SAAI,WAAU,oDAAmD;AAAA;AAAA,gBAAK,4BAAM,GAAG,KAAK,CAAC;AAAA,aAAE;AAAA,WAC1F;AAAA,SACF;AAAA,MAEA,6CAAC,SAAI,WAAU,gEACb;AAAA,oDAAC,qCAAa,QAAQ,SAAS,QAAQ,MAAM,IAAI;AAAA,QACjD,4CAAC,SAAI,WAAU,gCAAgC,mBAAS,QAAO;AAAA,QAC/D,6CAAC,SAAI,WAAU,yCAAwC;AAAA;AAAA,UACnD,OAAO,KAAK;AAAA,UAAE;AAAA,UAAE,SAAS;AAAA,WAC7B;AAAA,SACF;AAAA,MAEA,6CAAC,SAAI,WAAU,iFACb;AAAA,qDAAC,SAAI,WAAU,kDACb;AAAA,sDAAC,UAAK,WAAU,yBAAwB,oBAAM;AAAA,UAC9C,6CAAC,UAAK,WAAU,eAAe;AAAA,mBAAO,KAAK;AAAA,YAAE;AAAA,YAAE,SAAS;AAAA,aAAO;AAAA,WACjE;AAAA,QACA,6CAAC,SAAI,WAAU,kDACb;AAAA,sDAAC,UAAK,WAAU,yBAAwB,uBAAS;AAAA,UACjD,4CAAC,UAAK,WAAU,yBAAyB,0CAAM,GAAG,KAAK,CAAC,GAAE;AAAA,WAC5D;AAAA,QACA,6CAAC,SAAI,WAAU,kDACb;AAAA,sDAAC,UAAK,WAAU,yBAAwB,sBAAQ;AAAA,UAChD,4CAAC,UAAK,WAAU,eAAe,mBAAS,QAAO;AAAA,WACjD;AAAA,QACA,6CAAC,SAAI,WAAU,kDACb;AAAA,sDAAC,UAAK,WAAU,yBAAwB,kBAAI;AAAA,UAC5C,4CAAC,UAAK,WAAU,yBAAwB,sBAAQ;AAAA,WAClD;AAAA,SACF;AAAA,MAEA,6CAAC,SAAI,WAAU,wFACb;AAAA,oDAAC,UAAK,WAAU,yBAAwB,2BAAa;AAAA,QACrD,4CAAC,UAAK,WAAU,eACb,qBAAW,gBAAgB,MAAM,OAAG,0BAAI,IAAI,KAAK,IAAI,CAAC,CAAC,IAAI,IAAI,SAAS,QAAQ,SAAS,KAAK,KAAK,oBACtG;AAAA,SACF;AAAA,MACC,YAAY,6CAAC,OAAE,WAAU,iCAAgC;AAAA;AAAA,QAAsB;AAAA,SAAS;AAAA,MAEzF,6CAAC,SAAI,WAAU,cACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,SAAS,MAAM,eAAe,KAAK;AAAA,YACnC,WAAU;AAAA,YACX;AAAA;AAAA,QAED;AAAA,QACA,4CAAC,qCAAa,QAAO,SAAQ,KAAG,MAAC,SAAS,MAAM,WAAU,UAAS,qBAEnE;AAAA,SACF;AAAA,OACF,GACF;AAAA,IAGD,WAAW,gBAAgB,4CAAC,mCAAY,OAAM,2BAAqB;AAAA,IACnE,WAAW,aAAa,UACvB;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,YAAY;AAAA,QACnB,SAAS,YAAY;AAAA,QACrB;AAAA,QACA,SAAS,MAAM;AACb,gBAAM;AACN,iBAAO;AAAA,QACT;AAAA;AAAA,IACF;AAAA,KAEJ;AAEJ;","names":["import_action_button"]}
|
|
@@ -15,7 +15,9 @@ import { CurrencySheet } from "./currency-sheet.js";
|
|
|
15
15
|
import { WALLET_TOKENS } from "../../utils/media-wallet/wallet-tokens.js";
|
|
16
16
|
import { SuccessDialog } from "./success-dialog.js";
|
|
17
17
|
import { useMediaWalletApp } from "./types.js";
|
|
18
|
+
import { shortenAddress } from "../../utils/address.js";
|
|
18
19
|
import { runIntentCalls } from "../../utils/run-intent-calls.js";
|
|
20
|
+
import { successMessages } from "../../utils/success-messages.js";
|
|
19
21
|
import { useMedialaneApp } from "../medialane-app.js";
|
|
20
22
|
function isValidStarknetAddress(address) {
|
|
21
23
|
try {
|
|
@@ -64,6 +66,7 @@ function MediaWalletSend({
|
|
|
64
66
|
const [fee, setFee] = useState(null);
|
|
65
67
|
const [feeError, setFeeError] = useState(null);
|
|
66
68
|
const recipientValid = isValidStarknetAddress(to);
|
|
69
|
+
const sentMessage = successMessages.sent({ amount: amount.trim(), symbol: currency.symbol, to: shortenAddress(to.trim()) });
|
|
67
70
|
let amountRaw;
|
|
68
71
|
try {
|
|
69
72
|
amountRaw = amount.trim() ? BigInt(parseAmount(amount.trim(), currency.decimals)) : null;
|
|
@@ -270,8 +273,8 @@ function MediaWalletSend({
|
|
|
270
273
|
status === "success" && txHash && /* @__PURE__ */ jsx(
|
|
271
274
|
SuccessDialog,
|
|
272
275
|
{
|
|
273
|
-
title:
|
|
274
|
-
message:
|
|
276
|
+
title: sentMessage.title,
|
|
277
|
+
message: sentMessage.description,
|
|
275
278
|
txHash,
|
|
276
279
|
onClose: () => {
|
|
277
280
|
reset();
|
|
@@ -1 +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/run-intent-calls.js\";\nimport { useMedialaneApp } from \"../medialane-app.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, useWriteAction } = useMediaWalletApp();\n const { getClient } = useMedialaneApp();\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(\"STRK\", address);\n const eth = useTokenBalance(\"ETH\", address);\n const usdc = useTokenBalance(\"USDC\", address);\n const wbtc = useTokenBalance(\"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(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(getClient().provider, address, currency.address, to.trim(), amountRaw)\n .then((f) => setFee({ raw: f.feeRaw, unit: f.unit }))\n .catch((e) => setFeeError(describeError(e).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.intents.create(\"transfer-token\", { 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 {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-2xs 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":[]}
|
|
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 { shortenAddress } from \"../../utils/address.js\";\nimport { runIntentCalls } from \"../../utils/run-intent-calls.js\";\nimport { successMessages } from \"../../utils/success-messages.js\";\nimport { useMedialaneApp } from \"../medialane-app.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, useWriteAction } = useMediaWalletApp();\n const { getClient } = useMedialaneApp();\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(\"STRK\", address);\n const eth = useTokenBalance(\"ETH\", address);\n const usdc = useTokenBalance(\"USDC\", address);\n const wbtc = useTokenBalance(\"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(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 const sentMessage = successMessages.sent({ amount: amount.trim(), symbol: currency.symbol, to: shortenAddress(to.trim()) });\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(getClient().provider, address, currency.address, to.trim(), amountRaw)\n .then((f) => setFee({ raw: f.feeRaw, unit: f.unit }))\n .catch((e) => setFeeError(describeError(e).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.intents.create(\"transfer-token\", { 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 {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-2xs 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={sentMessage.title}\n message={sentMessage.description}\n txHash={txHash}\n onClose={() => {\n reset();\n onDone();\n }}\n />\n )}\n </main>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -44,16 +44,10 @@ function SuccessDialog({
|
|
|
44
44
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_action_modal.CanvasPortal, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "absolute inset-0 z-[70] grid place-items-center p-6", onClick: onClose, children: [
|
|
45
45
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_action_modal.ActionBackdrop, {}),
|
|
46
46
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "card-base relative z-10 w-full max-w-[320px] p-6 text-center", onClick: (e) => e.stopPropagation(), children: [
|
|
47
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
48
|
-
"
|
|
49
|
-
{
|
|
50
|
-
|
|
51
|
-
style: { background: BRAND_GRADIENT },
|
|
52
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "30", height: "30", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.6", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M20 6L9 17l-5-5" }) })
|
|
53
|
-
}
|
|
54
|
-
),
|
|
55
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "mt-4 font-[family-name:var(--font-display)] text-xl font-extrabold tracking-tight", children: title }),
|
|
56
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "mt-1.5 text-sm leading-relaxed text-muted-foreground", children: message }),
|
|
47
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { role: "status", children: [
|
|
48
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "font-[family-name:var(--font-display)] text-xl font-extrabold tracking-tight", children: title }),
|
|
49
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "mt-1.5 text-sm leading-relaxed text-muted-foreground", children: message })
|
|
50
|
+
] }),
|
|
57
51
|
txHash && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
58
52
|
"a",
|
|
59
53
|
{
|
|
@@ -61,7 +55,7 @@ function SuccessDialog({
|
|
|
61
55
|
target: "_blank",
|
|
62
56
|
rel: "noopener noreferrer",
|
|
63
57
|
className: "mt-3 inline-block text-xs text-brand-blue hover:underline",
|
|
64
|
-
children: "View
|
|
58
|
+
children: "View transaction \u2197"
|
|
65
59
|
}
|
|
66
60
|
),
|
|
67
61
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_action_button.ActionButton, { big: true, onClick: onClose, className: "mt-5 w-full", style: { "--ml-grad": BRAND_GRADIENT }, children: actionLabel })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/media-wallet/success-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect } from \"react\";\nimport { ActionButton } from \"../action-button.js\";\nimport { ActionBackdrop, CanvasPortal } from \"./action-modal.js\";\nimport { fireConfetti } from \"../../utils/media-wallet/confetti.js\";\nimport { explorerTxUrl } from \"../../utils/media-wallet/wallet-format.js\";\nimport { useMediaWalletApp } from \"./types.js\";\n\nconst BRAND_GRADIENT = \"linear-gradient(115deg, #3b7bff, #8a5cf6, #f6608f, #fb8b46, #3b7bff)\";\n\nexport function SuccessDialog({\n title,\n message,\n actionLabel = \"Done\",\n txHash,\n onClose,\n}: {\n title: string;\n message: string;\n actionLabel?: string;\n txHash?: string;\n onClose: () => void;\n}) {\n const { explorerUrl } = useMediaWalletApp();\n useEffect(() => {\n fireConfetti();\n }, []);\n return (\n <CanvasPortal>\n <div className=\"absolute inset-0 z-[70] grid place-items-center p-6\" onClick={onClose}>\n <ActionBackdrop />\n <div className=\"card-base relative z-10 w-full max-w-[320px] p-6 text-center\" onClick={(e) => e.stopPropagation()}>\n <div
|
|
1
|
+
{"version":3,"sources":["../../../src/components/media-wallet/success-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect } from \"react\";\nimport { ActionButton } from \"../action-button.js\";\nimport { ActionBackdrop, CanvasPortal } from \"./action-modal.js\";\nimport { fireConfetti } from \"../../utils/media-wallet/confetti.js\";\nimport { explorerTxUrl } from \"../../utils/media-wallet/wallet-format.js\";\nimport { useMediaWalletApp } from \"./types.js\";\n\nconst BRAND_GRADIENT = \"linear-gradient(115deg, #3b7bff, #8a5cf6, #f6608f, #fb8b46, #3b7bff)\";\n\nexport function SuccessDialog({\n title,\n message,\n actionLabel = \"Done\",\n txHash,\n onClose,\n}: {\n title: string;\n message: string;\n actionLabel?: string;\n txHash?: string;\n onClose: () => void;\n}) {\n const { explorerUrl } = useMediaWalletApp();\n useEffect(() => {\n fireConfetti();\n }, []);\n return (\n <CanvasPortal>\n <div className=\"absolute inset-0 z-[70] grid place-items-center p-6\" onClick={onClose}>\n <ActionBackdrop />\n <div className=\"card-base relative z-10 w-full max-w-[320px] p-6 text-center\" onClick={(e) => e.stopPropagation()}>\n <div role=\"status\">\n <h2 className=\"font-[family-name:var(--font-display)] text-xl font-extrabold tracking-tight\">{title}</h2>\n <p className=\"mt-1.5 text-sm leading-relaxed text-muted-foreground\">{message}</p>\n </div>\n {txHash && (\n <a\n href={explorerTxUrl(explorerUrl, txHash)}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"mt-3 inline-block text-xs text-brand-blue hover:underline\"\n >\n View transaction ↗\n </a>\n )}\n <ActionButton big onClick={onClose} className=\"mt-5 w-full\" style={{ \"--ml-grad\": BRAND_GRADIENT } as React.CSSProperties}>\n {actionLabel}\n </ActionButton>\n </div>\n </div>\n </CanvasPortal>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA+BQ;AA7BR,mBAA0B;AAC1B,2BAA6B;AAC7B,0BAA6C;AAC7C,sBAA6B;AAC7B,2BAA8B;AAC9B,mBAAkC;AAElC,MAAM,iBAAiB;AAEhB,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA;AACF,GAMG;AACD,QAAM,EAAE,YAAY,QAAI,gCAAkB;AAC1C,8BAAU,MAAM;AACd,sCAAa;AAAA,EACf,GAAG,CAAC,CAAC;AACL,SACE,4CAAC,oCACC,uDAAC,SAAI,WAAU,uDAAsD,SAAS,SAC5E;AAAA,gDAAC,sCAAe;AAAA,IAChB,6CAAC,SAAI,WAAU,gEAA+D,SAAS,CAAC,MAAM,EAAE,gBAAgB,GAC9G;AAAA,mDAAC,SAAI,MAAK,UACR;AAAA,oDAAC,QAAG,WAAU,gFAAgF,iBAAM;AAAA,QACpG,4CAAC,OAAE,WAAU,wDAAwD,mBAAQ;AAAA,SAC/E;AAAA,MACC,UACC;AAAA,QAAC;AAAA;AAAA,UACC,UAAM,oCAAc,aAAa,MAAM;AAAA,UACvC,QAAO;AAAA,UACP,KAAI;AAAA,UACJ,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,MAEF,4CAAC,qCAAa,KAAG,MAAC,SAAS,SAAS,WAAU,eAAc,OAAO,EAAE,aAAa,eAAe,GAC9F,uBACH;AAAA,OACF;AAAA,KACF,GACF;AAEJ;","names":[]}
|
|
@@ -21,16 +21,10 @@ function SuccessDialog({
|
|
|
21
21
|
return /* @__PURE__ */ jsx(CanvasPortal, { children: /* @__PURE__ */ jsxs("div", { className: "absolute inset-0 z-[70] grid place-items-center p-6", onClick: onClose, children: [
|
|
22
22
|
/* @__PURE__ */ jsx(ActionBackdrop, {}),
|
|
23
23
|
/* @__PURE__ */ jsxs("div", { className: "card-base relative z-10 w-full max-w-[320px] p-6 text-center", onClick: (e) => e.stopPropagation(), children: [
|
|
24
|
-
/* @__PURE__ */
|
|
25
|
-
"
|
|
26
|
-
{
|
|
27
|
-
|
|
28
|
-
style: { background: BRAND_GRADIENT },
|
|
29
|
-
children: /* @__PURE__ */ jsx("svg", { width: "30", height: "30", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.6", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M20 6L9 17l-5-5" }) })
|
|
30
|
-
}
|
|
31
|
-
),
|
|
32
|
-
/* @__PURE__ */ jsx("h2", { className: "mt-4 font-[family-name:var(--font-display)] text-xl font-extrabold tracking-tight", children: title }),
|
|
33
|
-
/* @__PURE__ */ jsx("p", { className: "mt-1.5 text-sm leading-relaxed text-muted-foreground", children: message }),
|
|
24
|
+
/* @__PURE__ */ jsxs("div", { role: "status", children: [
|
|
25
|
+
/* @__PURE__ */ jsx("h2", { className: "font-[family-name:var(--font-display)] text-xl font-extrabold tracking-tight", children: title }),
|
|
26
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1.5 text-sm leading-relaxed text-muted-foreground", children: message })
|
|
27
|
+
] }),
|
|
34
28
|
txHash && /* @__PURE__ */ jsx(
|
|
35
29
|
"a",
|
|
36
30
|
{
|
|
@@ -38,7 +32,7 @@ function SuccessDialog({
|
|
|
38
32
|
target: "_blank",
|
|
39
33
|
rel: "noopener noreferrer",
|
|
40
34
|
className: "mt-3 inline-block text-xs text-brand-blue hover:underline",
|
|
41
|
-
children: "View
|
|
35
|
+
children: "View transaction \u2197"
|
|
42
36
|
}
|
|
43
37
|
),
|
|
44
38
|
/* @__PURE__ */ jsx(ActionButton, { big: true, onClick: onClose, className: "mt-5 w-full", style: { "--ml-grad": BRAND_GRADIENT }, children: actionLabel })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/media-wallet/success-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect } from \"react\";\nimport { ActionButton } from \"../action-button.js\";\nimport { ActionBackdrop, CanvasPortal } from \"./action-modal.js\";\nimport { fireConfetti } from \"../../utils/media-wallet/confetti.js\";\nimport { explorerTxUrl } from \"../../utils/media-wallet/wallet-format.js\";\nimport { useMediaWalletApp } from \"./types.js\";\n\nconst BRAND_GRADIENT = \"linear-gradient(115deg, #3b7bff, #8a5cf6, #f6608f, #fb8b46, #3b7bff)\";\n\nexport function SuccessDialog({\n title,\n message,\n actionLabel = \"Done\",\n txHash,\n onClose,\n}: {\n title: string;\n message: string;\n actionLabel?: string;\n txHash?: string;\n onClose: () => void;\n}) {\n const { explorerUrl } = useMediaWalletApp();\n useEffect(() => {\n fireConfetti();\n }, []);\n return (\n <CanvasPortal>\n <div className=\"absolute inset-0 z-[70] grid place-items-center p-6\" onClick={onClose}>\n <ActionBackdrop />\n <div className=\"card-base relative z-10 w-full max-w-[320px] p-6 text-center\" onClick={(e) => e.stopPropagation()}>\n <div
|
|
1
|
+
{"version":3,"sources":["../../../src/components/media-wallet/success-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect } from \"react\";\nimport { ActionButton } from \"../action-button.js\";\nimport { ActionBackdrop, CanvasPortal } from \"./action-modal.js\";\nimport { fireConfetti } from \"../../utils/media-wallet/confetti.js\";\nimport { explorerTxUrl } from \"../../utils/media-wallet/wallet-format.js\";\nimport { useMediaWalletApp } from \"./types.js\";\n\nconst BRAND_GRADIENT = \"linear-gradient(115deg, #3b7bff, #8a5cf6, #f6608f, #fb8b46, #3b7bff)\";\n\nexport function SuccessDialog({\n title,\n message,\n actionLabel = \"Done\",\n txHash,\n onClose,\n}: {\n title: string;\n message: string;\n actionLabel?: string;\n txHash?: string;\n onClose: () => void;\n}) {\n const { explorerUrl } = useMediaWalletApp();\n useEffect(() => {\n fireConfetti();\n }, []);\n return (\n <CanvasPortal>\n <div className=\"absolute inset-0 z-[70] grid place-items-center p-6\" onClick={onClose}>\n <ActionBackdrop />\n <div className=\"card-base relative z-10 w-full max-w-[320px] p-6 text-center\" onClick={(e) => e.stopPropagation()}>\n <div role=\"status\">\n <h2 className=\"font-[family-name:var(--font-display)] text-xl font-extrabold tracking-tight\">{title}</h2>\n <p className=\"mt-1.5 text-sm leading-relaxed text-muted-foreground\">{message}</p>\n </div>\n {txHash && (\n <a\n href={explorerTxUrl(explorerUrl, txHash)}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"mt-3 inline-block text-xs text-brand-blue hover:underline\"\n >\n View transaction ↗\n </a>\n )}\n <ActionButton big onClick={onClose} className=\"mt-5 w-full\" style={{ \"--ml-grad\": BRAND_GRADIENT } as React.CSSProperties}>\n {actionLabel}\n </ActionButton>\n </div>\n </div>\n </CanvasPortal>\n );\n}\n"],"mappings":";AA+BQ,cAEE,YAFF;AA7BR,SAAS,iBAAiB;AAC1B,SAAS,oBAAoB;AAC7B,SAAS,gBAAgB,oBAAoB;AAC7C,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAC9B,SAAS,yBAAyB;AAElC,MAAM,iBAAiB;AAEhB,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA;AACF,GAMG;AACD,QAAM,EAAE,YAAY,IAAI,kBAAkB;AAC1C,YAAU,MAAM;AACd,iBAAa;AAAA,EACf,GAAG,CAAC,CAAC;AACL,SACE,oBAAC,gBACC,+BAAC,SAAI,WAAU,uDAAsD,SAAS,SAC5E;AAAA,wBAAC,kBAAe;AAAA,IAChB,qBAAC,SAAI,WAAU,gEAA+D,SAAS,CAAC,MAAM,EAAE,gBAAgB,GAC9G;AAAA,2BAAC,SAAI,MAAK,UACR;AAAA,4BAAC,QAAG,WAAU,gFAAgF,iBAAM;AAAA,QACpG,oBAAC,OAAE,WAAU,wDAAwD,mBAAQ;AAAA,SAC/E;AAAA,MACC,UACC;AAAA,QAAC;AAAA;AAAA,UACC,MAAM,cAAc,aAAa,MAAM;AAAA,UACvC,QAAO;AAAA,UACP,KAAI;AAAA,UACJ,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,MAEF,oBAAC,gBAAa,KAAG,MAAC,SAAS,SAAS,WAAU,eAAc,OAAO,EAAE,aAAa,eAAe,GAC9F,uBACH;AAAA,OACF;AAAA,KACF,GACF;AAEJ;","names":[]}
|
|
@@ -34,6 +34,7 @@ var import_medialane_app = require("./medialane-app.js");
|
|
|
34
34
|
var import_claim_proof = require("../utils/drop/claim-proof.js");
|
|
35
35
|
var import_run_intent_calls = require("../utils/run-intent-calls.js");
|
|
36
36
|
var import_use_pop = require("../utils/use-pop.js");
|
|
37
|
+
var import_success_messages = require("../utils/success-messages.js");
|
|
37
38
|
var import_use_transaction = require("../utils/use-transaction.js");
|
|
38
39
|
function PopClaimButton({ collectionAddress }) {
|
|
39
40
|
const app = (0, import_medialane_app.useMedialaneApp)();
|
|
@@ -77,8 +78,7 @@ function PopClaimButton({ collectionAddress }) {
|
|
|
77
78
|
import_transaction_success.TransactionSuccess,
|
|
78
79
|
{
|
|
79
80
|
name: "Credential",
|
|
80
|
-
|
|
81
|
-
description: "Your proof of participation is now on-chain.",
|
|
81
|
+
...import_success_messages.successMessages.claimed(),
|
|
82
82
|
txHash: tx.txHash,
|
|
83
83
|
actions: [{ label: "Done", onClick: tx.reset }],
|
|
84
84
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_reward_earned.RewardEarned, { actionType: "claim_pop" })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/pop-claim-button.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { Award, Loader2 } from \"lucide-react\";\nimport { popClaimState, type PopClaimInfo } from \"@medialane/sdk/starknet\";\nimport { Button } from \"./button.js\";\nimport { TransactionDialog } from \"./transaction-dialog.js\";\nimport { TransactionSuccess } from \"./transaction-success.js\";\nimport { RewardEarned } from \"./rewards/reward-earned.js\";\nimport { useMedialaneApp } from \"./medialane-app.js\";\nimport { claimProofFor } from \"../utils/drop/claim-proof.js\";\nimport { runIntentCalls } from \"../utils/run-intent-calls.js\";\nimport { usePopClaimStatus } from \"../utils/use-pop.js\";\nimport { useTransaction } from \"../utils/use-transaction.js\";\n\nexport function PopClaimButton({ collectionAddress }: { collectionAddress: string }) {\n const app = useMedialaneApp();\n const { walletAddress } = app;\n const { hasClaimed, mutate } = usePopClaimStatus(collectionAddress, walletAddress);\n const [proof, setProof] = useState<string[] | null>(null);\n const [info, setInfo] = useState<PopClaimInfo | null>(null);\n const tx = useTransaction();\n const busy = tx.phase === \"preparing\" || tx.phase === \"submitting\" || tx.phase === \"confirming\";\n\n useEffect(() => {\n let storage: Storage | null = null;\n try {\n storage = window.sessionStorage;\n } catch {\n storage = null;\n }\n setProof(claimProofFor(storage, collectionAddress, window.location.hash));\n app.getClient().api.chainReads.popClaimInfo(collectionAddress)\n .then(setInfo)\n .catch(() => setInfo(null));\n }, [app, collectionAddress]);\n\n useEffect(() => {\n if (tx.phase === \"success\") void mutate();\n }, [tx.phase, mutate]);\n\n const state = popClaimState({\n hasClaimed,\n proof,\n wallet: walletAddress,\n info: info && { ...info, now: Math.floor(Date.now() / 1000) },\n });\n\n const claim = () => {\n if (!proof) return;\n void tx.run(async (signer) => {\n await runIntentCalls(signer, () => app.getClient().api.intents.create(\"pop-claim\", { claimer: signer.address, collection: collectionAddress, proof }));\n });\n };\n\n return (\n <>\n {(state === \"ready\" || busy) && (\n <Button size=\"sm\" className=\"w-full gap-1.5\" onClick={claim} disabled={busy}>\n {busy ? <Loader2 className=\"h-3.5 w-3.5 animate-spin\" /> : <Award className=\"h-3.5 w-3.5\" />}\n {busy ? \"Claiming…\" : \"Claim credential\"}\n </Button>\n )}\n <TransactionDialog tx={tx} title=\"Claim credential\" workingLabel=\"Claiming your credential…\" firstStepLabel=\"Prepare claim\">\n <TransactionSuccess\n name=\"Credential\"\n
|
|
1
|
+
{"version":3,"sources":["../../src/components/pop-claim-button.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { Award, Loader2 } from \"lucide-react\";\nimport { popClaimState, type PopClaimInfo } from \"@medialane/sdk/starknet\";\nimport { Button } from \"./button.js\";\nimport { TransactionDialog } from \"./transaction-dialog.js\";\nimport { TransactionSuccess } from \"./transaction-success.js\";\nimport { RewardEarned } from \"./rewards/reward-earned.js\";\nimport { useMedialaneApp } from \"./medialane-app.js\";\nimport { claimProofFor } from \"../utils/drop/claim-proof.js\";\nimport { runIntentCalls } from \"../utils/run-intent-calls.js\";\nimport { usePopClaimStatus } from \"../utils/use-pop.js\";\nimport { successMessages } from \"../utils/success-messages.js\";\nimport { useTransaction } from \"../utils/use-transaction.js\";\n\nexport function PopClaimButton({ collectionAddress }: { collectionAddress: string }) {\n const app = useMedialaneApp();\n const { walletAddress } = app;\n const { hasClaimed, mutate } = usePopClaimStatus(collectionAddress, walletAddress);\n const [proof, setProof] = useState<string[] | null>(null);\n const [info, setInfo] = useState<PopClaimInfo | null>(null);\n const tx = useTransaction();\n const busy = tx.phase === \"preparing\" || tx.phase === \"submitting\" || tx.phase === \"confirming\";\n\n useEffect(() => {\n let storage: Storage | null = null;\n try {\n storage = window.sessionStorage;\n } catch {\n storage = null;\n }\n setProof(claimProofFor(storage, collectionAddress, window.location.hash));\n app.getClient().api.chainReads.popClaimInfo(collectionAddress)\n .then(setInfo)\n .catch(() => setInfo(null));\n }, [app, collectionAddress]);\n\n useEffect(() => {\n if (tx.phase === \"success\") void mutate();\n }, [tx.phase, mutate]);\n\n const state = popClaimState({\n hasClaimed,\n proof,\n wallet: walletAddress,\n info: info && { ...info, now: Math.floor(Date.now() / 1000) },\n });\n\n const claim = () => {\n if (!proof) return;\n void tx.run(async (signer) => {\n await runIntentCalls(signer, () => app.getClient().api.intents.create(\"pop-claim\", { claimer: signer.address, collection: collectionAddress, proof }));\n });\n };\n\n return (\n <>\n {(state === \"ready\" || busy) && (\n <Button size=\"sm\" className=\"w-full gap-1.5\" onClick={claim} disabled={busy}>\n {busy ? <Loader2 className=\"h-3.5 w-3.5 animate-spin\" /> : <Award className=\"h-3.5 w-3.5\" />}\n {busy ? \"Claiming…\" : \"Claim credential\"}\n </Button>\n )}\n <TransactionDialog tx={tx} title=\"Claim credential\" workingLabel=\"Claiming your credential…\" firstStepLabel=\"Prepare claim\">\n <TransactionSuccess\n name=\"Credential\"\n {...successMessages.claimed()}\n txHash={tx.txHash}\n actions={[{ label: \"Done\", onClick: tx.reset }]}\n >\n <RewardEarned actionType=\"claim_pop\" />\n </TransactionSuccess>\n </TransactionDialog>\n </>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAyDI;AAvDJ,mBAAoC;AACpC,0BAA+B;AAC/B,sBAAiD;AACjD,oBAAuB;AACvB,gCAAkC;AAClC,iCAAmC;AACnC,2BAA6B;AAC7B,2BAAgC;AAChC,yBAA8B;AAC9B,8BAA+B;AAC/B,qBAAkC;AAClC,8BAAgC;AAChC,6BAA+B;AAExB,SAAS,eAAe,EAAE,kBAAkB,GAAkC;AACnF,QAAM,UAAM,sCAAgB;AAC5B,QAAM,EAAE,cAAc,IAAI;AAC1B,QAAM,EAAE,YAAY,OAAO,QAAI,kCAAkB,mBAAmB,aAAa;AACjF,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAA0B,IAAI;AACxD,QAAM,CAAC,MAAM,OAAO,QAAI,uBAA8B,IAAI;AAC1D,QAAM,SAAK,uCAAe;AAC1B,QAAM,OAAO,GAAG,UAAU,eAAe,GAAG,UAAU,gBAAgB,GAAG,UAAU;AAEnF,8BAAU,MAAM;AACd,QAAI,UAA0B;AAC9B,QAAI;AACF,gBAAU,OAAO;AAAA,IACnB,QAAQ;AACN,gBAAU;AAAA,IACZ;AACA,iBAAS,kCAAc,SAAS,mBAAmB,OAAO,SAAS,IAAI,CAAC;AACxE,QAAI,UAAU,EAAE,IAAI,WAAW,aAAa,iBAAiB,EAC1D,KAAK,OAAO,EACZ,MAAM,MAAM,QAAQ,IAAI,CAAC;AAAA,EAC9B,GAAG,CAAC,KAAK,iBAAiB,CAAC;AAE3B,8BAAU,MAAM;AACd,QAAI,GAAG,UAAU,UAAW,MAAK,OAAO;AAAA,EAC1C,GAAG,CAAC,GAAG,OAAO,MAAM,CAAC;AAErB,QAAM,YAAQ,+BAAc;AAAA,IAC1B;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,MAAM,QAAQ,EAAE,GAAG,MAAM,KAAK,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI,EAAE;AAAA,EAC9D,CAAC;AAED,QAAM,QAAQ,MAAM;AAClB,QAAI,CAAC,MAAO;AACZ,SAAK,GAAG,IAAI,OAAO,WAAW;AAC5B,gBAAM,wCAAe,QAAQ,MAAM,IAAI,UAAU,EAAE,IAAI,QAAQ,OAAO,aAAa,EAAE,SAAS,OAAO,SAAS,YAAY,mBAAmB,MAAM,CAAC,CAAC;AAAA,IACvJ,CAAC;AAAA,EACH;AAEA,SACE,4EACI;AAAA,eAAU,WAAW,SACrB,6CAAC,wBAAO,MAAK,MAAK,WAAU,kBAAiB,SAAS,OAAO,UAAU,MACpE;AAAA,aAAO,4CAAC,+BAAQ,WAAU,4BAA2B,IAAK,4CAAC,6BAAM,WAAU,eAAc;AAAA,MACzF,OAAO,mBAAc;AAAA,OACxB;AAAA,IAEF,4CAAC,+CAAkB,IAAQ,OAAM,oBAAmB,cAAa,kCAA4B,gBAAe,iBAC1G;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACJ,GAAG,wCAAgB,QAAQ;AAAA,QAC5B,QAAQ,GAAG;AAAA,QACX,SAAS,CAAC,EAAE,OAAO,QAAQ,SAAS,GAAG,MAAM,CAAC;AAAA,QAE9C,sDAAC,qCAAa,YAAW,aAAY;AAAA;AAAA,IACvC,GACF;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -11,6 +11,7 @@ import { useMedialaneApp } from "./medialane-app.js";
|
|
|
11
11
|
import { claimProofFor } from "../utils/drop/claim-proof.js";
|
|
12
12
|
import { runIntentCalls } from "../utils/run-intent-calls.js";
|
|
13
13
|
import { usePopClaimStatus } from "../utils/use-pop.js";
|
|
14
|
+
import { successMessages } from "../utils/success-messages.js";
|
|
14
15
|
import { useTransaction } from "../utils/use-transaction.js";
|
|
15
16
|
function PopClaimButton({ collectionAddress }) {
|
|
16
17
|
const app = useMedialaneApp();
|
|
@@ -54,8 +55,7 @@ function PopClaimButton({ collectionAddress }) {
|
|
|
54
55
|
TransactionSuccess,
|
|
55
56
|
{
|
|
56
57
|
name: "Credential",
|
|
57
|
-
|
|
58
|
-
description: "Your proof of participation is now on-chain.",
|
|
58
|
+
...successMessages.claimed(),
|
|
59
59
|
txHash: tx.txHash,
|
|
60
60
|
actions: [{ label: "Done", onClick: tx.reset }],
|
|
61
61
|
children: /* @__PURE__ */ jsx(RewardEarned, { actionType: "claim_pop" })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/pop-claim-button.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { Award, Loader2 } from \"lucide-react\";\nimport { popClaimState, type PopClaimInfo } from \"@medialane/sdk/starknet\";\nimport { Button } from \"./button.js\";\nimport { TransactionDialog } from \"./transaction-dialog.js\";\nimport { TransactionSuccess } from \"./transaction-success.js\";\nimport { RewardEarned } from \"./rewards/reward-earned.js\";\nimport { useMedialaneApp } from \"./medialane-app.js\";\nimport { claimProofFor } from \"../utils/drop/claim-proof.js\";\nimport { runIntentCalls } from \"../utils/run-intent-calls.js\";\nimport { usePopClaimStatus } from \"../utils/use-pop.js\";\nimport { useTransaction } from \"../utils/use-transaction.js\";\n\nexport function PopClaimButton({ collectionAddress }: { collectionAddress: string }) {\n const app = useMedialaneApp();\n const { walletAddress } = app;\n const { hasClaimed, mutate } = usePopClaimStatus(collectionAddress, walletAddress);\n const [proof, setProof] = useState<string[] | null>(null);\n const [info, setInfo] = useState<PopClaimInfo | null>(null);\n const tx = useTransaction();\n const busy = tx.phase === \"preparing\" || tx.phase === \"submitting\" || tx.phase === \"confirming\";\n\n useEffect(() => {\n let storage: Storage | null = null;\n try {\n storage = window.sessionStorage;\n } catch {\n storage = null;\n }\n setProof(claimProofFor(storage, collectionAddress, window.location.hash));\n app.getClient().api.chainReads.popClaimInfo(collectionAddress)\n .then(setInfo)\n .catch(() => setInfo(null));\n }, [app, collectionAddress]);\n\n useEffect(() => {\n if (tx.phase === \"success\") void mutate();\n }, [tx.phase, mutate]);\n\n const state = popClaimState({\n hasClaimed,\n proof,\n wallet: walletAddress,\n info: info && { ...info, now: Math.floor(Date.now() / 1000) },\n });\n\n const claim = () => {\n if (!proof) return;\n void tx.run(async (signer) => {\n await runIntentCalls(signer, () => app.getClient().api.intents.create(\"pop-claim\", { claimer: signer.address, collection: collectionAddress, proof }));\n });\n };\n\n return (\n <>\n {(state === \"ready\" || busy) && (\n <Button size=\"sm\" className=\"w-full gap-1.5\" onClick={claim} disabled={busy}>\n {busy ? <Loader2 className=\"h-3.5 w-3.5 animate-spin\" /> : <Award className=\"h-3.5 w-3.5\" />}\n {busy ? \"Claiming…\" : \"Claim credential\"}\n </Button>\n )}\n <TransactionDialog tx={tx} title=\"Claim credential\" workingLabel=\"Claiming your credential…\" firstStepLabel=\"Prepare claim\">\n <TransactionSuccess\n name=\"Credential\"\n
|
|
1
|
+
{"version":3,"sources":["../../src/components/pop-claim-button.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { Award, Loader2 } from \"lucide-react\";\nimport { popClaimState, type PopClaimInfo } from \"@medialane/sdk/starknet\";\nimport { Button } from \"./button.js\";\nimport { TransactionDialog } from \"./transaction-dialog.js\";\nimport { TransactionSuccess } from \"./transaction-success.js\";\nimport { RewardEarned } from \"./rewards/reward-earned.js\";\nimport { useMedialaneApp } from \"./medialane-app.js\";\nimport { claimProofFor } from \"../utils/drop/claim-proof.js\";\nimport { runIntentCalls } from \"../utils/run-intent-calls.js\";\nimport { usePopClaimStatus } from \"../utils/use-pop.js\";\nimport { successMessages } from \"../utils/success-messages.js\";\nimport { useTransaction } from \"../utils/use-transaction.js\";\n\nexport function PopClaimButton({ collectionAddress }: { collectionAddress: string }) {\n const app = useMedialaneApp();\n const { walletAddress } = app;\n const { hasClaimed, mutate } = usePopClaimStatus(collectionAddress, walletAddress);\n const [proof, setProof] = useState<string[] | null>(null);\n const [info, setInfo] = useState<PopClaimInfo | null>(null);\n const tx = useTransaction();\n const busy = tx.phase === \"preparing\" || tx.phase === \"submitting\" || tx.phase === \"confirming\";\n\n useEffect(() => {\n let storage: Storage | null = null;\n try {\n storage = window.sessionStorage;\n } catch {\n storage = null;\n }\n setProof(claimProofFor(storage, collectionAddress, window.location.hash));\n app.getClient().api.chainReads.popClaimInfo(collectionAddress)\n .then(setInfo)\n .catch(() => setInfo(null));\n }, [app, collectionAddress]);\n\n useEffect(() => {\n if (tx.phase === \"success\") void mutate();\n }, [tx.phase, mutate]);\n\n const state = popClaimState({\n hasClaimed,\n proof,\n wallet: walletAddress,\n info: info && { ...info, now: Math.floor(Date.now() / 1000) },\n });\n\n const claim = () => {\n if (!proof) return;\n void tx.run(async (signer) => {\n await runIntentCalls(signer, () => app.getClient().api.intents.create(\"pop-claim\", { claimer: signer.address, collection: collectionAddress, proof }));\n });\n };\n\n return (\n <>\n {(state === \"ready\" || busy) && (\n <Button size=\"sm\" className=\"w-full gap-1.5\" onClick={claim} disabled={busy}>\n {busy ? <Loader2 className=\"h-3.5 w-3.5 animate-spin\" /> : <Award className=\"h-3.5 w-3.5\" />}\n {busy ? \"Claiming…\" : \"Claim credential\"}\n </Button>\n )}\n <TransactionDialog tx={tx} title=\"Claim credential\" workingLabel=\"Claiming your credential…\" firstStepLabel=\"Prepare claim\">\n <TransactionSuccess\n name=\"Credential\"\n {...successMessages.claimed()}\n txHash={tx.txHash}\n actions={[{ label: \"Done\", onClick: tx.reset }]}\n >\n <RewardEarned actionType=\"claim_pop\" />\n </TransactionSuccess>\n </TransactionDialog>\n </>\n );\n}\n"],"mappings":";AAyDI,mBAGc,KADV,YAFJ;AAvDJ,SAAS,WAAW,gBAAgB;AACpC,SAAS,OAAO,eAAe;AAC/B,SAAS,qBAAwC;AACjD,SAAS,cAAc;AACvB,SAAS,yBAAyB;AAClC,SAAS,0BAA0B;AACnC,SAAS,oBAAoB;AAC7B,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAC9B,SAAS,sBAAsB;AAC/B,SAAS,yBAAyB;AAClC,SAAS,uBAAuB;AAChC,SAAS,sBAAsB;AAExB,SAAS,eAAe,EAAE,kBAAkB,GAAkC;AACnF,QAAM,MAAM,gBAAgB;AAC5B,QAAM,EAAE,cAAc,IAAI;AAC1B,QAAM,EAAE,YAAY,OAAO,IAAI,kBAAkB,mBAAmB,aAAa;AACjF,QAAM,CAAC,OAAO,QAAQ,IAAI,SAA0B,IAAI;AACxD,QAAM,CAAC,MAAM,OAAO,IAAI,SAA8B,IAAI;AAC1D,QAAM,KAAK,eAAe;AAC1B,QAAM,OAAO,GAAG,UAAU,eAAe,GAAG,UAAU,gBAAgB,GAAG,UAAU;AAEnF,YAAU,MAAM;AACd,QAAI,UAA0B;AAC9B,QAAI;AACF,gBAAU,OAAO;AAAA,IACnB,QAAQ;AACN,gBAAU;AAAA,IACZ;AACA,aAAS,cAAc,SAAS,mBAAmB,OAAO,SAAS,IAAI,CAAC;AACxE,QAAI,UAAU,EAAE,IAAI,WAAW,aAAa,iBAAiB,EAC1D,KAAK,OAAO,EACZ,MAAM,MAAM,QAAQ,IAAI,CAAC;AAAA,EAC9B,GAAG,CAAC,KAAK,iBAAiB,CAAC;AAE3B,YAAU,MAAM;AACd,QAAI,GAAG,UAAU,UAAW,MAAK,OAAO;AAAA,EAC1C,GAAG,CAAC,GAAG,OAAO,MAAM,CAAC;AAErB,QAAM,QAAQ,cAAc;AAAA,IAC1B;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,MAAM,QAAQ,EAAE,GAAG,MAAM,KAAK,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI,EAAE;AAAA,EAC9D,CAAC;AAED,QAAM,QAAQ,MAAM;AAClB,QAAI,CAAC,MAAO;AACZ,SAAK,GAAG,IAAI,OAAO,WAAW;AAC5B,YAAM,eAAe,QAAQ,MAAM,IAAI,UAAU,EAAE,IAAI,QAAQ,OAAO,aAAa,EAAE,SAAS,OAAO,SAAS,YAAY,mBAAmB,MAAM,CAAC,CAAC;AAAA,IACvJ,CAAC;AAAA,EACH;AAEA,SACE,iCACI;AAAA,eAAU,WAAW,SACrB,qBAAC,UAAO,MAAK,MAAK,WAAU,kBAAiB,SAAS,OAAO,UAAU,MACpE;AAAA,aAAO,oBAAC,WAAQ,WAAU,4BAA2B,IAAK,oBAAC,SAAM,WAAU,eAAc;AAAA,MACzF,OAAO,mBAAc;AAAA,OACxB;AAAA,IAEF,oBAAC,qBAAkB,IAAQ,OAAM,oBAAmB,cAAa,kCAA4B,gBAAe,iBAC1G;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACJ,GAAG,gBAAgB,QAAQ;AAAA,QAC5B,QAAQ,GAAG;AAAA,QACX,SAAS,CAAC,EAAE,OAAO,QAAQ,SAAS,GAAG,MAAM,CAAC;AAAA,QAE9C,8BAAC,gBAAa,YAAW,aAAY;AAAA;AAAA,IACvC,GACF;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -47,6 +47,7 @@ var import_transaction_dialog = require("./transaction-dialog.js");
|
|
|
47
47
|
var import_transaction_success = require("./transaction-success.js");
|
|
48
48
|
var import_wallet_required = require("./wallet-required.js");
|
|
49
49
|
var import_run_intent_calls = require("../utils/run-intent-calls.js");
|
|
50
|
+
var import_success_messages = require("../utils/success-messages.js");
|
|
50
51
|
var import_use_collections = require("../utils/use-collections.js");
|
|
51
52
|
var import_use_transaction = require("../utils/use-transaction.js");
|
|
52
53
|
function parseAddresses(raw) {
|
|
@@ -164,7 +165,7 @@ function PopManagePage({ contract }) {
|
|
|
164
165
|
const isSubmitting = tx.phase === "preparing" || tx.phase === "submitting" || tx.phase === "confirming";
|
|
165
166
|
const isOwner = walletAddress && collection?.owner && (0, import_sdk.normalizeAddress)("STARKNET", walletAddress) === (0, import_sdk.normalizeAddress)("STARKNET", collection.owner);
|
|
166
167
|
const issue = (recipient) => {
|
|
167
|
-
setDone(
|
|
168
|
+
setDone(import_success_messages.successMessages.credentialIssued());
|
|
168
169
|
void tx.run(async (signer) => {
|
|
169
170
|
await (0, import_run_intent_calls.runIntentCalls)(signer, () => app.getClient().api.intents.create("pop-manage", { owner: signer.address, collection: contract, action: "issue", recipient }));
|
|
170
171
|
});
|
|
@@ -172,7 +173,7 @@ function PopManagePage({ contract }) {
|
|
|
172
173
|
const publish = (addresses) => {
|
|
173
174
|
const list = (0, import_starknet.buildPopAllowlist)(addresses);
|
|
174
175
|
const count = Object.keys(list.proofs).length;
|
|
175
|
-
setDone({
|
|
176
|
+
setDone(import_success_messages.successMessages.participantsPublished({ count }));
|
|
176
177
|
void tx.run(async (signer) => {
|
|
177
178
|
await (0, import_run_intent_calls.runIntentCalls)(signer, () => app.getClient().api.intents.create("pop-manage", { owner: signer.address, collection: contract, action: "set_allowlist_root", root: list.root }));
|
|
178
179
|
}).then((ok) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/pop-manage-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { normalizeAddress } from \"@medialane/sdk\";\nimport { buildPopAllowlist, popClaimLinks, popClaimLinksCsv, type PopClaimLink } from \"@medialane/sdk/starknet\";\nimport { ArrowLeft, Award, AlertCircle, CheckCircle2, Download, Loader2, Send, Users } from \"lucide-react\";\nimport { Button } from \"./button.js\";\nimport Link from \"./link.js\";\nimport { useMedialaneApp } from \"./medialane-app.js\";\nimport { FadeIn } from \"./motion-primitives.js\";\nimport { Skeleton } from \"./skeleton.js\";\nimport { Textarea } from \"./textarea.js\";\nimport { TransactionDialog } from \"./transaction-dialog.js\";\nimport { TransactionSuccess } from \"./transaction-success.js\";\nimport { WalletRequired } from \"./wallet-required.js\";\nimport { runIntentCalls } from \"../utils/run-intent-calls.js\";\nimport { useCollection } from \"../utils/use-collections.js\";\nimport { useTransaction } from \"../utils/use-transaction.js\";\n\nfunction parseAddresses(raw: string): string[] {\n return raw\n .split(/[\\n,\\s]+/)\n .map((a) => a.trim())\n .filter((a) => /^0x[0-9a-fA-F]+$/.test(a));\n}\n\nfunction downloadCsv(links: PopClaimLink[]) {\n const href = URL.createObjectURL(new Blob([popClaimLinksCsv(links)], { type: \"text/csv\" }));\n const anchor = Object.assign(document.createElement(\"a\"), { href, download: \"claim-links.csv\" });\n anchor.click();\n URL.revokeObjectURL(href);\n}\n\nfunction IssueSection({\n onIssue,\n isSubmitting,\n}: {\n onIssue: (address: string) => void;\n isSubmitting: boolean;\n}) {\n const [raw, setRaw] = useState(\"\");\n const address = raw.trim();\n const valid = /^0x[0-9a-fA-F]{1,64}$/.test(address);\n\n return (\n <div className=\"bento-cell p-5 space-y-3\">\n <div className=\"flex items-center gap-2\">\n <Award className=\"h-4 w-4 text-green-500\" />\n <span className=\"font-semibold text-sm\">Issue directly</span>\n </div>\n <p className=\"text-xs text-muted-foreground\">\n Send the credential straight to one wallet — for a late participant, without republishing the list or\n changing anyone's claim link.\n </p>\n <input\n type=\"text\"\n placeholder=\"0x...\"\n value={raw}\n onChange={(e) => setRaw(e.target.value)}\n className=\"w-full rounded-lg border border-border bg-background px-3 py-2 text-sm tabular-nums placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring\"\n />\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"w-full\"\n disabled={!valid || isSubmitting}\n onClick={() => {\n onIssue(address);\n setRaw(\"\");\n }}\n >\n <Send className=\"h-3.5 w-3.5 mr-1.5\" />\n Issue credential\n </Button>\n </div>\n );\n}\n\nfunction AllowlistSection({\n onPublish,\n isSubmitting,\n links,\n}: {\n onPublish: (addresses: string[]) => void;\n isSubmitting: boolean;\n links: PopClaimLink[] | null;\n}) {\n const [raw, setRaw] = useState(\"\");\n const parsed = parseAddresses(raw);\n\n return (\n <div className=\"bento-cell p-5 space-y-3\">\n <div className=\"flex items-center gap-2\">\n <Users className=\"h-4 w-4 text-green-500\" />\n <span className=\"font-semibold text-sm\">Participants</span>\n {parsed.length > 0 && (\n <span className=\"ml-auto text-xs text-muted-foreground\">\n {parsed.length} address{parsed.length !== 1 ? \"es\" : \"\"}\n </span>\n )}\n </div>\n <p className=\"text-xs text-muted-foreground\">\n Paste every participant's wallet address. Publishing replaces the previous list and every link\n sent before it — send the new links to everyone who hasn't claimed yet. The list stays in this\n browser: download the claim links and send each participant theirs.\n </p>\n <Textarea\n placeholder={\"Paste Starknet addresses, one per line:\\n0x04a...\\n0x06b...\"}\n rows={8}\n value={raw}\n onChange={(e) => setRaw(e.target.value)}\n className=\"tabular-nums text-xs resize-none\"\n />\n <Button\n size=\"sm\"\n className=\"w-full bg-green-600 hover:bg-green-700 text-white\"\n disabled={parsed.length === 0 || isSubmitting}\n onClick={() => onPublish(parsed)}\n >\n {isSubmitting ? (\n <>\n <Loader2 className=\"h-3.5 w-3.5 animate-spin mr-1.5\" />\n Publishing…\n </>\n ) : (\n <>\n <CheckCircle2 className=\"h-3.5 w-3.5 mr-1.5\" />\n Publish {parsed.length > 0 ? `${parsed.length} participant${parsed.length !== 1 ? \"s\" : \"\"}` : \"participants\"}\n </>\n )}\n </Button>\n {links && (\n <div className=\"space-y-2 pt-2\">\n <Button variant=\"outline\" size=\"sm\" className=\"w-full\" onClick={() => downloadCsv(links)}>\n <Download className=\"h-3.5 w-3.5 mr-1.5\" />\n Download claim links (CSV)\n </Button>\n <ul className=\"max-h-48 overflow-auto text-xs tabular-nums space-y-1 text-muted-foreground\">\n {links.map((link) => (\n <li key={link.address} className=\"truncate\">{link.address}</li>\n ))}\n </ul>\n </div>\n )}\n </div>\n );\n}\n\nexport function PopManagePage({ contract }: { contract: string }) {\n const app = useMedialaneApp();\n const walletAddress = app.walletAddress;\n const { collection, isLoading } = useCollection(contract);\n const tx = useTransaction();\n const [done, setDone] = useState({ title: \"\", description: \"\" });\n const [links, setLinks] = useState<PopClaimLink[] | null>(null);\n const isSubmitting = tx.phase === \"preparing\" || tx.phase === \"submitting\" || tx.phase === \"confirming\";\n\n const isOwner =\n walletAddress &&\n collection?.owner &&\n normalizeAddress(\"STARKNET\", walletAddress) === normalizeAddress(\"STARKNET\", collection.owner);\n\n const issue = (recipient: string) => {\n setDone({ title: \"Credential issued\", description: \"The credential is now in their wallet.\" });\n void tx.run(async (signer) => {\n await runIntentCalls(signer, () => app.getClient().api.intents.create(\"pop-manage\", { owner: signer.address, collection: contract, action: \"issue\", recipient }));\n });\n };\n\n const publish = (addresses: string[]) => {\n const list = buildPopAllowlist(addresses);\n const count = Object.keys(list.proofs).length;\n setDone({ title: \"Participants published\", description: `Published ${count} participant${count !== 1 ? \"s\" : \"\"}.` });\n void tx\n .run(async (signer) => {\n await runIntentCalls(signer, () => app.getClient().api.intents.create(\"pop-manage\", { owner: signer.address, collection: contract, action: \"set_allowlist_root\", root: list.root }));\n })\n .then((ok) => {\n if (ok) setLinks(popClaimLinks(window.location.origin, contract, list));\n });\n };\n\n return (\n <WalletRequired icon={Award} title=\"Connect your wallet\" description=\"Connect to manage your event.\">\n {isLoading ? (\n <div className=\"max-w-xl mx-auto px-4 pt-10 pb-16 space-y-4\">\n <Skeleton className=\"h-6 w-24\" />\n <Skeleton className=\"h-32 w-full rounded-2xl\" />\n <Skeleton className=\"h-64 w-full rounded-2xl\" />\n </div>\n ) : !collection ? (\n <div className=\"max-w-xl mx-auto px-4 pt-24 pb-8 text-center space-y-4\">\n <AlertCircle className=\"h-10 w-10 text-muted-foreground/20 mx-auto\" />\n <p className=\"text-muted-foreground\">Collection not found.</p>\n <Button asChild variant=\"outline\" size=\"sm\">\n <Link href=\"/launchpad/pop\">← Back</Link>\n </Button>\n </div>\n ) : !isOwner ? (\n <div className=\"max-w-xl mx-auto px-4 pt-24 pb-8 text-center space-y-4\">\n <Award className=\"h-10 w-10 text-muted-foreground/20 mx-auto\" />\n <p className=\"text-muted-foreground\">You are not the organizer of this event.</p>\n <Button asChild variant=\"outline\" size=\"sm\">\n <Link href=\"/launchpad/pop\">← Back to events</Link>\n </Button>\n </div>\n ) : (\n <div className=\"max-w-xl mx-auto px-4 pt-10 pb-16 space-y-6\">\n <TransactionDialog tx={tx} title=\"Manage event\" workingLabel=\"Updating your event…\" firstStepLabel=\"Prepare\">\n <TransactionSuccess name={collection.name ?? \"Event\"} title={done.title} description={done.description} txHash={tx.txHash} actions={[{ label: \"Done\", onClick: tx.reset }]} />\n </TransactionDialog>\n\n <FadeIn>\n <Button asChild variant=\"ghost\" size=\"sm\" className=\"-ml-2\">\n <Link href=\"/launchpad/pop\">\n <ArrowLeft className=\"h-3.5 w-3.5 mr-1.5\" />\n All events\n </Link>\n </Button>\n </FadeIn>\n\n <FadeIn delay={0.04}>\n <div>\n <span className=\"pill-badge inline-flex gap-1.5 mb-2\">\n <Award className=\"h-3 w-3\" />\n Organizer\n </span>\n <h1 className=\"text-2xl font-bold mt-1\">Manage Event</h1>\n <p className=\"text-sm text-muted-foreground\">{collection.name ?? contract}</p>\n </div>\n </FadeIn>\n\n <FadeIn delay={0.08}>\n <div className=\"bento-cell p-4 flex items-center gap-3\">\n <Award className=\"h-4 w-4 text-green-500 shrink-0\" />\n <p className=\"text-xs text-muted-foreground\">\n Only participants on your <strong className=\"text-foreground\">published list</strong> can claim,\n with the link you send them.\n </p>\n </div>\n </FadeIn>\n\n <FadeIn delay={0.12}>\n <AllowlistSection onPublish={publish} isSubmitting={isSubmitting} links={links} />\n </FadeIn>\n\n <FadeIn delay={0.16}>\n <IssueSection onIssue={issue} isSubmitting={isSubmitting} />\n </FadeIn>\n </div>\n )}\n </WalletRequired>\n );\n}\n"],"mappings":"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","names":["Link"]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/pop-manage-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { normalizeAddress } from \"@medialane/sdk\";\nimport { buildPopAllowlist, popClaimLinks, popClaimLinksCsv, type PopClaimLink } from \"@medialane/sdk/starknet\";\nimport { ArrowLeft, Award, AlertCircle, CheckCircle2, Download, Loader2, Send, Users } from \"lucide-react\";\nimport { Button } from \"./button.js\";\nimport Link from \"./link.js\";\nimport { useMedialaneApp } from \"./medialane-app.js\";\nimport { FadeIn } from \"./motion-primitives.js\";\nimport { Skeleton } from \"./skeleton.js\";\nimport { Textarea } from \"./textarea.js\";\nimport { TransactionDialog } from \"./transaction-dialog.js\";\nimport { TransactionSuccess } from \"./transaction-success.js\";\nimport { WalletRequired } from \"./wallet-required.js\";\nimport { runIntentCalls } from \"../utils/run-intent-calls.js\";\nimport { successMessages } from \"../utils/success-messages.js\";\nimport { useCollection } from \"../utils/use-collections.js\";\nimport { useTransaction } from \"../utils/use-transaction.js\";\n\nfunction parseAddresses(raw: string): string[] {\n return raw\n .split(/[\\n,\\s]+/)\n .map((a) => a.trim())\n .filter((a) => /^0x[0-9a-fA-F]+$/.test(a));\n}\n\nfunction downloadCsv(links: PopClaimLink[]) {\n const href = URL.createObjectURL(new Blob([popClaimLinksCsv(links)], { type: \"text/csv\" }));\n const anchor = Object.assign(document.createElement(\"a\"), { href, download: \"claim-links.csv\" });\n anchor.click();\n URL.revokeObjectURL(href);\n}\n\nfunction IssueSection({\n onIssue,\n isSubmitting,\n}: {\n onIssue: (address: string) => void;\n isSubmitting: boolean;\n}) {\n const [raw, setRaw] = useState(\"\");\n const address = raw.trim();\n const valid = /^0x[0-9a-fA-F]{1,64}$/.test(address);\n\n return (\n <div className=\"bento-cell p-5 space-y-3\">\n <div className=\"flex items-center gap-2\">\n <Award className=\"h-4 w-4 text-green-500\" />\n <span className=\"font-semibold text-sm\">Issue directly</span>\n </div>\n <p className=\"text-xs text-muted-foreground\">\n Send the credential straight to one wallet — for a late participant, without republishing the list or\n changing anyone's claim link.\n </p>\n <input\n type=\"text\"\n placeholder=\"0x...\"\n value={raw}\n onChange={(e) => setRaw(e.target.value)}\n className=\"w-full rounded-lg border border-border bg-background px-3 py-2 text-sm tabular-nums placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring\"\n />\n <Button\n size=\"sm\"\n variant=\"outline\"\n className=\"w-full\"\n disabled={!valid || isSubmitting}\n onClick={() => {\n onIssue(address);\n setRaw(\"\");\n }}\n >\n <Send className=\"h-3.5 w-3.5 mr-1.5\" />\n Issue credential\n </Button>\n </div>\n );\n}\n\nfunction AllowlistSection({\n onPublish,\n isSubmitting,\n links,\n}: {\n onPublish: (addresses: string[]) => void;\n isSubmitting: boolean;\n links: PopClaimLink[] | null;\n}) {\n const [raw, setRaw] = useState(\"\");\n const parsed = parseAddresses(raw);\n\n return (\n <div className=\"bento-cell p-5 space-y-3\">\n <div className=\"flex items-center gap-2\">\n <Users className=\"h-4 w-4 text-green-500\" />\n <span className=\"font-semibold text-sm\">Participants</span>\n {parsed.length > 0 && (\n <span className=\"ml-auto text-xs text-muted-foreground\">\n {parsed.length} address{parsed.length !== 1 ? \"es\" : \"\"}\n </span>\n )}\n </div>\n <p className=\"text-xs text-muted-foreground\">\n Paste every participant's wallet address. Publishing replaces the previous list and every link\n sent before it — send the new links to everyone who hasn't claimed yet. The list stays in this\n browser: download the claim links and send each participant theirs.\n </p>\n <Textarea\n placeholder={\"Paste Starknet addresses, one per line:\\n0x04a...\\n0x06b...\"}\n rows={8}\n value={raw}\n onChange={(e) => setRaw(e.target.value)}\n className=\"tabular-nums text-xs resize-none\"\n />\n <Button\n size=\"sm\"\n className=\"w-full bg-green-600 hover:bg-green-700 text-white\"\n disabled={parsed.length === 0 || isSubmitting}\n onClick={() => onPublish(parsed)}\n >\n {isSubmitting ? (\n <>\n <Loader2 className=\"h-3.5 w-3.5 animate-spin mr-1.5\" />\n Publishing…\n </>\n ) : (\n <>\n <CheckCircle2 className=\"h-3.5 w-3.5 mr-1.5\" />\n Publish {parsed.length > 0 ? `${parsed.length} participant${parsed.length !== 1 ? \"s\" : \"\"}` : \"participants\"}\n </>\n )}\n </Button>\n {links && (\n <div className=\"space-y-2 pt-2\">\n <Button variant=\"outline\" size=\"sm\" className=\"w-full\" onClick={() => downloadCsv(links)}>\n <Download className=\"h-3.5 w-3.5 mr-1.5\" />\n Download claim links (CSV)\n </Button>\n <ul className=\"max-h-48 overflow-auto text-xs tabular-nums space-y-1 text-muted-foreground\">\n {links.map((link) => (\n <li key={link.address} className=\"truncate\">{link.address}</li>\n ))}\n </ul>\n </div>\n )}\n </div>\n );\n}\n\nexport function PopManagePage({ contract }: { contract: string }) {\n const app = useMedialaneApp();\n const walletAddress = app.walletAddress;\n const { collection, isLoading } = useCollection(contract);\n const tx = useTransaction();\n const [done, setDone] = useState({ title: \"\", description: \"\" });\n const [links, setLinks] = useState<PopClaimLink[] | null>(null);\n const isSubmitting = tx.phase === \"preparing\" || tx.phase === \"submitting\" || tx.phase === \"confirming\";\n\n const isOwner =\n walletAddress &&\n collection?.owner &&\n normalizeAddress(\"STARKNET\", walletAddress) === normalizeAddress(\"STARKNET\", collection.owner);\n\n const issue = (recipient: string) => {\n setDone(successMessages.credentialIssued());\n void tx.run(async (signer) => {\n await runIntentCalls(signer, () => app.getClient().api.intents.create(\"pop-manage\", { owner: signer.address, collection: contract, action: \"issue\", recipient }));\n });\n };\n\n const publish = (addresses: string[]) => {\n const list = buildPopAllowlist(addresses);\n const count = Object.keys(list.proofs).length;\n setDone(successMessages.participantsPublished({ count }));\n void tx\n .run(async (signer) => {\n await runIntentCalls(signer, () => app.getClient().api.intents.create(\"pop-manage\", { owner: signer.address, collection: contract, action: \"set_allowlist_root\", root: list.root }));\n })\n .then((ok) => {\n if (ok) setLinks(popClaimLinks(window.location.origin, contract, list));\n });\n };\n\n return (\n <WalletRequired icon={Award} title=\"Connect your wallet\" description=\"Connect to manage your event.\">\n {isLoading ? (\n <div className=\"max-w-xl mx-auto px-4 pt-10 pb-16 space-y-4\">\n <Skeleton className=\"h-6 w-24\" />\n <Skeleton className=\"h-32 w-full rounded-2xl\" />\n <Skeleton className=\"h-64 w-full rounded-2xl\" />\n </div>\n ) : !collection ? (\n <div className=\"max-w-xl mx-auto px-4 pt-24 pb-8 text-center space-y-4\">\n <AlertCircle className=\"h-10 w-10 text-muted-foreground/20 mx-auto\" />\n <p className=\"text-muted-foreground\">Collection not found.</p>\n <Button asChild variant=\"outline\" size=\"sm\">\n <Link href=\"/launchpad/pop\">← Back</Link>\n </Button>\n </div>\n ) : !isOwner ? (\n <div className=\"max-w-xl mx-auto px-4 pt-24 pb-8 text-center space-y-4\">\n <Award className=\"h-10 w-10 text-muted-foreground/20 mx-auto\" />\n <p className=\"text-muted-foreground\">You are not the organizer of this event.</p>\n <Button asChild variant=\"outline\" size=\"sm\">\n <Link href=\"/launchpad/pop\">← Back to events</Link>\n </Button>\n </div>\n ) : (\n <div className=\"max-w-xl mx-auto px-4 pt-10 pb-16 space-y-6\">\n <TransactionDialog tx={tx} title=\"Manage event\" workingLabel=\"Updating your event…\" firstStepLabel=\"Prepare\">\n <TransactionSuccess name={collection.name ?? \"Event\"} title={done.title} description={done.description} txHash={tx.txHash} actions={[{ label: \"Done\", onClick: tx.reset }]} />\n </TransactionDialog>\n\n <FadeIn>\n <Button asChild variant=\"ghost\" size=\"sm\" className=\"-ml-2\">\n <Link href=\"/launchpad/pop\">\n <ArrowLeft className=\"h-3.5 w-3.5 mr-1.5\" />\n All events\n </Link>\n </Button>\n </FadeIn>\n\n <FadeIn delay={0.04}>\n <div>\n <span className=\"pill-badge inline-flex gap-1.5 mb-2\">\n <Award className=\"h-3 w-3\" />\n Organizer\n </span>\n <h1 className=\"text-2xl font-bold mt-1\">Manage Event</h1>\n <p className=\"text-sm text-muted-foreground\">{collection.name ?? contract}</p>\n </div>\n </FadeIn>\n\n <FadeIn delay={0.08}>\n <div className=\"bento-cell p-4 flex items-center gap-3\">\n <Award className=\"h-4 w-4 text-green-500 shrink-0\" />\n <p className=\"text-xs text-muted-foreground\">\n Only participants on your <strong className=\"text-foreground\">published list</strong> can claim,\n with the link you send them.\n </p>\n </div>\n </FadeIn>\n\n <FadeIn delay={0.12}>\n <AllowlistSection onPublish={publish} isSubmitting={isSubmitting} links={links} />\n </FadeIn>\n\n <FadeIn delay={0.16}>\n <IssueSection onIssue={issue} isSubmitting={isSubmitting} />\n </FadeIn>\n </div>\n )}\n </WalletRequired>\n );\n}\n"],"mappings":"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","names":["Link"]}
|
|
@@ -14,6 +14,7 @@ import { TransactionDialog } from "./transaction-dialog.js";
|
|
|
14
14
|
import { TransactionSuccess } from "./transaction-success.js";
|
|
15
15
|
import { WalletRequired } from "./wallet-required.js";
|
|
16
16
|
import { runIntentCalls } from "../utils/run-intent-calls.js";
|
|
17
|
+
import { successMessages } from "../utils/success-messages.js";
|
|
17
18
|
import { useCollection } from "../utils/use-collections.js";
|
|
18
19
|
import { useTransaction } from "../utils/use-transaction.js";
|
|
19
20
|
function parseAddresses(raw) {
|
|
@@ -131,7 +132,7 @@ function PopManagePage({ contract }) {
|
|
|
131
132
|
const isSubmitting = tx.phase === "preparing" || tx.phase === "submitting" || tx.phase === "confirming";
|
|
132
133
|
const isOwner = walletAddress && collection?.owner && normalizeAddress("STARKNET", walletAddress) === normalizeAddress("STARKNET", collection.owner);
|
|
133
134
|
const issue = (recipient) => {
|
|
134
|
-
setDone(
|
|
135
|
+
setDone(successMessages.credentialIssued());
|
|
135
136
|
void tx.run(async (signer) => {
|
|
136
137
|
await runIntentCalls(signer, () => app.getClient().api.intents.create("pop-manage", { owner: signer.address, collection: contract, action: "issue", recipient }));
|
|
137
138
|
});
|
|
@@ -139,7 +140,7 @@ function PopManagePage({ contract }) {
|
|
|
139
140
|
const publish = (addresses) => {
|
|
140
141
|
const list = buildPopAllowlist(addresses);
|
|
141
142
|
const count = Object.keys(list.proofs).length;
|
|
142
|
-
setDone({
|
|
143
|
+
setDone(successMessages.participantsPublished({ count }));
|
|
143
144
|
void tx.run(async (signer) => {
|
|
144
145
|
await runIntentCalls(signer, () => app.getClient().api.intents.create("pop-manage", { owner: signer.address, collection: contract, action: "set_allowlist_root", root: list.root }));
|
|
145
146
|
}).then((ok) => {
|