diff --git a/apps/customer_dashboard/src/app/page.tsx b/apps/customer_dashboard/src/app/page.tsx index 3273a95e7..f3abbaec8 100644 --- a/apps/customer_dashboard/src/app/page.tsx +++ b/apps/customer_dashboard/src/app/page.tsx @@ -7,6 +7,7 @@ import { DashboardBody } from "@oko-wallet-ct-dashboard/components/dashboard_bod import { DashboardHeader } from "@oko-wallet-ct-dashboard/components/dashboard_header/dashboard_header"; import { HomeBanner } from "@oko-wallet-ct-dashboard/components/home_banner/home_banner"; import { LeftBar } from "@oko-wallet-ct-dashboard/components/left_bar/left_bar"; +import { ServiceShutdownModal } from "@oko-wallet-ct-dashboard/components/service_shutdown_modal/service_shutdown_modal"; import { ToastContainer } from "@oko-wallet-ct-dashboard/components/toast"; export default function Home() { @@ -41,6 +42,7 @@ export default function Home() { + ); } diff --git a/apps/customer_dashboard/src/components/left_bar/left_bar.module.scss b/apps/customer_dashboard/src/components/left_bar/left_bar.module.scss index d4d38b7ff..f4de23e79 100644 --- a/apps/customer_dashboard/src/components/left_bar/left_bar.module.scss +++ b/apps/customer_dashboard/src/components/left_bar/left_bar.module.scss @@ -62,3 +62,36 @@ background-color: var(--bg-primary-hover); } } + +.shutdownNotice { + display: flex; + flex-direction: column; + gap: 6px; + padding: 12px; + border-radius: 8px; + background: #fff8ed; + border: 1px solid #f9c86a; +} + +.shutdownNoticeHeader { + display: flex; + align-items: center; + gap: 6px; +} + +.shutdownNoticeTitle { + font-family: Inter, sans-serif; + font-size: var(--font-size-xs); + font-weight: var(--font-weight-semibold); + color: #dc6803; + line-height: 18px; +} + +.shutdownNoticeBody { + font-family: Inter, sans-serif; + font-size: var(--font-size-xs); + font-weight: var(--font-weight-medium); + color: #b54708; + line-height: 18px; + margin: 0; +} diff --git a/apps/customer_dashboard/src/components/left_bar/left_bar.tsx b/apps/customer_dashboard/src/components/left_bar/left_bar.tsx index ec00a457b..2b367e645 100644 --- a/apps/customer_dashboard/src/components/left_bar/left_bar.tsx +++ b/apps/customer_dashboard/src/components/left_bar/left_bar.tsx @@ -1,6 +1,7 @@ "use client"; import { Badge } from "@oko-wallet/oko-common-ui/badge"; +import { AlertTriangleIcon } from "@oko-wallet/oko-common-ui/icons/alert_triangle_icon"; import { HomeOutlinedIcon } from "@oko-wallet/oko-common-ui/icons/home_outlined"; import { UsersIcon } from "@oko-wallet/oko-common-ui/icons/users"; import { MenuItem } from "@oko-wallet/oko-common-ui/menu"; @@ -49,6 +50,17 @@ export const LeftBar: FC = () => {
+
+
+ + Important Notice +
+

+ Oko is shutting down on June 1, 2026. Please remove Oko from your + dapp and inform your users to export their private keys. +

