게시물 등록 기능 추가
All checks were successful
Build And Test / build-and-push (push) Successful in 1m42s

This commit is contained in:
2025-05-25 01:12:01 +09:00
parent b94f6cea2e
commit add285da04
5 changed files with 224 additions and 22 deletions

View File

@ -0,0 +1,98 @@
// src/components/Board/PostForm.js
import React, { useState } from "react";
import { createPost } from "../../api/boardApi";
const PostForm = ({ boardSlug, onClose, onCreated }) => {
const [form, setForm] = useState({
title: "",
content: "",
tags: "",
});
const handleChange = (e) => {
setForm({ ...form, [e.target.name]: e.target.value });
};
const handleSubmit = async (e) => {
e.preventDefault();
if (!boardSlug) {
alert("⚠ 게시판이 선택되지 않았습니다.");
return;
}
const payload = {
title: form.title,
content: form.content,
tags: form.tags
.split(",")
.map((tag) => tag.trim())
.filter((tag) => tag !== ""),
};
console.log("✅ 요청 대상 boardSlug:", boardSlug);
console.log("✅ 전송할 payload:", payload);
try {
await createPost(boardSlug, payload);
alert("✅ 게시글이 등록되었습니다.");
setForm({ title: "", content: "", tags: "" });
onCreated();
onClose();
} catch (err) {
console.error("❌ 게시글 등록 실패", err);
console.log("🚨 서버 응답 내용:", err.response?.data);
alert("등록 실패: " + (err.response?.data?.detail || err.message));
}
};
return (
<div className="p-4 border rounded shadow bg-white">
<h2 className="text-lg font-bold mb-4">📝 게시글 작성</h2>
<form onSubmit={handleSubmit} className="space-y-2">
<input
type="text"
name="title"
placeholder="제목"
value={form.title}
onChange={handleChange}
className="w-full border px-2 py-1 rounded"
required
/>
<textarea
name="content"
placeholder="내용"
value={form.content}
onChange={handleChange}
className="w-full border px-2 py-1 rounded h-32"
required
/>
<input
type="text"
name="tags"
placeholder="태그 (쉼표로 구분)"
value={form.tags}
onChange={handleChange}
className="w-full border px-2 py-1 rounded"
/>
<div className="flex justify-end gap-2">
<button
type="button"
onClick={onClose}
className="px-4 py-1 bg-gray-300 rounded"
>
취소
</button>
<button
type="submit"
className="px-4 py-1 bg-blue-500 text-white rounded"
>
등록
</button>
</div>
</form>
</div>
);
};
export default PostForm;

View File

@ -0,0 +1,72 @@
// src/pages/BoardsPage.js
import React, { useState } from "react";
import BoardList from "../components/Board/BoardList";
import PostList from "../components/Board/PostList";
import PostSearchPanel from "../components/Board/PostSearchPanel";
import PostForm from "../components/Board/PostForm";
const BoardsPage = () => {
const [selectedBoard, setSelectedBoard] = useState(null);
const [search, setSearch] = useState("");
const [tag, setTag] = useState("");
const [showForm, setShowForm] = useState(false);
const [refreshKey, setRefreshKey] = useState(0); // 게시글 새로고침 트리거
const handleCreated = () => setRefreshKey(prev => prev + 1);
return (
<div className="grid grid-cols-3 gap-4 p-4">
{/* 좌측: 게시판 리스트 */}
<div>
<BoardList
selectedBoard={selectedBoard}
onSelectBoard={(slug) => {
setSelectedBoard(slug);
setSearch("");
setTag("");
}}
/>
</div>
{/* 중앙: 게시글 리스트 or 등록폼 */}
<div>
{selectedBoard && !showForm && (
<div className="mb-2">
<button
className="bg-green-500 text-white px-4 py-2 rounded"
onClick={() => setShowForm(true)}
>
게시글 등록
</button>
</div>
)}
{showForm ? (
<PostForm
boardSlug={selectedBoard}
onClose={() => setShowForm(false)}
onCreated={handleCreated}
/>
) : (
<PostList
boardSlug={selectedBoard}
search={search}
tag={tag}
key={refreshKey}
/>
)}
</div>
{/* 우측: 검색 + 태그 */}
<div>
<PostSearchPanel
boardSlug={selectedBoard}
onSearch={setSearch}
onTagSelect={setTag}
/>
</div>
</div>
);
};
export default BoardsPage;

