diff --git a/apps/user_dashboard/src/app/export_private_key/page.module.scss b/apps/user_dashboard/src/app/export_private_key/page.module.scss index 7277424a7..6db4d4a98 100644 --- a/apps/user_dashboard/src/app/export_private_key/page.module.scss +++ b/apps/user_dashboard/src/app/export_private_key/page.module.scss @@ -5,6 +5,7 @@ flex-wrap: wrap; gap: 64px; align-items: flex-start; + max-width: 1280px; } .heading { @@ -109,66 +110,92 @@ /* Step 2 styles */ -.privateKeySection { +.keySection { display: flex; flex-direction: column; } -.privateKeyLabel { - margin-bottom: 12px; +.sectionHeader { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 16px; +} + +.sectionKeyIcon { + display: flex; + align-items: center; + justify-content: center; + width: 20px; + height: 20px; + flex-shrink: 0; + color: var(--fg-quaternary); } -.privateKeyField { - position: relative; - min-height: 68px; +.keyIframe { width: 100%; - cursor: pointer; + border: none; + display: block; +} - &:hover .privateKeyBg { - background-color: var(--bg-secondary-hover, #f5f5f5); - } +.chainsList { + display: flex; + align-items: flex-start; + gap: 12px; + padding: 8px; + border-radius: 12px; } -.privateKeyBg { +.chainsTitle { display: flex; align-items: center; - justify-content: center; - padding: 12px 16px; - background-color: var(--bg-secondary); - border-radius: 12px; - overflow: hidden; - word-break: break-all; + gap: 12px; + flex-shrink: 0; } -.privateKeyTextBlurred { - filter: blur(4px); - opacity: 0.5; +.chainsSeparator { + width: 1px; + height: 12px; + background-color: var(--border-primary); + flex-shrink: 0; } -.privateKeyHint { - position: absolute; - inset: 0; +.chainsItems { display: flex; align-items: center; - gap: 12px; - padding: 12px 16px; + gap: 8px; + flex-wrap: wrap; } -.eyeOffIcon { +.chainItem { display: flex; align-items: center; - justify-content: center; - width: 24px; - height: 24px; - flex-shrink: 0; - color: var(--fg-primary); + gap: 4px; +} + +.divider { + border: none; + border-top: 1px solid var(--border-primary); + margin: 32px 0; } -.copyButtonIcon { +.infoBox { + display: flex; + flex-direction: column; + gap: 12px; + padding: 16px; + background-color: var(--bg-secondary); + border-radius: 12px; +} + +.infoBoxTitle { display: flex; align-items: center; - justify-content: center; - width: 24px; - height: 24px; + gap: 8px; +} + +.infoBoxIcon { + width: 20px; + height: 20px; flex-shrink: 0; } diff --git a/apps/user_dashboard/src/app/export_private_key/page.tsx b/apps/user_dashboard/src/app/export_private_key/page.tsx index 033ff40d1..12fc0be1a 100644 --- a/apps/user_dashboard/src/app/export_private_key/page.tsx +++ b/apps/user_dashboard/src/app/export_private_key/page.tsx @@ -1,19 +1,27 @@ "use client"; import { Button } from "@oko-wallet/oko-common-ui/button"; +import { ArbitrumIcon } from "@oko-wallet/oko-common-ui/icons/arbitrum_icon"; +import { BaseIcon } from "@oko-wallet/oko-common-ui/icons/base_icon"; +import { CosmosIcon } from "@oko-wallet/oko-common-ui/icons/cosmos_icon"; import { DiscordIcon } from "@oko-wallet/oko-common-ui/icons/discord_icon"; +import { EthereumIcon } from "@oko-wallet/oko-common-ui/icons/ethereum_icon"; import { GoogleIcon } from "@oko-wallet/oko-common-ui/icons/google_icon"; +import { InfoCircleIcon } from "@oko-wallet/oko-common-ui/icons/info_circle"; +import { InitiaIcon } from "@oko-wallet/oko-common-ui/icons/initia_icon"; import { MailboxIcon } from "@oko-wallet/oko-common-ui/icons/mailbox"; +import { RialoIcon } from "@oko-wallet/oko-common-ui/icons/rialo_icon"; +import { SolanaCircleIcon } from "@oko-wallet/oko-common-ui/icons/solana_circle_icon"; import { TelegramIcon } from "@oko-wallet/oko-common-ui/icons/telegram_icon"; import { XIcon } from "@oko-wallet/oko-common-ui/icons/x_icon"; +import { ZigchainIcon } from "@oko-wallet/oko-common-ui/icons/zigchain_icon"; import { Typography } from "@oko-wallet/oko-common-ui/typography"; import type { AuthType } from "@oko-wallet/oko-types/auth"; -import { type ReactNode, useCallback, useState } from "react"; +import { type ReactNode, useCallback, useEffect, useRef, useState } from "react"; -import type { OkoWalletMsgExportPrivateKeyAck } from "../../../../../sdk/oko_sdk_core/dist/types"; +import type { OkoWalletMsgExportPrivateKeyAck } from "@oko-wallet/oko-sdk-core"; import styles from "./page.module.scss"; import { displayToast } from "@oko-wallet-user-dashboard/components/toast"; -import { useCopyToClipboard } from "@oko-wallet-user-dashboard/hooks/use_copy_to_clipboard"; import { selectCosmosSDK, useSDKState, @@ -102,11 +110,11 @@ const KeyIcon = () => { ); }; -const CopyIcon = () => { +const SectionKeyIcon = () => { return ( { strokeLinecap="round" strokeLinejoin="round" > - copy - + key + ); }; -const EyeOffIcon = () => { +const EVM_COSMOS_CHAINS = [ + { name: "Ethereum", icon: }, + { name: "Base", icon: }, + { name: "Arbitrum", icon: }, + { name: "Cosmos Hub", icon: }, + { name: "Initia", icon: }, + { name: "Zigchain", icon: }, +]; + +const SVM_CHAINS = [ + { name: "Solana", icon: }, + { name: "Rialo", icon: }, +]; + +const ChainsList = ({ + chains, +}: { + chains: { name: string; icon: ReactNode }[]; +}) => { return ( - - eye off - - +
+
+ + Examples + + +
+
+ {chains.map((chain) => ( + + {chain.icon} + + {chain.name} + + + ))} +
+
); }; @@ -218,140 +249,141 @@ const Step1Content = ({ }; const Step2Content = ({ - privateKeys, - revealedKeys, - onToggleReveal, - onCopy, + attachedOrigin, + onReady, }: { - privateKeys: { secp256k1: string; ed25519: string }; - revealedKeys: { secp256k1: boolean; ed25519: boolean }; - onToggleReveal: (key: "secp256k1" | "ed25519") => void; - onCopy: (key: string) => void; + attachedOrigin: string; + onReady?: () => void; }) => { + const [secpIframeHeight, setSecpIframeHeight] = useState(0); + const [edIframeHeight, setEdIframeHeight] = useState(0); + + useEffect(() => { + const handler = (event: MessageEvent) => { + if (event.origin !== attachedOrigin) { + return; + } + const { data } = event; + if (data?.target !== "oko_user_dashboard") { + return; + } + + if (data.msg_type === "__export_display_resize__") { + if (data.key_type === "secp256k1") { + setSecpIframeHeight(data.height); + } else if (data.key_type === "ed25519") { + setEdIframeHeight(data.height); + } + } else if (data.msg_type === "__export_display_copied__") { + displayToast({ variant: "success", title: "Copied!" }); + } else if (data.msg_type === "__export_display_copy_failed__") { + displayToast({ + variant: "confirm", + title: "Copy Failed", + description: "Could not copy to clipboard.", + }); + } + }; + + window.addEventListener("message", handler); + return () => { + window.removeEventListener("message", handler); + }; + }, [attachedOrigin]); + + const iframesReady = secpIframeHeight > 0 && edIframeHeight > 0; + + const onReadyFired = useRef(false); + useEffect(() => { + if (!onReady || onReadyFired.current) return; + if (iframesReady) { + onReadyFired.current = true; + onReady(); + return; + } + const timer = setTimeout(() => { + if (!onReadyFired.current) { + onReadyFired.current = true; + onReady(); + } + }, 5000); + return () => clearTimeout(timer); + }, [iframesReady, onReady]); + return ( - <> +
- View and copy your private keys + View and copy your private key -
+
-
- - EVM/Cosmos Private Key - -
onToggleReveal("secp256k1")} - role="button" - tabIndex={0} - onKeyDown={(e) => { - if (e.key === "Enter" || e.key === " ") { - onToggleReveal("secp256k1"); - } - }} - > -
- - {privateKeys.secp256k1} - -
- {!revealedKeys.secp256k1 && ( -
- - - - - Click or tap to reveal your private key. -
- Ensure no one else can see your screen. -
-
- )} + {/* EVM & Cosmos Section */} +
+
+ + + + + EVM & Cosmos +
-
-
+