remove wallet functionality
This commit is contained in:
15
src/App.tsx
15
src/App.tsx
@@ -1,4 +1,3 @@
|
||||
import { lazy, Suspense } from "react";
|
||||
import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom";
|
||||
import { I18nProvider } from "./i18n";
|
||||
import { PublicLayout } from "./layouts/PublicLayout";
|
||||
@@ -14,12 +13,6 @@ import { AdminRouterModeProvider } from "./adminRouterMode";
|
||||
import { ImageLightboxProvider } from "./components/messageStream/overlays/ImageLightbox";
|
||||
import { VideoPlayerProvider } from "./components/messageStream/overlays/VideoPlayer";
|
||||
|
||||
const WalletPage = lazy(() =>
|
||||
import("./pages/Wallet").then((module) => ({
|
||||
default: module.WalletPage,
|
||||
})),
|
||||
);
|
||||
|
||||
const adminEnabled = import.meta.env.VITE_DISABLE_ADMIN !== "true";
|
||||
|
||||
export default function App() {
|
||||
@@ -36,14 +29,6 @@ export default function App() {
|
||||
<Route path="/category/:slug" element={<CategoryPage />} />
|
||||
<Route path="/search" element={<SearchPage />} />
|
||||
<Route path="/resource/:id" element={<PostRedirect />} />
|
||||
<Route
|
||||
path="/wallet"
|
||||
element={
|
||||
<Suspense fallback={null}>
|
||||
<WalletPage />
|
||||
</Suspense>
|
||||
}
|
||||
/>
|
||||
<Route path="/about" element={<AboutPage />} />
|
||||
</Route>
|
||||
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
import { ConnectButton } from "@rainbow-me/rainbowkit";
|
||||
import { useAccount, useDisconnect, useSignMessage } from "wagmi";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { postJSON, apiBase } from "../api";
|
||||
import {
|
||||
clearWalletToken,
|
||||
getWalletToken,
|
||||
setWalletToken,
|
||||
} from "../walletToken";
|
||||
import { useI18n } from "../i18n";
|
||||
|
||||
export function WalletLoginControls() {
|
||||
const { t } = useI18n();
|
||||
const { address, isConnected } = useAccount();
|
||||
const { disconnectAsync } = useDisconnect();
|
||||
const { signMessageAsync, isPending: signing } = useSignMessage();
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [err, setErr] = useState<string | null>(null);
|
||||
const [sessionOk, setSessionOk] = useState(false);
|
||||
|
||||
const checkSession = useCallback(async () => {
|
||||
const tok = getWalletToken();
|
||||
if (!tok || !address) {
|
||||
setSessionOk(false);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const r = await fetch(`${apiBase}/api/auth/wallet/me`, {
|
||||
headers: { Authorization: `Bearer ${tok}` },
|
||||
});
|
||||
if (!r.ok) {
|
||||
clearWalletToken();
|
||||
setSessionOk(false);
|
||||
return;
|
||||
}
|
||||
const j = (await r.json()) as { wallet: string };
|
||||
setSessionOk(j.wallet?.toLowerCase() === address.toLowerCase());
|
||||
} catch {
|
||||
setSessionOk(false);
|
||||
}
|
||||
}, [address]);
|
||||
|
||||
useEffect(() => {
|
||||
void checkSession();
|
||||
}, [checkSession]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!address) clearWalletToken();
|
||||
}, [address]);
|
||||
|
||||
const signIn = async () => {
|
||||
if (!address) return;
|
||||
setErr(null);
|
||||
setBusy(true);
|
||||
try {
|
||||
const nonceRes = await postJSON<{ message: string }>(
|
||||
"/api/auth/wallet/nonce",
|
||||
{ address },
|
||||
);
|
||||
const sig = await signMessageAsync({ message: nonceRes.message });
|
||||
const out = await postJSON<{ token: string }>("/api/auth/wallet/verify", {
|
||||
address,
|
||||
message: nonceRes.message,
|
||||
signature: sig,
|
||||
});
|
||||
setWalletToken(out.token);
|
||||
setSessionOk(true);
|
||||
} catch (e) {
|
||||
setErr(String(e));
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
};
|
||||
|
||||
const signOut = async () => {
|
||||
clearWalletToken();
|
||||
setSessionOk(false);
|
||||
await disconnectAsync();
|
||||
};
|
||||
|
||||
if (!import.meta.env.VITE_WALLETCONNECT_PROJECT_ID) {
|
||||
return (
|
||||
<span
|
||||
className="text-xs text-amber-500/90 max-w-[220px] text-right leading-tight"
|
||||
title={t("walletMissingProjectId")}
|
||||
>
|
||||
{t("walletSetupNeeded")}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-end gap-1 min-w-[200px]">
|
||||
<div className="flex flex-wrap items-center justify-end gap-2">
|
||||
<ConnectButton chainStatus="icon" showBalance={false} />
|
||||
{isConnected && address ? (
|
||||
sessionOk ? (
|
||||
<span className="text-xs text-ark-gold2 whitespace-nowrap">
|
||||
{t("walletSignedIn")}
|
||||
</span>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
disabled={busy || signing}
|
||||
onClick={() => void signIn()}
|
||||
className="rounded-lg border border-ark-gold bg-ark-gold/10 px-3 py-1.5 text-xs font-medium text-ark-gold2 hover:bg-ark-gold/20 disabled:opacity-50"
|
||||
>
|
||||
{busy || signing ? "…" : t("signInWallet")}
|
||||
</button>
|
||||
)
|
||||
) : null}
|
||||
{isConnected && sessionOk ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => void signOut()}
|
||||
className="text-xs text-neutral-500 hover:text-white"
|
||||
>
|
||||
{t("walletLogout")}
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
{err ? (
|
||||
<p className="text-xs text-red-400 max-w-xs text-right">{err}</p>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
33
src/i18n.tsx
33
src/i18n.tsx
@@ -33,7 +33,6 @@ const zhDict: Dict = {
|
||||
preview: "预览",
|
||||
download: "下载",
|
||||
share: "分享",
|
||||
profile: "个人中心",
|
||||
langLabel: "语言",
|
||||
admin: "后台",
|
||||
login: "登录",
|
||||
@@ -67,21 +66,6 @@ const zhDict: Dict = {
|
||||
total: "总资料",
|
||||
views: "浏览",
|
||||
downloads: "下载",
|
||||
wallet: "钱包",
|
||||
walletPageTitle: "钱包登录",
|
||||
walletPageIntro:
|
||||
"连接 Web3 钱包以使用会员相关功能。采用标准签名登录,不发送交易、不消耗 gas。",
|
||||
walletStepExtension:
|
||||
"电脑已安装浏览器扩展钱包(如 MetaMask)时,可直接连接。",
|
||||
walletStepQR:
|
||||
"电脑未安装钱包时:在连接窗口选择 WalletConnect,用手机钱包扫描 QR Code。",
|
||||
walletStepSign: "连接成功后,点击「签署登录」并在钱包内签名即可完成验证。",
|
||||
signInWallet: "签署登录",
|
||||
walletSignedIn: "已验证登录",
|
||||
walletLogout: "退出钱包",
|
||||
walletMissingProjectId:
|
||||
"请配置 VITE_WALLETCONNECT_PROJECT_ID(Reown Cloud),否则无法使用 WalletConnect/扫码。",
|
||||
walletSetupNeeded: "钱包扫码未启用(请在服务器配置环境变量)",
|
||||
lang_zh_CN: "中文",
|
||||
lang_en: "English",
|
||||
lang_ja: "日本語",
|
||||
@@ -158,7 +142,6 @@ const enDict: Dict = {
|
||||
preview: "Preview",
|
||||
download: "Download",
|
||||
share: "Share",
|
||||
profile: "Profile",
|
||||
langLabel: "Language",
|
||||
admin: "Admin",
|
||||
login: "Sign in",
|
||||
@@ -192,22 +175,6 @@ const enDict: Dict = {
|
||||
total: "Total items",
|
||||
views: "Views",
|
||||
downloads: "Downloads",
|
||||
wallet: "Wallet",
|
||||
walletPageTitle: "Wallet sign-in",
|
||||
walletPageIntro:
|
||||
"Connect a Web3 wallet for member features. This uses a standard signed message — no transaction and no gas.",
|
||||
walletStepExtension:
|
||||
"On desktop with a browser extension (e.g. MetaMask), connect directly.",
|
||||
walletStepQR:
|
||||
"On desktop without an extension: choose WalletConnect in the modal and scan the QR code with your mobile wallet.",
|
||||
walletStepSign:
|
||||
'After connecting, tap "Sign in" and approve the message in your wallet to verify.',
|
||||
signInWallet: "Sign in",
|
||||
walletSignedIn: "Signed in",
|
||||
walletLogout: "Disconnect",
|
||||
walletMissingProjectId:
|
||||
"Set VITE_WALLETCONNECT_PROJECT_ID (free on Reown Cloud). Required for WalletConnect / QR login.",
|
||||
walletSetupNeeded: "Wallet QR login disabled (set env on server)",
|
||||
lang_zh_CN: "Chinese",
|
||||
lang_en: "English",
|
||||
lang_ja: "Japanese",
|
||||
|
||||
@@ -20,7 +20,6 @@ type PublicNavWhich =
|
||||
| "browseLatest"
|
||||
| "browseRecommended"
|
||||
| "browsePopular"
|
||||
| "wallet"
|
||||
| "about";
|
||||
|
||||
function navIsActive(
|
||||
@@ -43,8 +42,6 @@ function navIsActive(
|
||||
return pathname === "/browse" && sp.get("sort") === "recommended";
|
||||
case "browsePopular":
|
||||
return pathname === "/browse" && sp.get("sort") === "popular";
|
||||
case "wallet":
|
||||
return pathname === "/wallet";
|
||||
case "about":
|
||||
return pathname === "/about";
|
||||
default:
|
||||
@@ -240,13 +237,6 @@ export function PublicLayout() {
|
||||
>
|
||||
{t("popular")}
|
||||
</Link>
|
||||
<Link
|
||||
to="/wallet"
|
||||
className={navClassName(na("wallet"))}
|
||||
aria-current={na("wallet") ? "page" : undefined}
|
||||
>
|
||||
{t("wallet")}
|
||||
</Link>
|
||||
</nav>
|
||||
|
||||
<div className="flex min-w-0 flex-1 items-center justify-end gap-2 min-[1200px]:flex-none">
|
||||
@@ -344,14 +334,6 @@ export function PublicLayout() {
|
||||
>
|
||||
{t("popular")}
|
||||
</Link>
|
||||
<Link
|
||||
to="/wallet"
|
||||
className={navClassName(na("wallet"))}
|
||||
aria-current={na("wallet") ? "page" : undefined}
|
||||
onClick={() => setOpen(false)}
|
||||
>
|
||||
{t("wallet")}
|
||||
</Link>
|
||||
<Link
|
||||
to="/about"
|
||||
className={navClassName(na("about"))}
|
||||
@@ -376,12 +358,6 @@ export function PublicLayout() {
|
||||
>
|
||||
{t("footerAbout")}
|
||||
</Link>
|
||||
<Link
|
||||
to="/wallet"
|
||||
className="rounded-sm outline-none hover:text-ark-gold2 focus-visible:ring-2 focus-visible:ring-ark-gold/80 focus-visible:ring-offset-2 focus-visible:ring-offset-ark-bg"
|
||||
>
|
||||
{t("profile")}
|
||||
</Link>
|
||||
{import.meta.env.VITE_DISABLE_ADMIN !== "true" ? (
|
||||
<Link
|
||||
to={`${adminUiPrefix}/login`}
|
||||
@@ -443,7 +419,7 @@ function BottomNavIcon({
|
||||
}: {
|
||||
to: string;
|
||||
label: string;
|
||||
icon: "home" | "document" | "heart" | "profile" | "update";
|
||||
icon: "home" | "document" | "heart" | "update";
|
||||
active: boolean;
|
||||
}) {
|
||||
const src = active
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import "./index.css";
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
const adminOnly = import.meta.env.VITE_ADMIN_ONLY === "true";
|
||||
|
||||
void (async () => {
|
||||
@@ -23,9 +20,7 @@ void (async () => {
|
||||
const { default: App } = await import("./App");
|
||||
ReactDOM.createRoot(root).render(
|
||||
<React.StrictMode>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<App />
|
||||
</QueryClientProvider>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
);
|
||||
})();
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
import { RainbowKitProvider, darkTheme } from "@rainbow-me/rainbowkit";
|
||||
import { WagmiProvider } from "wagmi";
|
||||
import "@rainbow-me/rainbowkit/styles.css";
|
||||
import { WalletLoginControls } from "../../components/WalletLoginControls";
|
||||
import { useI18n } from "../../i18n";
|
||||
import { wagmiConfig } from "../../wagmiConfig";
|
||||
|
||||
export function WalletPage() {
|
||||
const { t } = useI18n();
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-lg space-y-6">
|
||||
<h1 className="text-2xl font-bold">{t("walletPageTitle")}</h1>
|
||||
<p className="text-neutral-300 text-sm leading-relaxed">
|
||||
{t("walletPageIntro")}
|
||||
</p>
|
||||
<ul className="text-sm text-neutral-400 space-y-2 list-disc pl-5">
|
||||
<li>{t("walletStepExtension")}</li>
|
||||
<li>{t("walletStepQR")}</li>
|
||||
<li>{t("walletStepSign")}</li>
|
||||
</ul>
|
||||
<div className="rounded-2xl border border-ark-line bg-ark-panel p-6 space-y-4">
|
||||
{import.meta.env.VITE_WALLETCONNECT_PROJECT_ID ? (
|
||||
<WagmiProvider config={wagmiConfig}>
|
||||
<RainbowKitProvider
|
||||
theme={darkTheme({
|
||||
accentColor: "#d4af37",
|
||||
accentColorForeground: "#0a0a0a",
|
||||
borderRadius: "medium",
|
||||
})}
|
||||
modalSize="wide"
|
||||
>
|
||||
<WalletLoginControls />
|
||||
</RainbowKitProvider>
|
||||
</WagmiProvider>
|
||||
) : (
|
||||
<p
|
||||
className="text-sm text-amber-500/90 leading-relaxed"
|
||||
title={t("walletMissingProjectId")}
|
||||
>
|
||||
{t("walletSetupNeeded")}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
1
src/vite-env.d.ts
vendored
1
src/vite-env.d.ts
vendored
@@ -3,7 +3,6 @@
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_API_URL: string;
|
||||
readonly VITE_API_PREFIX?: string;
|
||||
readonly VITE_WALLETCONNECT_PROJECT_ID: string;
|
||||
readonly VITE_ADMIN_UI_PREFIX?: string;
|
||||
/** When `"true"`, bundle admin UI only (no public pages); use with `VITE_ADMIN_UI_PREFIX` or default secret prefix. */
|
||||
readonly VITE_ADMIN_ONLY?: string;
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import { getDefaultConfig } from "@rainbow-me/rainbowkit";
|
||||
import { arbitrum, bsc, mainnet, polygon, sepolia } from "wagmi/chains";
|
||||
|
||||
/**
|
||||
* Get a free Project ID: https://cloud.reown.com (WalletConnect / Reown)
|
||||
* Without it, WalletConnect (mobile / QR on desktop) will not work; browser extensions may still work in some setups.
|
||||
*/
|
||||
const projectId = import.meta.env.VITE_WALLETCONNECT_PROJECT_ID || "";
|
||||
|
||||
export const wagmiConfig = getDefaultConfig({
|
||||
appName: "ARK Database",
|
||||
projectId: projectId || "00000000000000000000000000000000",
|
||||
chains: [mainnet, bsc, arbitrum, polygon, sepolia],
|
||||
ssr: false,
|
||||
});
|
||||
@@ -1,13 +0,0 @@
|
||||
const KEY = "ark_wallet_token";
|
||||
|
||||
export function getWalletToken() {
|
||||
return localStorage.getItem(KEY) || "";
|
||||
}
|
||||
|
||||
export function setWalletToken(t: string) {
|
||||
localStorage.setItem(KEY, t);
|
||||
}
|
||||
|
||||
export function clearWalletToken() {
|
||||
localStorage.removeItem(KEY);
|
||||
}
|
||||
Reference in New Issue
Block a user