Clear existing content

This commit is contained in:
卡若
2026-01-09 11:57:57 +08:00
parent 924307a470
commit 2bdf275cba
172 changed files with 0 additions and 16577 deletions

View File

@@ -1,151 +0,0 @@
"use client"
import { useState, useEffect } from "react"
import Link from "next/link"
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 } from "@/lib/book-data"
export default function MyPage() {
const { user, isLoggedIn, logout } = useStore()
const [showAuthModal, setShowAuthModal] = useState(false)
const [mounted, setMounted] = useState(false)
useEffect(() => {
setMounted(true)
}, [])
if (!mounted) {
return (
<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-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>
<AuthModal isOpen={showAuthModal} onClose={() => setShowAuthModal(false)} />
</main>
)
}
const fullBookPrice = getFullBookPrice()
return (
<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>
{/* 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>
{/* 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>
)}
{/* 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>
<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>
{/* 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>
)
}

View File

@@ -1,109 +0,0 @@
"use client"
import Link from "next/link"
import { ChevronLeft, BookOpen, CheckCircle } from "lucide-react"
import { useStore } from "@/lib/store"
import { bookData, getAllSections } from "@/lib/book-data"
export default function MyPurchasesPage() {
const { user, isLoggedIn } = useStore()
if (!isLoggedIn || !user) {
return (
<div className="min-h-screen bg-[#0a1628] text-white flex items-center justify-center">
<div className="text-center">
<p className="text-gray-400 mb-4"></p>
<Link href="/" className="text-[#38bdac] hover:underline">
</Link>
</div>
</div>
)
}
const allSections = getAllSections()
const purchasedCount = user.hasFullBook ? allSections.length : user.purchasedSections.length
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">
<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>
</header>
<main className="max-w-4xl mx-auto px-4 py-8">
{/* Stats */}
<div className="bg-[#0f2137]/60 backdrop-blur-md rounded-xl p-6 border border-gray-700/50 mb-8">
<div className="grid grid-cols-2 gap-6">
<div className="text-center">
<p className="text-3xl font-bold text-white">{purchasedCount}</p>
<p className="text-gray-400 text-sm"></p>
</div>
<div className="text-center">
<p className="text-3xl font-bold text-[#38bdac]">
{user.hasFullBook ? "全书" : `${purchasedCount}/${allSections.length}`}
</p>
<p className="text-gray-400 text-sm">{user.hasFullBook ? "已解锁" : "进度"}</p>
</div>
</div>
</div>
{/* Purchased sections */}
{user.hasFullBook ? (
<div className="bg-gradient-to-r from-[#38bdac]/20 to-[#0f2137] rounded-xl p-6 border border-[#38bdac]/30 text-center mb-8">
<CheckCircle className="w-12 h-12 text-[#38bdac] mx-auto mb-3" />
<h3 className="text-xl font-semibold text-white mb-2"></h3>
<p className="text-gray-400">55,</p>
</div>
) : user.purchasedSections.length === 0 ? (
<div className="text-center py-12">
<BookOpen className="w-16 h-16 text-gray-600 mx-auto mb-4" />
<p className="text-gray-400 mb-4"></p>
<Link href="/chapters" className="text-[#38bdac] hover:underline">
</Link>
</div>
) : (
<div className="space-y-4">
<h2 className="text-gray-400 text-sm mb-4"></h2>
{bookData.map((part) => {
const purchasedInPart = part.chapters.flatMap((c) =>
c.sections.filter((s) => user.purchasedSections.includes(s.id)),
)
if (purchasedInPart.length === 0) return null
return (
<div key={part.id} className="bg-[#0f2137]/40 rounded-xl border border-gray-800/50 overflow-hidden">
<div className="px-4 py-3 bg-[#0a1628]/50">
<p className="text-gray-400 text-sm">{part.title}</p>
</div>
<div className="divide-y divide-gray-800/30">
{purchasedInPart.map((section) => (
<Link
key={section.id}
href={`/read/${section.id}`}
className="flex items-center gap-3 px-4 py-3 hover:bg-[#0f2137]/40 transition-colors"
>
<CheckCircle className="w-4 h-4 text-[#38bdac]" />
<span className="text-gray-400 font-mono text-sm">{section.id}</span>
<span className="text-gray-300">{section.title}</span>
</Link>
))}
</div>
</div>
)
})}
</div>
)}
</main>
</div>
)
}