+
+
diff --git a/apps/customer_dashboard/src/components/service_shutdown_modal/service_shutdown_modal.module.scss b/apps/customer_dashboard/src/components/service_shutdown_modal/service_shutdown_modal.module.scss new file mode 100644 index 000000000..5ed725c4f --- /dev/null +++ b/apps/customer_dashboard/src/components/service_shutdown_modal/service_shutdown_modal.module.scss @@ -0,0 +1,116 @@ +@use "../../styles/viewport.module.scss" as *; + +.modalBackground { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + background: rgba(0, 0, 0, 0.4); +} + +.modal { + position: relative; + width: 100%; + max-width: 90vw; + max-height: 90vh; + + @media (min-width: $desktop_min_width) { + width: auto; + } +} + +.modalCard { + background: var(--bg-primary); + border: 1px solid var(--border-primary); + border-radius: 16px; + box-shadow: var(--shadow-xl); + width: 100%; + max-width: 400px; + box-sizing: border-box; + padding: 0; +} + +.header { + display: flex; + justify-content: flex-end; + align-items: center; + padding: 20px 20px 0; +} + +.closeButton { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + padding: 6px; + border: none; + background: none; + border-radius: 8px; + cursor: pointer; + color: var(--fg-quaternary); + + &:hover { + background: var(--bg-secondary); + } +} + +.content { + display: flex; + flex-direction: column; + align-items: center; + padding: 0 20px 8px; +} + +.logoWrapper { + display: flex; + justify-content: center; + width: 100%; +} + +.title { + text-align: center; + width: 100%; +} + +.body { + text-align: center; + width: 100%; +} + +.warningBox { + display: flex; + align-items: flex-start; + gap: 8px; + width: 100%; + padding: 12px; + border-radius: 12px; + background: #fef0c7; + box-sizing: border-box; +} + +.warningText { + flex: 1; + color: #dc6803; + font-family: Inter, sans-serif; + font-size: var(--font-size-sm); + font-weight: var(--font-weight-medium); + line-height: 20px; + text-align: center; +} + +.footer { + display: flex; + width: 100%; + padding: 12px 24px 16px; + box-sizing: border-box; +} + +.footerButton { + flex: 1; +} diff --git a/apps/customer_dashboard/src/components/service_shutdown_modal/service_shutdown_modal.tsx b/apps/customer_dashboard/src/components/service_shutdown_modal/service_shutdown_modal.tsx new file mode 100644 index 000000000..3b2b67fad --- /dev/null +++ b/apps/customer_dashboard/src/components/service_shutdown_modal/service_shutdown_modal.tsx @@ -0,0 +1,110 @@ +"use client"; + +import { Button } from "@oko-wallet/oko-common-ui/button"; +import { Card } from "@oko-wallet/oko-common-ui/card"; +import { OkoLogoIcon } from "@oko-wallet/oko-common-ui/icons/oko_logo_icon"; +import { XCloseIcon } from "@oko-wallet/oko-common-ui/icons/x_close"; +import { Spacing } from "@oko-wallet/oko-common-ui/spacing"; +import { Typography } from "@oko-wallet/oko-common-ui/typography"; +import { type FC, useEffect, useState } from "react"; + +import styles from "./service_shutdown_modal.module.scss"; + +const SESSION_KEY = "oko_ct_shutdown_noticed"; + +export const ServiceShutdownModal: FC = () => { + const [isOpen, setIsOpen] = useState(false); + + useEffect(() => { + if (!sessionStorage.getItem(SESSION_KEY)) { + setIsOpen(true); + sessionStorage.setItem(SESSION_KEY, "1"); + } + }, []); + + const onClose = () => setIsOpen(false); + + if (!isOpen) { + return null; + } + + return ( +
+
e.stopPropagation()} + > + +
+ +
+ +
+
+ +
+ + + +
+ + Service Shutdown Notice + +
+ + + +
+ + Oko is shutting down its service on June 1, 2026. + +
+ + + +
+

+ Please remove Oko SDK and API integrations from your dapp before + the shutdown date. +

