This commit is contained in:
freedakgmail
2025-11-24 16:07:24 +08:00
parent 3d075c6076
commit b25f4bea02
426 changed files with 3619 additions and 4468 deletions
+10 -13
View File
@@ -9,13 +9,13 @@ import { MemberForm } from "@/components/members/member-form"
import { Button } from "@/components/ui/button"
import { ArrowLeft, Edit, Trash, Share2, Printer, CircleUser, CircleUserRound, Images, BookOpen, UserPlus, Camera } from "lucide-react"
import type { FamilyMember } from "@/types/family"
import { db } from "@/lib/db"
import { PhotoGallery } from "@/components/members/photo-gallery"
import { StoryManager } from "@/components/members/story-manager"
import { useDialog } from "@/components/ui/alert-dialog-custom"
import { permissions } from "@/lib/permissions"
import { MemberNameWithStatus } from "@/components/member-name-with-status"
import { MemberVersionHistory } from "@/components/members/member-version-history"
import { useSession } from "next-auth/react"
export default function MemberProfilePage() {
const { id } = useParams()
@@ -23,9 +23,17 @@ export default function MemberProfilePage() {
const role = currentTree?.currentUserRole
const { showConfirm } = useDialog()
const router = useRouter()
const { data: session, status } = useSession()
const [isEditing, setIsEditing] = useState(false)
const [avatarBlobUrl, setAvatarBlobUrl] = useState<string | undefined>(undefined)
const [isUploadingAvatar, setIsUploadingAvatar] = useState(false)
// 未登录时重定向到登录页
useEffect(() => {
if (status === 'unauthenticated') {
router.push('/auth/signin')
}
}, [status, router])
const member = getMember(id as string)
const allMembers = Object.values(treeData.members)
@@ -54,23 +62,12 @@ export default function MemberProfilePage() {
// Load avatar
useEffect(() => {
// 优先使用 avatarUrl(服务器存储)
if (member?.avatarUrl) {
setAvatarBlobUrl(member.avatarUrl)
}
// 兼容旧的 IndexedDB 存储
else if (member?.avatarImageId) {
db.images.get(member.avatarImageId).then((image) => {
if (image) {
const url = URL.createObjectURL(image.blob)
setAvatarBlobUrl(url)
return () => URL.revokeObjectURL(url)
}
})
} else {
setAvatarBlobUrl(undefined)
}
}, [member?.avatarUrl, member?.avatarImageId])
}, [member?.avatarUrl])
// 显示加载状态
if (isLoading) {
+10 -1
View File
@@ -7,12 +7,21 @@ import { MemberForm } from "@/components/members/member-form"
import { Button } from "@/components/ui/button"
import { ArrowLeft } from "lucide-react"
import type { FamilyMember } from "@/types/family"
import { useMemo } from "react"
import { useMemo, useEffect } from "react"
import { useSession } from "next-auth/react"
export default function NewMemberPage() {
const router = useRouter()
const searchParams = useSearchParams()
const { addMember, treeData, getMember } = useFamily()
const { data: session, status } = useSession()
// 未登录时重定向到登录页
useEffect(() => {
if (status === 'unauthenticated') {
router.push('/auth/signin')
}
}, [status, router])
const existingMembers = Object.values(treeData.members)
const isFirstMember = existingMembers.length === 0
+17 -2
View File
@@ -7,7 +7,7 @@ import { useRouter } from "next/navigation"
import { Input } from "@/components/ui/input"
import { Button } from "@/components/ui/button"
import { Card, CardContent } from "@/components/ui/card"
import { Search, Plus, Filter, X } from "lucide-react"
import { Search, Plus, Filter, X, Users, User } from "lucide-react"
import Link from "next/link"
import { AvatarDisplay } from "@/components/ui/avatar-display"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
@@ -18,6 +18,8 @@ import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover
import type { FamilyMember } from "@/types/family"
import { permissions } from "@/lib/permissions"
import { MemberNameWithStatus } from "@/components/member-name-with-status"
import { useSession } from "next-auth/react"
import { EmptyStateBadge } from "@/components/empty-state-badge"
// 占位符类型
interface PlaceholderMember {
@@ -92,7 +94,7 @@ const MemberCard = memo(function MemberCard({
? 'bg-pink-50/50 dark:bg-pink-950/20 border-pink-200/50 dark:border-pink-800/30'
: 'bg-blue-50/50 dark:bg-blue-950/20 border-blue-200/50 dark:border-blue-800/30'
}`}>
<CardContent className="p-3 flex items-center gap-5">
<CardContent className="px-3 py-2 flex items-center gap-5">
<div className="relative flex-shrink-0">
<AvatarDisplay
imageUrl={member.avatarUrl}
@@ -198,10 +200,18 @@ const MemberCard = memo(function MemberCard({
export default function MembersPage() {
const { treeData, currentTree, searchMembers, setHighlightedMemberId } = useFamily()
const { data: session, status } = useSession()
const router = useRouter()
const [query, setQuery] = useState("")
const [showFilters, setShowFilters] = useState(false)
// 未登录时重定向到登录页
useEffect(() => {
if (status === 'unauthenticated') {
router.push('/auth/signin')
}
}, [status, router])
// 从 URL 参数读取搜索关键词
useEffect(() => {
const params = new URLSearchParams(window.location.search)
@@ -365,6 +375,11 @@ export default function MembersPage() {
(statusFilter !== "all" ? 1 : 0) +
(generationRange[0] > 1 || generationRange[1] < 100 ? 1 : 0)
// 未登录时不渲染内容(已在 useEffect 中重定向)
if (status === 'loading' || !session) {
return null
}
return (
<div className="min-h-screen bg-background flex flex-col font-sans">
<SiteHeader />