feat: refactor homepage and navigation structure
Remove unused pages, redesign author page, update homepage with new chapter display, and modify bottom navigation. #VERCEL_SKIP Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
This commit is contained in:
@@ -1,15 +1,16 @@
|
||||
"use client"
|
||||
|
||||
import Link from "next/link"
|
||||
import { ChevronLeft, Clock, MessageCircle, BookOpen, Users, Award, TrendingUp } from "lucide-react"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { useState } from "react"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { ChevronLeft, Clock, MessageCircle, BookOpen, Users, Award, TrendingUp } from "lucide-react"
|
||||
import { QRCodeModal } from "@/components/modules/marketing/qr-code-modal"
|
||||
import { useStore } from "@/lib/store"
|
||||
|
||||
export default function AboutPage() {
|
||||
const router = useRouter()
|
||||
const [showQRModal, setShowQRModal] = useState(false)
|
||||
const { settings } = useStore()
|
||||
|
||||
const authorInfo = settings?.authorInfo || {
|
||||
name: "卡若",
|
||||
description: "连续创业者,私域运营专家",
|
||||
@@ -17,6 +18,13 @@ export default function AboutPage() {
|
||||
platform: "Soul派对房",
|
||||
}
|
||||
|
||||
const stats = [
|
||||
{ icon: BookOpen, value: "55+", label: "真实案例" },
|
||||
{ icon: Users, value: "10000+", label: "派对房听众" },
|
||||
{ icon: Award, value: "15年", label: "创业经验" },
|
||||
{ icon: TrendingUp, value: "3000万", label: "最高年流水" },
|
||||
]
|
||||
|
||||
const milestones = [
|
||||
{ year: "2012", event: "开始做游戏推广,从魔兽世界外挂代理起步" },
|
||||
{ year: "2015", event: "转型电商,做天猫虚拟充值,月流水380万" },
|
||||
@@ -26,126 +34,129 @@ export default function AboutPage() {
|
||||
{ year: "2024", event: "在Soul派对房每日直播,分享真实商业故事" },
|
||||
]
|
||||
|
||||
const stats = [
|
||||
{ icon: BookOpen, value: "55+", label: "真实案例" },
|
||||
{ icon: Users, value: "10000+", label: "派对房听众" },
|
||||
{ icon: Award, value: "15年", label: "创业经验" },
|
||||
{ icon: TrendingUp, value: "3000万", label: "最高年流水" },
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-[#0a1628] text-white pb-20">
|
||||
{/* Header */}
|
||||
<header className="sticky top-0 z-50 bg-[#0a1628]/90 backdrop-blur-md border-b border-gray-800">
|
||||
<div className="max-w-4xl mx-auto px-4 py-4 flex items-center">
|
||||
<Link href="/" className="flex items-center gap-2 text-gray-400 hover:text-white transition-colors">
|
||||
<ChevronLeft className="w-5 h-5" />
|
||||
<span>返回</span>
|
||||
</Link>
|
||||
<h1 className="flex-1 text-center text-lg font-semibold">关于作者</h1>
|
||||
<div className="w-16" />
|
||||
<div className="min-h-screen bg-black text-white pb-24">
|
||||
{/* 顶部导航 */}
|
||||
<header className="sticky top-0 z-40 bg-black/90 backdrop-blur-xl border-b border-white/5">
|
||||
<div className="px-4 py-3 flex items-center justify-between">
|
||||
<button
|
||||
onClick={() => router.back()}
|
||||
className="w-9 h-9 rounded-full bg-[#1c1c1e] flex items-center justify-center"
|
||||
>
|
||||
<ChevronLeft className="w-5 h-5 text-gray-400" />
|
||||
</button>
|
||||
<h1 className="text-lg font-semibold text-[#ffd700]">关于作者</h1>
|
||||
<div className="w-9" />
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main className="max-w-4xl mx-auto px-4 py-8">
|
||||
{/* Author Card */}
|
||||
<div className="bg-gradient-to-br from-[#38bdac]/20 to-[#0f2137] rounded-2xl p-8 border border-[#38bdac]/30 mb-8">
|
||||
<div className="flex flex-col md:flex-row items-center gap-6">
|
||||
<div className="w-24 h-24 rounded-full bg-gradient-to-br from-[#38bdac] to-[#1a5a50] flex items-center justify-center text-4xl font-bold text-white">
|
||||
<main className="px-4 py-6 space-y-6">
|
||||
{/* 作者头像卡片 */}
|
||||
<div className="p-6 rounded-2xl bg-gradient-to-br from-[#1c1c1e] to-[#2c2c2e] border border-white/5">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="w-20 h-20 rounded-full bg-gradient-to-br from-[#ff3b5c] to-[#ff6b8a] flex items-center justify-center text-3xl font-bold text-white flex-shrink-0">
|
||||
{authorInfo.name.charAt(0)}
|
||||
</div>
|
||||
<div className="text-center md:text-left flex-1">
|
||||
<h2 className="text-2xl font-bold text-white mb-2">{authorInfo.name}</h2>
|
||||
<p className="text-gray-400 mb-4">{authorInfo.description}</p>
|
||||
<div className="flex items-center justify-center md:justify-start gap-4 text-sm">
|
||||
<span className="flex items-center gap-1 text-[#38bdac]">
|
||||
<Clock className="w-4 h-4" />
|
||||
<div className="flex-1 min-w-0">
|
||||
<h2 className="text-xl font-bold text-white">{authorInfo.name}</h2>
|
||||
<p className="text-gray-400 text-sm mt-1">{authorInfo.description}</p>
|
||||
<div className="flex flex-wrap items-center gap-3 mt-3">
|
||||
<span className="flex items-center gap-1 text-[#ff3b5c] text-xs bg-[#ff3b5c]/10 px-2 py-1 rounded-lg">
|
||||
<Clock className="w-3 h-3" />
|
||||
每日 {authorInfo.liveTime}
|
||||
</span>
|
||||
<span className="flex items-center gap-1 text-gray-400">
|
||||
<MessageCircle className="w-4 h-4" />
|
||||
<span className="flex items-center gap-1 text-gray-400 text-xs">
|
||||
<MessageCircle className="w-3 h-3" />
|
||||
{authorInfo.platform}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<Button onClick={() => setShowQRModal(true)} className="bg-[#38bdac] hover:bg-[#2da396] text-white">
|
||||
<MessageCircle className="w-4 h-4 mr-2" />
|
||||
加入派对群
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Stats */}
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-8">
|
||||
{/* 数据统计 */}
|
||||
<div className="grid grid-cols-4 gap-3">
|
||||
{stats.map((stat, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="bg-[#0f2137]/60 backdrop-blur-md rounded-xl p-4 border border-gray-700/50 text-center"
|
||||
>
|
||||
<stat.icon className="w-6 h-6 text-[#38bdac] mx-auto mb-2" />
|
||||
<p className="text-2xl font-bold text-white">{stat.value}</p>
|
||||
<p className="text-gray-400 text-sm">{stat.label}</p>
|
||||
<div key={index} className="p-3 rounded-xl bg-[#1c1c1e] border border-white/5 text-center">
|
||||
<stat.icon className="w-5 h-5 text-[#ff3b5c] mx-auto mb-2" />
|
||||
<p className="text-lg font-bold text-white">{stat.value}</p>
|
||||
<p className="text-gray-500 text-[10px]">{stat.label}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Introduction */}
|
||||
<div className="bg-[#0f2137]/60 backdrop-blur-md rounded-xl p-6 border border-gray-700/50 mb-8">
|
||||
<h3 className="text-lg font-semibold text-white mb-4">关于这本书</h3>
|
||||
<div className="space-y-4 text-gray-300 leading-relaxed">
|
||||
{/* 关于这本书 */}
|
||||
<div className="p-5 rounded-2xl bg-[#1c1c1e] border border-white/5">
|
||||
<h3 className="text-base font-semibold text-white mb-4">关于这本书</h3>
|
||||
<div className="space-y-3 text-gray-300 text-sm leading-relaxed">
|
||||
<p>"这不是一本教你成功的鸡汤书。"</p>
|
||||
<p>
|
||||
这是我每天早上6点到9点,在Soul派对房和几百个陌生人分享的真实故事。 有人来找项目,有人来找钱,有人来找方向。
|
||||
</p>
|
||||
<p>
|
||||
我见过凌晨四点还在撸运费险的年轻人,见过七十岁还在开滴滴做生意的老人,
|
||||
见过一个月赚七八块却拼命倒卖游戏金币的大学生。
|
||||
</p>
|
||||
<p className="text-[#38bdac] font-semibold">"社会不是靠努力,是靠洞察与选择。"</p>
|
||||
<p>
|
||||
这本书,就是把那些在派对房里讲过的、能让人清醒的故事,整理成文字。每个案例都真实发生过,每个教训都是用钱换来的。
|
||||
</p>
|
||||
<p>这是我每天早上6点到9点,在Soul派对房和几百个陌生人分享的真实故事。</p>
|
||||
<p className="text-[#ff3b5c] font-medium">"社会不是靠努力,是靠洞察与选择。"</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Timeline */}
|
||||
<div className="bg-[#0f2137]/60 backdrop-blur-md rounded-xl p-6 border border-gray-700/50 mb-8">
|
||||
<h3 className="text-lg font-semibold text-white mb-6">创业历程</h3>
|
||||
{/* 创业历程 */}
|
||||
<div className="p-5 rounded-2xl bg-[#1c1c1e] border border-white/5">
|
||||
<h3 className="text-base font-semibold text-white mb-4">创业历程</h3>
|
||||
<div className="space-y-4">
|
||||
{milestones.map((item, index) => (
|
||||
<div key={index} className="flex gap-4">
|
||||
<div key={index} className="flex gap-3">
|
||||
<div className="flex flex-col items-center">
|
||||
<div className="w-3 h-3 rounded-full bg-[#38bdac]" />
|
||||
{index < milestones.length - 1 && <div className="w-0.5 h-full bg-gray-700 mt-1" />}
|
||||
<div className="w-2.5 h-2.5 rounded-full bg-[#ff3b5c]" />
|
||||
{index < milestones.length - 1 && <div className="w-0.5 flex-1 bg-gray-700 mt-1" />}
|
||||
</div>
|
||||
<div className="pb-4">
|
||||
<p className="text-[#38bdac] font-semibold">{item.year}</p>
|
||||
<p className="text-gray-300">{item.event}</p>
|
||||
<div className="pb-4 flex-1">
|
||||
<p className="text-[#ff3b5c] font-semibold text-sm">{item.year}</p>
|
||||
<p className="text-gray-300 text-sm mt-0.5">{item.event}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* CTA */}
|
||||
<div className="bg-gradient-to-r from-[#38bdac]/10 to-[#1a3a4a]/50 rounded-2xl p-6 border border-[#38bdac]/30 text-center">
|
||||
<h3 className="text-xl font-semibold text-white mb-2">想听更多真实故事?</h3>
|
||||
<p className="text-gray-400 mb-6">每天早上6-9点,卡若在Soul派对房免费分享</p>
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<Button onClick={() => setShowQRModal(true)} className="bg-[#38bdac] hover:bg-[#2da396] text-white">
|
||||
<MessageCircle className="w-4 h-4 mr-2" />
|
||||
加入派对群
|
||||
</Button>
|
||||
<Link href="/chapters">
|
||||
<Button variant="outline" className="border-gray-600 text-white hover:bg-gray-700/50 bg-transparent">
|
||||
<BookOpen className="w-4 h-4 mr-2" />
|
||||
开始阅读
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
{/* 行动引导 */}
|
||||
<div className="p-5 rounded-2xl bg-gradient-to-r from-[#ff3b5c]/10 to-[#ff6b8a]/10 border border-[#ff3b5c]/20">
|
||||
<h3 className="text-base font-semibold text-white mb-2">想听更多真实故事?</h3>
|
||||
<p className="text-gray-400 text-sm mb-4">每天早上6-9点,卡若在Soul派对房免费分享</p>
|
||||
<button
|
||||
onClick={() => setShowQRModal(true)}
|
||||
className="w-full py-3 rounded-xl bg-[#ff3b5c] text-white font-medium flex items-center justify-center gap-2 active:scale-[0.98] transition-transform"
|
||||
>
|
||||
<MessageCircle className="w-4 h-4" />
|
||||
加入派对群
|
||||
</button>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{/* 底部导航 */}
|
||||
<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-3">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<button
|
||||
onClick={() => router.push("/")}
|
||||
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
|
||||
>
|
||||
首页
|
||||
</button>
|
||||
<button
|
||||
onClick={() => router.push("/chapters")}
|
||||
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
|
||||
>
|
||||
目录
|
||||
</button>
|
||||
<button className="flex-1 py-2.5 rounded-xl bg-[#ff3b5c]/20 text-[#ff3b5c] text-sm font-medium text-center">
|
||||
作者
|
||||
</button>
|
||||
<button
|
||||
onClick={() => router.push("/my")}
|
||||
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
|
||||
>
|
||||
我的
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<QRCodeModal isOpen={showQRModal} onClose={() => setShowQRModal(false)} />
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -1,54 +1,251 @@
|
||||
import Link from "next/link"
|
||||
import { ChevronLeft } from "lucide-react"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { specialSections, FULL_BOOK_PRICE } from "@/lib/book-data"
|
||||
import { getBookStructure } from "@/lib/book-file-system"
|
||||
import { ChaptersList } from "@/components/chapters-list"
|
||||
"use client"
|
||||
|
||||
import { BuyFullBookButton } from "@/components/buy-full-book-button"
|
||||
import { useState } from "react"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { ChevronLeft, ChevronRight, Lock, Unlock, Book, BookOpen, Sparkles } from "lucide-react"
|
||||
import { useStore } from "@/lib/store"
|
||||
import { bookData, getTotalSectionCount, specialSections, getFullBookPrice } from "@/lib/book-data"
|
||||
import { AuthModal } from "@/components/modules/auth/auth-modal"
|
||||
import { PaymentModal } from "@/components/payment-modal"
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
export default function ChaptersPage() {
|
||||
const router = useRouter()
|
||||
const { user, isLoggedIn, hasPurchased } = useStore()
|
||||
const [expandedPart, setExpandedPart] = useState<string | null>("part-1")
|
||||
const [isAuthOpen, setIsAuthOpen] = useState(false)
|
||||
const [isPaymentOpen, setIsPaymentOpen] = useState(false)
|
||||
|
||||
export default async function ChaptersPage() {
|
||||
const parts = getBookStructure()
|
||||
const totalSections = getTotalSectionCount()
|
||||
const purchasedCount = user?.purchasedSections?.length || 0
|
||||
const hasFullBook = user?.hasFullBook || false
|
||||
const fullBookPrice = getFullBookPrice()
|
||||
|
||||
// Format special sections for the client component
|
||||
const specialSectionsData = {
|
||||
preface: { title: specialSections.preface.title },
|
||||
epilogue: { title: specialSections.epilogue.title }
|
||||
const handleSectionClick = (sectionId: string, isFree: boolean) => {
|
||||
router.push(`/read/${sectionId}`)
|
||||
}
|
||||
|
||||
const handleBuyFullBook = () => {
|
||||
if (!isLoggedIn) {
|
||||
setIsAuthOpen(true)
|
||||
return
|
||||
}
|
||||
setIsPaymentOpen(true)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-[#0a1628] text-white">
|
||||
{/* Header */}
|
||||
<header className="sticky top-0 z-50 bg-[#0a1628]/90 backdrop-blur-md border-b border-gray-800">
|
||||
<div className="max-w-4xl mx-auto px-4 py-4 flex items-center justify-between">
|
||||
<Link href="/" className="flex items-center gap-2 text-gray-400 hover:text-white transition-colors">
|
||||
<ChevronLeft className="w-5 h-5" />
|
||||
<span>返回</span>
|
||||
</Link>
|
||||
<h1 className="text-lg font-semibold">目录</h1>
|
||||
<BuyFullBookButton size="sm" price={9.9} className="bg-[#38bdac] hover:bg-[#2da396] text-white" />
|
||||
<div className="min-h-screen bg-black text-white pb-24">
|
||||
{/* 顶部导航 */}
|
||||
<header className="sticky top-0 z-40 bg-black/90 backdrop-blur-xl border-b border-white/5">
|
||||
<div className="px-4 py-3 flex items-center justify-between">
|
||||
<button
|
||||
onClick={() => router.push("/")}
|
||||
className="w-9 h-9 rounded-full bg-[#1c1c1e] flex items-center justify-center"
|
||||
>
|
||||
<ChevronLeft className="w-5 h-5 text-gray-400" />
|
||||
</button>
|
||||
<h1 className="text-lg font-semibold text-[#ffd700]">我要看</h1>
|
||||
<div className="w-9" />
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Content */}
|
||||
<main className="max-w-4xl mx-auto px-4 py-8">
|
||||
<ChaptersList parts={parts} specialSections={specialSectionsData} />
|
||||
|
||||
{/* Bottom CTA */}
|
||||
<div className="mt-12 bg-gradient-to-r from-[#38bdac]/20 to-[#0f2137] rounded-2xl p-6 border border-[#38bdac]/30">
|
||||
<div className="flex flex-col md:flex-row items-center justify-between gap-4">
|
||||
<div>
|
||||
<h3 className="text-white text-lg font-semibold mb-1">购买整本书,省82%</h3>
|
||||
<p className="text-gray-400">全部55节内容,永久阅读,后续更新免费获取</p>
|
||||
</div>
|
||||
<BuyFullBookButton size="lg" price={9.9} className="bg-[#38bdac] hover:bg-[#2da396] text-white px-8">
|
||||
立即购买 ¥9.9
|
||||
</BuyFullBookButton>
|
||||
{/* 书籍信息卡片 */}
|
||||
<div className="mx-4 mt-4 p-4 rounded-2xl bg-gradient-to-br from-[#1c1c1e] to-[#2c2c2e] border border-white/5">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-12 h-12 rounded-xl bg-gradient-to-br from-[#ff3b5c] to-[#ff6b8a] flex items-center justify-center">
|
||||
<Book className="w-6 h-6 text-white" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h2 className="text-white font-semibold">一场SOUL的创业实验场</h2>
|
||||
<p className="text-gray-500 text-xs mt-0.5">来自Soul派对房的真实商业故事</p>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<div className="text-xl font-bold text-[#ff3b5c]">{totalSections}</div>
|
||||
<div className="text-[10px] text-gray-500">章节</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 购买全书按钮 */}
|
||||
{!hasFullBook && (
|
||||
<button
|
||||
onClick={handleBuyFullBook}
|
||||
className="w-full mt-4 py-3 rounded-xl bg-gradient-to-r from-[#ff3b5c] to-[#ff6b8a] text-white font-medium flex items-center justify-center gap-2 active:scale-[0.98] transition-transform"
|
||||
>
|
||||
<Sparkles className="w-4 h-4" />
|
||||
<span>解锁全部 {totalSections} 章</span>
|
||||
<span className="ml-1">¥{fullBookPrice}</span>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 目录内容 */}
|
||||
<main className="px-4 py-4">
|
||||
{/* 序言 */}
|
||||
<button
|
||||
onClick={() => handleSectionClick("preface", true)}
|
||||
className="w-full mb-3 p-3 rounded-xl bg-[#1c1c1e] flex items-center justify-between active:bg-[#2c2c2e] transition-colors border border-white/5"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-8 h-8 rounded-lg bg-[#ff3b5c]/20 flex items-center justify-center">
|
||||
<BookOpen className="w-4 h-4 text-[#ff3b5c]" />
|
||||
</div>
|
||||
<span className="text-sm font-medium text-white">序言|为什么我每天早上6点在Soul开播?</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs text-[#00E5FF]">免费</span>
|
||||
<ChevronRight className="w-4 h-4 text-gray-500" />
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{/* 五篇目录 */}
|
||||
{bookData.map((part) => (
|
||||
<div key={part.id} className="mb-3">
|
||||
<button
|
||||
onClick={() => setExpandedPart(expandedPart === part.id ? null : part.id)}
|
||||
className="w-full p-3 rounded-xl bg-[#1c1c1e] flex items-center justify-between active:bg-[#2c2c2e] transition-colors border border-white/5"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-[#ff3b5c] to-[#ff6b8a] flex items-center justify-center text-sm font-bold text-white">
|
||||
{part.number}
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<div className="text-sm font-semibold text-white">{part.title}</div>
|
||||
<div className="text-[10px] text-gray-500">{part.subtitle}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs text-gray-500">
|
||||
{part.chapters.reduce((acc, ch) => acc + ch.sections.length, 0)}章
|
||||
</span>
|
||||
<ChevronRight
|
||||
className={`w-4 h-4 text-gray-500 transition-transform ${expandedPart === part.id ? "rotate-90" : ""}`}
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{expandedPart === part.id && (
|
||||
<div className="mt-2 ml-2 space-y-1">
|
||||
{part.chapters.map((chapter) => (
|
||||
<div key={chapter.id} className="rounded-lg bg-[#1c1c1e]/50 overflow-hidden border border-white/5">
|
||||
<div className="px-3 py-2 text-xs font-medium text-gray-400 border-b border-white/5">
|
||||
{chapter.title}
|
||||
</div>
|
||||
{chapter.sections.map((section) => {
|
||||
const isPurchased = hasFullBook || hasPurchased(section.id)
|
||||
const canRead = section.isFree || isPurchased
|
||||
|
||||
return (
|
||||
<button
|
||||
key={section.id}
|
||||
onClick={() => handleSectionClick(section.id, section.isFree)}
|
||||
className="w-full px-3 py-2.5 flex items-center justify-between border-b border-white/5 last:border-0 active:bg-white/5 transition-colors"
|
||||
>
|
||||
<div className="flex items-center gap-2 flex-1 min-w-0">
|
||||
{canRead ? (
|
||||
<Unlock className="w-3.5 h-3.5 text-[#ff3b5c] flex-shrink-0" />
|
||||
) : (
|
||||
<Lock className="w-3.5 h-3.5 text-gray-500 flex-shrink-0" />
|
||||
)}
|
||||
<span className={`text-xs truncate ${canRead ? "text-white" : "text-gray-400"}`}>
|
||||
{section.id} {section.title}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 flex-shrink-0 ml-2">
|
||||
{section.isFree ? (
|
||||
<span className="text-[10px] text-[#00E5FF] px-1.5 py-0.5 rounded bg-[#00E5FF]/10">
|
||||
免费
|
||||
</span>
|
||||
) : isPurchased ? (
|
||||
<span className="text-[10px] text-[#ff3b5c]">已购</span>
|
||||
) : (
|
||||
<span className="text-[10px] text-gray-500">¥{section.price}</span>
|
||||
)}
|
||||
<ChevronRight className="w-3.5 h-3.5 text-gray-600" />
|
||||
</div>
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* 尾声 */}
|
||||
<button
|
||||
onClick={() => handleSectionClick("epilogue", true)}
|
||||
className="w-full mb-3 p-3 rounded-xl bg-[#1c1c1e] flex items-center justify-between active:bg-[#2c2c2e] transition-colors border border-white/5"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-8 h-8 rounded-lg bg-[#ff3b5c]/20 flex items-center justify-center">
|
||||
<BookOpen className="w-4 h-4 text-[#ff3b5c]" />
|
||||
</div>
|
||||
<span className="text-sm font-medium text-white">尾声|这本书的真实目的</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs text-[#00E5FF]">免费</span>
|
||||
<ChevronRight className="w-4 h-4 text-gray-500" />
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{/* 附录 */}
|
||||
<div className="mb-3 p-3 rounded-xl bg-[#1c1c1e] border border-white/5">
|
||||
<div className="text-xs font-medium text-gray-400 mb-2">附录</div>
|
||||
{specialSections.appendix.map((item) => (
|
||||
<button
|
||||
key={item.id}
|
||||
onClick={() => handleSectionClick(item.id, true)}
|
||||
className="w-full py-2 flex items-center justify-between border-b border-white/5 last:border-0 active:bg-white/5"
|
||||
>
|
||||
<span className="text-xs text-gray-300">{item.title}</span>
|
||||
<ChevronRight className="w-3.5 h-3.5 text-gray-600" />
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{/* 底部导航 */}
|
||||
<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-3">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<button
|
||||
onClick={() => router.push("/")}
|
||||
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
|
||||
>
|
||||
首页
|
||||
</button>
|
||||
<button className="flex-1 py-2.5 rounded-xl bg-[#ff3b5c]/20 text-[#ff3b5c] text-sm font-medium text-center">
|
||||
目录
|
||||
</button>
|
||||
<button
|
||||
onClick={() => router.push("/about")}
|
||||
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
|
||||
>
|
||||
作者
|
||||
</button>
|
||||
<button
|
||||
onClick={() => router.push("/my")}
|
||||
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
|
||||
>
|
||||
我的
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{/* 登录弹窗 */}
|
||||
<AuthModal isOpen={isAuthOpen} onClose={() => setIsAuthOpen(false)} />
|
||||
|
||||
{/* 支付弹窗 */}
|
||||
<PaymentModal
|
||||
isOpen={isPaymentOpen}
|
||||
onClose={() => setIsPaymentOpen(false)}
|
||||
type="fullbook"
|
||||
sectionId=""
|
||||
sectionTitle=""
|
||||
amount={fullBookPrice}
|
||||
onSuccess={() => window.location.reload()}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
209
app/my/page.tsx
209
app/my/page.tsx
@@ -1,13 +1,14 @@
|
||||
"use client"
|
||||
|
||||
import { useState, useEffect } from "react"
|
||||
import Link from "next/link"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { User, ChevronRight, Copy, Check } from "lucide-react"
|
||||
import { useStore } from "@/lib/store"
|
||||
import { AuthModal } from "@/components/modules/auth/auth-modal"
|
||||
import { getFullBookPrice, getTotalSectionCount } from "@/lib/book-data"
|
||||
|
||||
export default function MyPage() {
|
||||
const router = useRouter()
|
||||
const { user, isLoggedIn, logout, getAllPurchases } = useStore()
|
||||
const [showAuthModal, setShowAuthModal] = useState(false)
|
||||
const [mounted, setMounted] = useState(false)
|
||||
@@ -28,8 +29,6 @@ export default function MyPage() {
|
||||
const fullBookPrice = getFullBookPrice()
|
||||
const totalSections = getTotalSectionCount()
|
||||
const purchasedCount = user?.hasFullBook ? totalSections : user?.purchasedSections?.length || 0
|
||||
|
||||
// 计算阅读时长(模拟数据,实际应该从localStorage读取)
|
||||
const readingMinutes = Math.floor(Math.random() * 100)
|
||||
const bookmarks = user?.purchasedSections?.length || 0
|
||||
|
||||
@@ -47,7 +46,7 @@ export default function MyPage() {
|
||||
<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-[#ffd700]">Soul派对·创业实验</h1>
|
||||
<h1 className="text-lg font-medium text-[#ffd700]">我的</h1>
|
||||
</div>
|
||||
|
||||
{/* 用户卡片 - 未登录 */}
|
||||
@@ -64,7 +63,6 @@ export default function MyPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 统计数据 */}
|
||||
<div className="grid grid-cols-3 gap-4 pt-4 border-t border-white/10">
|
||||
<div className="text-center">
|
||||
<p className="text-[#ff3b5c] text-xl font-bold">0</p>
|
||||
@@ -91,7 +89,6 @@ export default function MyPage() {
|
||||
<span className="text-[#ff3b5c] text-sm bg-[#ff3b5c]/10 px-2 py-1 rounded">佣金比例: 90%</span>
|
||||
</div>
|
||||
|
||||
{/* 收益卡片 */}
|
||||
<div className="bg-[#2c2c2e] rounded-xl p-4 mb-4">
|
||||
<p className="text-white/50 text-sm text-center mb-2">累计收益</p>
|
||||
<p className="text-[#ffd700] text-3xl font-bold text-center">¥0.00</p>
|
||||
@@ -107,7 +104,6 @@ export default function MyPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 按钮 */}
|
||||
<div className="grid grid-cols-2 gap-3 mb-4">
|
||||
<button
|
||||
onClick={() => setShowAuthModal(true)}
|
||||
@@ -123,7 +119,6 @@ export default function MyPage() {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* 统计 */}
|
||||
<div className="grid grid-cols-3 gap-4 pt-4 border-t border-white/10">
|
||||
<div className="text-center">
|
||||
<p className="text-[#ff3b5c] text-xl font-bold">0</p>
|
||||
@@ -139,7 +134,6 @@ export default function MyPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 邀请码 */}
|
||||
<div className="mt-4 pt-4 border-t border-white/10">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
@@ -156,76 +150,58 @@ export default function MyPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 菜单列表 */}
|
||||
{/* 菜单列表 - 精简版 */}
|
||||
<div className="mx-4 mt-4 rounded-2xl bg-[#1c1c1e] border border-white/5 overflow-hidden">
|
||||
<Link
|
||||
href="#"
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
setShowAuthModal(true)
|
||||
}}
|
||||
className="flex items-center justify-between p-4 border-b border-white/5 active:bg-white/5"
|
||||
<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" />
|
||||
</Link>
|
||||
<Link
|
||||
href="#"
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
setShowAuthModal(true)
|
||||
}}
|
||||
className="flex items-center justify-between p-4 border-b border-white/5 active:bg-white/5"
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setShowAuthModal(true)}
|
||||
className="w-full flex items-center justify-between p-4 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" />
|
||||
</Link>
|
||||
<Link
|
||||
href="#"
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
setShowAuthModal(true)
|
||||
}}
|
||||
className="flex items-center justify-between p-4 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" />
|
||||
</Link>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* 设置菜单 */}
|
||||
<div className="mx-4 mt-4 rounded-2xl bg-[#1c1c1e] border border-white/5 overflow-hidden">
|
||||
<Link href="#" className="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>
|
||||
{/* 底部导航 */}
|
||||
<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-3">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<button
|
||||
onClick={() => router.push("/")}
|
||||
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
|
||||
>
|
||||
首页
|
||||
</button>
|
||||
<button
|
||||
onClick={() => router.push("/chapters")}
|
||||
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
|
||||
>
|
||||
目录
|
||||
</button>
|
||||
<button
|
||||
onClick={() => router.push("/about")}
|
||||
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
|
||||
>
|
||||
作者
|
||||
</button>
|
||||
<button className="flex-1 py-2.5 rounded-xl bg-[#ff3b5c]/20 text-[#ff3b5c] text-sm font-medium text-center">
|
||||
我的
|
||||
</button>
|
||||
</div>
|
||||
<ChevronRight className="w-5 h-5 text-white/30" />
|
||||
</Link>
|
||||
<Link href="#" className="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" />
|
||||
</Link>
|
||||
<Link href="#" className="flex items-center justify-between p-4 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" />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<AuthModal isOpen={showAuthModal} onClose={() => setShowAuthModal(false)} />
|
||||
</main>
|
||||
@@ -240,7 +216,7 @@ export default function MyPage() {
|
||||
<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-[#ffd700]">Soul派对·创业实验</h1>
|
||||
<h1 className="text-lg font-medium text-[#ffd700]">我的</h1>
|
||||
</div>
|
||||
|
||||
{/* 用户卡片 */}
|
||||
@@ -255,7 +231,6 @@ export default function MyPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 统计数据 */}
|
||||
<div className="grid grid-cols-3 gap-4 pt-4 border-t border-white/10">
|
||||
<div className="text-center">
|
||||
<p className="text-[#ff3b5c] text-xl font-bold">{purchasedCount}</p>
|
||||
@@ -282,7 +257,6 @@ export default function MyPage() {
|
||||
<span className="text-[#ff3b5c] text-sm bg-[#ff3b5c]/10 px-2 py-1 rounded">佣金比例: 90%</span>
|
||||
</div>
|
||||
|
||||
{/* 收益卡片 */}
|
||||
<div className="bg-[#2c2c2e] rounded-xl p-4 mb-4">
|
||||
<p className="text-white/50 text-sm text-center mb-2">累计收益</p>
|
||||
<p className="text-[#ffd700] text-3xl font-bold text-center">¥{(user?.earnings || 0).toFixed(2)}</p>
|
||||
@@ -298,20 +272,21 @@ export default function MyPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 按钮 */}
|
||||
<div className="grid grid-cols-2 gap-3 mb-4">
|
||||
<Link href="/my/referral" className="py-3 rounded-xl bg-[#ff3b5c] text-white font-medium text-center">
|
||||
<button
|
||||
onClick={() => router.push("/my/referral")}
|
||||
className="py-3 rounded-xl bg-[#ff3b5c] text-white font-medium"
|
||||
>
|
||||
生成推广海报
|
||||
</Link>
|
||||
<Link
|
||||
href="/my/referral"
|
||||
className="py-3 rounded-xl bg-[#2c2c2e] text-white font-medium text-center border border-white/10"
|
||||
</button>
|
||||
<button
|
||||
onClick={() => router.push("/my/referral")}
|
||||
className="py-3 rounded-xl bg-[#2c2c2e] text-white font-medium border border-white/10"
|
||||
>
|
||||
立即提现
|
||||
</Link>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* 统计 */}
|
||||
<div className="grid grid-cols-3 gap-4 pt-4 border-t border-white/10">
|
||||
<div className="text-center">
|
||||
<p className="text-[#ff3b5c] text-xl font-bold">{user?.referralCount || 0}</p>
|
||||
@@ -327,7 +302,6 @@ export default function MyPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 邀请码 */}
|
||||
<div className="mt-4 pt-4 border-t border-white/10">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
@@ -345,66 +319,28 @@ export default function MyPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 菜单列表 */}
|
||||
{/* 菜单列表 - 精简版 */}
|
||||
<div className="mx-4 mt-4 rounded-2xl bg-[#1c1c1e] border border-white/5 overflow-hidden">
|
||||
<Link
|
||||
href="/my/purchases"
|
||||
className="flex items-center justify-between p-4 border-b border-white/5 active:bg-white/5"
|
||||
<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" />
|
||||
</Link>
|
||||
<Link
|
||||
href="/my/bookmarks"
|
||||
className="flex items-center justify-between p-4 border-b border-white/5 active:bg-white/5"
|
||||
</button>
|
||||
<button
|
||||
onClick={() => router.push("/my/bookmarks")}
|
||||
className="w-full flex items-center justify-between p-4 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" />
|
||||
</Link>
|
||||
<Link href="/my/notes" className="flex items-center justify-between p-4 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" />
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* 设置菜单 */}
|
||||
<div className="mx-4 mt-4 rounded-2xl bg-[#1c1c1e] border border-white/5 overflow-hidden">
|
||||
<Link
|
||||
href="/my/settings"
|
||||
className="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" />
|
||||
</Link>
|
||||
<Link
|
||||
href="/my/contact"
|
||||
className="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" />
|
||||
</Link>
|
||||
<Link href="/about" className="flex items-center justify-between p-4 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" />
|
||||
</Link>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* 退出登录 */}
|
||||
@@ -416,6 +352,35 @@ export default function MyPage() {
|
||||
退出登录
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* 底部导航 */}
|
||||
<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-3">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<button
|
||||
onClick={() => router.push("/")}
|
||||
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
|
||||
>
|
||||
首页
|
||||
</button>
|
||||
<button
|
||||
onClick={() => router.push("/chapters")}
|
||||
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
|
||||
>
|
||||
目录
|
||||
</button>
|
||||
<button
|
||||
onClick={() => router.push("/about")}
|
||||
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
|
||||
>
|
||||
作者
|
||||
</button>
|
||||
<button className="flex-1 py-2.5 rounded-xl bg-[#ff3b5c]/20 text-[#ff3b5c] text-sm font-medium text-center">
|
||||
我的
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import { useState } from "react"
|
||||
import Link from "next/link"
|
||||
import { ArrowLeft, Phone, Bell, Shield, HelpCircle } from "lucide-react"
|
||||
import { useStore } from "@/lib/store"
|
||||
|
||||
export default function SettingsPage() {
|
||||
const { user, updateUser } = useStore()
|
||||
const [nickname, setNickname] = useState(user?.nickname || "")
|
||||
const [saved, setSaved] = useState(false)
|
||||
|
||||
const handleSave = () => {
|
||||
if (user) {
|
||||
updateUser(user.id, { nickname })
|
||||
setSaved(true)
|
||||
setTimeout(() => setSaved(false), 2000)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="min-h-screen bg-[#0a1628] text-white pb-20">
|
||||
<div className="sticky top-0 z-10 bg-[#0a1628]/95 backdrop-blur-md border-b border-gray-700/50">
|
||||
<div className="max-w-md mx-auto flex items-center gap-4 p-4">
|
||||
<Link href="/my" className="p-2 -ml-2">
|
||||
<ArrowLeft className="w-5 h-5" />
|
||||
</Link>
|
||||
<h1 className="text-lg font-semibold">账户设置</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-4">
|
||||
<div className="max-w-md mx-auto space-y-4">
|
||||
{/* Profile Settings */}
|
||||
<div className="bg-[#0f2137]/60 rounded-xl p-4">
|
||||
<h3 className="text-gray-400 text-sm mb-4">个人信息</h3>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="text-gray-400 text-xs">昵称</label>
|
||||
<input
|
||||
type="text"
|
||||
value={nickname}
|
||||
onChange={(e) => setNickname(e.target.value)}
|
||||
className="w-full bg-[#0a1628] border border-gray-700 rounded-lg px-4 py-3 text-white mt-1"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="text-gray-400 text-xs">手机号</label>
|
||||
<div className="flex items-center gap-2 mt-1">
|
||||
<Phone className="w-4 h-4 text-gray-500" />
|
||||
<span className="text-gray-400">{user?.phone}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={handleSave}
|
||||
className="w-full mt-4 bg-[#38bdac] hover:bg-[#2da396] text-white py-3 rounded-lg font-medium"
|
||||
>
|
||||
{saved ? "已保存" : "保存修改"}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Other Settings */}
|
||||
<div className="bg-[#0f2137]/60 rounded-xl overflow-hidden">
|
||||
<div className="flex items-center justify-between p-4 border-b border-gray-700/30">
|
||||
<div className="flex items-center gap-3">
|
||||
<Bell className="w-5 h-5 text-gray-400" />
|
||||
<span>消息通知</span>
|
||||
</div>
|
||||
<div className="w-10 h-5 bg-[#38bdac] rounded-full relative">
|
||||
<div className="w-4 h-4 bg-white rounded-full absolute right-0.5 top-0.5" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between p-4 border-b border-gray-700/30">
|
||||
<div className="flex items-center gap-3">
|
||||
<Shield className="w-5 h-5 text-gray-400" />
|
||||
<span>隐私设置</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Link href="/docs" className="flex items-center justify-between p-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<HelpCircle className="w-5 h-5 text-gray-400" />
|
||||
<span>帮助文档</span>
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
565
app/page.tsx
565
app/page.tsx
@@ -1,349 +1,274 @@
|
||||
"use client"
|
||||
|
||||
import { useState } from "react"
|
||||
import { useState, useEffect, useRef, useCallback } from "react"
|
||||
import { useRouter } from "next/navigation"
|
||||
import { ChevronRight, Sparkles, Lock, Share2 } from "lucide-react"
|
||||
import { useStore } from "@/lib/store"
|
||||
import { bookData, getTotalSectionCount, specialSections } from "@/lib/book-data"
|
||||
import { Book, Lock, Unlock, ChevronRight, User, BookOpen } from "lucide-react"
|
||||
import { getFullBookPrice, getTotalSectionCount } from "@/lib/book-data"
|
||||
import { AuthModal } from "@/components/modules/auth/auth-modal"
|
||||
import { PaymentModal } from "@/components/payment-modal"
|
||||
|
||||
export default function HomePage() {
|
||||
const router = useRouter()
|
||||
const { user, isLoggedIn, hasPurchased } = useStore()
|
||||
const [activeTab, setActiveTab] = useState<"home" | "me">("home")
|
||||
const [expandedPart, setExpandedPart] = useState<string | null>("part-1")
|
||||
const [content, setContent] = useState<string>("")
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
const [showPaywall, setShowPaywall] = useState(false)
|
||||
const [readingProgress, setReadingProgress] = useState(0)
|
||||
const [isAuthOpen, setIsAuthOpen] = useState(false)
|
||||
const [isPaymentOpen, setIsPaymentOpen] = useState(false)
|
||||
const [paymentType, setPaymentType] = useState<"section" | "fullbook">("section")
|
||||
const contentRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const fullBookPrice = getFullBookPrice()
|
||||
const totalSections = getTotalSectionCount()
|
||||
const purchasedCount = user?.purchasedSections?.length || 0
|
||||
const hasFullBook = user?.hasFullBook || false
|
||||
|
||||
// 点击章节
|
||||
const handleSectionClick = (sectionId: string, isFree: boolean) => {
|
||||
if (isFree || hasFullBook || hasPurchased(sectionId)) {
|
||||
router.push(`/read/${sectionId}`)
|
||||
} else {
|
||||
router.push(`/read/${sectionId}`)
|
||||
}
|
||||
// 最新章节 - 使用1.1作为示例
|
||||
const latestSection = {
|
||||
id: "1.1",
|
||||
title: "荷包:电动车出租的被动收入模式",
|
||||
price: 1,
|
||||
isFree: true,
|
||||
filePath: "book/第一篇|真实的人/第1章|人与人之间的底层逻辑/1.1 荷包:电动车出租的被动收入模式.md",
|
||||
}
|
||||
|
||||
// 加载最新章节内容
|
||||
useEffect(() => {
|
||||
async function loadContent() {
|
||||
try {
|
||||
const response = await fetch(`/api/content?path=${encodeURIComponent(latestSection.filePath)}`)
|
||||
if (response.ok) {
|
||||
const data = await response.json()
|
||||
setContent(data.content || "")
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to load content:", error)
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
loadContent()
|
||||
}, [])
|
||||
|
||||
// 监听滚动进度
|
||||
const handleScroll = useCallback(() => {
|
||||
if (!contentRef.current) return
|
||||
|
||||
const scrollTop = window.scrollY
|
||||
const docHeight = document.documentElement.scrollHeight - window.innerHeight
|
||||
const progress = docHeight > 0 ? Math.min((scrollTop / docHeight) * 100, 100) : 0
|
||||
setReadingProgress(progress)
|
||||
|
||||
// 滚动超过20%时触发付费墙(非免费章节或未登录)
|
||||
if (progress >= 20 && !hasFullBook && !latestSection.isFree) {
|
||||
setShowPaywall(true)
|
||||
}
|
||||
}, [hasFullBook])
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener("scroll", handleScroll)
|
||||
return () => window.removeEventListener("scroll", handleScroll)
|
||||
}, [handleScroll])
|
||||
|
||||
const handlePurchaseClick = (type: "section" | "fullbook") => {
|
||||
if (!isLoggedIn) {
|
||||
setIsAuthOpen(true)
|
||||
return
|
||||
}
|
||||
setPaymentType(type)
|
||||
setIsPaymentOpen(true)
|
||||
}
|
||||
|
||||
const contentLines = content.split("\n").filter((line) => line.trim())
|
||||
// 如果需要付费墙,只显示前20%内容
|
||||
const displayContent =
|
||||
showPaywall && !hasFullBook && !latestSection.isFree
|
||||
? contentLines.slice(0, Math.ceil(contentLines.length * 0.2)).join("\n")
|
||||
: content
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-black text-white flex flex-col">
|
||||
{/* 顶部固定区域 - 书籍信息 */}
|
||||
<header className="flex-shrink-0 px-4 pt-safe-top pb-3 bg-gradient-to-b from-black to-transparent">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-14 h-14 rounded-xl bg-gradient-to-br from-[#30d158] to-[#00c7be] flex items-center justify-center shadow-lg">
|
||||
<Book className="w-7 h-7 text-white" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h1 className="text-lg font-bold tracking-tight">一场SOUL的创业实验场</h1>
|
||||
<p className="text-xs text-gray-400 mt-0.5">来自Soul派对房的真实商业故事</p>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<div className="text-2xl font-bold text-[#30d158]">{totalSections}</div>
|
||||
<div className="text-[10px] text-gray-500">章节</div>
|
||||
<div className="min-h-screen bg-black text-white pb-24">
|
||||
{/* 阅读进度条 */}
|
||||
<div className="fixed top-0 left-0 right-0 z-50 h-0.5 bg-[#1c1c1e]">
|
||||
<div
|
||||
className="h-full bg-gradient-to-r from-[#ff3b5c] to-[#ff6b8a] transition-all duration-150"
|
||||
style={{ width: `${readingProgress}%` }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 顶部标题区 */}
|
||||
<header className="sticky top-0 z-40 bg-black/90 backdrop-blur-xl border-b border-white/5">
|
||||
<div className="px-4 py-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-[#ffd700] text-lg font-semibold">Soul派对·创业实验</span>
|
||||
<span className="text-[10px] text-[#ff3b5c] bg-[#ff3b5c]/10 px-2 py-0.5 rounded">最新</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => {
|
||||
const url = window.location.href
|
||||
navigator.clipboard.writeText(url)
|
||||
alert("链接已复制")
|
||||
}}
|
||||
className="w-8 h-8 rounded-full bg-[#1c1c1e] flex items-center justify-center"
|
||||
>
|
||||
<Share2 className="w-4 h-4 text-gray-400" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* 主内容区域 - 可滚动的目录 */}
|
||||
{activeTab === "home" ? (
|
||||
<main className="flex-1 overflow-y-auto px-4 pb-20 scrollbar-hide">
|
||||
{/* 序言入口 */}
|
||||
<button
|
||||
onClick={() => handleSectionClick("preface", true)}
|
||||
className="w-full mb-3 p-3 rounded-xl bg-[#1c1c1e] flex items-center justify-between active:bg-[#2c2c2e] transition-colors"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-8 h-8 rounded-lg bg-[#30d158]/20 flex items-center justify-center">
|
||||
<BookOpen className="w-4 h-4 text-[#30d158]" />
|
||||
</div>
|
||||
<span className="text-sm font-medium">序言|为什么我每天早上6点在Soul开播?</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs text-[#30d158]">免费</span>
|
||||
<ChevronRight className="w-4 h-4 text-gray-500" />
|
||||
</div>
|
||||
</button>
|
||||
{/* 章节标题 */}
|
||||
<div className="px-4 pt-6 pb-4">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<span className="text-[#ff3b5c] text-sm font-medium bg-[#ff3b5c]/10 px-3 py-1 rounded-full">
|
||||
{latestSection.id}
|
||||
</span>
|
||||
{latestSection.isFree && (
|
||||
<span className="text-xs text-[#00E5FF] bg-[#00E5FF]/10 px-2 py-0.5 rounded">免费</span>
|
||||
)}
|
||||
</div>
|
||||
<h1 className="text-xl font-bold text-white leading-tight">{latestSection.title}</h1>
|
||||
<p className="text-gray-500 text-sm mt-2">第一篇|真实的人</p>
|
||||
</div>
|
||||
|
||||
{/* 五篇目录 */}
|
||||
{bookData.map((part) => (
|
||||
<div key={part.id} className="mb-3">
|
||||
{/* 篇标题 */}
|
||||
<button
|
||||
onClick={() => setExpandedPart(expandedPart === part.id ? null : part.id)}
|
||||
className="w-full p-3 rounded-xl bg-[#1c1c1e] flex items-center justify-between active:bg-[#2c2c2e] transition-colors"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-[#30d158] to-[#00c7be] flex items-center justify-center text-sm font-bold">
|
||||
{part.number}
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<div className="text-sm font-semibold">{part.title}</div>
|
||||
<div className="text-[10px] text-gray-500">{part.subtitle}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs text-gray-500">
|
||||
{part.chapters.reduce((acc, ch) => acc + ch.sections.length, 0)}章
|
||||
</span>
|
||||
<ChevronRight
|
||||
className={`w-4 h-4 text-gray-500 transition-transform ${expandedPart === part.id ? "rotate-90" : ""}`}
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{/* 展开的章节列表 */}
|
||||
{expandedPart === part.id && (
|
||||
<div className="mt-2 ml-2 space-y-1">
|
||||
{part.chapters.map((chapter) => (
|
||||
<div key={chapter.id} className="rounded-lg bg-[#1c1c1e]/50 overflow-hidden">
|
||||
<div className="px-3 py-2 text-xs font-medium text-gray-400 border-b border-white/5">
|
||||
{chapter.title}
|
||||
</div>
|
||||
{chapter.sections.map((section) => {
|
||||
const isPurchased = hasFullBook || hasPurchased(section.id)
|
||||
const canRead = section.isFree || isPurchased
|
||||
|
||||
return (
|
||||
<button
|
||||
key={section.id}
|
||||
onClick={() => handleSectionClick(section.id, section.isFree)}
|
||||
className="w-full px-3 py-2.5 flex items-center justify-between border-b border-white/5 last:border-0 active:bg-white/5 transition-colors"
|
||||
>
|
||||
<div className="flex items-center gap-2 flex-1 min-w-0">
|
||||
{canRead ? (
|
||||
<Unlock className="w-3.5 h-3.5 text-[#30d158] flex-shrink-0" />
|
||||
) : (
|
||||
<Lock className="w-3.5 h-3.5 text-gray-500 flex-shrink-0" />
|
||||
)}
|
||||
<span className={`text-xs truncate ${canRead ? "text-white" : "text-gray-400"}`}>
|
||||
{section.id} {section.title}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 flex-shrink-0 ml-2">
|
||||
{section.isFree ? (
|
||||
<span className="text-[10px] text-[#30d158] px-1.5 py-0.5 rounded bg-[#30d158]/10">
|
||||
免费
|
||||
</span>
|
||||
) : isPurchased ? (
|
||||
<span className="text-[10px] text-[#30d158]">已购</span>
|
||||
) : (
|
||||
<span className="text-[10px] text-gray-500">¥{section.price}</span>
|
||||
)}
|
||||
<ChevronRight className="w-3.5 h-3.5 text-gray-600" />
|
||||
</div>
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* 尾声入口 */}
|
||||
<button
|
||||
onClick={() => handleSectionClick("epilogue", true)}
|
||||
className="w-full mb-3 p-3 rounded-xl bg-[#1c1c1e] flex items-center justify-between active:bg-[#2c2c2e] transition-colors"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-8 h-8 rounded-lg bg-[#30d158]/20 flex items-center justify-center">
|
||||
<BookOpen className="w-4 h-4 text-[#30d158]" />
|
||||
</div>
|
||||
<span className="text-sm font-medium">尾声|这本书的真实目的</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs text-[#30d158]">免费</span>
|
||||
<ChevronRight className="w-4 h-4 text-gray-500" />
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{/* 附录 */}
|
||||
<div className="mb-3 p-3 rounded-xl bg-[#1c1c1e]">
|
||||
<div className="text-xs font-medium text-gray-400 mb-2">附录</div>
|
||||
{specialSections.appendix.map((item) => (
|
||||
<button
|
||||
key={item.id}
|
||||
onClick={() => handleSectionClick(item.id, true)}
|
||||
className="w-full py-2 flex items-center justify-between border-b border-white/5 last:border-0 active:bg-white/5"
|
||||
>
|
||||
<span className="text-xs text-gray-300">{item.title}</span>
|
||||
<ChevronRight className="w-3.5 h-3.5 text-gray-600" />
|
||||
</button>
|
||||
{/* 内容区域 */}
|
||||
<main ref={contentRef} className="px-4 pb-8">
|
||||
{isLoading ? (
|
||||
<div className="space-y-4">
|
||||
{[...Array(8)].map((_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="h-4 bg-[#1c1c1e] rounded animate-pulse"
|
||||
style={{ width: `${Math.random() * 40 + 60}%` }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</main>
|
||||
) : (
|
||||
<MyPage />
|
||||
)}
|
||||
) : (
|
||||
<article className="text-gray-300 leading-[1.9] text-[16px]">
|
||||
{displayContent.split("\n").map(
|
||||
(paragraph, index) =>
|
||||
paragraph.trim() && (
|
||||
<p key={index} className="mb-5">
|
||||
{paragraph}
|
||||
</p>
|
||||
),
|
||||
)}
|
||||
</article>
|
||||
)}
|
||||
|
||||
{/* 付费墙 - 只在非免费章节且滚动超过20%时显示 */}
|
||||
{showPaywall && !hasFullBook && !latestSection.isFree && (
|
||||
<div className="relative mt-4">
|
||||
{/* 渐变遮罩 */}
|
||||
<div className="absolute -top-32 left-0 right-0 h-32 bg-gradient-to-t from-black to-transparent pointer-events-none" />
|
||||
|
||||
{/* 付费卡片 */}
|
||||
<div className="p-6 rounded-2xl bg-gradient-to-b from-[#1c1c1e] to-[#2c2c2e] border border-white/10">
|
||||
<div className="text-center">
|
||||
<div className="w-14 h-14 mx-auto mb-3 rounded-2xl bg-[#ff3b5c]/10 flex items-center justify-center">
|
||||
<Lock className="w-7 h-7 text-[#ff3b5c]" />
|
||||
</div>
|
||||
<h3 className="text-lg font-semibold text-white mb-2">解锁完整内容</h3>
|
||||
<p className="text-gray-400 text-sm mb-5">{isLoggedIn ? "支付1元继续阅读" : "登录并支付1元继续阅读"}</p>
|
||||
|
||||
<div className="space-y-3 mb-4">
|
||||
<button
|
||||
onClick={() => handlePurchaseClick("section")}
|
||||
className="w-full py-3 px-5 rounded-xl bg-[#ff3b5c] text-white font-medium active:scale-[0.98] transition-transform"
|
||||
>
|
||||
<div className="flex items-center justify-center gap-2">
|
||||
<span>立即解锁</span>
|
||||
<span className="text-lg font-bold">¥1</span>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={() => handlePurchaseClick("fullbook")}
|
||||
className="w-full py-3 px-5 rounded-xl bg-[#2c2c2e] border border-white/10 text-white font-medium active:scale-[0.98] transition-transform"
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<Sparkles className="w-4 h-4 text-[#ffd700]" />
|
||||
<span>解锁全部 {totalSections} 章</span>
|
||||
</div>
|
||||
<span className="text-[#ffd700]">¥{fullBookPrice}</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p className="text-xs text-gray-500">分享给好友购买,你可获得90%佣金</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 底部引导 - 免费章节或已购买时显示 */}
|
||||
{!showPaywall && (
|
||||
<div className="mt-8 p-4 rounded-xl bg-[#1c1c1e] border border-white/5">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-white font-medium">想看更多内容?</p>
|
||||
<p className="text-gray-500 text-sm mt-1">共 {totalSections} 章精彩内容</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => router.push("/chapters")}
|
||||
className="px-4 py-2 rounded-lg bg-[#ff3b5c] text-white text-sm font-medium flex items-center gap-1"
|
||||
>
|
||||
查看目录
|
||||
<ChevronRight className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</main>
|
||||
|
||||
{/* 底部导航 */}
|
||||
<nav className="flex-shrink-0 fixed bottom-0 left-0 right-0 bg-[#1c1c1e]/90 backdrop-blur-xl border-t border-white/10 pb-safe-bottom">
|
||||
<div className="flex justify-around py-2">
|
||||
<button
|
||||
onClick={() => setActiveTab("home")}
|
||||
className={`flex flex-col items-center gap-0.5 px-6 py-1 ${activeTab === "home" ? "text-[#30d158]" : "text-gray-500"}`}
|
||||
>
|
||||
<Book className="w-5 h-5" />
|
||||
<span className="text-[10px]">首页</span>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActiveTab("me")}
|
||||
className={`flex flex-col items-center gap-0.5 px-6 py-1 ${activeTab === "me" ? "text-[#30d158]" : "text-gray-500"}`}
|
||||
>
|
||||
<User className="w-5 h-5" />
|
||||
<span className="text-[10px]">我的</span>
|
||||
</button>
|
||||
<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-3">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<button
|
||||
onClick={() => router.push("/chapters")}
|
||||
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
|
||||
>
|
||||
目录
|
||||
</button>
|
||||
<button
|
||||
onClick={() => router.push("/about")}
|
||||
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
|
||||
>
|
||||
作者
|
||||
</button>
|
||||
<button
|
||||
onClick={() => router.push("/my")}
|
||||
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
|
||||
>
|
||||
我的
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handlePurchaseClick("fullbook")}
|
||||
className="flex-1 py-2.5 rounded-xl bg-[#ff3b5c] text-white text-sm font-medium text-center active:scale-[0.98]"
|
||||
>
|
||||
购买
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{/* 登录弹窗 */}
|
||||
<AuthModal isOpen={isAuthOpen} onClose={() => setIsAuthOpen(false)} />
|
||||
|
||||
{/* 支付弹窗 */}
|
||||
<PaymentModal
|
||||
isOpen={isPaymentOpen}
|
||||
onClose={() => setIsPaymentOpen(false)}
|
||||
type={paymentType}
|
||||
sectionId={latestSection.id}
|
||||
sectionTitle={latestSection.title}
|
||||
amount={paymentType === "section" ? latestSection.price : fullBookPrice}
|
||||
onSuccess={() => window.location.reload()}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function MyPage() {
|
||||
const router = useRouter()
|
||||
const { user, isLoggedIn, logout } = useStore()
|
||||
const [showLogin, setShowLogin] = useState(false)
|
||||
|
||||
const purchasedCount = user?.purchasedSections?.length || 0
|
||||
const hasFullBook = user?.hasFullBook || false
|
||||
const earnings = user?.earnings || 0
|
||||
const totalSections = getTotalSectionCount()
|
||||
|
||||
// 计算阅读进度
|
||||
const readProgress = hasFullBook ? 100 : Math.round((purchasedCount / totalSections) * 100)
|
||||
|
||||
if (!isLoggedIn) {
|
||||
return (
|
||||
<div className="flex-1 flex flex-col items-center justify-center px-6 pb-20">
|
||||
<div className="w-20 h-20 rounded-full bg-[#1c1c1e] flex items-center justify-center mb-4">
|
||||
<User className="w-10 h-10 text-gray-500" />
|
||||
</div>
|
||||
<h2 className="text-lg font-semibold mb-2">登录后查看更多</h2>
|
||||
<p className="text-sm text-gray-500 text-center mb-6">登录后可查看购买记录、阅读进度和收益</p>
|
||||
<button
|
||||
onClick={() => router.push("/login")}
|
||||
className="px-8 py-3 bg-[#30d158] text-white font-medium rounded-xl active:scale-95 transition-transform"
|
||||
>
|
||||
立即登录
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="flex-1 overflow-y-auto px-4 pb-20 scrollbar-hide">
|
||||
{/* 用户信息卡片 */}
|
||||
<div className="p-4 rounded-2xl bg-gradient-to-br from-[#1c1c1e] to-[#2c2c2e] mb-4">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<div className="w-14 h-14 rounded-full bg-gradient-to-br from-[#30d158] to-[#00c7be] flex items-center justify-center text-xl font-bold">
|
||||
{user?.nickname?.charAt(0) || "U"}
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="font-semibold">{user?.nickname || "用户"}</div>
|
||||
<div className="text-xs text-gray-500">{user?.phone}</div>
|
||||
</div>
|
||||
{hasFullBook && (
|
||||
<div className="px-2 py-1 bg-[#30d158]/20 rounded-lg">
|
||||
<span className="text-xs text-[#30d158] font-medium">全书会员</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 数据统计 */}
|
||||
<div className="grid grid-cols-3 gap-3">
|
||||
<div className="p-3 rounded-xl bg-black/30 text-center">
|
||||
<div className="text-xl font-bold text-[#30d158]">{hasFullBook ? totalSections : purchasedCount}</div>
|
||||
<div className="text-[10px] text-gray-500 mt-1">已购章节</div>
|
||||
</div>
|
||||
<div className="p-3 rounded-xl bg-black/30 text-center">
|
||||
<div className="text-xl font-bold text-white">{readProgress}%</div>
|
||||
<div className="text-[10px] text-gray-500 mt-1">阅读进度</div>
|
||||
</div>
|
||||
<div className="p-3 rounded-xl bg-black/30 text-center">
|
||||
<div className="text-xl font-bold text-[#ff9500]">¥{earnings.toFixed(2)}</div>
|
||||
<div className="text-[10px] text-gray-500 mt-1">累计收益</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 阅读进度条 */}
|
||||
<div className="p-4 rounded-xl bg-[#1c1c1e] mb-4">
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<span className="text-sm font-medium">阅读进度</span>
|
||||
<span className="text-xs text-gray-500">
|
||||
{hasFullBook ? totalSections : purchasedCount}/{totalSections}章
|
||||
</span>
|
||||
</div>
|
||||
<div className="h-2 bg-black/50 rounded-full overflow-hidden">
|
||||
<div
|
||||
className="h-full bg-gradient-to-r from-[#30d158] to-[#00c7be] rounded-full transition-all duration-500"
|
||||
style={{ width: `${readProgress}%` }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 收益明细 */}
|
||||
<div className="p-4 rounded-xl bg-[#1c1c1e] mb-4">
|
||||
<div className="flex justify-between items-center mb-3">
|
||||
<span className="text-sm font-medium">收益明细</span>
|
||||
<button className="text-xs text-[#30d158]">查看详情</button>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-xs text-gray-400">可提现</span>
|
||||
<span className="text-sm font-medium text-[#30d158]">¥{(user?.pendingEarnings || 0).toFixed(2)}</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-xs text-gray-400">已提现</span>
|
||||
<span className="text-sm text-gray-400">¥{(user?.withdrawnEarnings || 0).toFixed(2)}</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-xs text-gray-400">推荐人数</span>
|
||||
<span className="text-sm text-gray-400">{user?.referralCount || 0}人</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 购买全书入口 */}
|
||||
{!hasFullBook && (
|
||||
<button
|
||||
onClick={() => router.push("/purchase")}
|
||||
className="w-full p-4 rounded-xl bg-gradient-to-r from-[#30d158] to-[#00c7be] mb-4 active:scale-[0.98] transition-transform"
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<div className="text-sm font-semibold text-white">解锁全部 {totalSections} 章</div>
|
||||
<div className="text-xs text-white/70 mt-0.5">一次购买,永久阅读</div>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<div className="text-2xl font-bold text-white">¥9.9</div>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* 邀请码 */}
|
||||
<div className="p-4 rounded-xl bg-[#1c1c1e] mb-4">
|
||||
<div className="text-sm font-medium mb-2">我的邀请码</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex-1 p-2 bg-black/30 rounded-lg text-center font-mono text-[#30d158]">
|
||||
{user?.referralCode || "N/A"}
|
||||
</div>
|
||||
<button className="px-4 py-2 bg-[#30d158]/20 text-[#30d158] text-sm rounded-lg active:bg-[#30d158]/30">
|
||||
复制
|
||||
</button>
|
||||
</div>
|
||||
<p className="text-[10px] text-gray-500 mt-2">邀请好友购买,获得90%佣金</p>
|
||||
</div>
|
||||
|
||||
{/* 退出登录 */}
|
||||
<button
|
||||
onClick={logout}
|
||||
className="w-full p-3 rounded-xl bg-[#1c1c1e] text-red-500 text-sm font-medium active:bg-[#2c2c2e] transition-colors"
|
||||
>
|
||||
退出登录
|
||||
</button>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user