+
+ + + +
+ + Also, please inform your users to export their private keys and + migrate to another wallet. After June 1, Oko API and SDK will no + longer be available. + +
+ + +
+ +
+ +
+
+
+
+ ); +}; diff --git a/apps/customer_dashboard/src/styles/viewport.module.scss b/apps/customer_dashboard/src/styles/viewport.module.scss index 5a61e2624..c456e550f 100644 --- a/apps/customer_dashboard/src/styles/viewport.module.scss +++ b/apps/customer_dashboard/src/styles/viewport.module.scss @@ -1 +1,3 @@ $width_360: 360px; +$tablet_min_width: 361px; +$desktop_min_width: 769px; diff --git a/apps/user_dashboard/src/app/layout.tsx b/apps/user_dashboard/src/app/layout.tsx index d428db613..80f4d57d8 100644 --- a/apps/user_dashboard/src/app/layout.tsx +++ b/apps/user_dashboard/src/app/layout.tsx @@ -8,6 +8,7 @@ import "@oko-wallet/oko-common-ui/styles/shadow.scss"; import "@oko-wallet/oko-common-ui/styles/animation.scss"; import { Providers } from "@oko-wallet-user-dashboard/components/providers/providers"; +import { ServiceShutdownModal } from "@oko-wallet-user-dashboard/components/service_shutdown_modal/service_shutdown_modal"; import "./globals.scss"; @@ -62,7 +63,10 @@ export default function RootLayout({ className={`${geistSans.variable} ${geistMono.variable} ${inter.variable} ${robotoMono.variable}`} suppressHydrationWarning > - {children} + + {children} + + ); diff --git a/apps/user_dashboard/src/app/page.tsx b/apps/user_dashboard/src/app/page.tsx index a34cdfe4d..2b4efcf6f 100644 --- a/apps/user_dashboard/src/app/page.tsx +++ b/apps/user_dashboard/src/app/page.tsx @@ -3,6 +3,7 @@ import { Authorized } from "@oko-wallet-user-dashboard/components/authorized/aut import { ConnectedApps } from "@oko-wallet-user-dashboard/components/connected_apps/connected_apps"; import { DashboardBody } from "@oko-wallet-user-dashboard/components/dashboard_body/dashboard_body"; import { DashboardHeader } from "@oko-wallet-user-dashboard/components/dashboard_header/dashboard_header"; +import { KeyExportPromptModal } from "@oko-wallet-user-dashboard/components/key_export_prompt_modal/key_export_prompt_modal"; import { LeftBar } from "@oko-wallet-user-dashboard/components/left_bar/left_bar"; import { MyAssets } from "@oko-wallet-user-dashboard/components/my_assets/my_assets"; import { ToastContainer } from "@oko-wallet-user-dashboard/components/toast"; @@ -25,6 +26,7 @@ export default function Home() {
+ ); } diff --git a/apps/user_dashboard/src/components/key_export_prompt_modal/key_export_prompt_modal.module.scss b/apps/user_dashboard/src/components/key_export_prompt_modal/key_export_prompt_modal.module.scss new file mode 100644 index 000000000..57f11dc2d --- /dev/null +++ b/apps/user_dashboard/src/components/key_export_prompt_modal/key_export_prompt_modal.module.scss @@ -0,0 +1,121 @@ +@use "../../styles/viewport.module.scss" as *; + +.modalBackground { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + background: rgba(0, 0, 0, 0.4); +} + +.modal { + position: relative; + width: 100%; + max-width: 90vw; + max-height: 90vh; + + @media (min-width: $desktop_min_width) { + width: auto; + } +} + +.modalCard { + background: var(--bg-primary); + border: 1px solid var(--border-primary); + border-radius: 16px; + box-shadow: var(--shadow-xl); + width: 100%; + max-width: 400px; + box-sizing: border-box; + padding: 0; + + @media (min-width: $desktop_min_width) { + width: 400px; + } +} + +.header { + display: flex; + justify-content: flex-end; + align-items: center; + padding: 20px 20px 0; +} + +.closeButton { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + padding: 6px; + border: none; + background: none; + border-radius: 8px; + cursor: pointer; + color: var(--fg-quaternary); + + &:hover { + background: var(--bg-secondary); + } +} + +.content { + display: flex; + flex-direction: column; + align-items: center; + padding: 0 20px 8px; +} + +.logoWrapper { + display: flex; + justify-content: center; + width: 100%; +} + +.title { + text-align: center; + width: 100%; +} + +.body { + text-align: center; + width: 100%; +} + +.warningBox { + display: flex; + align-items: flex-start; + gap: 8px; + width: 100%; + padding: 12px; + border-radius: 12px; + background: #fef0c7; + box-sizing: border-box; +} + +.warningText { + flex: 1; + color: #dc6803; + font-family: Inter, sans-serif; + font-size: var(--font-size-sm); + font-weight: var(--font-weight-medium); + line-height: 20px; + text-align: center; +} + +.footer { + display: flex; + gap: 8px; + width: 100%; + padding: 12px 24px 16px; + box-sizing: border-box; +} + +.footerButton { + flex: 1; +} diff --git a/apps/user_dashboard/src/components/key_export_prompt_modal/key_export_prompt_modal.tsx b/apps/user_dashboard/src/components/key_export_prompt_modal/key_export_prompt_modal.tsx new file mode 100644 index 000000000..2259d45ed --- /dev/null +++ b/apps/user_dashboard/src/components/key_export_prompt_modal/key_export_prompt_modal.tsx @@ -0,0 +1,126 @@ +"use client"; + +import { Button } from "@oko-wallet/oko-common-ui/button"; +import { Card } from "@oko-wallet/oko-common-ui/card"; +import { OkoLogoIcon } from "@oko-wallet/oko-common-ui/icons/oko_logo_icon"; +import { XCloseIcon } from "@oko-wallet/oko-common-ui/icons/x_close"; +import { Spacing } from "@oko-wallet/oko-common-ui/spacing"; +import { Typography } from "@oko-wallet/oko-common-ui/typography"; +import { useRouter } from "next/navigation"; +import { type FC, useEffect, useState } from "react"; + +import styles from "./key_export_prompt_modal.module.scss"; +import { paths } from "@oko-wallet-user-dashboard/paths"; + +const SESSION_KEY = "oko_key_export_prompted"; + +export const KeyExportPromptModal: FC = () => { + const [isOpen, setIsOpen] = useState(false); + const router = useRouter(); + + useEffect(() => { + if (!sessionStorage.getItem(SESSION_KEY)) { + setIsOpen(true); + sessionStorage.setItem(SESSION_KEY, "1"); + } + }, []); + + const onClose = () => setIsOpen(false); + + const onExportPrivateKey = () => { + onClose(); + window.dispatchEvent(new CustomEvent("oko:reset-export-step")); + router.push(paths.export_private_key); + }; + + if (!isOpen) { + return null; + } + + return ( +
+
e.stopPropagation()} + > + +
+ +
+ +
+
+ +
+ + + +
+ + Please Export Your Private Key + +
+ + + +
+ + Oko is shutting down its service on June 1, 2026. + +
+ + + +
+

