Files
soul-yongping/app/my/page.tsx
v0 7e1e2e7115 feat: add admin site config page and optimize my page
Add "Site Configuration" page and refactor "My" page
Expand store with site, menu, and page configurations.

#VERCEL_SKIP

Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
2026-01-14 07:57:58 +00:00

418 lines
18 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client"
import { useState, useEffect } from "react"
import { useRouter } from "next/navigation"
import { User, ChevronRight, Copy, Check, Home, List, TrendingUp, Gift, Star, Info } from "lucide-react"
import { useStore } from "@/lib/store"
import { AuthModal } from "@/components/modules/auth/auth-modal"
import { getFullBookPrice, getTotalSectionCount } from "@/lib/book-data"
function PlanetIcon({ className }: { className?: string }) {
return (
<svg className={className} viewBox="0 0 24 24" fill="currentColor">
<circle cx="12" cy="12" r="8" fill="currentColor" opacity="0.9" />
<ellipse cx="12" cy="12" rx="11" ry="4" fill="none" stroke="currentColor" strokeWidth="1.5" opacity="0.6" />
<circle cx="9" cy="10" r="1.5" fill="white" opacity="0.4" />
</svg>
)
}
export default function MyPage() {
const router = useRouter()
const { user, isLoggedIn, logout, getAllPurchases, settings } = useStore()
const [showAuthModal, setShowAuthModal] = useState(false)
const [mounted, setMounted] = useState(false)
const [copied, setCopied] = useState(false)
useEffect(() => {
setMounted(true)
}, [])
if (!mounted) {
return (
<div className="min-h-screen bg-black flex items-center justify-center">
<div className="animate-spin rounded-full h-8 w-8 border-t-2 border-b-2 border-[#00CED1]" />
</div>
)
}
const fullBookPrice = getFullBookPrice()
const totalSections = getTotalSectionCount()
const purchasedCount = user?.hasFullBook ? totalSections : user?.purchasedSections?.length || 0
const readingMinutes = Math.floor(Math.random() * 100)
const bookmarks = user?.purchasedSections?.length || 0
const authorInfo = settings?.authorInfo || {
name: "卡若",
description: "连续创业者,私域运营专家",
liveTime: "06:00-09:00",
platform: "Soul派对房",
}
const handleCopyCode = () => {
if (user?.referralCode) {
navigator.clipboard.writeText(user.referralCode)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
}
}
// 底部导航组件
const BottomNavBar = () => (
<nav className="fixed bottom-0 left-0 right-0 bg-[#1c1c1e]/95 backdrop-blur-xl border-t border-white/5 pb-safe-bottom">
<div className="px-4 py-2">
<div className="flex items-center justify-around">
<button onClick={() => router.push("/")} className="flex flex-col items-center py-2 px-4">
<Home className="w-5 h-5 text-gray-500 mb-1" />
<span className="text-gray-500 text-xs"></span>
</button>
<button onClick={() => router.push("/chapters")} className="flex flex-col items-center py-2 px-4">
<List className="w-5 h-5 text-gray-500 mb-1" />
<span className="text-gray-500 text-xs"></span>
</button>
{/* 匹配按钮 - 小星球图标 */}
<button onClick={() => router.push("/match")} className="flex flex-col items-center py-2 px-6 -mt-4">
<div className="w-14 h-14 rounded-full bg-gradient-to-br from-[#00CED1] to-[#20B2AA] flex items-center justify-center shadow-lg shadow-[#00CED1]/30">
<PlanetIcon className="w-7 h-7 text-white" />
</div>
<span className="text-gray-500 text-xs mt-1"></span>
</button>
<button className="flex flex-col items-center py-2 px-4">
<User className="w-5 h-5 text-[#00CED1] mb-1" />
<span className="text-[#00CED1] text-xs font-medium"></span>
</button>
</div>
</div>
</nav>
)
// 未登录状态
if (!isLoggedIn) {
return (
<main className="min-h-screen bg-black text-white pb-24">
<div className="text-center py-4 border-b border-white/10">
<h1 className="text-lg font-medium text-[#00CED1]"></h1>
</div>
{/* 用户卡片 - 突出个性化 */}
<div className="mx-4 mt-4 p-4 rounded-2xl bg-gradient-to-br from-[#1c1c1e] to-[#2c2c2e] border border-[#00CED1]/20">
<div className="flex items-center gap-3 mb-4">
<div className="w-16 h-16 rounded-full border-2 border-dashed border-[#00CED1]/50 flex items-center justify-center bg-gradient-to-br from-[#00CED1]/10 to-transparent">
<User className="w-8 h-8 text-white/30" />
</div>
<div className="flex-1">
<button onClick={() => setShowAuthModal(true)} className="text-[#00CED1] font-semibold text-lg">
</button>
<p className="text-white/30 text-sm"></p>
</div>
<div className="px-3 py-1 rounded-full bg-[#00CED1]/20 border border-[#00CED1]/30">
<span className="text-[#00CED1] text-xs">VIP</span>
</div>
</div>
{/* 个性化数据 */}
<div className="grid grid-cols-3 gap-2 pt-4 border-t border-white/10">
<div className="text-center p-2 rounded-lg bg-white/5">
<p className="text-[#00CED1] text-xl font-bold">0</p>
<p className="text-white/40 text-xs"></p>
</div>
<div className="text-center p-2 rounded-lg bg-white/5">
<p className="text-[#00CED1] text-xl font-bold">0</p>
<p className="text-white/40 text-xs"></p>
</div>
<div className="text-center p-2 rounded-lg bg-white/5">
<p className="text-[#00CED1] text-xl font-bold">0</p>
<p className="text-white/40 text-xs"></p>
</div>
</div>
</div>
{/* 收益中心 - 突出收益 */}
<div className="mx-4 mt-4 p-4 rounded-2xl bg-gradient-to-r from-[#FFD700]/10 via-[#1c1c1e] to-[#1c1c1e] border border-[#FFD700]/20">
<div className="flex items-center justify-between mb-4">
<div className="flex items-center gap-2">
<div className="w-8 h-8 rounded-lg bg-[#FFD700]/20 flex items-center justify-center">
<TrendingUp className="w-4 h-4 text-[#FFD700]" />
</div>
<span className="text-white font-medium"></span>
</div>
<span className="text-[#FFD700] text-sm bg-[#FFD700]/10 px-3 py-1 rounded-full">90%</span>
</div>
<div className="bg-gradient-to-r from-[#FFD700]/5 to-transparent rounded-xl p-4 mb-4">
<p className="text-white/50 text-sm text-center mb-1"></p>
<p className="text-[#FFD700] text-3xl font-bold text-center">¥0.00</p>
<div className="flex justify-center gap-8 mt-3">
<div className="text-center">
<p className="text-white/40 text-xs"></p>
<p className="text-white font-medium">¥0.00</p>
</div>
<div className="text-center">
<p className="text-white/40 text-xs"></p>
<p className="text-white font-medium">¥0.00</p>
</div>
</div>
</div>
<div className="grid grid-cols-2 gap-3 mb-4">
<button
onClick={() => setShowAuthModal(true)}
className="py-3 rounded-xl bg-gradient-to-r from-[#FFD700] to-[#FFA500] text-black font-medium flex items-center justify-center gap-2"
>
<Gift className="w-4 h-4" />
</button>
<button
onClick={() => setShowAuthModal(true)}
className="py-3 rounded-xl bg-[#2c2c2e] text-white font-medium border border-white/10"
>
</button>
</div>
<div className="grid grid-cols-3 gap-2 pt-4 border-t border-white/10">
<div className="text-center">
<p className="text-[#FFD700] text-xl font-bold">0</p>
<p className="text-white/40 text-xs"></p>
</div>
<div className="text-center">
<p className="text-[#FFD700] text-xl font-bold">0</p>
<p className="text-white/40 text-xs"></p>
</div>
<div className="text-center">
<p className="text-[#FFD700] text-xl font-bold">90%</p>
<p className="text-white/40 text-xs"></p>
</div>
</div>
<div className="mt-4 pt-4 border-t border-white/10">
<div className="flex items-center justify-between">
<div>
<p className="text-white/50 text-xs"></p>
<p className="text-[#FFD700] font-mono text-lg">- - -</p>
</div>
<button
onClick={() => setShowAuthModal(true)}
className="px-4 py-2 rounded-lg bg-[#2c2c2e] text-white text-sm"
>
</button>
</div>
</div>
</div>
{/* 菜单列表 */}
<div className="mx-4 mt-4 rounded-2xl bg-[#1c1c1e] border border-white/5 overflow-hidden">
<button
onClick={() => setShowAuthModal(true)}
className="w-full flex items-center justify-between p-4 border-b border-white/5 active:bg-white/5"
>
<div className="flex items-center gap-3">
<span className="text-xl">📦</span>
<span className="text-white"></span>
</div>
<ChevronRight className="w-5 h-5 text-white/30" />
</button>
<button
onClick={() => setShowAuthModal(true)}
className="w-full flex items-center justify-between p-4 border-b border-white/5 active:bg-white/5"
>
<div className="flex items-center gap-3">
<span className="text-xl">🏷</span>
<span className="text-white"></span>
</div>
<ChevronRight className="w-5 h-5 text-white/30" />
</button>
{/* 关于作者 - 小图标入口 */}
<button
onClick={() => router.push("/about")}
className="w-full flex items-center justify-between p-4 active:bg-white/5"
>
<div className="flex items-center gap-3">
<div className="w-6 h-6 rounded-full bg-gradient-to-br from-[#00CED1] to-[#20B2AA] flex items-center justify-center">
<Info className="w-3 h-3 text-white" />
</div>
<span className="text-white"></span>
</div>
<ChevronRight className="w-5 h-5 text-white/30" />
</button>
</div>
<BottomNavBar />
<AuthModal isOpen={showAuthModal} onClose={() => setShowAuthModal(false)} />
</main>
)
}
// 已登录状态
const userPurchases = getAllPurchases().filter((p) => p.userId === user?.id)
const completedOrders = userPurchases.filter((p) => p.status === "completed").length
return (
<main className="min-h-screen bg-black text-white pb-24">
<div className="text-center py-4 border-b border-white/10">
<h1 className="text-lg font-medium text-[#00CED1]"></h1>
</div>
{/* 用户卡片 - 突出个性化 */}
<div className="mx-4 mt-4 p-4 rounded-2xl bg-gradient-to-br from-[#1c1c1e] to-[#2c2c2e] border border-[#00CED1]/20">
<div className="flex items-center gap-3 mb-4">
<div className="w-16 h-16 rounded-full border-2 border-[#00CED1] flex items-center justify-center bg-gradient-to-br from-[#00CED1]/20 to-transparent">
<span className="text-2xl font-bold text-[#00CED1]">{user?.nickname?.charAt(0) || "U"}</span>
</div>
<div className="flex-1">
<p className="text-white font-semibold text-lg">{user?.nickname || "用户"}</p>
<p className="text-white/30 text-sm">ID: {user?.id?.slice(-8) || "---"}</p>
</div>
<div className="px-3 py-1 rounded-full bg-[#00CED1]/20 border border-[#00CED1]/30">
<span className="text-[#00CED1] text-xs flex items-center gap-1">
<Star className="w-3 h-3" />
VIP
</span>
</div>
</div>
{/* 个性化数据 */}
<div className="grid grid-cols-3 gap-2 pt-4 border-t border-white/10">
<div className="text-center p-2 rounded-lg bg-white/5">
<p className="text-[#00CED1] text-xl font-bold">{purchasedCount}</p>
<p className="text-white/40 text-xs"></p>
</div>
<div className="text-center p-2 rounded-lg bg-white/5">
<p className="text-[#00CED1] text-xl font-bold">{readingMinutes}</p>
<p className="text-white/40 text-xs">()</p>
</div>
<div className="text-center p-2 rounded-lg bg-white/5">
<p className="text-[#00CED1] text-xl font-bold">{bookmarks}</p>
<p className="text-white/40 text-xs"></p>
</div>
</div>
</div>
{/* 收益中心 - 突出收益 */}
<div className="mx-4 mt-4 p-4 rounded-2xl bg-gradient-to-r from-[#FFD700]/10 via-[#1c1c1e] to-[#1c1c1e] border border-[#FFD700]/20">
<div className="flex items-center justify-between mb-4">
<div className="flex items-center gap-2">
<div className="w-8 h-8 rounded-lg bg-[#FFD700]/20 flex items-center justify-center">
<TrendingUp className="w-4 h-4 text-[#FFD700]" />
</div>
<span className="text-white font-medium"></span>
</div>
<span className="text-[#FFD700] text-sm bg-[#FFD700]/10 px-3 py-1 rounded-full">90%</span>
</div>
<div className="bg-gradient-to-r from-[#FFD700]/5 to-transparent rounded-xl p-4 mb-4">
<p className="text-white/50 text-sm text-center mb-1"></p>
<p className="text-[#FFD700] text-3xl font-bold text-center">¥{(user?.earnings || 0).toFixed(2)}</p>
<div className="flex justify-center gap-8 mt-3">
<div className="text-center">
<p className="text-white/40 text-xs"></p>
<p className="text-white font-medium">¥{(user?.pendingEarnings || 0).toFixed(2)}</p>
</div>
<div className="text-center">
<p className="text-white/40 text-xs"></p>
<p className="text-white font-medium">¥{(user?.withdrawnEarnings || 0).toFixed(2)}</p>
</div>
</div>
</div>
<div className="grid grid-cols-2 gap-3 mb-4">
<button
onClick={() => router.push("/my/referral")}
className="py-3 rounded-xl bg-gradient-to-r from-[#FFD700] to-[#FFA500] text-black font-medium flex items-center justify-center gap-2"
>
<Gift className="w-4 h-4" />
</button>
<button
onClick={() => router.push("/my/referral")}
className="py-3 rounded-xl bg-[#2c2c2e] text-white font-medium border border-white/10"
>
</button>
</div>
<div className="grid grid-cols-3 gap-2 pt-4 border-t border-white/10">
<div className="text-center">
<p className="text-[#FFD700] text-xl font-bold">{user?.referralCount || 0}</p>
<p className="text-white/40 text-xs"></p>
</div>
<div className="text-center">
<p className="text-[#FFD700] text-xl font-bold">{completedOrders}</p>
<p className="text-white/40 text-xs"></p>
</div>
<div className="text-center">
<p className="text-[#FFD700] text-xl font-bold">90%</p>
<p className="text-white/40 text-xs"></p>
</div>
</div>
<div className="mt-4 pt-4 border-t border-white/10">
<div className="flex items-center justify-between">
<div>
<p className="text-white/50 text-xs"></p>
<p className="text-[#FFD700] font-mono text-lg">{user?.referralCode || "---"}</p>
</div>
<button
onClick={handleCopyCode}
className="px-4 py-2 rounded-lg bg-[#2c2c2e] text-white text-sm flex items-center gap-2"
>
{copied ? <Check className="w-4 h-4 text-[#00CED1]" /> : <Copy className="w-4 h-4" />}
{copied ? "已复制" : "复制"}
</button>
</div>
</div>
</div>
{/* 菜单列表 */}
<div className="mx-4 mt-4 rounded-2xl bg-[#1c1c1e] border border-white/5 overflow-hidden">
<button
onClick={() => router.push("/my/purchases")}
className="w-full flex items-center justify-between p-4 border-b border-white/5 active:bg-white/5"
>
<div className="flex items-center gap-3">
<span className="text-xl">📦</span>
<span className="text-white"></span>
</div>
<ChevronRight className="w-5 h-5 text-white/30" />
</button>
<button
onClick={() => router.push("/my/bookmarks")}
className="w-full flex items-center justify-between p-4 border-b border-white/5 active:bg-white/5"
>
<div className="flex items-center gap-3">
<span className="text-xl">🏷</span>
<span className="text-white"></span>
</div>
<ChevronRight className="w-5 h-5 text-white/30" />
</button>
{/* 关于作者 - 小图标入口 */}
<button
onClick={() => router.push("/about")}
className="w-full flex items-center justify-between p-4 active:bg-white/5"
>
<div className="flex items-center gap-3">
<div className="w-6 h-6 rounded-full bg-gradient-to-br from-[#00CED1] to-[#20B2AA] flex items-center justify-center">
<Info className="w-3 h-3 text-white" />
</div>
<span className="text-white"></span>
</div>
<ChevronRight className="w-5 h-5 text-white/30" />
</button>
</div>
<div className="mx-4 mt-4">
<button
onClick={logout}
className="w-full py-3 rounded-xl bg-[#1c1c1e] text-[#00CED1] font-medium border border-[#00CED1]/30"
>
退
</button>
</div>
<BottomNavBar />
</main>
)
}