refactor: full product interaction system redesign

Refactor homepage, reading modal, matching feature, and user profile for improved UX

#VERCEL_SKIP

Co-authored-by: undefined <undefined+undefined@users.noreply.github.com>
This commit is contained in:
v0
2026-01-14 05:17:59 +00:00
parent f3195d9331
commit 59ca3b2bbd
8 changed files with 1124 additions and 628 deletions

View File

@@ -2,177 +2,149 @@
import { useState, useEffect } from "react"
import Link from "next/link"
import { User, ShoppingBag, Share2, LogOut, ChevronRight, BookOpen, Copy, Check } from "lucide-react"
import { User, ShoppingBag, Share2, LogOut, ChevronRight, BookOpen } from "lucide-react"
import { useStore } from "@/lib/store"
import { AuthModal } from "@/components/modules/auth/auth-modal"
import { getFullBookPrice, getAllSections } from "@/lib/book-data"
import { getFullBookPrice } from "@/lib/book-data"
export default function MyPage() {
const { user, isLoggedIn, logout } = useStore()
const [showAuthModal, setShowAuthModal] = useState(false)
const [mounted, setMounted] = useState(false)
const [copied, setCopied] = useState(false)
useEffect(() => {
setMounted(true)
}, [])
const copyCode = () => {
if (user?.referralCode) {
navigator.clipboard.writeText(user.referralCode)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
}
}
if (!mounted) {
return (
<div className="min-h-screen bg-black flex items-center justify-center">
<div className="animate-spin rounded-full h-6 w-6 border-t-2 border-b-2 border-[var(--app-brand)]" />
<div className="min-h-screen bg-app-bg flex items-center justify-center">
<div className="animate-spin rounded-full h-8 w-8 border-t-2 border-b-2 border-app-brand" />
</div>
)
}
if (!isLoggedIn) {
return (
<main className="min-h-screen bg-black text-white pb-20 flex flex-col items-center justify-center px-4">
<div className="w-12 h-12 rounded-full bg-white/5 flex items-center justify-center mb-4">
<User className="w-6 h-6 text-white/40" />
<main className="min-h-screen bg-app-bg text-app-text pb-20 flex flex-col items-center justify-center">
<div className="p-4 w-full">
<div className="max-w-xs mx-auto text-center">
<div className="w-14 h-14 mx-auto mb-3 rounded-full bg-app-card flex items-center justify-center">
<User className="w-7 h-7 text-app-text-muted" />
</div>
<h2 className="text-base font-semibold mb-1"></h2>
<p className="text-app-text-muted text-xs mb-4"></p>
<button
onClick={() => setShowAuthModal(true)}
className="bg-app-brand hover:bg-app-brand-hover text-white px-6 py-2.5 rounded-full font-medium text-sm"
>
</button>
</div>
</div>
<h2 className="text-base font-medium mb-1"></h2>
<p className="text-white/40 text-xs mb-6"></p>
<button
onClick={() => setShowAuthModal(true)}
className="bg-[var(--app-brand)] text-white px-8 py-2.5 rounded-full font-medium text-sm"
>
</button>
<AuthModal isOpen={showAuthModal} onClose={() => setShowAuthModal(false)} />
</main>
)
}
const totalSections = getAllSections().length
const purchasedCount = user?.hasFullBook ? totalSections : user?.purchasedSections.length || 0
const purchaseProgress = Math.round((purchasedCount / totalSections) * 100)
const fullBookPrice = getFullBookPrice()
return (
<main className="min-h-screen bg-black text-white pb-20">
{/* 用户信息头部 */}
<div className="px-4 pt-10 pb-6">
<div className="flex items-center gap-3 mb-6">
<div className="w-12 h-12 rounded-full bg-[var(--app-brand)]/20 flex items-center justify-center">
<User className="w-6 h-6 text-[var(--app-brand)]" />
<main className="min-h-screen bg-app-bg text-app-text pb-20">
{/* User Profile Header */}
<div className="bg-gradient-to-b from-app-card to-app-bg p-4 pt-8">
<div className="max-w-xs mx-auto">
<div className="flex items-center gap-3 mb-3">
<div className="w-11 h-11 rounded-full bg-app-brand/20 flex items-center justify-center">
<User className="w-5 h-5 text-app-brand" />
</div>
<div>
<h2 className="text-sm font-semibold">{user?.nickname || "用户"}</h2>
<p className="text-app-text-muted text-xs">{user?.phone}</p>
</div>
</div>
<div>
<h2 className="text-base font-medium">{user?.nickname || "用户"}</h2>
<p className="text-white/40 text-xs">{user?.phone}</p>
{/* Stats */}
<div className="grid grid-cols-2 gap-2">
<div className="bg-app-card/60 rounded-lg p-2.5 text-center">
<p className="text-base font-bold text-app-brand">
{user?.hasFullBook ? "全部" : user?.purchasedSections.length || 0}
</p>
<p className="text-app-text-muted text-xs"></p>
</div>
<div className="bg-app-card/60 rounded-lg p-2.5 text-center">
<p className="text-base font-bold text-app-brand">¥{(user?.earnings || 0).toFixed(1)}</p>
<p className="text-app-text-muted text-xs"></p>
</div>
</div>
</div>
{/* 数据统计卡片 */}
<div className="grid grid-cols-2 gap-3 mb-4">
{/* 购买进度 */}
<div className="bg-white/[0.03] rounded-2xl p-4 border border-white/[0.06]">
<div className="flex items-center justify-between mb-2">
<span className="text-white/40 text-xs"></span>
<span className="text-[var(--app-brand)] text-xs font-medium">{purchaseProgress}%</span>
</div>
<div className="h-1.5 bg-white/10 rounded-full overflow-hidden mb-2">
<div
className="h-full bg-[var(--app-brand)] rounded-full transition-all"
style={{ width: `${purchaseProgress}%` }}
/>
</div>
<p className="text-white text-lg font-bold">
{user?.hasFullBook ? "全书" : `${purchasedCount}/${totalSections}`}
</p>
<p className="text-white/30 text-[10px]"></p>
</div>
{/* 分销收益 */}
<div className="bg-white/[0.03] rounded-2xl p-4 border border-white/[0.06]">
<div className="flex items-center justify-between mb-2">
<span className="text-white/40 text-xs"></span>
<Share2 className="w-3.5 h-3.5 text-white/30" />
</div>
<p className="text-[var(--app-brand)] text-lg font-bold mb-1">¥{(user?.earnings || 0).toFixed(2)}</p>
<p className="text-white/30 text-[10px]">{user?.referralCount || 0}</p>
</div>
</div>
{/* 购买整本书提示 */}
{!user?.hasFullBook && (
<Link href="/chapters" className="block mb-4">
<div className="bg-gradient-to-r from-[var(--app-brand)]/10 to-purple-500/10 rounded-2xl p-4 border border-[var(--app-brand)]/20">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<BookOpen className="w-5 h-5 text-[var(--app-brand)]" />
<div>
<p className="text-white text-sm font-medium"></p>
<p className="text-white/40 text-xs">{totalSections}</p>
</div>
</div>
<span className="text-[var(--app-brand)] font-bold">¥{fullBookPrice}</span>
</div>
</div>
</Link>
)}
</div>
{/* 菜单列表 */}
<div className="px-4">
<div className="bg-white/[0.03] rounded-2xl overflow-hidden border border-white/[0.06]">
<Link href="/my/purchases" className="flex items-center justify-between p-4 border-b border-white/[0.04]">
<div className="flex items-center gap-3">
<ShoppingBag className="w-4 h-4 text-white/40" />
<span className="text-sm"></span>
</div>
<div className="flex items-center gap-2">
<span className="text-white/40 text-xs">{purchasedCount}</span>
<ChevronRight className="w-4 h-4 text-white/20" />
</div>
</Link>
{/* Menu Items */}
<div className="p-4">
<div className="max-w-xs mx-auto space-y-2">
{/* Purchase prompt */}
{!user?.hasFullBook && (
<Link href="/chapters" className="block">
<div className="bg-gradient-to-r from-app-brand/20 to-app-card rounded-lg p-3 border border-app-brand/30">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<BookOpen className="w-4 h-4 text-app-brand" />
<span className="text-app-text text-sm"></span>
</div>
<span className="text-app-brand font-bold text-sm">¥{fullBookPrice}</span>
</div>
</div>
</Link>
)}
<Link href="/my/referral" className="flex items-center justify-between p-4">
<div className="flex items-center gap-3">
<Share2 className="w-4 h-4 text-white/40" />
<span className="text-sm"></span>
</div>
<div className="flex items-center gap-2">
<span className="text-[var(--app-brand)] text-xs">¥{(user?.earnings || 0).toFixed(1)}</span>
<ChevronRight className="w-4 h-4 text-white/20" />
</div>
</Link>
</div>
{/* Menu List - simplified, removed settings and docs */}
<div className="bg-app-card/60 rounded-lg overflow-hidden">
<Link href="/my/purchases" className="flex items-center justify-between p-3 border-b border-app-border">
<div className="flex items-center gap-2">
<ShoppingBag className="w-4 h-4 text-app-text-muted" />
<span className="text-sm"></span>
</div>
<ChevronRight className="w-4 h-4 text-app-text-muted" />
</Link>
{/* 邀请码 */}
<div className="bg-white/[0.03] rounded-2xl p-4 border border-white/[0.06] mt-3">
<div className="flex items-center justify-between">
<div>
<p className="text-white/40 text-xs mb-1"></p>
<code className="text-[var(--app-brand)] font-mono text-sm">{user?.referralCode}</code>
</div>
<button
onClick={copyCode}
className="flex items-center gap-1 px-3 py-1.5 rounded-lg bg-white/5 text-white/60 text-xs"
>
{copied ? <Check className="w-3 h-3" /> : <Copy className="w-3 h-3" />}
{copied ? "已复制" : "复制"}
</button>
<Link href="/my/referral" className="flex items-center justify-between p-3">
<div className="flex items-center gap-2">
<Share2 className="w-4 h-4 text-app-text-muted" />
<span className="text-sm"></span>
</div>
<div className="flex items-center gap-1">
<span className="text-app-brand text-xs">¥{(user?.earnings || 0).toFixed(1)}</span>
<ChevronRight className="w-4 h-4 text-app-text-muted" />
</div>
</Link>
</div>
<p className="text-white/30 text-[10px] mt-2">90%</p>
</div>
{/* 退出登录 */}
<button
onClick={logout}
className="w-full flex items-center justify-center gap-2 p-3 mt-6 text-white/40 text-sm"
>
<LogOut className="w-4 h-4" />
<span>退</span>
</button>
{/* Referral Code */}
<div className="bg-app-card/60 rounded-lg p-3">
<div className="flex items-center justify-between">
<div>
<p className="text-app-text-muted text-xs"></p>
<code className="text-app-brand font-mono text-sm">{user?.referralCode}</code>
</div>
<button
onClick={() => navigator.clipboard.writeText(user?.referralCode || "")}
className="text-app-text-muted text-xs hover:text-app-text px-2 py-1 rounded bg-app-card"
>
</button>
</div>
</div>
{/* Logout */}
<button
onClick={logout}
className="w-full flex items-center justify-center gap-2 p-2.5 text-app-text-muted hover:text-red-400 transition-colors text-sm"
>
<LogOut className="w-4 h-4" />
<span>退</span>
</button>
</div>
</div>
</main>
)