This commit is contained in:
98
src/components/Board/PostForm.js
Normal file
98
src/components/Board/PostForm.js
Normal 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;
|
72
src/pages/BoardsPage copy.js
Normal file
72
src/pages/BoardsPage copy.js
Normal 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;
|
@ -3,41 +3,73 @@ 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";
|
||||
import { useAuth } from "../context/AuthContext"; // ✅ 추가
|
||||
|
||||
const BoardsPage = () => {
|
||||
const [selectedBoard, setSelectedBoard] = useState(null);
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const [selectedTag, setSelectedTag] = useState("");
|
||||
const [search, setSearch] = 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 (
|
||||
<div className="grid grid-cols-12 gap-4 p-4">
|
||||
{/* 좌측: 게시판 리스트 */}
|
||||
<div className="col-span-2 bg-white p-4 shadow rounded">
|
||||
<div className="flex gap-6 p-6 min-h-screen bg-gray-50">
|
||||
{/* 좌측: 게시판 목록 */}
|
||||
<aside className="w-1/5 min-w-[180px] bg-white rounded shadow p-4 h-fit">
|
||||
<BoardList
|
||||
onSelectBoard={setSelectedBoard}
|
||||
selectedBoard={selectedBoard}
|
||||
onSelectBoard={(slug) => {
|
||||
setSelectedBoard(slug);
|
||||
setSearch("");
|
||||
setTag("");
|
||||
setShowForm(false);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
{/* 중앙: 게시글 리스트 */}
|
||||
<div className="col-span-7 bg-white p-4 shadow rounded">
|
||||
<PostList
|
||||
boardSlug={selectedBoard}
|
||||
search={searchQuery}
|
||||
tag={selectedTag}
|
||||
/>
|
||||
</div>
|
||||
{/* 중앙: 게시글 리스트 또는 작성 폼 */}
|
||||
<main className="flex-1 bg-white rounded shadow p-6">
|
||||
{selectedBoard && !showForm && isLoggedIn && ( // ✅ 로그인 조건 추가
|
||||
<div className="mb-4 text-right">
|
||||
<button
|
||||
className="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600"
|
||||
onClick={() => setShowForm(true)}
|
||||
>
|
||||
➕ 게시글 등록
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 우측: 검색 + 태그 */}
|
||||
<div className="col-span-3 bg-white p-4 shadow rounded">
|
||||
{showForm ? (
|
||||
<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
|
||||
boardSlug={selectedBoard}
|
||||
onSearch={setSearchQuery}
|
||||
onTagSelect={setSelectedTag}
|
||||
onSearch={setSearch}
|
||||
onTagSelect={setTag}
|
||||
/>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BoardsPage;
|
||||
export default BoardsPage;
|
||||
|
Reference in New Issue
Block a user