feat(post): persist new posts and wire like interactions
This commit is contained in:
@@ -1,27 +1,24 @@
|
||||
import { ArrowLeft, Heart, MessageCircle, Pin, Star } from "lucide-react"
|
||||
import { ArrowLeft, MessageCircle, Pin, Star } from "lucide-react"
|
||||
import Image from "next/image"
|
||||
import Link from "next/link"
|
||||
import { notFound } from "next/navigation"
|
||||
import { PostComments } from "@/components/post-comments"
|
||||
import { PostLikeButton } from "@/components/post-like-button"
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Card, CardContent, CardHeader } from "@/components/ui/card"
|
||||
import { Separator } from "@/components/ui/separator"
|
||||
import { getOrderById, getPlayerById, getPostById, listCommentsByPost } from "@/lib/api"
|
||||
import { roleLabels } from "@/lib/constants"
|
||||
import { mockComments, mockOrders, mockPlayers, mockPosts } from "@/lib/mock"
|
||||
|
||||
export default async function PostDetailPage({ params }: { params: Promise<{ id: string }> }) {
|
||||
const { id } = await params
|
||||
const post = mockPosts.find((p) => p.id === id)
|
||||
const post = getPostById(id)
|
||||
if (!post) notFound()
|
||||
|
||||
const comments = mockComments.filter((c) => c.postId === id)
|
||||
const linkedOrder = post.linkedOrderId
|
||||
? mockOrders.find((o) => o.id === post.linkedOrderId)
|
||||
: null
|
||||
const linkedPlayer = linkedOrder
|
||||
? mockPlayers.find((player) => player.id === linkedOrder.playerId)
|
||||
: null
|
||||
const comments = listCommentsByPost(id)
|
||||
const linkedOrder = post.linkedOrderId ? getOrderById(post.linkedOrderId) : null
|
||||
const linkedPlayer = linkedOrder ? getPlayerById(linkedOrder.playerId) : null
|
||||
|
||||
return (
|
||||
<div className="container mx-auto py-8 px-4 max-w-2xl">
|
||||
@@ -94,13 +91,7 @@ export default async function PostDetailPage({ params }: { params: Promise<{ id:
|
||||
)}
|
||||
|
||||
<div className="flex items-center gap-4 text-sm text-muted-foreground pt-2">
|
||||
<button
|
||||
type="button"
|
||||
className="flex items-center gap-1 hover:text-foreground transition-colors"
|
||||
>
|
||||
<Heart className={`h-4 w-4 ${post.liked ? "fill-red-500 text-red-500" : ""}`} />
|
||||
{post.likeCount}
|
||||
</button>
|
||||
<PostLikeButton initialLiked={post.liked} initialCount={post.likeCount} />
|
||||
<span className="flex items-center gap-1">
|
||||
<MessageCircle className="h-4 w-4" />
|
||||
{post.commentCount}
|
||||
|
||||
@@ -20,10 +20,10 @@ import {
|
||||
SelectValue,
|
||||
} from "@/components/ui/select"
|
||||
import { Textarea } from "@/components/ui/textarea"
|
||||
import { mockPosts } from "@/lib/mock"
|
||||
import { useRequireAuth } from "@/lib/use-require-auth"
|
||||
import { useAuthStore } from "@/store/auth"
|
||||
import { useOrderStore } from "@/store/orders"
|
||||
import { usePostStore } from "@/store/posts"
|
||||
|
||||
const postSchema = z.object({
|
||||
title: z.string().min(2, "标题至少2个字符").max(50, "标题最多50个字符"),
|
||||
@@ -37,7 +37,10 @@ export default function NewPostPage() {
|
||||
const { isAuthenticated, requireAuth } = useRequireAuth()
|
||||
const currentRole = useAuthStore((state) => state.currentRole)
|
||||
const userId = useAuthStore((state) => state.user?.id)
|
||||
const user = useAuthStore((state) => state.user)
|
||||
const orders = useOrderStore((state) => state.orders)
|
||||
const posts = usePostStore((state) => state.posts)
|
||||
const createPost = usePostStore((state) => state.createPost)
|
||||
const [postType, setPostType] = useState("normal")
|
||||
const [selectedTags, setSelectedTags] = useState<string[]>([])
|
||||
const [imageCount, setImageCount] = useState(0)
|
||||
@@ -48,7 +51,7 @@ export default function NewPostPage() {
|
||||
register,
|
||||
handleSubmit,
|
||||
formState: { errors, isSubmitting },
|
||||
} = useForm({
|
||||
} = useForm<z.infer<typeof postSchema>>({
|
||||
resolver: standardSchemaResolver(postSchema),
|
||||
})
|
||||
|
||||
@@ -68,14 +71,28 @@ export default function NewPostPage() {
|
||||
(order) => order.status === "completed" && order.consumerId === userId,
|
||||
)
|
||||
|
||||
const onSubmit = async () => {
|
||||
const onSubmit = async (data: z.infer<typeof postSchema>) => {
|
||||
if (!isAuthenticated) {
|
||||
requireAuth(() => undefined)
|
||||
return
|
||||
}
|
||||
|
||||
await new Promise((r) => setTimeout(r, 500))
|
||||
router.push("/community")
|
||||
requireAuth(() => {
|
||||
if (!user) return
|
||||
|
||||
createPost({
|
||||
author: user,
|
||||
authorRole: currentRole,
|
||||
title: data.title,
|
||||
content: data.content,
|
||||
images: Array.from({ length: imageCount }).map(() => "/posts/p1-1.jpg"),
|
||||
tags: selectedTags,
|
||||
linkedOrderId: postType === "show_order" ? selectedOrderId : undefined,
|
||||
quotedPostId: postType === "quote" ? selectedQuotePostId : undefined,
|
||||
})
|
||||
|
||||
router.push("/community")
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -134,7 +151,7 @@ export default function NewPostPage() {
|
||||
<SelectValue placeholder="选择要引用的帖子" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{mockPosts.map((post) => (
|
||||
{posts.map((post) => (
|
||||
<SelectItem key={post.id} value={post.id}>
|
||||
{post.title}
|
||||
</SelectItem>
|
||||
@@ -145,7 +162,7 @@ export default function NewPostPage() {
|
||||
<p className="font-medium text-foreground">预览:</p>
|
||||
{selectedQuotePostId ? (
|
||||
(() => {
|
||||
const post = mockPosts.find((p) => p.id === selectedQuotePostId)
|
||||
const post = posts.find((p) => p.id === selectedQuotePostId)
|
||||
if (!post) return <p className="mt-1">未找到帖子</p>
|
||||
return (
|
||||
<div className="mt-2 rounded border bg-background p-3">
|
||||
|
||||
Reference in New Issue
Block a user