diff --git a/Frontend/src/pages/Community/CommunityListPage.jsx b/Frontend/src/pages/Community/CommunityListPage.jsx index 8ae0ee8..0199e80 100644 --- a/Frontend/src/pages/Community/CommunityListPage.jsx +++ b/Frontend/src/pages/Community/CommunityListPage.jsx @@ -1,3 +1,196 @@ +// import React, { useEffect, useState } from "react"; +// import { Link, useNavigate } from "react-router-dom"; + +// /** +// * localStorage keys +// */ +// const LS_POSTS = "community_posts_v1"; + + +// const SEED_POSTS = [ +// { +// id: "1", +// author: "zelsa", +// title: "SSAFY VS SKALA", +// content: "둘 다 붙으면 어디를 가는 게 좋을까요?\n의견 부탁드립니다!", +// createdAt: "2024-11-11", +// likeCount: 2, +// commentCount: 1, +// }, +// { +// id: "2", +// author: "zelsa", +// title: "SSAFY VS SKALA", +// content: "둘 다 붙으면 어디를 가는 게 좋을까요?\n(중복 테스트)", +// createdAt: "2024-11-11", +// likeCount: 2, +// commentCount: 1, +// }, +// { +// id: "3", +// author: "zelsa", +// title: "SSAFY VS SKALA", +// content: "둘 다 붙으면 어디를 가는 게 좋을까요?\n(리스트 UI 테스트)", +// createdAt: "2024-11-11", +// likeCount: 2, +// commentCount: 0, +// }, +// ]; + +// function loadPosts() { +// const raw = localStorage.getItem(LS_POSTS); +// if (!raw) { +// localStorage.setItem(LS_POSTS, JSON.stringify(SEED_POSTS)); +// return SEED_POSTS; +// } +// try { +// const parsed = JSON.parse(raw); +// return Array.isArray(parsed) ? parsed : []; +// } catch { +// return []; +// } +// } + +// function savePosts(posts) { +// localStorage.setItem(LS_POSTS, JSON.stringify(posts)); +// } + +// function formatDate(yyyyMmDd) { +// const [y, m, d] = yyyyMmDd.split("-").map(Number); +// const monthNames = [ +// "Jan.", "Feb.", "Mar.", "Apr.", "May.", "Jun.", +// "Jul.", "Aug.", "Sep.", "Oct.", "Nov.", "Dec." +// ]; +// if (!y || !m || !d) return yyyyMmDd; +// return `${monthNames[m - 1]}${d}.${y}`; +// } + +// export default function CommunityListPage() { +// const navigate = useNavigate(); +// const [posts, setPosts] = useState([]); +// const [q, setQ] = useState(""); + +// useEffect(() => { +// setPosts(loadPosts()); +// }, []); + +// const onLike = (postId) => { +// const next = posts.map((p) => +// String(p.id) === String(postId) +// ? { ...p, likeCount: (p.likeCount ?? 0) + 1 } +// : p +// ); +// setPosts(next); +// savePosts(next); +// }; + +// return ( +//
+//
+//
+// 커뮤니티 +//
+ +//
+ +// setQ(e.target.value)} +// /> + +// + +// +//
+ +// {/* 리스트 */} +//
+// {posts.length === 0 ? ( +//
+// 게시글이 없습니다. +//
+// ) : ( +// posts.map((post) => ( +//
+ +//
+// 👤 +// {post.author} +//
+ +// +// {post.title} +// + +// +// {post.content} +// + +//
+//
+// {formatDate(post.createdAt)} + +// + +// 댓글 {post.commentCount ?? 0} +//
+//
+ +//
+//
+// )) +// )} +//
+//
+//
+// ); +// } + + + import React, { useEffect, useState } from "react"; import { Link, useNavigate } from "react-router-dom"; @@ -70,19 +263,38 @@ export default function CommunityListPage() { const [posts, setPosts] = useState([]); const [q, setQ] = useState(""); + useEffect(() => { - setPosts(loadPosts()); - }, []); - - const onLike = (postId) => { - const next = posts.map((p) => - String(p.id) === String(postId) - ? { ...p, likeCount: (p.likeCount ?? 0) + 1 } - : p - ); - setPosts(next); - savePosts(next); - }; + (async () => { + try { + const res = await fetch("/api/posts"); // nginx가 backend로 프록시 + if (!res.ok) throw new Error(`HTTP ${res.status}`); + const data = await res.json(); + + // ✅ 서버 응답 형태에 맞게 매핑 (필드명은 실제 응답 보고 조정) + const mapped = (Array.isArray(data) ? data : data?.content ?? []).map((p) => ({ + id: String(p.id), + author: + typeof p.author === "string" + ? p.author + : (p.author?.nickname ?? p.user?.nickname ?? "unknown"), + title: p.title, + content: p.content, + createdAt: (p.createdAt ?? p.created_at ?? "").slice(0, 10), // "YYYY-MM-DD" + likeCount: p.likeCount ?? p.like_count ?? 0, + commentCount: p.commentCount ?? p.comment_count ?? 0, + })); + + setPosts(mapped); + } catch (e) { + console.error("Failed to load posts:", e); + // 서버 장애 시 임시 데이터 fallback 쓰고 싶으면 아래 주석 해제 + // setPosts(loadPosts()); + setPosts([]); + } + })(); +}, []); + return (
diff --git a/Frontend/vite.config.js b/Frontend/vite.config.js index f2c2dc5..3b738e8 100644 --- a/Frontend/vite.config.js +++ b/Frontend/vite.config.js @@ -1,9 +1,9 @@ import path from 'path'; -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; const __dirname = path.resolve(); -// https://vitejs.dev/config/ + export default defineConfig({ plugins: [react()], @@ -12,10 +12,7 @@ export default defineConfig({ { find: '@', replacement: path.resolve(__dirname, 'src') }, { find: '@api', replacement: path.resolve(__dirname, 'src/api') }, { find: '@assets', replacement: path.resolve(__dirname, 'src/assets') }, - { - find: '@components', - replacement: path.resolve(__dirname, 'src/components'), - }, + { find: '@components', replacement: path.resolve(__dirname, 'src/components') }, { find: '@layout', replacement: path.resolve(__dirname, 'src/layout') }, { find: '@pages', replacement: path.resolve(__dirname, 'src/pages') }, { find: '@router', replacement: path.resolve(__dirname, 'src/router') }, @@ -23,4 +20,14 @@ export default defineConfig({ { find: '@styles', replacement: path.resolve(__dirname, 'src/styles') }, ], }, -}) \ No newline at end of file + + /** 배포 서버로 쏨 */ + server: { + proxy: { + '/api': { + target: 'http://solvemeup.com', + changeOrigin: true, + }, + }, + }, +});