+ You must export your keys and migrate your Oko wallet to another + wallet. +

+
+ + + +
+ + After this date, your Private Key will no longer be accessible. + +
+ + +
+ +
+ + +
+
+
+
+ ); +}; diff --git a/apps/user_dashboard/src/components/left_bar/constant.tsx b/apps/user_dashboard/src/components/left_bar/constant.tsx index 32c546365..227a22990 100644 --- a/apps/user_dashboard/src/components/left_bar/constant.tsx +++ b/apps/user_dashboard/src/components/left_bar/constant.tsx @@ -11,6 +11,23 @@ export interface NavigationItem { icon: React.ReactNode; } +const KeyNavIcon = () => ( + + key + + +); + export const navigationItems: NavigationItem[] = [ { label: "Home", @@ -22,4 +39,9 @@ export const navigationItems: NavigationItem[] = [ href: paths.transaction_history, icon: , }, + { + label: "Export Private Key", + href: paths.export_private_key, + icon: , + }, ]; diff --git a/apps/user_dashboard/src/components/service_shutdown_modal/service_shutdown_modal.module.scss b/apps/user_dashboard/src/components/service_shutdown_modal/service_shutdown_modal.module.scss new file mode 100644 index 000000000..299d1b638 --- /dev/null +++ b/apps/user_dashboard/src/components/service_shutdown_modal/service_shutdown_modal.module.scss @@ -0,0 +1,146 @@ +@use "../../styles/viewport.module.scss" as *; + +.pill { + position: fixed; + right: 24px; + bottom: 24px; + display: flex; + align-items: center; + gap: 10px; + height: 58px; + padding: 0 24px; + border: 1px solid var(--border-primary); + border-radius: 8px; + background: var(--bg-tertiary); + box-shadow: var(--shadow-xl); + cursor: pointer; + z-index: 9; + font-family: Inter, sans-serif; + + &:hover { + background: var(--bg-secondary); + } +} + +.pillIcon { + flex-shrink: 0; +} + +.modalBackground { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + background: rgba(0, 0, 0, 0.4); +} + +.modal { + position: relative; + width: 100%; + max-width: 90vw; + max-height: 90vh; + + @media (min-width: $desktop_min_width) { + width: auto; + } +} + +.modalCard { + background: var(--bg-primary); + border: 1px solid var(--border-primary); + border-radius: 16px; + box-shadow: var(--shadow-xl); + width: 100%; + max-width: 400px; + box-sizing: border-box; + padding: 0; + + @media (min-width: $desktop_min_width) { + width: 400px; + } +} + +.header { + display: flex; + justify-content: flex-end; + align-items: center; + padding: 20px 20px 0; +} + +.closeButton { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + padding: 6px; + border: none; + background: none; + border-radius: 8px; + cursor: pointer; + color: var(--fg-quaternary); + + &:hover { + background: var(--bg-secondary); + } +} + +.content { + display: flex; + flex-direction: column; + align-items: center; + padding: 0 20px 8px; +} + +.logoWrapper { + display: flex; + justify-content: center; + width: 100%; +} + +.title { + text-align: center; + width: 100%; +} + +.body { + text-align: center; + width: 100%; +} + +.warningBox { + display: flex; + align-items: flex-start; + gap: 8px; + width: 100%; + padding: 12px; + border-radius: 12px; + background: #fef0c7; + box-sizing: border-box; +} + +.warningText { + flex: 1; + color: #dc6803; + font-family: Inter, sans-serif; + font-size: var(--font-size-sm); + font-weight: var(--font-weight-medium); + line-height: 20px; + text-align: center; +} + +.footer { + display: flex; + width: 100%; + padding: 12px 24px 16px; + box-sizing: border-box; +} + +.footerButton { + flex: 1; +} diff --git a/apps/user_dashboard/src/components/service_shutdown_modal/service_shutdown_modal.tsx b/apps/user_dashboard/src/components/service_shutdown_modal/service_shutdown_modal.tsx new file mode 100644 index 000000000..02b15dc74 --- /dev/null +++ b/apps/user_dashboard/src/components/service_shutdown_modal/service_shutdown_modal.tsx @@ -0,0 +1,122 @@ +"use client"; + +import { Button } from "@oko-wallet/oko-common-ui/button"; +import { Card } from "@oko-wallet/oko-common-ui/card"; +import { AlertTriangleIcon } from "@oko-wallet/oko-common-ui/icons/alert_triangle_icon"; +import { OkoLogoIcon } from "@oko-wallet/oko-common-ui/icons/oko_logo_icon"; +import { XCloseIcon } from "@oko-wallet/oko-common-ui/icons/x_close"; +import { Spacing } from "@oko-wallet/oko-common-ui/spacing"; +import { Typography } from "@oko-wallet/oko-common-ui/typography"; +import { type FC, useState } from "react"; + +import styles from "./service_shutdown_modal.module.scss"; + +export const ServiceShutdownModal: FC = () => { + const [isOpen, setIsOpen] = useState(true); + + const onOpen = () => setIsOpen(true); + const onClose = () => setIsOpen(false); + + return ( + <> + + + {isOpen && ( +
+
e.stopPropagation()} + > + +
+ +
+ +
+
+ +
+ + + +
+ + Please Export Your Private Key + +
+ + + +
+ + Oko is shutting down its service on June 1, 2026. + +
+ + + +
+

+ You must export your keys and migrate your Oko wallet to + another wallet. +

+
+ + + +
+ + After this date, your Private Key will no longer be + accessible. + +
+ + +
+ +
+ +
+
+
+
+ )} + + ); +}; diff --git a/embed/oko_attached/src/components/modal_variants/error/error_modal.tsx b/embed/oko_attached/src/components/modal_variants/error/error_modal.tsx index 117930361..bada0eb84 100644 --- a/embed/oko_attached/src/components/modal_variants/error/error_modal.tsx +++ b/embed/oko_attached/src/components/modal_variants/error/error_modal.tsx @@ -76,15 +76,32 @@ export const ErrorModal: FC = ({ error }) => {
- {errorCode && ( - - Error Code: {errorCode} - - )} - {errorMessage && ( - - {errorMessage} + {errorCode === "SIGNUP_DISABLED" ? ( + + Oko is shutting down on June 1, 2026. New wallet creation is no + longer available. + ) : ( + <> + {errorCode && ( + + Error Code: {errorCode} + + )} + {errorMessage && ( + + {errorMessage} + + )} + )}
diff --git a/embed/oko_attached/src/components/sign_with_oko_box/sign_with_oko_box.module.scss b/embed/oko_attached/src/components/sign_with_oko_box/sign_with_oko_box.module.scss index 396fa3da3..b0d3b2481 100644 --- a/embed/oko_attached/src/components/sign_with_oko_box/sign_with_oko_box.module.scss +++ b/embed/oko_attached/src/components/sign_with_oko_box/sign_with_oko_box.module.scss @@ -1,7 +1,20 @@ .container { + display: flex; + flex-direction: column; + align-items: center; + gap: 2px; +} + +.signRow { display: flex; align-items: center; justify-content: center; + gap: 8px; +} + +.signWithSection { + display: flex; + align-items: center; gap: 4px; } @@ -12,3 +25,24 @@ padding: 1.1px; } + +.shutdownNotice { + font-family: Inter, sans-serif; + font-size: calc(var(--font-size-xs) + 2px); + font-weight: var(--font-weight-medium); + color: var(--fg-quaternary); + white-space: nowrap; +} + +.backupLink { + font-family: Inter, sans-serif; + font-size: var(--font-size-xs); + font-weight: var(--font-weight-semibold); + color: #dc6803; + text-decoration: none; + white-space: nowrap; + + &:hover { + text-decoration: underline; + } +} diff --git a/embed/oko_attached/src/components/sign_with_oko_box/sign_with_oko_box.tsx b/embed/oko_attached/src/components/sign_with_oko_box/sign_with_oko_box.tsx index 720dd653e..0784ad18a 100644 --- a/embed/oko_attached/src/components/sign_with_oko_box/sign_with_oko_box.tsx +++ b/embed/oko_attached/src/components/sign_with_oko_box/sign_with_oko_box.tsx @@ -4,31 +4,65 @@ import type { FC } from "react"; import styles from "./sign_with_oko_box.module.scss"; import { useMobileMode } from "@oko-wallet-attached/hooks/mobile_mode"; +import { isDemoOrSandboxOrigin } from "@oko-wallet-attached/requests/endpoints"; +import { useMemoryState } from "@oko-wallet-attached/store/memory"; import { OkoLogoWithNameIcon } from "@oko-wallet-common-ui/icons/oko_logo_with_name_icon"; +const BACKUP_URL = "https://home.oko.app/export_private_key"; + export const SignWithOkoBox: FC = ({ theme, hideText, }) => { const isMobile = useMobileMode(); + const hostOrigin = useMemoryState((s) => s.hostOrigin); + const isMobileNative = useMemoryState((s) => s.isMobileNative); + const mobileApiKey = useMemoryState((s) => s.apiKey); + const isDemo = + hostOrigin !== null && + isDemoOrSandboxOrigin(hostOrigin, { + isMobileNative, + apiKey: mobileApiKey, + }); + const showBackupLink = !hideText && !isDemo; return (
- {!hideText && ( - - Sign with - + {showBackupLink && ( + + Oko shuts down Jun 1, 2026. + )} -
- +
+
+ {!hideText && ( + + Sign with + + )} +
+ +
+
+ + {showBackupLink && ( + + Export your private key → + + )}
);