diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 2c96871..fc0c387 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,97 +5,12 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
+
+
@@ -109,6 +24,12 @@
+
{
@@ -139,7 +60,7 @@
"ModuleVcsDetector.initialDetectionPerformed": "true",
"RunOnceActivity.ShowReadmeOnStart": "true",
"RunOnceActivity.git.unshallow": "true",
- "git-widget-placeholder": "fillincode",
+ "git-widget-placeholder": "release-0.2",
"js.debugger.nextJs.config.created.client": "true",
"js.debugger.nextJs.config.created.server": "true",
"last_opened_file_path": "C:/Users/pkpk0/WebstormProjects/ddip/public/fonts",
@@ -160,11 +81,11 @@
+
-
@@ -199,7 +120,14 @@
-
+
+
+
+
+
+
+
+
@@ -211,7 +139,19 @@
diff --git a/jsconfig.json b/jsconfig.json
index e954206..1bcbd37 100644
--- a/jsconfig.json
+++ b/jsconfig.json
@@ -2,6 +2,7 @@
"compilerOptions": {
"baseUrl": "src",
"paths": {
+ "@/*": ["*"],
"@home/*": ["app/feature/home/*"],
"@constants/*": ["constants/*"],
"@auth/*": ["app/feature/auth/*"],
diff --git a/public/Write.png b/public/Write.png
new file mode 100644
index 0000000..3590643
Binary files /dev/null and b/public/Write.png differ
diff --git a/public/chat-back.svg b/public/chat-back.svg
new file mode 100644
index 0000000..9c3cdf0
--- /dev/null
+++ b/public/chat-back.svg
@@ -0,0 +1,3 @@
+
diff --git a/public/chat-send.svg b/public/chat-send.svg
new file mode 100644
index 0000000..7c06bc2
--- /dev/null
+++ b/public/chat-send.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/chat.png b/public/chat.png
new file mode 100644
index 0000000..859d21f
Binary files /dev/null and b/public/chat.png differ
diff --git a/src/app/api/route.js b/src/app/api/route.js
index 0f96f7d..233fca9 100644
--- a/src/app/api/route.js
+++ b/src/app/api/route.js
@@ -1,14 +1,24 @@
-import clientPromise from '@/lib/mongodb'
-import { NextResponse } from 'next/server'
+import clientPromise from '@/lib/mongodb';
export async function GET() {
try {
- const client = await clientPromise
- const db = client.db('ddip') // .env의 DB 이름과 동일하게
- const posts = await db.collection('posts').find({}).toArray()
- return NextResponse.json(posts)
+ const client = await clientPromise;
+ const db = client.db('ddip'); // ddip DB 선택
+ const collection = db.collection('object'); // object 컬렉션 선택
+ const data = await collection.find({}).toArray();
+
+ return new Response(JSON.stringify(data), {
+ status: 200,
+ headers: { 'Content-Type': 'application/json' },
+ });
} catch (error) {
- console.error(error)
- return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 })
+ console.error('MongoDB 조회 에러:', error);
+ return new Response(
+ JSON.stringify({ message: '서버 에러 발생' }),
+ {
+ status: 500,
+ headers: { 'Content-Type': 'application/json' },
+ }
+ );
}
}
diff --git a/src/app/components/chat/chat-component.js b/src/app/components/chat/chat-component.js
new file mode 100644
index 0000000..0f91bb3
--- /dev/null
+++ b/src/app/components/chat/chat-component.js
@@ -0,0 +1,23 @@
+import Image from "next/image";
+
+export default function ChatMessage({ chatId, name, lastUser, lastMessage, time, profileImg, onClick }) {
+ return (
+
+ {/* 프로필 이미지 */}
+
+
+
+
+ {/* 채팅 내용 */}
+
+
+
{lastUser}: {lastMessage}
+
+
+
+ );
+}
diff --git a/src/app/components/chat/chat-list.js b/src/app/components/chat/chat-list.js
new file mode 100644
index 0000000..ed8d6c3
--- /dev/null
+++ b/src/app/components/chat/chat-list.js
@@ -0,0 +1,62 @@
+import { useState } from "react";
+import ChatMessage from "./chat-component";
+import Chatting from "./chatting";
+
+export default function ChatList() {
+ const chatData = [
+ {
+ chatId: "1", //채팅에 고유번호를 부여해야하는 걸까요?
+ name: "고구마 한박스", //상품명
+ lastUser: '고구미',
+ lastMessage: "고구마 10개 사고 싶습니다!",
+ time: "13:45",
+ profileImg: "/none" //해당 상품 1번째 사진으로
+ },
+ {
+ chatId: "2",
+ name: "감자 10kg",
+ lastUser: '감자군',
+ lastMessage: "언제 만날까요?",
+ time: "12:20",
+ profileImg: "/none"
+ }
+ ];
+
+ const [selectedChat, setSelectedChat] = useState(null);
+
+ const handleCloseChat = () => {
+ setSelectedChat(null);
+ }
+
+ return (<>
+
+ {/* 상단 */}
+
+
+ {/* 채팅 목록 */}
+
+ {chatData.map(chat => (
+ setSelectedChat(chat)}
+ />
+ ))}
+
+
+
+ {/* 선택된 채팅창 모달 띄우기 */}
+ {selectedChat && (
+
+ )}
+ >
+ );
+}
diff --git a/src/app/components/chat/chatting.js b/src/app/components/chat/chatting.js
new file mode 100644
index 0000000..bd5b6b4
--- /dev/null
+++ b/src/app/components/chat/chatting.js
@@ -0,0 +1,117 @@
+// chatting.js
+import {useState, useEffect, useRef} from "react";
+import Image from "next/image";
+
+export default function Chatting({chatId, name, profileImg, onClose}) {
+ const [messages, setMessages] = useState([]);
+ const [input, setInput] = useState("");
+ const messagesEndRef = useRef(null); //스크롤 위치 제일 아래로
+
+ //리엑트에서 컴포넌트가 화면에 처음 나타나는 순간(컴포넌트 마운트)에 로컬스토리지에서 불러오기
+ useEffect(() => {
+ const stored = localStorage.getItem(`chatMessages-${chatId}`);
+ if (stored) setMessages(JSON.parse(stored));
+ }, [chatId]);
+
+ //메세지 보내기
+ const handleSend = () => {
+ if (input.trim() === "") return;
+
+ //본인 (보내는 사람) -> 로그인&회원가입에서 받은 정보를 바탕으로 수정
+ const newMessage = {
+ id: Date.now(),
+ text: input,
+ sender: "me",
+ name: "나", //별명
+ time: new Date().toLocaleTimeString([], {hour: "2-digit", minute: "2-digit"})
+ };
+
+ const updatedMessages = [...messages, newMessage];
+
+ //예시 메세지 (보낸 사람) -> 로그인&회원가입에서 받은 정보를 바탕으로 수정
+ const autoReply = {
+ id: Date.now() + 1,
+ text: "고구마 10개 사고 싶습니다!",
+ sender: "other", //상대 메세지
+ name: "고구미",
+ time: new Date().toLocaleTimeString([], {hour: "2-digit", minute: "2-digit"})
+ };
+
+ const finalMessages = [...messages, newMessage, autoReply];
+
+ setMessages(finalMessages);
+ localStorage.setItem(`chatMessages-${chatId}`, JSON.stringify(finalMessages));
+ setInput("");
+ };
+
+ //messages가 변경될 때마다 스크롤을 밑으로 이동
+ useEffect(() => {
+ if (messagesEndRef.current) {
+ messagesEndRef.current.scrollIntoView({behavior: "smooth"});
+ }
+ }, [messages]);
+
+
+ return (
+
+ {/* 상단 */}
+
+
+ {/* 채팅 부분 */}
+
+ {messages.map((msg) => (
+
+
+
+ {/* 이름 (상대방 메시지일 때만 표시) */}
+ {msg.sender !== "me" && (
+
+ {msg.name}
+
+ )}
+ {/* 말풍선 + 시간*/}
+
+ {/* 말풍선 */}
+
+ {msg.text}
+
+ {/* 시간 */}
+
+ {msg.time}
+
+
+
+
+ ))}
+ {/* 스크롤 제일 밑에 위치한 빈 div */}
+
+
+
+ {/* 입력 부분 */}
+
+ setInput(e.target.value)}
+ onKeyDown={(e) => e.key === "Enter" && handleSend()}
+ className="flex-1 px-2 text-sm focus:outline-none"
+ placeholder="메시지를 입력하세요."
+ />
+
+
+
+ );
+}
diff --git a/src/app/components/common/post.js b/src/app/components/common/post.js
new file mode 100644
index 0000000..31b1243
--- /dev/null
+++ b/src/app/components/common/post.js
@@ -0,0 +1,71 @@
+import { useState } from "react";
+import Image from "next/image";
+import category_lists from "@constants/simpleDB";
+
+export default function PostBox({ onClose }) {
+ const [activeTags, setActiveTags] = useState([]);
+
+ const handleClick = (value) => {
+ setActiveTags((prev) =>
+ prev.includes(value) ? prev.filter((v) => v !== value) : [...prev, value]
+ );
+ };
+
+ return (
+
+ {/* 상단 */}
+
+
+ {/* 제목 */}
+
+
+
+
+
+ {/* 이미지 첨부 */}
+
+
+ {/* 본문 입력 */}
+
+
+
+
+ {/* 카테고리 선택 */}
+
+
+
+
+
+ {category_lists.map((item) => {
+ const isActive = activeTags.includes(item.value);
+ return (
+
+ );
+ })}
+
+
+
+
+ );
+}
diff --git a/src/app/components/common/shortcut.js b/src/app/components/common/shortcut.js
new file mode 100644
index 0000000..5a39701
--- /dev/null
+++ b/src/app/components/common/shortcut.js
@@ -0,0 +1,36 @@
+import Image from 'next/image';
+import ChatList from '../chat/chat-list';
+import ChatBox from '../chat/chatting';
+import PostBox from './post';
+
+import {useEffect, useState} from "react";
+
+export default function Shortcut({}) {
+ const [isCOpen, setIsCOpen] = useState(false);
+ const [isPOpen, setIsPOpen] = useState(false);
+
+
+ const toggleChat = () => setIsCOpen(!isCOpen);
+ const togglePost = () => setIsPOpen(!isPOpen);
+
+ return (
+ <>
+
+ {isCOpen &&
}
+
+
+ {isPOpen &&
}
+ >
+ )
+}
\ No newline at end of file
diff --git a/src/app/feature/home/components/item-explain.js b/src/app/feature/home/components/item-explain.js
index 96edc25..975a478 100644
--- a/src/app/feature/home/components/item-explain.js
+++ b/src/app/feature/home/components/item-explain.js
@@ -1,47 +1,87 @@
-import Image from 'next/image'
-import ingredient_lists from '@constants/categoryDB';
-import category_lists from "@constants/simpleDB";
+import { useState, useEffect } from 'react';
+import Image from 'next/image';
-export default function ItemExplain({onSelect}) {
+export default function ItemExplain({ onSelect }) {
+ const [allData, setAllData] = useState([]);
+ const [productData, setProductData] = useState(null);
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState(null);
- const productData = ingredient_lists[onSelect];
+ useEffect(() => {
+ // 전체 데이터 불러오기
+ const fetchAll = async () => {
+ setLoading(true);
+ setError(null);
+ try {
+ const res = await fetch('/api');
+ if (!res.ok) throw new Error('데이터 불러오기 실패');
+ const data = await res.json();
+ setAllData(data);
+ } catch (err) {
+ setError(err.message);
+ } finally {
+ setLoading(false);
+ }
+ };
+ fetchAll();
+ }, []);
+
+ useEffect(() => {
+ if (!onSelect || allData.length === 0) {
+ setProductData(null);
+ return;
+ }
+ // id로 필터링
+ const found = allData.find(item => item._id === onSelect);
+ setProductData(found || null);
+ }, [onSelect, allData]);
+
+ if (loading) return
로딩중...
;
+ if (error) return
{error}
;
+ if (!productData) return
선택된 제품 정보를 찾을 수 없습니다.
;
return (
-
-
-
-
+
+
+
+
-
- 제품명:{productData.value || '이름 없음'}
+
+ 제품명: {productData.name || '이름 없음'}
-
- 상세설명:{productData.desc}
+
+ 상세설명: {productData.desc}
-
- DDIP:{productData.price}원 / {productData.team}명
+
+ DDIP: {productData.price}원 / {productData.max}명
-
+
현재인원
-
+
{Array.from({ length: productData.now }).map((_, idx) => (
-
+
))}
- {Array.from({ length: productData.team-productData.now }).map((_, idx) => (
+ {Array.from({ length: productData.max - productData.now }).map((_, idx) => (
))}
- )
-}
\ No newline at end of file
+ );
+}
diff --git a/src/app/feature/home/components/item-list.js b/src/app/feature/home/components/item-list.js
index 1c16b76..641c5d4 100644
--- a/src/app/feature/home/components/item-list.js
+++ b/src/app/feature/home/components/item-list.js
@@ -1,31 +1,66 @@
-import Image from 'next/image'
-import {useState} from "react";
-import ingredient_lists from '@constants/categoryDB';
+'use client';
+import Image from 'next/image';
+import { useState, useEffect } from 'react';
+import SimpleDB from "@constants/simpleDB";
-export default function ItemList({onSelect}) {
+export default function ItemList({ selectedCategoryValue, onSelect }) {
+ const [items, setItems] = useState([]);
const [activeIndex, setActiveIndex] = useState(null);
- const handleClick = (selected_index) => {
- setActiveIndex(selected_index);
- if (onSelect) onSelect(selected_index);
+
+ useEffect(() => {
+ const fetchData = async () => {
+ try {
+ const res = await fetch('/api'); // API 경로 수정
+ if (!res.ok) throw new Error('API 호출 실패');
+ const data = await res.json();
+ setItems(data);
+ } catch (error) {
+ console.error('데이터 불러오기 실패:', error);
+ }
+ };
+
+ fetchData();
+ }, []);
+
+ const handleClick = (id) => {
+ setActiveIndex(id);
+ if (onSelect) onSelect(id);
};
+
+ const filteredItems = selectedCategoryValue
+ ? items.filter(item => item.value === selectedCategoryValue)
+ : items;
+
return (
-
+
+
+ {
+ selectedCategoryValue
+ ? (SimpleDB.find(cat => cat.value === selectedCategoryValue)?.name || '알 수 없음')
+ : '전체 항목'
+ }
+
-
- {ingredient_lists.map(item => (
-