View File

@@ -1,233 +0,0 @@
"use client"
import { useState, useEffect } from "react"
import Link from "next/link"
import { ChevronLeft, Copy, Share2, Users, Wallet, MessageCircle, ImageIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import { useStore, type Purchase } from "@/lib/store"
import { PosterModal } from "@/components/modules/referral/poster-modal"
import { WithdrawalModal } from "@/components/modules/referral/withdrawal-modal"
export default function ReferralPage() {
const { user, isLoggedIn, settings, getAllPurchases, getAllUsers } = useStore()
const [copied, setCopied] = useState(false)
const [showPoster, setShowPoster] = useState(false)
const [showWithdrawal, setShowWithdrawal] = useState(false)
const [referralPurchases, setReferralPurchases] = useState<Purchase[]>([])
const [referralUsers, setReferralUsers] = useState<number>(0)
useEffect(() => {
if (user?.referralCode) {
const allPurchases = getAllPurchases()
const allUsers = getAllUsers()
const usersWithMyCode = allUsers.filter((u) => u.referredBy === user.referralCode)
const userIds = usersWithMyCode.map((u) => u.id)
const myReferralPurchases = allPurchases.filter((p) => userIds.includes(p.userId))
setReferralPurchases(myReferralPurchases)
setReferralUsers(usersWithMyCode.length)
}
}, [user, getAllPurchases, getAllUsers])
if (!isLoggedIn || !user) {
return (
<div className="min-h-screen bg-app-bg text-app-text flex items-center justify-center pb-20">
<div className="text-center">
<p className="text-app-text-muted mb-4"></p>
<Link href="/" className="text-app-brand hover:underline">
</Link>
</div>
</div>
)
}
const referralLink = `${typeof window !== "undefined" ? window.location.origin : ""}?ref=${user.referralCode}`
const distributorShare = settings?.distributorShare || 90
const totalEarnings = user.earnings || 0
const pendingEarnings = user.pendingEarnings || 0
const handleCopy = () => {
navigator.clipboard.writeText(referralLink)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
}
const handleShare = async () => {
const shareText = `我正在读《一场SOUL的创业实验场》每天6-9点的真实商业故事推荐给你${referralLink}`
try {
if (typeof navigator.share === 'function' && typeof navigator.canShare === 'function') {
await navigator.share({
title: "一场SOUL的创业实验场",
text: "来自Soul派对房的真实商业故事",
url: referralLink,
})
} else {
await navigator.clipboard.writeText(shareText)
alert("分享文案已复制快去朋友圈或Soul派对分享吧")
}
} catch {
await navigator.clipboard.writeText(shareText)
alert("分享文案已复制!")
}
}
const handleShareToWechat = async () => {
const shareText = `📖 推荐一本好书《一场SOUL的创业实验场》
这是卡若每天早上6-9点在Soul派对房分享的真实商业故事55个真实案例讲透创业的底层逻辑。
👉 点击阅读: ${referralLink}
#创业 #商业思维 #Soul派对`
await navigator.clipboard.writeText(shareText)
alert("朋友圈文案已复制!\n\n打开微信 → 发朋友圈 → 粘贴即可")
}
const handleShareToSoul = async () => {
const shareText = `在Soul派对房听卡若讲了好多真实的创业故事他把这些故事整理成了一本书《一场SOUL的创业实验场》推荐给你们
每天早上6-9点直播这本书就是直播内容的精华版。
链接: ${referralLink}`
await navigator.clipboard.writeText(shareText)
alert("Soul分享文案已复制\n\n打开Soul → 发动态 → 粘贴即可")
}
return (
<div className="min-h-screen bg-app-bg text-app-text pb-24">
{/* Header */}
<header className="sticky top-0 z-50 bg-app-bg/90 backdrop-blur-md border-b border-app-border">
<div className="max-w-xs mx-auto px-4 py-3 flex items-center">
<Link href="/my" className="flex items-center gap-1 text-app-text-muted hover:text-app-text">
<ChevronLeft className="w-5 h-5" />
</Link>
<h1 className="flex-1 text-center text-sm font-semibold"></h1>
<div className="w-5" />
</div>
</header>
<main className="max-w-xs mx-auto px-4 py-4">
{/* Earnings Card */}
<div className="bg-gradient-to-br from-app-brand/20 to-app-card rounded-xl p-4 border border-app-brand/30 mb-3">
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-2">
<Wallet className="w-4 h-4 text-app-brand" />
<span className="text-app-text-muted text-xs"></span>
</div>
<span className="text-app-brand text-xs">{distributorShare}%</span>
</div>
<p className="text-2xl font-bold text-app-text mb-0.5">¥{totalEarnings.toFixed(2)}</p>
<p className="text-app-text-muted text-xs mb-3">: ¥{pendingEarnings.toFixed(2)}</p>
<Button
disabled={totalEarnings < 10}
onClick={() => setShowWithdrawal(true)}
className="w-full bg-app-brand hover:bg-app-brand-hover text-white h-8 text-xs"
>
{totalEarnings < 10 ? `满10元可提现` : "申请提现"}
</Button>
</div>
{/* Stats */}
<div className="grid grid-cols-2 gap-2 mb-3">
<div className="bg-app-card/60 rounded-lg p-2.5 text-center">
<Users className="w-4 h-4 text-app-brand mx-auto mb-1" />
<p className="text-base font-bold text-app-text">{referralUsers}</p>
<p className="text-app-text-muted text-xs"></p>
</div>
<div className="bg-app-card/60 rounded-lg p-2.5 text-center">
<Share2 className="w-4 h-4 text-app-brand mx-auto mb-1" />
<p className="text-base font-bold text-app-text">{referralPurchases.length}</p>
<p className="text-app-text-muted text-xs"></p>
</div>
</div>
{/* Referral link */}
<div className="bg-app-card/60 rounded-xl p-3 border border-app-border mb-3">
<p className="text-app-text text-xs font-medium mb-2"></p>
<div className="flex gap-2 mb-2">
<div className="flex-1 bg-app-bg rounded-lg px-2.5 py-1.5 text-app-text-muted text-xs truncate font-mono">
{referralLink}
</div>
<Button
onClick={handleCopy}
size="sm"
variant="outline"
className="border-app-border text-app-text hover:bg-app-card bg-transparent text-xs h-7 px-2"
>
<Copy className="w-3 h-3 mr-1" />
{copied ? "已复制" : "复制"}
</Button>
</div>
<p className="text-app-text-muted text-xs">
: <span className="text-app-brand font-mono">{user.referralCode}</span>
</p>
</div>
{/* Share buttons - improved for WeChat/Soul */}
<div className="space-y-2 mb-3">
<Button
onClick={() => setShowPoster(true)}
className="w-full bg-indigo-600 hover:bg-indigo-700 text-white py-4 text-xs"
>
<ImageIcon className="w-4 h-4 mr-2" />
广
</Button>
<Button
onClick={handleShareToWechat}
className="w-full bg-green-600 hover:bg-green-700 text-white py-4 text-xs"
>
<MessageCircle className="w-4 h-4 mr-2" />
</Button>
<Button
onClick={handleShare}
variant="outline"
className="w-full border-app-border text-app-text hover:bg-app-card bg-transparent py-4 text-xs"
>
</Button>
</div>
<PosterModal
isOpen={showPoster}
onClose={() => setShowPoster(false)}
referralLink={referralLink}
referralCode={user.referralCode}
nickname={user.nickname}
/>
<WithdrawalModal
isOpen={showWithdrawal}
onClose={() => setShowWithdrawal(false)}
availableAmount={totalEarnings}
/>
{/* Recent earnings */}
{referralPurchases.length > 0 && (
<div className="bg-app-card/60 rounded-xl border border-app-border">
<div className="p-2.5 border-b border-app-border">
<p className="text-app-text text-xs font-medium"></p>
</div>
<div className="divide-y divide-app-border max-h-40 overflow-auto">
{referralPurchases.slice(0, 5).map((purchase) => (
<div key={purchase.id} className="p-2.5 flex items-center justify-between">
<div>
<p className="text-app-text text-xs">{purchase.type === "fullbook" ? "整本书" : "单节"}</p>
<p className="text-app-text-muted text-xs">
{new Date(purchase.createdAt).toLocaleDateString("zh-CN")}
</p>
</div>
<p className="text-app-brand text-sm font-semibold">
+¥{(purchase.referrerEarnings || 0).toFixed(2)}
</p>
</div>
))}
</div>
</div>
)}
</main>
</div>
)
}

View File

@@ -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>
)
}