7.5 추천/신고, 조회수 카운트 o

This commit is contained in:
koreacomp5
2025-10-09 17:05:19 +09:00
parent 60d7972762
commit 6d37881dd7
7 changed files with 97 additions and 2 deletions

View File

@@ -2,6 +2,7 @@
import { useEffect, useState } from "react";
import { useParams, useRouter } from "next/navigation";
import { useToast } from "@/app/components/ui/ToastProvider";
import { UploadButton } from "@/app/components/UploadButton";
export default function EditPostPage() {
const params = useParams<{ id: string }>();
@@ -43,6 +44,7 @@ export default function EditPostPage() {
<h1> </h1>
<input placeholder="제목" value={form.title} onChange={(e) => setForm({ ...form, title: e.target.value })} />
<textarea placeholder="내용" value={form.content} onChange={(e) => setForm({ ...form, content: e.target.value })} rows={10} />
<UploadButton onUploaded={(url) => setForm((f) => (!f ? f : { ...f, content: `${f.content}\n![image](${url})` }))} />
<button disabled={loading} onClick={submit}>{loading ? "저장 중..." : "저장"}</button>
</div>
);

View File

@@ -1,12 +1,31 @@
import { notFound } from "next/navigation";
import { useToast } from "@/app/components/ui/ToastProvider";
import { useEffect } from "react";
export default async function PostDetail({ params }: { params: { id: string } }) {
const res = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL ?? ""}/api/posts/${params.id}`, { cache: "no-store" });
if (!res.ok) return notFound();
const { post } = await res.json();
return (
<ClientPostDetail post={post} />
);
}
function ClientPostDetail({ post }: { post: { id: string; title: string; content: string } }) {
// client only
// @ts-expect-error react client hook use
const { show } = useToast();
// @ts-expect-error react client hook use
useEffect(() => {
fetch(`/api/posts/${post.id}/view`, { method: "POST" });
}, [post.id]);
return (
<div>
<h1>{post.title}</h1>
<div style={{ display: "flex", gap: 8, margin: "8px 0" }}>
<button onClick={async () => { await fetch(`/api/posts/${post.id}/recommend`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ clientHash: "anon" }) }); show("추천했습니다"); }}></button>
<button onClick={async () => { const reason = prompt("신고 사유?") || ""; if(!reason) return; await fetch(`/api/posts/${post.id}/report`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ reason }) }); show("신고되었습니다"); }}></button>
</div>
<p style={{ whiteSpace: "pre-wrap" }}>{post.content}</p>
</div>
);

View File

@@ -2,6 +2,7 @@
import { useState } from "react";
import { useRouter } from "next/navigation";
import { useToast } from "@/app/components/ui/ToastProvider";
import { UploadButton } from "@/app/components/UploadButton";
export default function NewPostPage() {
const router = useRouter();
@@ -32,6 +33,7 @@ export default function NewPostPage() {
<input placeholder="boardId" value={form.boardId} onChange={(e) => setForm({ ...form, boardId: e.target.value })} />
<input placeholder="제목" value={form.title} onChange={(e) => setForm({ ...form, title: e.target.value })} />
<textarea placeholder="내용" value={form.content} onChange={(e) => setForm({ ...form, content: e.target.value })} rows={10} />
<UploadButton onUploaded={(url) => setForm((f) => ({ ...f, content: `${f.content}\n![image](${url})` }))} />
<button disabled={loading} onClick={submit}>{loading ? "저장 중..." : "등록"}</button>
</div>
);