View File

@ -3,39 +3,71 @@ import React, { useState } from "react";
import BoardList from "../components/Board/BoardList"; import BoardList from "../components/Board/BoardList";
import PostList from "../components/Board/PostList"; import PostList from "../components/Board/PostList";
import PostSearchPanel from "../components/Board/PostSearchPanel"; import PostSearchPanel from "../components/Board/PostSearchPanel";
import PostForm from "../components/Board/PostForm";
import { useAuth } from "../context/AuthContext"; // ✅ 추가
const BoardsPage = () => { const BoardsPage = () => {
const [selectedBoard, setSelectedBoard] = useState(null); const [selectedBoard, setSelectedBoard] = useState(null);
const [searchQuery, setSearchQuery] = useState(""); const [search, setSearch] = useState("");
const [selectedTag, setSelectedTag] = useState(""); const [tag, setTag] = useState("");
const [showForm, setShowForm] = useState(false);
const [refreshKey, setRefreshKey] = useState(0);
const { isLoggedIn } = useAuth(); // ✅ 로그인 여부 가져오기
const handleCreated = () => setRefreshKey((prev) => prev + 1);
return ( return (
<div className="grid grid-cols-12 gap-4 p-4"> <div className="flex gap-6 p-6 min-h-screen bg-gray-50">
{/* 좌측: 게시판 리스트 */} {/* 좌측: 게시판 목록 */}
<div className="col-span-2 bg-white p-4 shadow rounded"> <aside className="w-1/5 min-w-[180px] bg-white rounded shadow p-4 h-fit">
<BoardList <BoardList
onSelectBoard={setSelectedBoard}
selectedBoard={selectedBoard} selectedBoard={selectedBoard}
onSelectBoard={(slug) => {
setSelectedBoard(slug);
setSearch("");
setTag("");
setShowForm(false);
}}
/> />
</div> </aside>
{/* 중앙: 게시글 리스트 */} {/* 중앙: 게시글 리스트 또는 작성 폼 */}
<div className="col-span-7 bg-white p-4 shadow rounded"> <main className="flex-1 bg-white rounded shadow p-6">
<PostList {selectedBoard && !showForm && isLoggedIn && ( // ✅ 로그인 조건 추가
boardSlug={selectedBoard} <div className="mb-4 text-right">
search={searchQuery} <button
tag={selectedTag} className="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600"
/> onClick={() => setShowForm(true)}
</div> >
게시글 등록
</button>
</div>
)}
{/* 우측: 검색 + 태그 */} {showForm ? (
<div className="col-span-3 bg-white p-4 shadow rounded"> <PostForm
boardSlug={selectedBoard}
onClose={() => setShowForm(false)}
onCreated={handleCreated}
/>
) : (
<PostList
boardSlug={selectedBoard}
search={search}
tag={tag}
key={refreshKey}
/>
)}
</main>
{/* 우측: 검색 + 태그 필터 */}
<aside className="w-1/4 min-w-[200px] bg-white rounded shadow p-4 h-fit">
<PostSearchPanel <PostSearchPanel
boardSlug={selectedBoard} boardSlug={selectedBoard}
onSearch={setSearchQuery} onSearch={setSearch}
onTagSelect={setSelectedTag} onTagSelect={setTag}
/> />
</div> </aside>
</div> </div>
); );
}; };

View File

@ -1 +1 @@
0.0.16 0.0.17-rc1