@medialane/ui 0.256.0 → 0.258.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/account/add-guardian-dialog.cjs +1 -1
- package/dist/components/account/add-guardian-dialog.cjs.map +1 -1
- package/dist/components/account/add-guardian-dialog.js +1 -1
- package/dist/components/account/add-guardian-dialog.js.map +1 -1
- package/dist/components/account/device-approval-dialog.cjs +2 -2
- package/dist/components/account/device-approval-dialog.cjs.map +1 -1
- package/dist/components/account/device-approval-dialog.js +2 -2
- package/dist/components/account/device-approval-dialog.js.map +1 -1
- package/dist/components/account/devices-section.cjs +1 -1
- package/dist/components/account/devices-section.cjs.map +1 -1
- package/dist/components/account/devices-section.js +1 -1
- package/dist/components/account/devices-section.js.map +1 -1
- package/dist/components/account/guardian-recovery-section.cjs +1 -1
- package/dist/components/account/guardian-recovery-section.cjs.map +1 -1
- package/dist/components/account/guardian-recovery-section.js +1 -1
- package/dist/components/account/guardian-recovery-section.js.map +1 -1
- package/dist/components/account/input-otp.d.cts +2 -2
- package/dist/components/account/input-otp.d.ts +2 -2
- package/dist/components/asset-page.cjs +8 -7
- package/dist/components/asset-page.cjs.map +1 -1
- package/dist/components/asset-page.js +8 -7
- package/dist/components/asset-page.js.map +1 -1
- package/dist/components/asset-publication.cjs +1 -3
- package/dist/components/asset-publication.cjs.map +1 -1
- package/dist/components/asset-publication.js +1 -3
- package/dist/components/asset-publication.js.map +1 -1
- package/dist/components/button.d.cts +2 -2
- package/dist/components/button.d.ts +2 -2
- package/dist/components/drop/create/launch-dialog.cjs +1 -1
- package/dist/components/drop/create/launch-dialog.cjs.map +1 -1
- package/dist/components/drop/create/launch-dialog.js +1 -1
- package/dist/components/drop/create/launch-dialog.js.map +1 -1
- package/dist/components/drop/page/drop-manage.cjs +1 -1
- package/dist/components/drop/page/drop-manage.cjs.map +1 -1
- package/dist/components/drop/page/drop-manage.js +1 -1
- package/dist/components/drop/page/drop-manage.js.map +1 -1
- package/dist/components/drop/page/drop-mint-dialog.cjs +1 -1
- package/dist/components/drop/page/drop-mint-dialog.cjs.map +1 -1
- package/dist/components/drop/page/drop-mint-dialog.js +1 -1
- package/dist/components/drop/page/drop-mint-dialog.js.map +1 -1
- package/dist/components/empty-or-error.cjs +2 -2
- package/dist/components/empty-or-error.cjs.map +1 -1
- package/dist/components/empty-or-error.js +2 -2
- package/dist/components/empty-or-error.js.map +1 -1
- package/dist/components/fast-mint/fast-mint.cjs +2 -1
- package/dist/components/fast-mint/fast-mint.cjs.map +1 -1
- package/dist/components/fast-mint/fast-mint.d.cts +2 -2
- package/dist/components/fast-mint/fast-mint.d.ts +2 -2
- package/dist/components/fast-mint/fast-mint.js +2 -1
- package/dist/components/fast-mint/fast-mint.js.map +1 -1
- package/dist/components/launchpad/edition-mint-schema.d.cts +2 -2
- package/dist/components/launchpad/edition-mint-schema.d.ts +2 -2
- package/dist/components/license-request-page.cjs +1 -1
- package/dist/components/license-request-page.cjs.map +1 -1
- package/dist/components/license-request-page.js +1 -1
- package/dist/components/license-request-page.js.map +1 -1
- package/dist/components/media-wallet/activate-card.cjs +1 -1
- package/dist/components/media-wallet/activate-card.cjs.map +1 -1
- package/dist/components/media-wallet/activate-card.js +1 -1
- package/dist/components/media-wallet/activate-card.js.map +1 -1
- package/dist/components/media-wallet/media-wallet-activity.cjs +1 -1
- package/dist/components/media-wallet/media-wallet-activity.cjs.map +1 -1
- package/dist/components/media-wallet/media-wallet-activity.js +1 -1
- package/dist/components/media-wallet/media-wallet-activity.js.map +1 -1
- package/dist/components/media-wallet/media-wallet-send.cjs +2 -6
- package/dist/components/media-wallet/media-wallet-send.cjs.map +1 -1
- package/dist/components/media-wallet/media-wallet-send.js +2 -6
- package/dist/components/media-wallet/media-wallet-send.js.map +1 -1
- package/dist/components/sheet.d.cts +1 -1
- package/dist/components/sheet.d.ts +1 -1
- package/dist/components/transaction-dialog.cjs +4 -4
- package/dist/components/transaction-dialog.cjs.map +1 -1
- package/dist/components/transaction-dialog.d.cts +3 -1
- package/dist/components/transaction-dialog.d.ts +3 -1
- package/dist/components/transaction-dialog.js +4 -4
- package/dist/components/transaction-dialog.js.map +1 -1
- package/dist/components/wallet/export-key-section.cjs +3 -3
- package/dist/components/wallet/export-key-section.cjs.map +1 -1
- package/dist/components/wallet/export-key-section.d.cts +1 -2
- package/dist/components/wallet/export-key-section.d.ts +1 -2
- package/dist/components/wallet/export-key-section.js +3 -3
- package/dist/components/wallet/export-key-section.js.map +1 -1
- package/dist/index.cjs +0 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +1 -1
- package/dist/utils/describe-error.cjs +16 -11
- package/dist/utils/describe-error.cjs.map +1 -1
- package/dist/utils/describe-error.d.cts +4 -4
- package/dist/utils/describe-error.d.ts +4 -4
- package/dist/utils/describe-error.js +16 -10
- package/dist/utils/describe-error.js.map +1 -1
- package/dist/utils/media-wallet/use-erc20-balance.d.cts +1 -1
- package/dist/utils/media-wallet/use-erc20-balance.d.ts +1 -1
- package/dist/utils/use-email-code.cjs +2 -2
- package/dist/utils/use-email-code.cjs.map +1 -1
- package/dist/utils/use-email-code.js +2 -2
- package/dist/utils/use-email-code.js.map +1 -1
- package/dist/utils/use-transaction.cjs +16 -2
- package/dist/utils/use-transaction.cjs.map +1 -1
- package/dist/utils/use-transaction.d.cts +1 -0
- package/dist/utils/use-transaction.d.ts +1 -0
- package/dist/utils/use-transaction.js +17 -3
- package/dist/utils/use-transaction.js.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/license-request-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { assetHref, getListableTokens, getTokenBySymbol, getService, resolveRemixPolicy, getDerivativesTerm } from \"@medialane/sdk\";\nimport Image from \"./image.js\";\nimport Link from \"./link.js\";\nimport { useRouter } from \"./router.js\";\nimport { ToggleGroup, Section } from \"./create-form-primitives.js\";\nimport { Button } from \"./button.js\";\nimport { Input } from \"./input.js\";\nimport { Textarea } from \"./textarea.js\";\nimport { Label } from \"./label.js\";\nimport { Skeleton } from \"./skeleton.js\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"./select.js\";\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from \"./collapsible.js\";\nimport { SignInPrompt } from \"./sign-in-prompt.js\";\nimport { useMedialaneApp } from \"./medialane-app.js\";\nimport { LICENSE_TYPES } from \"../data/ip.js\";\nimport { describeError } from \"../utils/describe-error.js\";\nimport { checkIsOwner } from \"../utils/ownership.js\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\nimport { useMedialaneClient } from \"../utils/use-medialane-client.js\";\nimport { useToken, useTokenBalance } from \"../utils/use-tokens.js\";\nimport { useCollection } from \"../utils/use-collections.js\";\nimport { ChevronLeft, ChevronDown, Shield, DollarSign, Percent, HandCoins, Loader2, Check } from \"lucide-react\";\n\nconst TOKENS = getListableTokens();\n\nexport function LicenseRequestPage({ contract, tokenId }: { contract: string; tokenId: string }) {\n const router = useRouter();\n const client = useMedialaneClient();\n const resolveImage = useImageUrl();\n const { walletAddress, walletLoading, ensureSignedIn } = useMedialaneApp();\n const { token, isLoading: tokenLoading } = useToken(contract, tokenId);\n const { collection: parentCollection } = useCollection(contract);\n\n const { amount: walletBalance } = useTokenBalance(contract, tokenId, walletAddress);\n const viewerIsOwner = checkIsOwner(token, walletAddress, walletBalance);\n const originalName = token?.metadata?.name ?? `Token #${tokenId}`;\n const originalImage = resolveImage(token?.metadata?.image, { width: 96 });\n const originalAttributes = Array.isArray(token?.metadata?.attributes)\n ? (token!.metadata!.attributes as { trait_type?: string; value?: string }[])\n : [];\n\n const policy = resolveRemixPolicy({\n parentNoDerivatives: getDerivativesTerm(originalAttributes) === \"Not Allowed\",\n viewerIsParentOwner: viewerIsOwner,\n dealAvailable: !!getService(parentCollection?.service),\n });\n\n const [licenseType, setLicenseType] = useState(\"CC BY\");\n const [commercial, setCommercial] = useState(false);\n const [derivatives, setDerivatives] = useState(true);\n const [royalty, setRoyalty] = useState(\"\");\n const [advancedOpen, setAdvancedOpen] = useState(false);\n const [price, setPrice] = useState(\"\");\n const [currency, setCurrency] = useState<string>(TOKENS[0]?.symbol ?? \"STRK\");\n const [message, setMessage] = useState(\"\");\n const [step, setStep] = useState<\"idle\" | \"success\" | \"error\">(\"idle\");\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n\n const handleLicenseChange = (value: string) => {\n setLicenseType(value);\n const preset = LICENSE_TYPES.find((l) => l.value === value);\n if (preset) {\n setCommercial(preset.commercialUse === \"Yes\");\n setDerivatives(preset.derivatives !== \"Not Allowed\");\n }\n };\n\n const handleSubmit = async () => {\n if (!price || isNaN(parseFloat(price)) || parseFloat(price) <= 0) {\n setError(\"Enter a license fee\");\n return;\n }\n setLoading(true);\n setError(null);\n try {\n await ensureSignedIn?.();\n const tokenInfo = getTokenBySymbol(currency);\n const decimals = tokenInfo?.decimals ?? 18;\n const rawPrice = BigInt(Math.round(parseFloat(price) * 10 ** decimals)).toString();\n await client.api.remix.submit({\n originalContract: contract,\n originalTokenId: tokenId,\n proposedPrice: rawPrice,\n proposedCurrency: tokenInfo?.address ?? \"\",\n licenseType,\n commercial,\n derivatives,\n royaltyPct: royalty ? parseInt(royalty) : undefined,\n message: message.trim() || undefined,\n });\n setStep(\"success\");\n } catch (err: unknown) {\n setStep(\"error\");\n setError(describeError(err, \"Failed to send license request\").message);\n } finally {\n setLoading(false);\n }\n };\n\n if (tokenLoading) {\n return (\n <div className=\"max-w-2xl mx-auto px-4 pt-14 pb-8 space-y-4\">\n <Skeleton className=\"h-8 w-48\" />\n {[1, 2, 3].map((i) => <Skeleton key={i} className=\"h-32 w-full rounded-xl\" />)}\n </div>\n );\n }\n if (!token) {\n return (\n <div className=\"max-w-2xl mx-auto px-4 py-24 text-center space-y-4\">\n <p className=\"text-2xl font-bold\">Asset not found</p>\n <Button asChild variant=\"outline\"><Link href=\"/\">Go home</Link></Button>\n </div>\n );\n }\n\n if (!walletAddress) {\n return (\n <div className=\"max-w-2xl mx-auto px-4 py-24\">\n {walletLoading ? <Skeleton className=\"h-40 w-full rounded-xl\" /> : <SignInPrompt icon={<HandCoins className=\"h-10 w-10 text-muted-foreground/30\" />} title=\"Sign in to request a license\" />}\n </div>\n );\n }\n\n if (viewerIsOwner || !policy.dealAvailable) {\n router.replace(assetHref(\"STARKNET\", contract, tokenId));\n return null;\n }\n\n return (\n <div className=\"max-w-2xl mx-auto px-4 pt-14 pb-12 space-y-6\">\n <div className=\"space-y-3\">\n <Link href={assetHref(\"STARKNET\", contract, tokenId)} className=\"inline-flex items-center gap-1.5 text-sm text-muted-foreground hover:text-foreground transition-colors\">\n <ChevronLeft className=\"h-4 w-4\" /> Back to asset\n </Link>\n <div className=\"flex items-center gap-2 text-primary\">\n <HandCoins className=\"h-5 w-5\" />\n <span className=\"text-sm font-semibold\">Request a license</span>\n </div>\n <h1 className=\"text-3xl font-bold\">License this asset</h1>\n <p className=\"text-muted-foreground max-w-xl\">\n Propose license terms and a fee to the creator. If they accept, the licensed derivative is minted and listed for you.\n </p>\n </div>\n\n <div className=\"flex items-center gap-3 rounded-xl border border-border bg-card p-4\">\n {originalImage && (\n <Image src={originalImage} alt={originalName} width={48} height={48} className=\"rounded-lg object-cover\" unoptimized />\n )}\n <div className=\"min-w-0\">\n <p className=\"text-sm font-semibold truncate\">{originalName}</p>\n <p className=\"text-xs text-muted-foreground truncate\">{parentCollection?.name ?? contract.slice(0, 10) + \"…\"}</p>\n </div>\n </div>\n\n {step === \"success\" ? (\n <div className=\"rounded-xl border border-border p-8 text-center space-y-4\">\n <div className=\"h-14 w-14 mx-auto rounded-full bg-primary/10 flex items-center justify-center\">\n <Check className=\"h-7 w-7 text-primary\" />\n </div>\n <p className=\"text-lg font-semibold\">License request sent</p>\n <p className=\"text-sm text-muted-foreground\">The creator will review it. Track it under Portfolio → Licensing.</p>\n <Button asChild variant=\"outline\"><Link href=\"/portfolio/licensing\">View my requests</Link></Button>\n </div>\n ) : (\n <>\n <Section title=\"License Terms\" icon={<Shield className=\"h-4 w-4\" />}>\n <div className=\"space-y-1.5\">\n <Label>License Type</Label>\n <Select value={licenseType} onValueChange={handleLicenseChange}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n {LICENSE_TYPES.map((l) => <SelectItem key={l.value} value={l.value}>{l.value}</SelectItem>)}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid grid-cols-2 gap-4\">\n <div className=\"space-y-1.5\">\n <Label className=\"text-xs text-muted-foreground uppercase tracking-wide\">Commercial Use</Label>\n <ToggleGroup value={commercial ? \"Yes\" : \"No\"} options={[\"Yes\", \"No\"]} onChange={(v) => setCommercial(v === \"Yes\")} />\n </div>\n <div className=\"space-y-1.5\">\n <Label className=\"text-xs text-muted-foreground uppercase tracking-wide\">Derivatives</Label>\n <ToggleGroup value={derivatives ? \"Allowed\" : \"Not Allowed\"} options={[\"Allowed\", \"Not Allowed\"]} onChange={(v) => setDerivatives(v === \"Allowed\")} />\n </div>\n </div>\n <Collapsible open={advancedOpen} onOpenChange={setAdvancedOpen}>\n <CollapsibleTrigger asChild>\n <button type=\"button\" className=\"flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground transition-colors\">\n <ChevronDown className={`h-3.5 w-3.5 transition-transform ${advancedOpen ? \"rotate-180\" : \"\"}`} /> Royalty & advanced\n </button>\n </CollapsibleTrigger>\n <CollapsibleContent className=\"pt-3 space-y-3\">\n <div className=\"space-y-1.5\">\n <Label className=\"flex items-center gap-1.5\"><Percent className=\"h-3.5 w-3.5\" /> Royalty %</Label>\n <Input type=\"number\" min=\"0\" max=\"50\" step=\"1\" placeholder=\"0\" value={royalty} onChange={(e) => setRoyalty(e.target.value)} />\n <p className=\"text-xs text-muted-foreground\">Percentage of future sales sent back to the creator (0–50%)</p>\n </div>\n </CollapsibleContent>\n </Collapsible>\n </Section>\n\n <Section title=\"License fee\" icon={<DollarSign className=\"h-4 w-4\" />}>\n <p className=\"text-xs text-muted-foreground -mt-1\">The amount you're offering to pay the creator for this license.</p>\n <div className=\"flex gap-2\">\n <Input type=\"number\" min=\"0\" step=\"any\" placeholder=\"0.00\" value={price} onChange={(e) => setPrice(e.target.value)} className=\"flex-1\" />\n <Select value={currency} onValueChange={setCurrency}>\n <SelectTrigger className=\"w-28\"><SelectValue /></SelectTrigger>\n <SelectContent>\n {TOKENS.map((t) => <SelectItem key={t.symbol} value={t.symbol}>{t.symbol}</SelectItem>)}\n </SelectContent>\n </Select>\n </div>\n </Section>\n\n <Section title=\"Message (optional)\" icon={<HandCoins className=\"h-4 w-4\" />}>\n <Textarea placeholder=\"Add a note for the creator…\" value={message} onChange={(e) => setMessage(e.target.value)} rows={3} />\n </Section>\n\n {error && <p className=\"text-sm text-destructive\">{error}</p>}\n\n <button\n className=\"w-full h-12 rounded-[11px] bg-brand-purple text-white text-sm font-semibold flex items-center justify-center gap-2 hover:brightness-110 active:scale-[0.98] transition-all disabled:opacity-50\"\n onClick={handleSubmit}\n disabled={loading}\n >\n {loading ? <Loader2 className=\"h-5 w-5 animate-spin\" /> : <HandCoins className=\"h-5 w-5\" />}\n Send license request\n </button>\n </>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/license-request-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { assetHref, getListableTokens, getTokenBySymbol, getService, resolveRemixPolicy, getDerivativesTerm } from \"@medialane/sdk\";\nimport Image from \"./image.js\";\nimport Link from \"./link.js\";\nimport { useRouter } from \"./router.js\";\nimport { ToggleGroup, Section } from \"./create-form-primitives.js\";\nimport { Button } from \"./button.js\";\nimport { Input } from \"./input.js\";\nimport { Textarea } from \"./textarea.js\";\nimport { Label } from \"./label.js\";\nimport { Skeleton } from \"./skeleton.js\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"./select.js\";\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from \"./collapsible.js\";\nimport { SignInPrompt } from \"./sign-in-prompt.js\";\nimport { useMedialaneApp } from \"./medialane-app.js\";\nimport { LICENSE_TYPES } from \"../data/ip.js\";\nimport { describeError } from \"../utils/describe-error.js\";\nimport { checkIsOwner } from \"../utils/ownership.js\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\nimport { useMedialaneClient } from \"../utils/use-medialane-client.js\";\nimport { useToken, useTokenBalance } from \"../utils/use-tokens.js\";\nimport { useCollection } from \"../utils/use-collections.js\";\nimport { ChevronLeft, ChevronDown, Shield, DollarSign, Percent, HandCoins, Loader2, Check } from \"lucide-react\";\n\nconst TOKENS = getListableTokens();\n\nexport function LicenseRequestPage({ contract, tokenId }: { contract: string; tokenId: string }) {\n const router = useRouter();\n const client = useMedialaneClient();\n const resolveImage = useImageUrl();\n const { walletAddress, walletLoading, ensureSignedIn } = useMedialaneApp();\n const { token, isLoading: tokenLoading } = useToken(contract, tokenId);\n const { collection: parentCollection } = useCollection(contract);\n\n const { amount: walletBalance } = useTokenBalance(contract, tokenId, walletAddress);\n const viewerIsOwner = checkIsOwner(token, walletAddress, walletBalance);\n const originalName = token?.metadata?.name ?? `Token #${tokenId}`;\n const originalImage = resolveImage(token?.metadata?.image, { width: 96 });\n const originalAttributes = Array.isArray(token?.metadata?.attributes)\n ? (token!.metadata!.attributes as { trait_type?: string; value?: string }[])\n : [];\n\n const policy = resolveRemixPolicy({\n parentNoDerivatives: getDerivativesTerm(originalAttributes) === \"Not Allowed\",\n viewerIsParentOwner: viewerIsOwner,\n dealAvailable: !!getService(parentCollection?.service),\n });\n\n const [licenseType, setLicenseType] = useState(\"CC BY\");\n const [commercial, setCommercial] = useState(false);\n const [derivatives, setDerivatives] = useState(true);\n const [royalty, setRoyalty] = useState(\"\");\n const [advancedOpen, setAdvancedOpen] = useState(false);\n const [price, setPrice] = useState(\"\");\n const [currency, setCurrency] = useState<string>(TOKENS[0]?.symbol ?? \"STRK\");\n const [message, setMessage] = useState(\"\");\n const [step, setStep] = useState<\"idle\" | \"success\" | \"error\">(\"idle\");\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n\n const handleLicenseChange = (value: string) => {\n setLicenseType(value);\n const preset = LICENSE_TYPES.find((l) => l.value === value);\n if (preset) {\n setCommercial(preset.commercialUse === \"Yes\");\n setDerivatives(preset.derivatives !== \"Not Allowed\");\n }\n };\n\n const handleSubmit = async () => {\n if (!price || isNaN(parseFloat(price)) || parseFloat(price) <= 0) {\n setError(\"Enter a license fee\");\n return;\n }\n setLoading(true);\n setError(null);\n try {\n await ensureSignedIn?.();\n const tokenInfo = getTokenBySymbol(currency);\n const decimals = tokenInfo?.decimals ?? 18;\n const rawPrice = BigInt(Math.round(parseFloat(price) * 10 ** decimals)).toString();\n await client.api.remix.submit({\n originalContract: contract,\n originalTokenId: tokenId,\n proposedPrice: rawPrice,\n proposedCurrency: tokenInfo?.address ?? \"\",\n licenseType,\n commercial,\n derivatives,\n royaltyPct: royalty ? parseInt(royalty) : undefined,\n message: message.trim() || undefined,\n });\n setStep(\"success\");\n } catch (err: unknown) {\n setStep(\"error\");\n setError(describeError(err).message);\n } finally {\n setLoading(false);\n }\n };\n\n if (tokenLoading) {\n return (\n <div className=\"max-w-2xl mx-auto px-4 pt-14 pb-8 space-y-4\">\n <Skeleton className=\"h-8 w-48\" />\n {[1, 2, 3].map((i) => <Skeleton key={i} className=\"h-32 w-full rounded-xl\" />)}\n </div>\n );\n }\n if (!token) {\n return (\n <div className=\"max-w-2xl mx-auto px-4 py-24 text-center space-y-4\">\n <p className=\"text-2xl font-bold\">Asset not found</p>\n <Button asChild variant=\"outline\"><Link href=\"/\">Go home</Link></Button>\n </div>\n );\n }\n\n if (!walletAddress) {\n return (\n <div className=\"max-w-2xl mx-auto px-4 py-24\">\n {walletLoading ? <Skeleton className=\"h-40 w-full rounded-xl\" /> : <SignInPrompt icon={<HandCoins className=\"h-10 w-10 text-muted-foreground/30\" />} title=\"Sign in to request a license\" />}\n </div>\n );\n }\n\n if (viewerIsOwner || !policy.dealAvailable) {\n router.replace(assetHref(\"STARKNET\", contract, tokenId));\n return null;\n }\n\n return (\n <div className=\"max-w-2xl mx-auto px-4 pt-14 pb-12 space-y-6\">\n <div className=\"space-y-3\">\n <Link href={assetHref(\"STARKNET\", contract, tokenId)} className=\"inline-flex items-center gap-1.5 text-sm text-muted-foreground hover:text-foreground transition-colors\">\n <ChevronLeft className=\"h-4 w-4\" /> Back to asset\n </Link>\n <div className=\"flex items-center gap-2 text-primary\">\n <HandCoins className=\"h-5 w-5\" />\n <span className=\"text-sm font-semibold\">Request a license</span>\n </div>\n <h1 className=\"text-3xl font-bold\">License this asset</h1>\n <p className=\"text-muted-foreground max-w-xl\">\n Propose license terms and a fee to the creator. If they accept, the licensed derivative is minted and listed for you.\n </p>\n </div>\n\n <div className=\"flex items-center gap-3 rounded-xl border border-border bg-card p-4\">\n {originalImage && (\n <Image src={originalImage} alt={originalName} width={48} height={48} className=\"rounded-lg object-cover\" unoptimized />\n )}\n <div className=\"min-w-0\">\n <p className=\"text-sm font-semibold truncate\">{originalName}</p>\n <p className=\"text-xs text-muted-foreground truncate\">{parentCollection?.name ?? contract.slice(0, 10) + \"…\"}</p>\n </div>\n </div>\n\n {step === \"success\" ? (\n <div className=\"rounded-xl border border-border p-8 text-center space-y-4\">\n <div className=\"h-14 w-14 mx-auto rounded-full bg-primary/10 flex items-center justify-center\">\n <Check className=\"h-7 w-7 text-primary\" />\n </div>\n <p className=\"text-lg font-semibold\">License request sent</p>\n <p className=\"text-sm text-muted-foreground\">The creator will review it. Track it under Portfolio → Licensing.</p>\n <Button asChild variant=\"outline\"><Link href=\"/portfolio/licensing\">View my requests</Link></Button>\n </div>\n ) : (\n <>\n <Section title=\"License Terms\" icon={<Shield className=\"h-4 w-4\" />}>\n <div className=\"space-y-1.5\">\n <Label>License Type</Label>\n <Select value={licenseType} onValueChange={handleLicenseChange}>\n <SelectTrigger><SelectValue /></SelectTrigger>\n <SelectContent>\n {LICENSE_TYPES.map((l) => <SelectItem key={l.value} value={l.value}>{l.value}</SelectItem>)}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid grid-cols-2 gap-4\">\n <div className=\"space-y-1.5\">\n <Label className=\"text-xs text-muted-foreground uppercase tracking-wide\">Commercial Use</Label>\n <ToggleGroup value={commercial ? \"Yes\" : \"No\"} options={[\"Yes\", \"No\"]} onChange={(v) => setCommercial(v === \"Yes\")} />\n </div>\n <div className=\"space-y-1.5\">\n <Label className=\"text-xs text-muted-foreground uppercase tracking-wide\">Derivatives</Label>\n <ToggleGroup value={derivatives ? \"Allowed\" : \"Not Allowed\"} options={[\"Allowed\", \"Not Allowed\"]} onChange={(v) => setDerivatives(v === \"Allowed\")} />\n </div>\n </div>\n <Collapsible open={advancedOpen} onOpenChange={setAdvancedOpen}>\n <CollapsibleTrigger asChild>\n <button type=\"button\" className=\"flex items-center gap-1.5 text-xs text-muted-foreground hover:text-foreground transition-colors\">\n <ChevronDown className={`h-3.5 w-3.5 transition-transform ${advancedOpen ? \"rotate-180\" : \"\"}`} /> Royalty & advanced\n </button>\n </CollapsibleTrigger>\n <CollapsibleContent className=\"pt-3 space-y-3\">\n <div className=\"space-y-1.5\">\n <Label className=\"flex items-center gap-1.5\"><Percent className=\"h-3.5 w-3.5\" /> Royalty %</Label>\n <Input type=\"number\" min=\"0\" max=\"50\" step=\"1\" placeholder=\"0\" value={royalty} onChange={(e) => setRoyalty(e.target.value)} />\n <p className=\"text-xs text-muted-foreground\">Percentage of future sales sent back to the creator (0–50%)</p>\n </div>\n </CollapsibleContent>\n </Collapsible>\n </Section>\n\n <Section title=\"License fee\" icon={<DollarSign className=\"h-4 w-4\" />}>\n <p className=\"text-xs text-muted-foreground -mt-1\">The amount you're offering to pay the creator for this license.</p>\n <div className=\"flex gap-2\">\n <Input type=\"number\" min=\"0\" step=\"any\" placeholder=\"0.00\" value={price} onChange={(e) => setPrice(e.target.value)} className=\"flex-1\" />\n <Select value={currency} onValueChange={setCurrency}>\n <SelectTrigger className=\"w-28\"><SelectValue /></SelectTrigger>\n <SelectContent>\n {TOKENS.map((t) => <SelectItem key={t.symbol} value={t.symbol}>{t.symbol}</SelectItem>)}\n </SelectContent>\n </Select>\n </div>\n </Section>\n\n <Section title=\"Message (optional)\" icon={<HandCoins className=\"h-4 w-4\" />}>\n <Textarea placeholder=\"Add a note for the creator…\" value={message} onChange={(e) => setMessage(e.target.value)} rows={3} />\n </Section>\n\n {error && <p className=\"text-sm text-destructive\">{error}</p>}\n\n <button\n className=\"w-full h-12 rounded-[11px] bg-brand-purple text-white text-sm font-semibold flex items-center justify-center gap-2 hover:brightness-110 active:scale-[0.98] transition-all disabled:opacity-50\"\n onClick={handleSubmit}\n disabled={loading}\n >\n {loading ? <Loader2 className=\"h-5 w-5 animate-spin\" /> : <HandCoins className=\"h-5 w-5\" />}\n Send license request\n </button>\n </>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -40,7 +40,7 @@ function ActivateCard({ onActivated }) {
|
|
|
40
40
|
});
|
|
41
41
|
onActivated();
|
|
42
42
|
} catch (e) {
|
|
43
|
-
setError((0, import_describe_error.describeError)(e
|
|
43
|
+
setError((0, import_describe_error.describeError)(e).message);
|
|
44
44
|
} finally {
|
|
45
45
|
setBusy(false);
|
|
46
46
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/media-wallet/activate-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { ActionButton } from \"../action-button.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { useMediaWalletApp } from \"./types.js\";\n\nconst BRAND_GRADIENT = \"linear-gradient(115deg,#3b7bff,#8a5cf6,#f6608f,#fb8b46,#3b7bff)\";\n\nexport function ActivateCard({ onActivated }: { onActivated: (txHash?: string) => void }) {\n const { wallet } = useMediaWalletApp();\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const activate = async () => {\n setError(null);\n setBusy(true);\n try {\n await wallet.completeDeployment(() => {});\n onActivated();\n } catch (e) {\n setError(describeError(e
|
|
1
|
+
{"version":3,"sources":["../../../src/components/media-wallet/activate-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { ActionButton } from \"../action-button.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { useMediaWalletApp } from \"./types.js\";\n\nconst BRAND_GRADIENT = \"linear-gradient(115deg,#3b7bff,#8a5cf6,#f6608f,#fb8b46,#3b7bff)\";\n\nexport function ActivateCard({ onActivated }: { onActivated: (txHash?: string) => void }) {\n const { wallet } = useMediaWalletApp();\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const activate = async () => {\n setError(null);\n setBusy(true);\n try {\n await wallet.completeDeployment(() => {});\n onActivated();\n } catch (e) {\n setError(describeError(e).message);\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <div className=\"card-base p-5\">\n <div className=\"flex flex-col items-center gap-3 text-center\">\n <ActionButton\n action=\"buy\"\n big\n onClick={activate}\n disabled={busy}\n className=\"w-full disabled:opacity-40 disabled:pointer-events-none\"\n style={{ \"--ml-grad\": BRAND_GRADIENT } as React.CSSProperties}\n >\n {busy && <span className=\"h-4 w-4 animate-spin rounded-full border-2 border-foreground/25 border-t-foreground\" />}\n Activate my wallet\n </ActionButton>\n <p className=\"mx-auto max-w-[22rem] text-sm leading-relaxed text-muted-foreground\">\n Your account is stored securely and ready whenever you need it. Activating is free — no gas fees.\n </p>\n {error && <p className=\"text-xs text-destructive\">{error}</p>}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA8BQ;AA5BR,mBAAyB;AACzB,2BAA6B;AAC7B,4BAA8B;AAC9B,mBAAkC;AAElC,MAAM,iBAAiB;AAEhB,SAAS,aAAa,EAAE,YAAY,GAA+C;AACxF,QAAM,EAAE,OAAO,QAAI,gCAAkB;AACrC,QAAM,CAAC,MAAM,OAAO,QAAI,uBAAS,KAAK;AACtC,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAwB,IAAI;AAEtD,QAAM,WAAW,YAAY;AAC3B,aAAS,IAAI;AACb,YAAQ,IAAI;AACZ,QAAI;AACF,YAAM,OAAO,mBAAmB,MAAM;AAAA,MAAC,CAAC;AACxC,kBAAY;AAAA,IACd,SAAS,GAAG;AACV,mBAAS,qCAAc,CAAC,EAAE,OAAO;AAAA,IACnC,UAAE;AACA,cAAQ,KAAK;AAAA,IACf;AAAA,EACF;AAEA,SACE,4CAAC,SAAI,WAAU,iBACb,uDAAC,SAAI,WAAU,gDACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,QAAO;AAAA,QACP,KAAG;AAAA,QACH,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAU;AAAA,QACV,OAAO,EAAE,aAAa,eAAe;AAAA,QAEpC;AAAA,kBAAQ,4CAAC,UAAK,WAAU,uFAAsF;AAAA,UAAG;AAAA;AAAA;AAAA,IAEpH;AAAA,IACA,4CAAC,OAAE,WAAU,uEAAsE,oHAEnF;AAAA,IACC,SAAS,4CAAC,OAAE,WAAU,4BAA4B,iBAAM;AAAA,KAC3D,GACF;AAEJ;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/media-wallet/activate-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { ActionButton } from \"../action-button.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { useMediaWalletApp } from \"./types.js\";\n\nconst BRAND_GRADIENT = \"linear-gradient(115deg,#3b7bff,#8a5cf6,#f6608f,#fb8b46,#3b7bff)\";\n\nexport function ActivateCard({ onActivated }: { onActivated: (txHash?: string) => void }) {\n const { wallet } = useMediaWalletApp();\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const activate = async () => {\n setError(null);\n setBusy(true);\n try {\n await wallet.completeDeployment(() => {});\n onActivated();\n } catch (e) {\n setError(describeError(e
|
|
1
|
+
{"version":3,"sources":["../../../src/components/media-wallet/activate-card.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { ActionButton } from \"../action-button.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { useMediaWalletApp } from \"./types.js\";\n\nconst BRAND_GRADIENT = \"linear-gradient(115deg,#3b7bff,#8a5cf6,#f6608f,#fb8b46,#3b7bff)\";\n\nexport function ActivateCard({ onActivated }: { onActivated: (txHash?: string) => void }) {\n const { wallet } = useMediaWalletApp();\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const activate = async () => {\n setError(null);\n setBusy(true);\n try {\n await wallet.completeDeployment(() => {});\n onActivated();\n } catch (e) {\n setError(describeError(e).message);\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <div className=\"card-base p-5\">\n <div className=\"flex flex-col items-center gap-3 text-center\">\n <ActionButton\n action=\"buy\"\n big\n onClick={activate}\n disabled={busy}\n className=\"w-full disabled:opacity-40 disabled:pointer-events-none\"\n style={{ \"--ml-grad\": BRAND_GRADIENT } as React.CSSProperties}\n >\n {busy && <span className=\"h-4 w-4 animate-spin rounded-full border-2 border-foreground/25 border-t-foreground\" />}\n Activate my wallet\n </ActionButton>\n <p className=\"mx-auto max-w-[22rem] text-sm leading-relaxed text-muted-foreground\">\n Your account is stored securely and ready whenever you need it. Activating is free — no gas fees.\n </p>\n {error && <p className=\"text-xs text-destructive\">{error}</p>}\n </div>\n </div>\n );\n}\n"],"mappings":";AA8BQ,SAQW,KARX;AA5BR,SAAS,gBAAgB;AACzB,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAC9B,SAAS,yBAAyB;AAElC,MAAM,iBAAiB;AAEhB,SAAS,aAAa,EAAE,YAAY,GAA+C;AACxF,QAAM,EAAE,OAAO,IAAI,kBAAkB;AACrC,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,IAAI;AAEtD,QAAM,WAAW,YAAY;AAC3B,aAAS,IAAI;AACb,YAAQ,IAAI;AACZ,QAAI;AACF,YAAM,OAAO,mBAAmB,MAAM;AAAA,MAAC,CAAC;AACxC,kBAAY;AAAA,IACd,SAAS,GAAG;AACV,eAAS,cAAc,CAAC,EAAE,OAAO;AAAA,IACnC,UAAE;AACA,cAAQ,KAAK;AAAA,IACf;AAAA,EACF;AAEA,SACE,oBAAC,SAAI,WAAU,iBACb,+BAAC,SAAI,WAAU,gDACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,QAAO;AAAA,QACP,KAAG;AAAA,QACH,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAU;AAAA,QACV,OAAO,EAAE,aAAa,eAAe;AAAA,QAEpC;AAAA,kBAAQ,oBAAC,UAAK,WAAU,uFAAsF;AAAA,UAAG;AAAA;AAAA;AAAA,IAEpH;AAAA,IACA,oBAAC,OAAE,WAAU,uEAAsE,oHAEnF;AAAA,IACC,SAAS,oBAAC,OAAE,WAAU,4BAA4B,iBAAM;AAAA,KAC3D,GACF;AAEJ;","names":[]}
|
|
@@ -78,7 +78,7 @@ function MediaWalletActivity({ onNavigate }) {
|
|
|
78
78
|
]);
|
|
79
79
|
if (live) setItems((0, import_activity_feed.mergeActivityFeeds)(walletRes.data, protocolRes.data));
|
|
80
80
|
} catch (e) {
|
|
81
|
-
if (live) setError((0, import_describe_error.describeError)(e
|
|
81
|
+
if (live) setError((0, import_describe_error.describeError)(e).message);
|
|
82
82
|
} finally {
|
|
83
83
|
if (live) setLoading(false);
|
|
84
84
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/media-wallet/media-wallet-activity.tsx"],"sourcesContent":["\"use client\";\n\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { useCallback, useEffect, useState } from \"react\";\nimport Image from \"../image.js\";\nimport type { ApiWalletActivity, ApiActivity } from \"@medialane/sdk\";\nimport { getTokenBySymbol } from \"@medialane/sdk\";\nimport { mergeActivityFeeds, type MergedActivityItem } from \"../../utils/media-wallet/activity-feed.js\";\nimport { walletActivityTitle, walletActivitySubtitle, walletActivityAmount } from \"../../utils/media-wallet/wallet-activity.js\";\nimport { short, when, explorerTxUrl, fmt } from \"../../utils/media-wallet/wallet-format.js\";\nimport { BackButton } from \"./back-button.js\";\nimport { WalletActivityIcon } from \"./wallet-activity-icon.js\";\nimport { ActionModal } from \"./action-modal.js\";\nimport { useMediaWalletApp, type MediaWalletView } from \"./types.js\";\nimport { useMedialaneApp } from \"../medialane-app.js\";\n\nconst GRADS = [\n \"linear-gradient(135deg,#3b7bff,#8a5cf6)\",\n \"linear-gradient(135deg,#8a5cf6,#f6608f)\",\n \"linear-gradient(135deg,#f6608f,#fb8b46)\",\n \"linear-gradient(135deg,#5b4ce6,#3b7bff)\",\n];\nconst gradFor = (seed: string) => {\n let h = 0;\n for (let i = 0; i < seed.length; i++) h = (h * 31 + seed.charCodeAt(i)) | 0;\n return GRADS[Math.abs(h) % GRADS.length];\n};\n\nexport function MediaWalletActivity({ onNavigate }: { onNavigate: (view: MediaWalletView) => void }) {\n const { useWalletSession } = useMediaWalletApp();\n const { getClient } = useMedialaneApp();\n const { address } = useWalletSession();\n const [items, setItems] = useState<MergedActivityItem[] | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n const [selected, setSelected] = useState<ApiWalletActivity | null>(null);\n\n const load = useCallback(() => {\n if (!address) return;\n let live = true;\n setLoading(true);\n setError(null);\n (async () => {\n try {\n const client = getClient().api;\n const [walletRes, protocolRes] = await Promise.all([\n client.activity.wallet(address),\n client.activity.byAddress(address, { page: 1, limit: 50 }),\n ]);\n if (live) setItems(mergeActivityFeeds(walletRes.data, protocolRes.data));\n } catch (e) {\n if (live) setError(describeError(e, \"We couldn't load your activity. Please try again.\").message);\n } finally {\n if (live) setLoading(false);\n }\n })();\n return () => { live = false; };\n }, [address, getClient]);\n\n useEffect(() => load(), [load]);\n\n return (\n <main className=\"flex flex-col gap-4 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\">Activity</h1>\n </div>\n\n {!address && <div className=\"text-sm text-muted-foreground\">No wallet found on this device.</div>}\n {error && <ActivityLoadError onRetry={load} />}\n {loading && !items && !error && <ActivityLoading />}\n {items && items.length === 0 && <div className=\"text-sm text-muted-foreground\">No activity yet.</div>}\n\n {items && items.length > 0 && (\n <div className=\"flex flex-col gap-2\">\n {items.map((item) =>\n item.source === \"wallet\" ? (\n <WalletActivityRow key={item.data.id} a={item.data} timestamp={item.timestamp} onOpen={setSelected} />\n ) : (\n <ProtocolActivityRow key={`${item.data.txHash}-${item.data.type}`} item={item.data} />\n ),\n )}\n </div>\n )}\n\n {selected && <ActivityDetailModal a={selected} onClose={() => setSelected(null)} />}\n </main>\n );\n}\n\nfunction WalletActivityRow({\n a,\n timestamp,\n onOpen,\n}: {\n a: ApiWalletActivity;\n timestamp: string;\n onOpen: (a: ApiWalletActivity) => void;\n}) {\n const subtitle = walletActivitySubtitle(a);\n const amount = walletActivityAmount(a);\n return (\n <button\n onClick={() => onOpen(a)}\n className=\"flex items-center gap-3 rounded-2xl bg-card/40 px-4 py-3 text-left backdrop-blur-sm transition-colors hover:bg-card/60\"\n >\n <WalletActivityIcon a={a} />\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-sm font-semibold\">{walletActivityTitle(a)}</div>\n {subtitle && <div className=\"truncate text-xs text-muted-foreground\">{subtitle}</div>}\n </div>\n <div className=\"shrink-0 text-right\">\n {amount && <div className=\"text-sm font-semibold tabular-nums\">{amount}</div>}\n <div className=\"text-xs text-muted-foreground\">{when(timestamp)}</div>\n </div>\n </button>\n );\n}\n\nfunction ActivityDetailModal({ a, onClose }: { a: ApiWalletActivity; onClose: () => void }) {\n const { explorerUrl } = useMediaWalletApp();\n const [copied, setCopied] = useState(false);\n const subtitle = walletActivitySubtitle(a);\n const amount = walletActivityAmount(a);\n const fullDate = new Date(a.timestamp).toLocaleString(undefined, {\n dateStyle: \"medium\",\n timeStyle: \"short\",\n });\n\n const copyHash = () => {\n navigator.clipboard?.writeText(a.txHash).catch(() => {});\n setCopied(true);\n setTimeout(() => setCopied(false), 1500);\n };\n\n return (\n <ActionModal title={walletActivityTitle(a)} onClose={onClose}>\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex flex-col items-center gap-2 py-2 text-center\">\n <WalletActivityIcon a={a} />\n {amount && <div className=\"text-2xl font-bold tabular-nums\">{amount}</div>}\n {subtitle && <div className=\"text-sm text-muted-foreground\">{subtitle}</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\">\n <span className=\"text-xs text-muted-foreground\">Date</span>\n <span className=\"text-sm font-medium\">{fullDate}</span>\n </div>\n <div className=\"flex items-center justify-between py-3\">\n <span className=\"text-xs text-muted-foreground\">Transaction</span>\n <button onClick={copyHash} className=\"font-mono text-sm font-medium transition-opacity active:opacity-60\">\n {copied ? \"Copied ✓\" : short(a.txHash)}\n </button>\n </div>\n </div>\n\n <a\n href={explorerTxUrl(explorerUrl, a.txHash)}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-center text-xs font-medium text-muted-foreground underline underline-offset-2\"\n >\n View on Voyager ↗\n </a>\n </div>\n </ActionModal>\n );\n}\n\nfunction ProtocolActivityRow({ item }: { item: ApiActivity }) {\n const { resolveImage } = useMediaWalletApp();\n const img = resolveImage(item.token?.image ?? null);\n const seed = item.txHash ?? item.orderHash ?? item.type;\n return (\n <div className=\"flex items-center gap-3 rounded-2xl bg-card/40 px-4 py-3 backdrop-blur-sm\">\n <div className=\"relative h-11 w-11 shrink-0 overflow-hidden rounded-2xl\" style={img ? undefined : { background: gradFor(seed) }}>\n {img && (\n <Image src={img} alt=\"\" fill className=\"object-cover\" />\n )}\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-sm font-semibold capitalize\">{item.type}</div>\n {item.token?.name && <div className=\"truncate text-xs text-muted-foreground\">{item.token.name}</div>}\n </div>\n <div className=\"shrink-0 text-right\">\n {item.price?.raw && item.price.currency && (\n <div className=\"text-sm font-semibold tabular-nums\">\n {fmt(BigInt(item.price.raw), getTokenBySymbol(item.price.currency)?.decimals ?? 18)} <span className=\"text-xs text-muted-foreground\">{item.price.currency}</span>\n </div>\n )}\n <div className=\"text-xs text-muted-foreground\">{when(item.timestamp)}</div>\n </div>\n </div>\n );\n}\n\nfunction ActivityLoading() {\n return (\n <div className=\"flex min-h-[40vh] flex-col items-center justify-center gap-3\">\n <span className=\"h-6 w-6 animate-spin rounded-full border-2 border-border border-t-foreground\" />\n <div className=\"text-sm text-muted-foreground\">Loading your activity…</div>\n </div>\n );\n}\n\nfunction ActivityLoadError({ onRetry }: { onRetry: () => void }) {\n return (\n <div className=\"card-base flex flex-col items-center gap-3 px-6 py-8 text-center\">\n <div className=\"grid h-11 w-11 place-items-center rounded-2xl bg-destructive/10 text-destructive\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M10.3 3.9L2.3 18a2 2 0 001.7 3h16a2 2 0 001.7-3L13.7 3.9a2 2 0 00-3.4 0z\" />\n <path d=\"M12 9v4M12 17h.01\" />\n </svg>\n </div>\n <div>\n <div className=\"text-sm font-semibold\">Couldn't load your activity</div>\n <p className=\"mx-auto mt-1 max-w-[16rem] text-xs leading-relaxed text-muted-foreground\">\n There was a problem reaching the server. Check your connection and try again.\n </p>\n </div>\n <button\n onClick={onRetry}\n className=\"rounded-full border border-border px-4 py-2 text-xs font-semibold text-foreground transition-colors hover:bg-card\"\n >\n Try again\n </button>\n </div>\n );\n}\n"],"mappings":"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","names":["Image"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/media-wallet/media-wallet-activity.tsx"],"sourcesContent":["\"use client\";\n\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { useCallback, useEffect, useState } from \"react\";\nimport Image from \"../image.js\";\nimport type { ApiWalletActivity, ApiActivity } from \"@medialane/sdk\";\nimport { getTokenBySymbol } from \"@medialane/sdk\";\nimport { mergeActivityFeeds, type MergedActivityItem } from \"../../utils/media-wallet/activity-feed.js\";\nimport { walletActivityTitle, walletActivitySubtitle, walletActivityAmount } from \"../../utils/media-wallet/wallet-activity.js\";\nimport { short, when, explorerTxUrl, fmt } from \"../../utils/media-wallet/wallet-format.js\";\nimport { BackButton } from \"./back-button.js\";\nimport { WalletActivityIcon } from \"./wallet-activity-icon.js\";\nimport { ActionModal } from \"./action-modal.js\";\nimport { useMediaWalletApp, type MediaWalletView } from \"./types.js\";\nimport { useMedialaneApp } from \"../medialane-app.js\";\n\nconst GRADS = [\n \"linear-gradient(135deg,#3b7bff,#8a5cf6)\",\n \"linear-gradient(135deg,#8a5cf6,#f6608f)\",\n \"linear-gradient(135deg,#f6608f,#fb8b46)\",\n \"linear-gradient(135deg,#5b4ce6,#3b7bff)\",\n];\nconst gradFor = (seed: string) => {\n let h = 0;\n for (let i = 0; i < seed.length; i++) h = (h * 31 + seed.charCodeAt(i)) | 0;\n return GRADS[Math.abs(h) % GRADS.length];\n};\n\nexport function MediaWalletActivity({ onNavigate }: { onNavigate: (view: MediaWalletView) => void }) {\n const { useWalletSession } = useMediaWalletApp();\n const { getClient } = useMedialaneApp();\n const { address } = useWalletSession();\n const [items, setItems] = useState<MergedActivityItem[] | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n const [selected, setSelected] = useState<ApiWalletActivity | null>(null);\n\n const load = useCallback(() => {\n if (!address) return;\n let live = true;\n setLoading(true);\n setError(null);\n (async () => {\n try {\n const client = getClient().api;\n const [walletRes, protocolRes] = await Promise.all([\n client.activity.wallet(address),\n client.activity.byAddress(address, { page: 1, limit: 50 }),\n ]);\n if (live) setItems(mergeActivityFeeds(walletRes.data, protocolRes.data));\n } catch (e) {\n if (live) setError(describeError(e).message);\n } finally {\n if (live) setLoading(false);\n }\n })();\n return () => { live = false; };\n }, [address, getClient]);\n\n useEffect(() => load(), [load]);\n\n return (\n <main className=\"flex flex-col gap-4 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\">Activity</h1>\n </div>\n\n {!address && <div className=\"text-sm text-muted-foreground\">No wallet found on this device.</div>}\n {error && <ActivityLoadError onRetry={load} />}\n {loading && !items && !error && <ActivityLoading />}\n {items && items.length === 0 && <div className=\"text-sm text-muted-foreground\">No activity yet.</div>}\n\n {items && items.length > 0 && (\n <div className=\"flex flex-col gap-2\">\n {items.map((item) =>\n item.source === \"wallet\" ? (\n <WalletActivityRow key={item.data.id} a={item.data} timestamp={item.timestamp} onOpen={setSelected} />\n ) : (\n <ProtocolActivityRow key={`${item.data.txHash}-${item.data.type}`} item={item.data} />\n ),\n )}\n </div>\n )}\n\n {selected && <ActivityDetailModal a={selected} onClose={() => setSelected(null)} />}\n </main>\n );\n}\n\nfunction WalletActivityRow({\n a,\n timestamp,\n onOpen,\n}: {\n a: ApiWalletActivity;\n timestamp: string;\n onOpen: (a: ApiWalletActivity) => void;\n}) {\n const subtitle = walletActivitySubtitle(a);\n const amount = walletActivityAmount(a);\n return (\n <button\n onClick={() => onOpen(a)}\n className=\"flex items-center gap-3 rounded-2xl bg-card/40 px-4 py-3 text-left backdrop-blur-sm transition-colors hover:bg-card/60\"\n >\n <WalletActivityIcon a={a} />\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-sm font-semibold\">{walletActivityTitle(a)}</div>\n {subtitle && <div className=\"truncate text-xs text-muted-foreground\">{subtitle}</div>}\n </div>\n <div className=\"shrink-0 text-right\">\n {amount && <div className=\"text-sm font-semibold tabular-nums\">{amount}</div>}\n <div className=\"text-xs text-muted-foreground\">{when(timestamp)}</div>\n </div>\n </button>\n );\n}\n\nfunction ActivityDetailModal({ a, onClose }: { a: ApiWalletActivity; onClose: () => void }) {\n const { explorerUrl } = useMediaWalletApp();\n const [copied, setCopied] = useState(false);\n const subtitle = walletActivitySubtitle(a);\n const amount = walletActivityAmount(a);\n const fullDate = new Date(a.timestamp).toLocaleString(undefined, {\n dateStyle: \"medium\",\n timeStyle: \"short\",\n });\n\n const copyHash = () => {\n navigator.clipboard?.writeText(a.txHash).catch(() => {});\n setCopied(true);\n setTimeout(() => setCopied(false), 1500);\n };\n\n return (\n <ActionModal title={walletActivityTitle(a)} onClose={onClose}>\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex flex-col items-center gap-2 py-2 text-center\">\n <WalletActivityIcon a={a} />\n {amount && <div className=\"text-2xl font-bold tabular-nums\">{amount}</div>}\n {subtitle && <div className=\"text-sm text-muted-foreground\">{subtitle}</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\">\n <span className=\"text-xs text-muted-foreground\">Date</span>\n <span className=\"text-sm font-medium\">{fullDate}</span>\n </div>\n <div className=\"flex items-center justify-between py-3\">\n <span className=\"text-xs text-muted-foreground\">Transaction</span>\n <button onClick={copyHash} className=\"font-mono text-sm font-medium transition-opacity active:opacity-60\">\n {copied ? \"Copied ✓\" : short(a.txHash)}\n </button>\n </div>\n </div>\n\n <a\n href={explorerTxUrl(explorerUrl, a.txHash)}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-center text-xs font-medium text-muted-foreground underline underline-offset-2\"\n >\n View on Voyager ↗\n </a>\n </div>\n </ActionModal>\n );\n}\n\nfunction ProtocolActivityRow({ item }: { item: ApiActivity }) {\n const { resolveImage } = useMediaWalletApp();\n const img = resolveImage(item.token?.image ?? null);\n const seed = item.txHash ?? item.orderHash ?? item.type;\n return (\n <div className=\"flex items-center gap-3 rounded-2xl bg-card/40 px-4 py-3 backdrop-blur-sm\">\n <div className=\"relative h-11 w-11 shrink-0 overflow-hidden rounded-2xl\" style={img ? undefined : { background: gradFor(seed) }}>\n {img && (\n <Image src={img} alt=\"\" fill className=\"object-cover\" />\n )}\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-sm font-semibold capitalize\">{item.type}</div>\n {item.token?.name && <div className=\"truncate text-xs text-muted-foreground\">{item.token.name}</div>}\n </div>\n <div className=\"shrink-0 text-right\">\n {item.price?.raw && item.price.currency && (\n <div className=\"text-sm font-semibold tabular-nums\">\n {fmt(BigInt(item.price.raw), getTokenBySymbol(item.price.currency)?.decimals ?? 18)} <span className=\"text-xs text-muted-foreground\">{item.price.currency}</span>\n </div>\n )}\n <div className=\"text-xs text-muted-foreground\">{when(item.timestamp)}</div>\n </div>\n </div>\n );\n}\n\nfunction ActivityLoading() {\n return (\n <div className=\"flex min-h-[40vh] flex-col items-center justify-center gap-3\">\n <span className=\"h-6 w-6 animate-spin rounded-full border-2 border-border border-t-foreground\" />\n <div className=\"text-sm text-muted-foreground\">Loading your activity…</div>\n </div>\n );\n}\n\nfunction ActivityLoadError({ onRetry }: { onRetry: () => void }) {\n return (\n <div className=\"card-base flex flex-col items-center gap-3 px-6 py-8 text-center\">\n <div className=\"grid h-11 w-11 place-items-center rounded-2xl bg-destructive/10 text-destructive\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M10.3 3.9L2.3 18a2 2 0 001.7 3h16a2 2 0 001.7-3L13.7 3.9a2 2 0 00-3.4 0z\" />\n <path d=\"M12 9v4M12 17h.01\" />\n </svg>\n </div>\n <div>\n <div className=\"text-sm font-semibold\">Couldn't load your activity</div>\n <p className=\"mx-auto mt-1 max-w-[16rem] text-xs leading-relaxed text-muted-foreground\">\n There was a problem reaching the server. Check your connection and try again.\n </p>\n </div>\n <button\n onClick={onRetry}\n className=\"rounded-full border border-border px-4 py-2 text-xs font-semibold text-foreground transition-colors hover:bg-card\"\n >\n Try again\n </button>\n </div>\n );\n}\n"],"mappings":"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","names":["Image"]}
|
|
@@ -45,7 +45,7 @@ function MediaWalletActivity({ onNavigate }) {
|
|
|
45
45
|
]);
|
|
46
46
|
if (live) setItems(mergeActivityFeeds(walletRes.data, protocolRes.data));
|
|
47
47
|
} catch (e) {
|
|
48
|
-
if (live) setError(describeError(e
|
|
48
|
+
if (live) setError(describeError(e).message);
|
|
49
49
|
} finally {
|
|
50
50
|
if (live) setLoading(false);
|
|
51
51
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/media-wallet/media-wallet-activity.tsx"],"sourcesContent":["\"use client\";\n\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { useCallback, useEffect, useState } from \"react\";\nimport Image from \"../image.js\";\nimport type { ApiWalletActivity, ApiActivity } from \"@medialane/sdk\";\nimport { getTokenBySymbol } from \"@medialane/sdk\";\nimport { mergeActivityFeeds, type MergedActivityItem } from \"../../utils/media-wallet/activity-feed.js\";\nimport { walletActivityTitle, walletActivitySubtitle, walletActivityAmount } from \"../../utils/media-wallet/wallet-activity.js\";\nimport { short, when, explorerTxUrl, fmt } from \"../../utils/media-wallet/wallet-format.js\";\nimport { BackButton } from \"./back-button.js\";\nimport { WalletActivityIcon } from \"./wallet-activity-icon.js\";\nimport { ActionModal } from \"./action-modal.js\";\nimport { useMediaWalletApp, type MediaWalletView } from \"./types.js\";\nimport { useMedialaneApp } from \"../medialane-app.js\";\n\nconst GRADS = [\n \"linear-gradient(135deg,#3b7bff,#8a5cf6)\",\n \"linear-gradient(135deg,#8a5cf6,#f6608f)\",\n \"linear-gradient(135deg,#f6608f,#fb8b46)\",\n \"linear-gradient(135deg,#5b4ce6,#3b7bff)\",\n];\nconst gradFor = (seed: string) => {\n let h = 0;\n for (let i = 0; i < seed.length; i++) h = (h * 31 + seed.charCodeAt(i)) | 0;\n return GRADS[Math.abs(h) % GRADS.length];\n};\n\nexport function MediaWalletActivity({ onNavigate }: { onNavigate: (view: MediaWalletView) => void }) {\n const { useWalletSession } = useMediaWalletApp();\n const { getClient } = useMedialaneApp();\n const { address } = useWalletSession();\n const [items, setItems] = useState<MergedActivityItem[] | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n const [selected, setSelected] = useState<ApiWalletActivity | null>(null);\n\n const load = useCallback(() => {\n if (!address) return;\n let live = true;\n setLoading(true);\n setError(null);\n (async () => {\n try {\n const client = getClient().api;\n const [walletRes, protocolRes] = await Promise.all([\n client.activity.wallet(address),\n client.activity.byAddress(address, { page: 1, limit: 50 }),\n ]);\n if (live) setItems(mergeActivityFeeds(walletRes.data, protocolRes.data));\n } catch (e) {\n if (live) setError(describeError(e, \"We couldn't load your activity. Please try again.\").message);\n } finally {\n if (live) setLoading(false);\n }\n })();\n return () => { live = false; };\n }, [address, getClient]);\n\n useEffect(() => load(), [load]);\n\n return (\n <main className=\"flex flex-col gap-4 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\">Activity</h1>\n </div>\n\n {!address && <div className=\"text-sm text-muted-foreground\">No wallet found on this device.</div>}\n {error && <ActivityLoadError onRetry={load} />}\n {loading && !items && !error && <ActivityLoading />}\n {items && items.length === 0 && <div className=\"text-sm text-muted-foreground\">No activity yet.</div>}\n\n {items && items.length > 0 && (\n <div className=\"flex flex-col gap-2\">\n {items.map((item) =>\n item.source === \"wallet\" ? (\n <WalletActivityRow key={item.data.id} a={item.data} timestamp={item.timestamp} onOpen={setSelected} />\n ) : (\n <ProtocolActivityRow key={`${item.data.txHash}-${item.data.type}`} item={item.data} />\n ),\n )}\n </div>\n )}\n\n {selected && <ActivityDetailModal a={selected} onClose={() => setSelected(null)} />}\n </main>\n );\n}\n\nfunction WalletActivityRow({\n a,\n timestamp,\n onOpen,\n}: {\n a: ApiWalletActivity;\n timestamp: string;\n onOpen: (a: ApiWalletActivity) => void;\n}) {\n const subtitle = walletActivitySubtitle(a);\n const amount = walletActivityAmount(a);\n return (\n <button\n onClick={() => onOpen(a)}\n className=\"flex items-center gap-3 rounded-2xl bg-card/40 px-4 py-3 text-left backdrop-blur-sm transition-colors hover:bg-card/60\"\n >\n <WalletActivityIcon a={a} />\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-sm font-semibold\">{walletActivityTitle(a)}</div>\n {subtitle && <div className=\"truncate text-xs text-muted-foreground\">{subtitle}</div>}\n </div>\n <div className=\"shrink-0 text-right\">\n {amount && <div className=\"text-sm font-semibold tabular-nums\">{amount}</div>}\n <div className=\"text-xs text-muted-foreground\">{when(timestamp)}</div>\n </div>\n </button>\n );\n}\n\nfunction ActivityDetailModal({ a, onClose }: { a: ApiWalletActivity; onClose: () => void }) {\n const { explorerUrl } = useMediaWalletApp();\n const [copied, setCopied] = useState(false);\n const subtitle = walletActivitySubtitle(a);\n const amount = walletActivityAmount(a);\n const fullDate = new Date(a.timestamp).toLocaleString(undefined, {\n dateStyle: \"medium\",\n timeStyle: \"short\",\n });\n\n const copyHash = () => {\n navigator.clipboard?.writeText(a.txHash).catch(() => {});\n setCopied(true);\n setTimeout(() => setCopied(false), 1500);\n };\n\n return (\n <ActionModal title={walletActivityTitle(a)} onClose={onClose}>\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex flex-col items-center gap-2 py-2 text-center\">\n <WalletActivityIcon a={a} />\n {amount && <div className=\"text-2xl font-bold tabular-nums\">{amount}</div>}\n {subtitle && <div className=\"text-sm text-muted-foreground\">{subtitle}</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\">\n <span className=\"text-xs text-muted-foreground\">Date</span>\n <span className=\"text-sm font-medium\">{fullDate}</span>\n </div>\n <div className=\"flex items-center justify-between py-3\">\n <span className=\"text-xs text-muted-foreground\">Transaction</span>\n <button onClick={copyHash} className=\"font-mono text-sm font-medium transition-opacity active:opacity-60\">\n {copied ? \"Copied ✓\" : short(a.txHash)}\n </button>\n </div>\n </div>\n\n <a\n href={explorerTxUrl(explorerUrl, a.txHash)}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-center text-xs font-medium text-muted-foreground underline underline-offset-2\"\n >\n View on Voyager ↗\n </a>\n </div>\n </ActionModal>\n );\n}\n\nfunction ProtocolActivityRow({ item }: { item: ApiActivity }) {\n const { resolveImage } = useMediaWalletApp();\n const img = resolveImage(item.token?.image ?? null);\n const seed = item.txHash ?? item.orderHash ?? item.type;\n return (\n <div className=\"flex items-center gap-3 rounded-2xl bg-card/40 px-4 py-3 backdrop-blur-sm\">\n <div className=\"relative h-11 w-11 shrink-0 overflow-hidden rounded-2xl\" style={img ? undefined : { background: gradFor(seed) }}>\n {img && (\n <Image src={img} alt=\"\" fill className=\"object-cover\" />\n )}\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-sm font-semibold capitalize\">{item.type}</div>\n {item.token?.name && <div className=\"truncate text-xs text-muted-foreground\">{item.token.name}</div>}\n </div>\n <div className=\"shrink-0 text-right\">\n {item.price?.raw && item.price.currency && (\n <div className=\"text-sm font-semibold tabular-nums\">\n {fmt(BigInt(item.price.raw), getTokenBySymbol(item.price.currency)?.decimals ?? 18)} <span className=\"text-xs text-muted-foreground\">{item.price.currency}</span>\n </div>\n )}\n <div className=\"text-xs text-muted-foreground\">{when(item.timestamp)}</div>\n </div>\n </div>\n );\n}\n\nfunction ActivityLoading() {\n return (\n <div className=\"flex min-h-[40vh] flex-col items-center justify-center gap-3\">\n <span className=\"h-6 w-6 animate-spin rounded-full border-2 border-border border-t-foreground\" />\n <div className=\"text-sm text-muted-foreground\">Loading your activity…</div>\n </div>\n );\n}\n\nfunction ActivityLoadError({ onRetry }: { onRetry: () => void }) {\n return (\n <div className=\"card-base flex flex-col items-center gap-3 px-6 py-8 text-center\">\n <div className=\"grid h-11 w-11 place-items-center rounded-2xl bg-destructive/10 text-destructive\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M10.3 3.9L2.3 18a2 2 0 001.7 3h16a2 2 0 001.7-3L13.7 3.9a2 2 0 00-3.4 0z\" />\n <path d=\"M12 9v4M12 17h.01\" />\n </svg>\n </div>\n <div>\n <div className=\"text-sm font-semibold\">Couldn't load your activity</div>\n <p className=\"mx-auto mt-1 max-w-[16rem] text-xs leading-relaxed text-muted-foreground\">\n There was a problem reaching the server. Check your connection and try again.\n </p>\n </div>\n <button\n onClick={onRetry}\n className=\"rounded-full border border-border px-4 py-2 text-xs font-semibold text-foreground transition-colors hover:bg-card\"\n >\n Try again\n </button>\n </div>\n );\n}\n"],"mappings":";AA+DM,SACE,KADF;AA7DN,SAAS,qBAAqB;AAC9B,SAAS,aAAa,WAAW,gBAAgB;AACjD,OAAO,WAAW;AAElB,SAAS,wBAAwB;AACjC,SAAS,0BAAmD;AAC5D,SAAS,qBAAqB,wBAAwB,4BAA4B;AAClF,SAAS,OAAO,MAAM,eAAe,WAAW;AAChD,SAAS,kBAAkB;AAC3B,SAAS,0BAA0B;AACnC,SAAS,mBAAmB;AAC5B,SAAS,yBAA+C;AACxD,SAAS,uBAAuB;AAEhC,MAAM,QAAQ;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AACA,MAAM,UAAU,CAAC,SAAiB;AAChC,MAAI,IAAI;AACR,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,IAAK,KAAK,IAAI,KAAK,KAAK,WAAW,CAAC,IAAK;AAC1E,SAAO,MAAM,KAAK,IAAI,CAAC,IAAI,MAAM,MAAM;AACzC;AAEO,SAAS,oBAAoB,EAAE,WAAW,GAAoD;AACnG,QAAM,EAAE,iBAAiB,IAAI,kBAAkB;AAC/C,QAAM,EAAE,UAAU,IAAI,gBAAgB;AACtC,QAAM,EAAE,QAAQ,IAAI,iBAAiB;AACrC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAsC,IAAI;AACpE,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,IAAI;AACtD,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAC5C,QAAM,CAAC,UAAU,WAAW,IAAI,SAAmC,IAAI;AAEvE,QAAM,OAAO,YAAY,MAAM;AAC7B,QAAI,CAAC,QAAS;AACd,QAAI,OAAO;AACX,eAAW,IAAI;AACf,aAAS,IAAI;AACb,KAAC,YAAY;AACX,UAAI;AACF,cAAM,SAAS,UAAU,EAAE;AAC3B,cAAM,CAAC,WAAW,WAAW,IAAI,MAAM,QAAQ,IAAI;AAAA,UACjD,OAAO,SAAS,OAAO,OAAO;AAAA,UAC9B,OAAO,SAAS,UAAU,SAAS,EAAE,MAAM,GAAG,OAAO,GAAG,CAAC;AAAA,QAC3D,CAAC;AACD,YAAI,KAAM,UAAS,mBAAmB,UAAU,MAAM,YAAY,IAAI,CAAC;AAAA,MACzE,SAAS,GAAG;AACV,YAAI,KAAM,UAAS,cAAc,GAAG,mDAAmD,EAAE,OAAO;AAAA,MAClG,UAAE;AACA,YAAI,KAAM,YAAW,KAAK;AAAA,MAC5B;AAAA,IACF,GAAG;AACH,WAAO,MAAM;AAAE,aAAO;AAAA,IAAO;AAAA,EAC/B,GAAG,CAAC,SAAS,SAAS,CAAC;AAEvB,YAAU,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC;AAE9B,SACE,qBAAC,UAAK,WAAU,sCACd;AAAA,yBAAC,SAAI,WAAU,2BACb;AAAA,0BAAC,cAAW,QAAQ,MAAM,WAAW,EAAE,MAAM,OAAO,CAAC,GAAG;AAAA,MACxD,oBAAC,QAAG,WAAU,iFAAgF,sBAAQ;AAAA,OACxG;AAAA,IAEC,CAAC,WAAW,oBAAC,SAAI,WAAU,iCAAgC,6CAA+B;AAAA,IAC1F,SAAS,oBAAC,qBAAkB,SAAS,MAAM;AAAA,IAC3C,WAAW,CAAC,SAAS,CAAC,SAAS,oBAAC,mBAAgB;AAAA,IAChD,SAAS,MAAM,WAAW,KAAK,oBAAC,SAAI,WAAU,iCAAgC,8BAAgB;AAAA,IAE9F,SAAS,MAAM,SAAS,KACvB,oBAAC,SAAI,WAAU,uBACZ,gBAAM;AAAA,MAAI,CAAC,SACV,KAAK,WAAW,WACd,oBAAC,qBAAqC,GAAG,KAAK,MAAM,WAAW,KAAK,WAAW,QAAQ,eAA/D,KAAK,KAAK,EAAkE,IAEpG,oBAAC,uBAAkE,MAAM,KAAK,QAApD,GAAG,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,IAAI,EAAqB;AAAA,IAExF,GACF;AAAA,IAGD,YAAY,oBAAC,uBAAoB,GAAG,UAAU,SAAS,MAAM,YAAY,IAAI,GAAG;AAAA,KACnF;AAEJ;AAEA,SAAS,kBAAkB;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,WAAW,uBAAuB,CAAC;AACzC,QAAM,SAAS,qBAAqB,CAAC;AACrC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAS,MAAM,OAAO,CAAC;AAAA,MACvB,WAAU;AAAA,MAEV;AAAA,4BAAC,sBAAmB,GAAM;AAAA,QAC1B,qBAAC,SAAI,WAAU,kBACb;AAAA,8BAAC,SAAI,WAAU,yBAAyB,8BAAoB,CAAC,GAAE;AAAA,UAC9D,YAAY,oBAAC,SAAI,WAAU,0CAA0C,oBAAS;AAAA,WACjF;AAAA,QACA,qBAAC,SAAI,WAAU,uBACZ;AAAA,oBAAU,oBAAC,SAAI,WAAU,sCAAsC,kBAAO;AAAA,UACvE,oBAAC,SAAI,WAAU,iCAAiC,eAAK,SAAS,GAAE;AAAA,WAClE;AAAA;AAAA;AAAA,EACF;AAEJ;AAEA,SAAS,oBAAoB,EAAE,GAAG,QAAQ,GAAkD;AAC1F,QAAM,EAAE,YAAY,IAAI,kBAAkB;AAC1C,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAC1C,QAAM,WAAW,uBAAuB,CAAC;AACzC,QAAM,SAAS,qBAAqB,CAAC;AACrC,QAAM,WAAW,IAAI,KAAK,EAAE,SAAS,EAAE,eAAe,QAAW;AAAA,IAC/D,WAAW;AAAA,IACX,WAAW;AAAA,EACb,CAAC;AAED,QAAM,WAAW,MAAM;AACrB,cAAU,WAAW,UAAU,EAAE,MAAM,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AACvD,cAAU,IAAI;AACd,eAAW,MAAM,UAAU,KAAK,GAAG,IAAI;AAAA,EACzC;AAEA,SACE,oBAAC,eAAY,OAAO,oBAAoB,CAAC,GAAG,SAC1C,+BAAC,SAAI,WAAU,uBACb;AAAA,yBAAC,SAAI,WAAU,qDACb;AAAA,0BAAC,sBAAmB,GAAM;AAAA,MACzB,UAAU,oBAAC,SAAI,WAAU,mCAAmC,kBAAO;AAAA,MACnE,YAAY,oBAAC,SAAI,WAAU,iCAAiC,oBAAS;AAAA,OACxE;AAAA,IAEA,qBAAC,SAAI,WAAU,iFACb;AAAA,2BAAC,SAAI,WAAU,0CACb;AAAA,4BAAC,UAAK,WAAU,iCAAgC,kBAAI;AAAA,QACpD,oBAAC,UAAK,WAAU,uBAAuB,oBAAS;AAAA,SAClD;AAAA,MACA,qBAAC,SAAI,WAAU,0CACb;AAAA,4BAAC,UAAK,WAAU,iCAAgC,yBAAW;AAAA,QAC3D,oBAAC,YAAO,SAAS,UAAU,WAAU,sEAClC,mBAAS,kBAAa,MAAM,EAAE,MAAM,GACvC;AAAA,SACF;AAAA,OACF;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,cAAc,aAAa,EAAE,MAAM;AAAA,QACzC,QAAO;AAAA,QACP,KAAI;AAAA,QACJ,WAAU;AAAA,QACX;AAAA;AAAA,IAED;AAAA,KACF,GACF;AAEJ;AAEA,SAAS,oBAAoB,EAAE,KAAK,GAA0B;AAC5D,QAAM,EAAE,aAAa,IAAI,kBAAkB;AAC3C,QAAM,MAAM,aAAa,KAAK,OAAO,SAAS,IAAI;AAClD,QAAM,OAAO,KAAK,UAAU,KAAK,aAAa,KAAK;AACnD,SACE,qBAAC,SAAI,WAAU,6EACb;AAAA,wBAAC,SAAI,WAAU,2DAA0D,OAAO,MAAM,SAAY,EAAE,YAAY,QAAQ,IAAI,EAAE,GAC3H,iBACC,oBAAC,SAAM,KAAK,KAAK,KAAI,IAAG,MAAI,MAAC,WAAU,gBAAe,GAE1D;AAAA,IACA,qBAAC,SAAI,WAAU,kBACb;AAAA,0BAAC,SAAI,WAAU,oCAAoC,eAAK,MAAK;AAAA,MAC5D,KAAK,OAAO,QAAQ,oBAAC,SAAI,WAAU,0CAA0C,eAAK,MAAM,MAAK;AAAA,OAChG;AAAA,IACA,qBAAC,SAAI,WAAU,uBACZ;AAAA,WAAK,OAAO,OAAO,KAAK,MAAM,YAC7B,qBAAC,SAAI,WAAU,sCACZ;AAAA,YAAI,OAAO,KAAK,MAAM,GAAG,GAAG,iBAAiB,KAAK,MAAM,QAAQ,GAAG,YAAY,EAAE;AAAA,QAAE;AAAA,QAAC,oBAAC,UAAK,WAAU,iCAAiC,eAAK,MAAM,UAAS;AAAA,SAC5J;AAAA,MAEF,oBAAC,SAAI,WAAU,iCAAiC,eAAK,KAAK,SAAS,GAAE;AAAA,OACvE;AAAA,KACF;AAEJ;AAEA,SAAS,kBAAkB;AACzB,SACE,qBAAC,SAAI,WAAU,gEACb;AAAA,wBAAC,UAAK,WAAU,gFAA+E;AAAA,IAC/F,oBAAC,SAAI,WAAU,iCAAgC,yCAAsB;AAAA,KACvE;AAEJ;AAEA,SAAS,kBAAkB,EAAE,QAAQ,GAA4B;AAC/D,SACE,qBAAC,SAAI,WAAU,oEACb;AAAA,wBAAC,SAAI,WAAU,oFACb,+BAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI;AAAA,0BAAC,UAAK,GAAE,4EAA2E;AAAA,MACnF,oBAAC,UAAK,GAAE,qBAAoB;AAAA,OAC9B,GACF;AAAA,IACA,qBAAC,SACC;AAAA,0BAAC,SAAI,WAAU,yBAAwB,yCAAgC;AAAA,MACvE,oBAAC,OAAE,WAAU,4EAA2E,2FAExF;AAAA,OACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,SAAS;AAAA,QACT,WAAU;AAAA,QACX;AAAA;AAAA,IAED;AAAA,KACF;AAEJ;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/media-wallet/media-wallet-activity.tsx"],"sourcesContent":["\"use client\";\n\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { useCallback, useEffect, useState } from \"react\";\nimport Image from \"../image.js\";\nimport type { ApiWalletActivity, ApiActivity } from \"@medialane/sdk\";\nimport { getTokenBySymbol } from \"@medialane/sdk\";\nimport { mergeActivityFeeds, type MergedActivityItem } from \"../../utils/media-wallet/activity-feed.js\";\nimport { walletActivityTitle, walletActivitySubtitle, walletActivityAmount } from \"../../utils/media-wallet/wallet-activity.js\";\nimport { short, when, explorerTxUrl, fmt } from \"../../utils/media-wallet/wallet-format.js\";\nimport { BackButton } from \"./back-button.js\";\nimport { WalletActivityIcon } from \"./wallet-activity-icon.js\";\nimport { ActionModal } from \"./action-modal.js\";\nimport { useMediaWalletApp, type MediaWalletView } from \"./types.js\";\nimport { useMedialaneApp } from \"../medialane-app.js\";\n\nconst GRADS = [\n \"linear-gradient(135deg,#3b7bff,#8a5cf6)\",\n \"linear-gradient(135deg,#8a5cf6,#f6608f)\",\n \"linear-gradient(135deg,#f6608f,#fb8b46)\",\n \"linear-gradient(135deg,#5b4ce6,#3b7bff)\",\n];\nconst gradFor = (seed: string) => {\n let h = 0;\n for (let i = 0; i < seed.length; i++) h = (h * 31 + seed.charCodeAt(i)) | 0;\n return GRADS[Math.abs(h) % GRADS.length];\n};\n\nexport function MediaWalletActivity({ onNavigate }: { onNavigate: (view: MediaWalletView) => void }) {\n const { useWalletSession } = useMediaWalletApp();\n const { getClient } = useMedialaneApp();\n const { address } = useWalletSession();\n const [items, setItems] = useState<MergedActivityItem[] | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n const [selected, setSelected] = useState<ApiWalletActivity | null>(null);\n\n const load = useCallback(() => {\n if (!address) return;\n let live = true;\n setLoading(true);\n setError(null);\n (async () => {\n try {\n const client = getClient().api;\n const [walletRes, protocolRes] = await Promise.all([\n client.activity.wallet(address),\n client.activity.byAddress(address, { page: 1, limit: 50 }),\n ]);\n if (live) setItems(mergeActivityFeeds(walletRes.data, protocolRes.data));\n } catch (e) {\n if (live) setError(describeError(e).message);\n } finally {\n if (live) setLoading(false);\n }\n })();\n return () => { live = false; };\n }, [address, getClient]);\n\n useEffect(() => load(), [load]);\n\n return (\n <main className=\"flex flex-col gap-4 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\">Activity</h1>\n </div>\n\n {!address && <div className=\"text-sm text-muted-foreground\">No wallet found on this device.</div>}\n {error && <ActivityLoadError onRetry={load} />}\n {loading && !items && !error && <ActivityLoading />}\n {items && items.length === 0 && <div className=\"text-sm text-muted-foreground\">No activity yet.</div>}\n\n {items && items.length > 0 && (\n <div className=\"flex flex-col gap-2\">\n {items.map((item) =>\n item.source === \"wallet\" ? (\n <WalletActivityRow key={item.data.id} a={item.data} timestamp={item.timestamp} onOpen={setSelected} />\n ) : (\n <ProtocolActivityRow key={`${item.data.txHash}-${item.data.type}`} item={item.data} />\n ),\n )}\n </div>\n )}\n\n {selected && <ActivityDetailModal a={selected} onClose={() => setSelected(null)} />}\n </main>\n );\n}\n\nfunction WalletActivityRow({\n a,\n timestamp,\n onOpen,\n}: {\n a: ApiWalletActivity;\n timestamp: string;\n onOpen: (a: ApiWalletActivity) => void;\n}) {\n const subtitle = walletActivitySubtitle(a);\n const amount = walletActivityAmount(a);\n return (\n <button\n onClick={() => onOpen(a)}\n className=\"flex items-center gap-3 rounded-2xl bg-card/40 px-4 py-3 text-left backdrop-blur-sm transition-colors hover:bg-card/60\"\n >\n <WalletActivityIcon a={a} />\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-sm font-semibold\">{walletActivityTitle(a)}</div>\n {subtitle && <div className=\"truncate text-xs text-muted-foreground\">{subtitle}</div>}\n </div>\n <div className=\"shrink-0 text-right\">\n {amount && <div className=\"text-sm font-semibold tabular-nums\">{amount}</div>}\n <div className=\"text-xs text-muted-foreground\">{when(timestamp)}</div>\n </div>\n </button>\n );\n}\n\nfunction ActivityDetailModal({ a, onClose }: { a: ApiWalletActivity; onClose: () => void }) {\n const { explorerUrl } = useMediaWalletApp();\n const [copied, setCopied] = useState(false);\n const subtitle = walletActivitySubtitle(a);\n const amount = walletActivityAmount(a);\n const fullDate = new Date(a.timestamp).toLocaleString(undefined, {\n dateStyle: \"medium\",\n timeStyle: \"short\",\n });\n\n const copyHash = () => {\n navigator.clipboard?.writeText(a.txHash).catch(() => {});\n setCopied(true);\n setTimeout(() => setCopied(false), 1500);\n };\n\n return (\n <ActionModal title={walletActivityTitle(a)} onClose={onClose}>\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex flex-col items-center gap-2 py-2 text-center\">\n <WalletActivityIcon a={a} />\n {amount && <div className=\"text-2xl font-bold tabular-nums\">{amount}</div>}\n {subtitle && <div className=\"text-sm text-muted-foreground\">{subtitle}</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\">\n <span className=\"text-xs text-muted-foreground\">Date</span>\n <span className=\"text-sm font-medium\">{fullDate}</span>\n </div>\n <div className=\"flex items-center justify-between py-3\">\n <span className=\"text-xs text-muted-foreground\">Transaction</span>\n <button onClick={copyHash} className=\"font-mono text-sm font-medium transition-opacity active:opacity-60\">\n {copied ? \"Copied ✓\" : short(a.txHash)}\n </button>\n </div>\n </div>\n\n <a\n href={explorerTxUrl(explorerUrl, a.txHash)}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-center text-xs font-medium text-muted-foreground underline underline-offset-2\"\n >\n View on Voyager ↗\n </a>\n </div>\n </ActionModal>\n );\n}\n\nfunction ProtocolActivityRow({ item }: { item: ApiActivity }) {\n const { resolveImage } = useMediaWalletApp();\n const img = resolveImage(item.token?.image ?? null);\n const seed = item.txHash ?? item.orderHash ?? item.type;\n return (\n <div className=\"flex items-center gap-3 rounded-2xl bg-card/40 px-4 py-3 backdrop-blur-sm\">\n <div className=\"relative h-11 w-11 shrink-0 overflow-hidden rounded-2xl\" style={img ? undefined : { background: gradFor(seed) }}>\n {img && (\n <Image src={img} alt=\"\" fill className=\"object-cover\" />\n )}\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-sm font-semibold capitalize\">{item.type}</div>\n {item.token?.name && <div className=\"truncate text-xs text-muted-foreground\">{item.token.name}</div>}\n </div>\n <div className=\"shrink-0 text-right\">\n {item.price?.raw && item.price.currency && (\n <div className=\"text-sm font-semibold tabular-nums\">\n {fmt(BigInt(item.price.raw), getTokenBySymbol(item.price.currency)?.decimals ?? 18)} <span className=\"text-xs text-muted-foreground\">{item.price.currency}</span>\n </div>\n )}\n <div className=\"text-xs text-muted-foreground\">{when(item.timestamp)}</div>\n </div>\n </div>\n );\n}\n\nfunction ActivityLoading() {\n return (\n <div className=\"flex min-h-[40vh] flex-col items-center justify-center gap-3\">\n <span className=\"h-6 w-6 animate-spin rounded-full border-2 border-border border-t-foreground\" />\n <div className=\"text-sm text-muted-foreground\">Loading your activity…</div>\n </div>\n );\n}\n\nfunction ActivityLoadError({ onRetry }: { onRetry: () => void }) {\n return (\n <div className=\"card-base flex flex-col items-center gap-3 px-6 py-8 text-center\">\n <div className=\"grid h-11 w-11 place-items-center rounded-2xl bg-destructive/10 text-destructive\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M10.3 3.9L2.3 18a2 2 0 001.7 3h16a2 2 0 001.7-3L13.7 3.9a2 2 0 00-3.4 0z\" />\n <path d=\"M12 9v4M12 17h.01\" />\n </svg>\n </div>\n <div>\n <div className=\"text-sm font-semibold\">Couldn't load your activity</div>\n <p className=\"mx-auto mt-1 max-w-[16rem] text-xs leading-relaxed text-muted-foreground\">\n There was a problem reaching the server. Check your connection and try again.\n </p>\n </div>\n <button\n onClick={onRetry}\n className=\"rounded-full border border-border px-4 py-2 text-xs font-semibold text-foreground transition-colors hover:bg-card\"\n >\n Try again\n </button>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -111,7 +111,7 @@ function MediaWalletSend({
|
|
|
111
111
|
setFeeError(null);
|
|
112
112
|
setFee(null);
|
|
113
113
|
setConfirmOpen(true);
|
|
114
|
-
estimateSendFee(getClient().provider, address, currency.address, to.trim(), amountRaw).then((f) => setFee({ raw: f.feeRaw, unit: f.unit })).catch((e) => setFeeError((0, import_describe_error.describeError)(e
|
|
114
|
+
estimateSendFee(getClient().provider, address, currency.address, to.trim(), amountRaw).then((f) => setFee({ raw: f.feeRaw, unit: f.unit })).catch((e) => setFeeError((0, import_describe_error.describeError)(e).message));
|
|
115
115
|
};
|
|
116
116
|
const send = async () => {
|
|
117
117
|
if (!composeReady || amountRaw == null) return;
|
|
@@ -132,11 +132,7 @@ function MediaWalletSend({
|
|
|
132
132
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_back_button.BackButton, { onBack: () => onNavigate({ name: "home" }) }),
|
|
133
133
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { className: "font-[family-name:var(--font-display)] text-2xl font-extrabold tracking-tight", children: "Send" })
|
|
134
134
|
] }),
|
|
135
|
-
error && /* @__PURE__ */ (0, import_jsx_runtime.
|
|
136
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("b", { children: "Something went wrong." }),
|
|
137
|
-
" ",
|
|
138
|
-
error
|
|
139
|
-
] }),
|
|
135
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rounded-2xl border border-destructive/40 bg-destructive/10 p-3 text-xs leading-relaxed", children: error }),
|
|
140
136
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-3", children: [
|
|
141
137
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
142
138
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
@@ -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, \"We couldn't estimate the network fee. Please try again.\").message));\n };\n\n const send = async () => {\n if (!composeReady || amountRaw == null) return;\n setConfirmOpen(false);\n const dest = to.trim();\n const amt = amountRaw;\n await run(async (signer) => {\n const result = await runIntentCalls(signer, () =>\n getClient().api.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 <b>Something went wrong.</b> {error}\n </div>\n )}\n\n <div className=\"flex flex-col gap-3\">\n <div>\n <div className=\"flex items-center gap-2\">\n <input\n value={to}\n onChange={(e) => setTo(e.target.value)}\n placeholder=\"Recipient 0x…\"\n spellCheck={false}\n className=\"w-0 flex-1 rounded-2xl border border-border bg-foreground/[0.05] px-4 py-3 font-mono text-sm outline-none transition-colors focus:border-brand-purple\"\n />\n {to.trim() === \"\" && (\n <button\n onClick={pasteRecipient}\n className=\"shrink-0 rounded-2xl border border-border bg-foreground/[0.05] px-3 py-3 text-xs font-semibold text-muted-foreground transition-colors hover:text-foreground\"\n >\n Paste\n </button>\n )}\n </div>\n {to.trim() !== \"\" && !recipientValid && (\n <p className=\"mt-1.5 px-1 text-xs text-destructive\">Not a valid Starknet address.</p>\n )}\n </div>\n\n <div>\n <div className=\"relative\">\n <input\n value={amount}\n onChange={(e) => setAmount(e.target.value.replace(/[^0-9.]/g, \"\"))}\n placeholder=\"0.00\"\n inputMode=\"decimal\"\n className=\"w-full rounded-2xl border border-border bg-foreground/[0.05] px-4 py-3 pr-36 text-sm outline-none transition-colors focus:border-brand-purple\"\n />\n <div className=\"absolute right-2.5 top-1/2 flex -translate-y-1/2 items-center gap-1.5\">\n <button\n onClick={setMax}\n className=\"rounded-full bg-foreground/[0.06] px-2 py-1 text-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 { 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":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA4HM;AA1HN,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,8BAA+B;AAC/B,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,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,OAAM;AAAA,QACN,SAAS,GAAG,OAAO,KAAK,CAAC,IAAI,SAAS,MAAM;AAAA,QAC5C;AAAA,QACA,SAAS,MAAM;AACb,gBAAM;AACN,iBAAO;AAAA,QACT;AAAA;AAAA,IACF;AAAA,KAEJ;AAEJ;","names":["import_action_button"]}
|
|
@@ -88,7 +88,7 @@ function MediaWalletSend({
|
|
|
88
88
|
setFeeError(null);
|
|
89
89
|
setFee(null);
|
|
90
90
|
setConfirmOpen(true);
|
|
91
|
-
estimateSendFee(getClient().provider, address, currency.address, to.trim(), amountRaw).then((f) => setFee({ raw: f.feeRaw, unit: f.unit })).catch((e) => setFeeError(describeError(e
|
|
91
|
+
estimateSendFee(getClient().provider, address, currency.address, to.trim(), amountRaw).then((f) => setFee({ raw: f.feeRaw, unit: f.unit })).catch((e) => setFeeError(describeError(e).message));
|
|
92
92
|
};
|
|
93
93
|
const send = async () => {
|
|
94
94
|
if (!composeReady || amountRaw == null) return;
|
|
@@ -109,11 +109,7 @@ function MediaWalletSend({
|
|
|
109
109
|
/* @__PURE__ */ jsx(BackButton, { onBack: () => onNavigate({ name: "home" }) }),
|
|
110
110
|
/* @__PURE__ */ jsx("h1", { className: "font-[family-name:var(--font-display)] text-2xl font-extrabold tracking-tight", children: "Send" })
|
|
111
111
|
] }),
|
|
112
|
-
error && /* @__PURE__ */
|
|
113
|
-
/* @__PURE__ */ jsx("b", { children: "Something went wrong." }),
|
|
114
|
-
" ",
|
|
115
|
-
error
|
|
116
|
-
] }),
|
|
112
|
+
error && /* @__PURE__ */ jsx("div", { className: "rounded-2xl border border-destructive/40 bg-destructive/10 p-3 text-xs leading-relaxed", children: error }),
|
|
117
113
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
118
114
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
119
115
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|