Files
chinese-family-tree-2/app/members/new/page.tsx
T
freedakgmail 86e889cc2a 0.3.1.2
2025-11-30 19:10:30 +08:00

250 lines
9.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client"
import { ChineseCard, ChineseCardContent, ChineseCardHeader, ChineseCardTitle } from "@/components/ui/chinese-card"
import { useRouter, useSearchParams } from "next/navigation"
import { useFamily } from "@/context/family-context"
import { SiteHeader } from "@/components/site-header"
import { MemberForm } from "@/components/members/member-form"
import { Button } from "@/components/ui/button"
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { UserPlus } from "lucide-react"
import type { FamilyMember } from "@/types/family"
import { useMemo, useEffect, useState } from "react"
import { useSession } from "next-auth/react"
import { BackButton } from "@/components/ui/back-button"
export default function NewMemberPage() {
const router = useRouter()
const searchParams = useSearchParams()
const { addMember, treeData, getMember } = useFamily()
const { data: session, status } = useSession()
const [activeTab, setActiveTab] = useState("info")
// 未登录时重定向到登录页
useEffect(() => {
if (status === 'unauthenticated') {
router.push('/auth/signin')
}
}, [status, router])
const existingMembers = Object.values(treeData.members)
const isFirstMember = existingMembers.length === 0
// 从URL参数获取预填信息
const initialData = useMemo(() => {
const fatherId = searchParams.get('fatherId')
const motherId = searchParams.get('motherId')
const spouseId = searchParams.get('spouseId')
const childId = searchParams.get('childId')
const generation = searchParams.get('generation')
const gender = searchParams.get('gender')
if (!fatherId && !motherId && !spouseId && !childId && !generation && !gender) return undefined
const data: Partial<FamilyMember> = {}
// 处理父母信息
if (fatherId) {
data.fatherId = fatherId
}
if (motherId) {
data.motherId = motherId
}
// 如果只有父亲没有母亲,尝试自动获取母亲(父亲的配偶)
if (fatherId && !motherId) {
const father = getMember(fatherId)
console.log('Looking for mother (father\'s spouse):', { fatherId, father, spouseIds: father?.spouseIds })
if (father?.spouseIds && father.spouseIds.length > 0) {
data.motherId = father.spouseIds[0]
console.log('Found mother:', data.motherId)
}
}
// 如果只有母亲没有父亲,尝试自动获取父亲(母亲的配偶)
if (motherId && !fatherId) {
const mother = getMember(motherId)
console.log('Looking for father (mother\'s spouse):', { motherId, mother, spouseIds: mother?.spouseIds })
if (mother?.spouseIds && mother.spouseIds.length > 0) {
data.fatherId = mother.spouseIds[0]
console.log('Found father:', data.fatherId)
}
}
// 处理配偶信息
if (spouseId) {
data.spouseIds = [spouseId]
}
// 处理子女信息
const childrenIds = searchParams.getAll('childrenIds')
if (childrenIds.length > 0) {
data.childrenIds = childrenIds
} else if (childId) {
data.childrenIds = [childId]
}
// 处理世代
if (generation) {
data.generation = parseInt(generation)
}
// 处理性别
if (gender) {
data.gender = gender.toUpperCase() as 'MALE' | 'FEMALE'
}
return data
}, [searchParams, getMember])
// 检测添加成员的类型
const memberType = useMemo(() => {
const fatherId = searchParams.get('fatherId')
const motherId = searchParams.get('motherId')
const spouseId = searchParams.get('spouseId')
const childId = searchParams.get('childId')
const childrenIds = searchParams.getAll('childrenIds')
if (isFirstMember) return '始祖'
if (fatherId || motherId) return '子女'
if (spouseId) return '配偶'
if (childId || childrenIds.length > 0) return '父母'
return '成员'
}, [searchParams, isFirstMember])
const handleSave = async (newMember: FamilyMember) => {
try {
// 如果是第一个成员,自动设置为始祖
const memberData = isFirstMember ? {
...newMember,
generation: 1,
isFounder: true,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
} : {
...newMember,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
}
await addMember(memberData)
// 跳转到成员列表页,保留treeId参数
const params = new URLSearchParams(window.location.search)
router.push(`/members?${params.toString()}`)
} catch (error) {
console.error('添加成员失败:', error)
alert('添加成员失败: ' + (error as Error).message)
}
}
return (
<div className="min-h-screen flex flex-col bg-background">
<SiteHeader />
<main className="container mx-auto py-8 px-4 md:px-6">
<Tabs value={activeTab} onValueChange={setActiveTab} className="flex flex-col h-[calc(100vh-8rem)]">
{/* 固定头部区域 */}
<div className="flex-shrink-0 pb-4 border-b border-border">
{/* 返回按钮 */}
<BackButton onClick={() => router.back()} />
{/* Header Section */}
<div className="flex flex-col md:flex-row justify-between items-start gap-6 pb-4">
<div className="flex items-start gap-6">
<div className={`h-24 w-24 rounded-lg bg-muted flex items-center justify-center border-2 ${isFirstMember ? 'border-amber-400 bg-amber-50/30' : 'border-primary/20'} overflow-hidden`}>
{isFirstMember ? (
<span className="text-4xl">👑</span>
) : (
<UserPlus className="h-16 w-16 text-muted-foreground" />
)}
</div>
<div>
<div className="flex items-center gap-3 mb-2">
<h1 className="text-3xl font-bold font-serif text-foreground flex items-center gap-2">
{isFirstMember && <span className="text-amber-600 text-2xl">👑</span>}
{isFirstMember ? '添加家族始祖' : `添加家族${memberType}`}
</h1>
{isFirstMember && (
<span className="px-3 py-1 bg-gradient-to-r from-amber-100 to-orange-100 text-amber-800 text-sm font-semibold rounded-full border-2 border-amber-300 shadow-sm">
· 1
</span>
)}
</div>
<p className="text-muted-foreground">
{isFirstMember
? '请认真填写始祖信息,这将是家族历史的起点'
: `填写${memberType}信息,完善家族树`}
</p>
</div>
</div>
<div className="flex gap-2 flex-wrap">
<Button type="button" variant="outline" onClick={() => router.back()}>
</Button>
<Button
type="button"
className="bg-primary text-primary-foreground hover:bg-primary/90"
onClick={() => {
const form = document.querySelector('form')
if (form) {
form.requestSubmit()
}
}}
>
</Button>
</div>
</div>
{/* Tab 导航栏 */}
<TabsList className="flex flex-wrap gap-2 bg-muted/70 p-1 w-fit">
<TabsTrigger value="info"></TabsTrigger>
<TabsTrigger value="details"></TabsTrigger>
<TabsTrigger value="photos"></TabsTrigger>
<TabsTrigger value="stories"></TabsTrigger>
</TabsList>
{/* 始祖特殊提示框 */}
{isFirstMember && (
<div className="mt-6 p-6 bg-gradient-to-br from-amber-50 via-orange-50 to-amber-50 border-2 border-amber-400 rounded-xl shadow-md">
<div className="flex items-start gap-4">
<div className="flex-shrink-0 w-14 h-14 bg-gradient-to-br from-amber-200 to-orange-200 rounded-full flex items-center justify-center shadow-sm">
<span className="text-3xl">👑</span>
</div>
<div className="flex-1">
<h2 className="text-2xl font-serif font-bold text-amber-900 mb-3">
</h2>
<p className="text-base text-amber-800 leading-relaxed font-serif">
<span className="font-bold text-amber-900"></span>
<span className="font-bold text-amber-900"></span>
<br />
</p>
</div>
</div>
</div>
)}
</div>
{/* Tab 内容区域 - 可滚动 */}
<div className="flex-1 overflow-y-auto">
<MemberForm
initialData={initialData}
existingMembers={existingMembers}
onSubmit={handleSave}
onCancel={() => router.back()}
isFounder={isFirstMember}
hideTabs={true}
activeTab={activeTab}
/>
</div>
</Tabs>
</main>
</div>
)
}