diff --git a/src/api/prompt/prompt.js b/src/api/prompt/prompt.js
index be07cd1..2282ba5 100644
--- a/src/api/prompt/prompt.js
+++ b/src/api/prompt/prompt.js
@@ -2,6 +2,7 @@ import { sendRequest } from "../request";
import { aiChatInstance, blockInstance, promptInstance } from "../instance";
import {
activeBlocksState,
+ activeAiBlocksState,
// activeCategoryState,
availableCategoriesState,
blockDetailsState,
@@ -10,7 +11,7 @@ import {
categoryBlockShapesState,
activeCategoryState,
promptEvaluationState,
- promptEvaluationErrorState,
+ promptEvaluationErrorState, fetchAiBlocksState,
} from "../../recoil/prompt/promptRecoilState";
import { useRecoilState, useSetRecoilState } from "recoil";
@@ -19,12 +20,14 @@ export const usePromptHook = () => {
const [activeCategory, setActiveCategory] =
useRecoilState(activeCategoryState);
const setActiveBlocks = useSetRecoilState(activeBlocksState);
+ const setActiveAiBlocks = useSetRecoilState(activeAiBlocksState);
const setCombinations = useSetRecoilState(combinationsState);
const setCategoryColors = useSetRecoilState(categoryColorsState);
const setBlockDetails = useSetRecoilState(blockDetailsState);
const setCategoryBlockShapes = useSetRecoilState(categoryBlockShapesState);
const setEvaluation = useSetRecoilState(promptEvaluationState);
const setEvaluationError = useSetRecoilState(promptEvaluationErrorState);
+ const setFetchAiBlocksState = useSetRecoilState(fetchAiBlocksState);
// 새로운 함수: API 데이터로부터 프롬프트 구조 갱신
const updatePromptStructureFromApiData = (apiData) => {
if (
@@ -128,6 +131,106 @@ export const usePromptHook = () => {
await updatePromptStructureFromApiData(response.data);
};
+ const updateAiPromptStructureFromApiData = (apiData) => {
+ if (
+ !apiData.responseDto ||
+ !Array.isArray(apiData.responseDto.selectBlock)
+ ) {
+ console.error("Unexpected API response structure:", apiData);
+ return;
+ }
+
+ const blocks = apiData.responseDto.selectBlock;
+ blocks.forEach((block, index) => {
+ if (!block.blockValue) {
+ console.warn("Block missing blockValue:", block);
+ }
+ if (!block.blockId) {
+ block.blockId = 10000+index;
+ console.warn(`Generated blockId for block:`, block);
+ }
+ });
+
+ console.log("blocks: ", blocks);
+ // 카테고리 추출 및 중복 제거
+ const categories = [
+ ...new Set(blocks.map((block) => block.blockCategory)),
+ ];
+ console.log("categories: ", categories);
+
+ // 블록을 카테고리별로 그룹화
+ const groupedBlocks = categories.reduce((acc, category) => {
+ acc[category] = blocks.filter(
+ (block) => block.blockCategory === category,
+ );
+ return acc;
+ }, {});
+ console.log("groupedBlocks: ", groupedBlocks);
+
+ // 색상 생성 (간단한 예시, 실제로는 더 복잡한 로직이 필요할 수 있습니다)
+ const colors = categories.reduce((acc, category, index) => {
+ const predefinedColors = [
+ "var(--block-main-color)",
+ "var(--block-purple)",
+ "var(--block-pink)",
+ "var(--block-red)",
+ "var(--block-orange)",
+ "var(--block-green)",
+ "var(--block-blue)",
+ ];
+ acc[category] = predefinedColors[index % predefinedColors.length];
+ return acc;
+ }, {});
+ console.log("colors: ", colors);
+ // 블록 모양 정의
+ //const predefinedShapes = [1, 2, 3, 4, 5, 6, 7];
+
+ // 블록 모양 정의
+ // const shapes = categories.reduce((acc, category, index) => {
+ // acc[category] = predefinedShapes[index % predefinedShapes.length];
+ // return acc;
+ // }, {});
+ // 상태 업데이트
+ // 1. 카테고리 설정
+ //setAiAvailableCategories(categories);
+ // 2. 카테고리 중 첫번째로 active되게끔 설정
+ //TODO- 에러나면 무조건 여기임 -QA 이후 확인
+ // 2. activeCategory가 없거나 categories에 없는 경우에만 새로 설정
+ // if (!aiActiveCategory || !categories.includes(aiActiveCategory)) {
+ // setAiActiveCategory(categories[0] || null);
+ // }
+
+ // 3. 모든 카테고리들에 해당하는 블록들을 설정
+ const activeBlocksData = Object.fromEntries(
+ categories.map((category) => [
+ category,
+ (groupedBlocks[category] || []).map((block) => block.blockId),
+ ]),
+ );
+ console.log(activeBlocksData);
+ // 3.5 active된 block들을 setting해준다.
+ setActiveAiBlocks(activeBlocksData);
+
+ // 7. 블럭들의 detail들을 추가 할당한다.
+ setBlockDetails((prevBlockDetails) => {
+ const newBlocks = Object.fromEntries(blocks.map((block) => [block.blockId, block]));
+ return { ...prevBlockDetails, ...newBlocks };
+ });
+ };
+
+ const fetchAiBlocks = async (promptMethod, promptCategory) => {
+ const params = {
+ promptMethod: promptMethod,
+ promptCategory: promptCategory,
+ };
+
+ const response = await sendRequest(aiChatInstance, "get", `/recommend`, {
+ params,
+ });
+ await updateAiPromptStructureFromApiData(response.data);
+ setFetchAiBlocksState(true);
+ };
+
const makeBlock = async (
blockValue,
blockDescription,
@@ -187,11 +290,27 @@ export const usePromptHook = () => {
return response;
};
+ const userHistory = async (userHistory, promptMethod, promptCategory) => {
+ const response = await sendRequest(
+ promptInstance,
+ "post",
+ `/history`,
+ {
+ promptHistory: userHistory,
+ promptMethod: promptMethod,
+ promptCategory: promptCategory
+ }
+ );
+ return response;
+ }
+
return {
fetchBlocks,
makeBlock,
savePrompt,
deleteBlock,
evaluatePrompt,
+ fetchAiBlocks,
+ userHistory,
};
};
diff --git a/src/components/Chatting/components/ChattingMain.jsx b/src/components/Chatting/components/ChattingMain.jsx
index 31178df..a13a4f8 100644
--- a/src/components/Chatting/components/ChattingMain.jsx
+++ b/src/components/Chatting/components/ChattingMain.jsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from "react";
+import React, {useEffect, useState} from "react";
import { useNavigate } from "react-router-dom";
import { H1 } from "../../../styles/font-styles";
import styles from "./ChattingMain.module.css";
@@ -11,16 +11,22 @@ import { useSetRecoilState } from "recoil";
import { useChattingRoomHooks } from "../../../api/chatting/chatting";
import { setLocalPromptMethod } from "../../../util/localStorage";
import { t } from "i18next";
+import CreatePromptModal from "../../SideBar/components/Prompt/Modal/CreatePromptModal";
function ChattingMain() {
const navigate = useNavigate();
const setPromptMethod = useSetRecoilState(promptMethodState);
const { getChattingRoomList } = useChattingRoomHooks();
const userName = localStorage.getItem("userName");
+ const [isPromptModalOpen, setIsPromptModalOpen] = useState(false);
const handlePromptCreateClick = (type) => {
+ setIsPromptModalOpen(true);
setPromptMethod(type);
setLocalPromptMethod(type);
- navigate(`/promptMaking/`);
+ };
+
+ const closePromptModal = () => {
+ setIsPromptModalOpen(false);
};
useEffect(() => {
@@ -54,6 +60,10 @@ function ChattingMain() {
onClick={() => handlePromptCreateClick("Free")}
/>
+
);
}
diff --git a/src/components/PromptMaking/CombinationArea/SavePromptModal.jsx b/src/components/PromptMaking/CombinationArea/SavePromptModal.jsx
index c80fd2c..b2e1773 100644
--- a/src/components/PromptMaking/CombinationArea/SavePromptModal.jsx
+++ b/src/components/PromptMaking/CombinationArea/SavePromptModal.jsx
@@ -6,7 +6,7 @@ import ModalButton from "../../common/ModalButton";
import {
promptMethodState,
promptListState,
- blockDetailsState,
+ blockDetailsState, userHistoryState,
} from "../../../recoil/prompt/promptRecoilState";
import { useRecoilValue } from "recoil";
import RefinedPromptText from "../FinalPromptArea/RefinedPromptText";
@@ -14,6 +14,7 @@ import { usePromptHook } from "../../../api/prompt/prompt";
import { useChattingRoomHooks } from "../../../api/chatting/chatting";
import ModalContainer from "../../common/ModalContainer";
import { t } from "i18next";
+import {getLocalPromptCategory} from "../../../util/localStorage";
const allCategories = ["IT", "게임", "글쓰기", "건강", "교육", "예술", "기타"];
@@ -30,10 +31,12 @@ const SavePromptModal = ({
const prompt = promptList.find((p) => p.promptId === promptId);
const [promptTitle, setPromptTitle] = useState("");
const [promptDescription, setPromptDescription] = useState("");
- const [promptCategory, setPromptCategory] = useState("IT");
+ const localPromptCategory = getLocalPromptCategory();
+ const [promptCategory, setPromptCategory] = useState(localPromptCategory);
const promptMethod = useRecoilValue(promptMethodState);
+ const userHistoryValue = useRecoilValue(userHistoryState);
- const { savePrompt } = usePromptHook();
+ const { savePrompt, userHistory } = usePromptHook();
const { fetchPromptList, patchPromptBlock, patchPromptInfo } =
useChattingRoomHooks();
@@ -46,7 +49,7 @@ const SavePromptModal = ({
// Reset state if no prompt is found
setPromptTitle("");
setPromptDescription("");
- setPromptCategory("IT");
+ setPromptCategory(localPromptCategory);
}
}, [prompt]);
@@ -65,7 +68,7 @@ const SavePromptModal = ({
console.log("listPromptAtom:", listPromptAtom);
console.log("promptPreview", promptPreview);
patchPromptBlock(
- promptId,
+ promptId,
listPromptAtom,
promptPreview,
);
@@ -90,6 +93,18 @@ const SavePromptModal = ({
listPromptAtom,
);
+ userHistory(
+ userHistoryValue,
+ promptMethod,
+ promptCategory
+ );
+
+ console.log({
+ userHistoryValue,
+ promptMethod,
+ promptCategory
+ });
+
console.log({
promptTitle,
promptDescription,
@@ -155,7 +170,7 @@ const SavePromptModal = ({
{allCategories.map((category) => (
setPromptCategory(category)}
+ onClick={(e) => setPromptCategory(category)}
className={`${styles.option} ${
category === promptCategory
? styles.active
diff --git a/src/components/PromptMaking/PromptMakingSideBar/PromptMakingSideBar.jsx b/src/components/PromptMaking/PromptMakingSideBar/PromptMakingSideBar.jsx
index 00c7842..1138e73 100644
--- a/src/components/PromptMaking/PromptMakingSideBar/PromptMakingSideBar.jsx
+++ b/src/components/PromptMaking/PromptMakingSideBar/PromptMakingSideBar.jsx
@@ -1,44 +1,19 @@
-import React, { useEffect, useState } from "react";
-import { useRecoilState, useRecoilValue } from "recoil";
-import { Droppable, Draggable } from "react-beautiful-dnd";
+import React, {useEffect} from "react";
import styles from "./PromptMakingSidebar.module.css";
-import { H4, B5 } from "../../../styles/font-styles";
-import PromptValueBlock from "../../common/Prompt/PromptValueBlock";
-import {
- activeBlocksState,
- activeCategoryState,
- availableCategoriesState,
- categoryColorsState,
- blockDetailsState,
- categoryBlockShapesState,
-} from "../../../recoil/prompt/promptRecoilState";
+import { H4 } from "../../../styles/font-styles";
import logo from "../../../assets/logos/promaLogoSmall.svg";
-import CreateBlockModal from "./CreateBlockModal";
-import { usePromptHook } from "../../../api/prompt/prompt";
-import { getLocalPromptMethod } from "../../../util/localStorage";
-import { t } from "i18next";
import { Link } from "react-router-dom";
+import AiBlockSection from "./components/AiBlockSection";
+import BlockSection from "./components/BlockSection";
+import {useRecoilState, useSetRecoilState} from "recoil";
+import {userHistoryState} from "../../../recoil/prompt/promptRecoilState";
const PromptMakingSidebar = () => {
- const [activeCategory, setActiveCategory] =
- useRecoilState(activeCategoryState);
- const activeBlocks = useRecoilValue(activeBlocksState);
- const categories = useRecoilValue(availableCategoriesState);
- const categoryColors = useRecoilValue(categoryColorsState);
- const categoryBlockShapes = useRecoilValue(categoryBlockShapesState);
- const blockDetails = useRecoilValue(blockDetailsState);
- const [isModalOpen, setIsModalOpen] = useState(false);
- const localPromptMethod = getLocalPromptMethod();
- const { fetchBlocks } = usePromptHook();
-
- const getActiveColor = () => {
- return categoryColors[activeCategory] || "purple";
- };
+ const setUserHistory = useSetRecoilState(userHistoryState);
+ //userhistory 초기화
useEffect(() => {
- fetchBlocks(localPromptMethod);
- console.log("blocks 불러오기");
- // eslint-disable-next-line react-hooks/exhaustive-deps
+ setUserHistory({});
}, []);
return (
@@ -50,95 +25,19 @@ const PromptMakingSidebar = () => {
className={styles.promaLogo}
/>
+
PROMA prompt
-
- {categories.map((category) => (
-
setActiveCategory(category)}
- style={{
- "--category-color": categoryColors[category],
- "--category-active-color": `${categoryColors[category]}33`,
- }}
- >
- {category}
-
- ))}
-
-
-
- {(provided) => (
-
- {activeBlocks[activeCategory]?.map(
- (blockId, index) => {
- const block = blockDetails[blockId];
- return (
-
- {(provided) => (
-
- )}
-
- );
- },
- )}
- {provided.placeholder}
-
- )}
-
-
-
-
setIsModalOpen(false)}
- categories={categories}
- />
+
+
+
+
+
AI recommend
+
+
);
diff --git a/src/components/PromptMaking/PromptMakingSideBar/components/AiBlockSection.jsx b/src/components/PromptMaking/PromptMakingSideBar/components/AiBlockSection.jsx
new file mode 100644
index 0000000..7de7ef6
--- /dev/null
+++ b/src/components/PromptMaking/PromptMakingSideBar/components/AiBlockSection.jsx
@@ -0,0 +1,141 @@
+import React, {useEffect, useState} from 'react';
+import styles from "./AiBlockSection.module.css";
+import {B4, B5} from "../../../../styles/font-styles";
+import {Draggable, Droppable} from "react-beautiful-dnd";
+import PromptValueBlock from "../../../common/Prompt/PromptValueBlock";
+import {t} from "i18next";
+import {useRecoilState, useRecoilValue} from "recoil";
+import {
+ activeAiBlocksState, activeBlocksState, activeCategoryState, availableCategoriesState, blockDetailsState,
+ categoryBlockShapesState,
+ categoryColorsState, fetchAiBlocksState,
+} from "../../../../recoil/prompt/promptRecoilState";
+import {getLocalPromptCategory, getLocalPromptMethod} from "../../../../util/localStorage";
+import {usePromptHook} from "../../../../api/prompt/prompt";
+import promaAnimation from "../../../../assets/animation/promaAnimation.json";
+import Lottie from "react-lottie";
+
+function AiBlockSection() {
+ const categoryColors = useRecoilValue(categoryColorsState);
+ const categoryBlockShapes = useRecoilValue(categoryBlockShapesState);
+ const localPromptMethod = getLocalPromptMethod();
+ const localPromptCategory = getLocalPromptCategory();
+ const { fetchAiBlocks } = usePromptHook();
+ const [isLoading,setFetchAiBlocksState] = useRecoilState(fetchAiBlocksState);
+ const activeBlocksData = useRecoilValue(activeBlocksState);
+ const [activeCategory, setActiveCategory] = useRecoilState(activeCategoryState);
+ const activeBlocks = useRecoilValue(activeAiBlocksState);
+ const categories = useRecoilValue(availableCategoriesState);
+ const blockDetails = useRecoilValue(blockDetailsState);
+ const defaultOptions = {
+ loop: true,
+ autoplay: true,
+ animationData: promaAnimation,
+ rendererSettings: {
+ preserveAspectRatio: "xMidYMid slice",
+ },
+ };
+
+ const getActiveColor = () => {
+ return categoryColors[activeCategory] || "purple";
+ };
+
+ useEffect(() => {
+ setFetchAiBlocksState(false);
+ fetchAiBlocks(localPromptMethod, localPromptCategory);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ return (
+
+
+
+ {categories.map((category) => (
+
setActiveCategory(category)}
+ style={{
+ "--category-color": categoryColors[category],
+ "--category-active-color": `${categoryColors[category]}33`,
+ }}
+ >
+ {category}
+
+ ))}
+
+ {(isLoading) ?
+
+ {(provided) => (
+
+ {activeBlocks[activeCategory]?.map(
+ (blockId, index) => {
+ const block = blockDetails[blockId];
+ return (
+
+ {(provided) => (
+
+ )}
+
+ );
+ },
+ )}
+ {provided.placeholder}
+
+ )}
+
+
:
+
+
+ {t(`promptMaking.aiRecommend`)}
+
+
+
+ }
+
+
+ );
+}
+
+export default AiBlockSection;
diff --git a/src/components/PromptMaking/PromptMakingSideBar/components/AiBlockSection.module.css b/src/components/PromptMaking/PromptMakingSideBar/components/AiBlockSection.module.css
new file mode 100644
index 0000000..7103134
--- /dev/null
+++ b/src/components/PromptMaking/PromptMakingSideBar/components/AiBlockSection.module.css
@@ -0,0 +1,86 @@
+.sidebar {
+ display: flex;
+ width: 100%;
+ height: auto;
+ background-color: var(--white);
+ border-radius: 15px;
+ overflow: hidden;
+}
+
+.categories {
+ width: auto;
+ display: flex;
+ flex-direction: column;
+ padding: 25px 0;
+ background-color: var(--white);
+}
+
+.category {
+ padding: 15px 10px;
+ padding-right: 10px;
+ border-top-right-radius: 50px;
+ border-bottom-right-radius: 50px;
+ cursor: pointer;
+ text-orientation: upright;
+ word-break: break-word; /* 긴 단어를 줄바꿈 */
+ transition: all 0.3s;
+ font-size: 14px;
+ background-color: var(--category-color);
+ white-space: nowrap;
+ z-index: 10;
+}
+
+.category.active {
+ margin-right: -15px;
+ padding-right: 25px;
+ padding-left: 25px;
+}
+
+.blocksContainer {
+ flex-grow: 1;
+ display: flex;
+ flex-direction: column;
+ padding: 25px;
+ background-color: #fff;
+}
+
+.blocks {
+ overflow-y: auto;
+ display: flex;
+ flex-wrap: wrap;
+ align-items: flex-start;
+ gap: 10px;
+}
+
+.block {
+ cursor: move;
+ opacity: 0.9;
+ transition: opacity 0.3s;
+}
+
+.block:hover {
+ opacity: 1;
+}
+
+.addButton {
+ width: auto;
+ padding: 8px 30px;
+ background-color: var(--white);
+ border: none;
+ border-radius: 20px;
+ box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.2);
+ cursor: pointer;
+ margin: 10px;
+ align-self: center;
+}
+
+.addButton:hover {
+ opacity: 0.9;
+}
+
+.loadingSection {
+ flex-grow: 1;
+ display: flex;
+ flex-direction: column;
+ padding: 25px;
+}
diff --git a/src/components/PromptMaking/PromptMakingSideBar/components/BlockSection.jsx b/src/components/PromptMaking/PromptMakingSideBar/components/BlockSection.jsx
new file mode 100644
index 0000000..688f4fc
--- /dev/null
+++ b/src/components/PromptMaking/PromptMakingSideBar/components/BlockSection.jsx
@@ -0,0 +1,131 @@
+import React, {useEffect, useState} from 'react';
+import styles from "./BlockSection.module.css";
+import {B5} from "../../../../styles/font-styles";
+import {Draggable, Droppable} from "react-beautiful-dnd";
+import PromptValueBlock from "../../../common/Prompt/PromptValueBlock";
+import {t} from "i18next";
+import CreateBlockModal from "../CreateBlockModal";
+import {useRecoilState, useRecoilValue} from "recoil";
+import {
+ activeBlocksState, activeCategoryState, availableCategoriesState, blockDetailsState,
+ categoryBlockShapesState,
+ categoryColorsState,
+} from "../../../../recoil/prompt/promptRecoilState";
+import {getLocalPromptMethod} from "../../../../util/localStorage";
+import {usePromptHook} from "../../../../api/prompt/prompt";
+
+function BlockSection() {
+ const categoryColors = useRecoilValue(categoryColorsState);
+ const categoryBlockShapes = useRecoilValue(categoryBlockShapesState);
+ const [isModalOpen, setIsModalOpen] = useState(false);
+ const localPromptMethod = getLocalPromptMethod();
+ const { fetchBlocks } = usePromptHook();
+
+ const [activeCategory, setActiveCategory] = useRecoilState(activeCategoryState);
+ const activeBlocks = useRecoilValue(activeBlocksState);
+ const categories = useRecoilValue(availableCategoriesState);
+ const blockDetails = useRecoilValue(blockDetailsState);
+
+ const getActiveColor = () => {
+ return categoryColors[activeCategory] || "purple";
+ };
+
+ useEffect(() => {
+ fetchBlocks(localPromptMethod);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ return (
+
+
+
+ {categories.map((category) => (
+
setActiveCategory(category)}
+ style={{
+ "--category-color": categoryColors[category],
+ "--category-active-color": `${categoryColors[category]}33`,
+ }}
+ >
+ {category}
+
+ ))}
+
+
+
+ {(provided) => (
+
+ {activeBlocks[activeCategory]?.map(
+ (blockId, index) => {
+ const block = blockDetails[blockId];
+ return (
+
+ {(provided) => (
+
+ )}
+
+ );
+ },
+ )}
+ {provided.placeholder}
+
+ )}
+
+
+
+
+
setIsModalOpen(false)}
+ categories={categories}
+ />
+
+ );
+}
+
+export default BlockSection;
diff --git a/src/components/PromptMaking/PromptMakingSideBar/components/BlockSection.module.css b/src/components/PromptMaking/PromptMakingSideBar/components/BlockSection.module.css
new file mode 100644
index 0000000..ec6aa42
--- /dev/null
+++ b/src/components/PromptMaking/PromptMakingSideBar/components/BlockSection.module.css
@@ -0,0 +1,79 @@
+.sidebar {
+ display: flex;
+ width: 100%;
+ height: auto;
+ background-color: var(--white);
+ border-radius: 15px;
+ overflow: hidden;
+}
+
+.categories {
+ width: auto;
+ display: flex;
+ flex-direction: column;
+ padding: 25px 0;
+ background-color: var(--white);
+}
+
+.category {
+ padding: 15px 10px;
+ padding-right: 10px;
+ border-top-right-radius: 50px;
+ border-bottom-right-radius: 50px;
+ cursor: pointer;
+ text-orientation: upright;
+ word-break: break-word; /* 긴 단어를 줄바꿈 */
+ transition: all 0.3s;
+ font-size: 14px;
+ background-color: var(--category-color);
+ white-space: nowrap;
+ z-index: 10;
+}
+
+.category.active {
+ margin-right: -15px;
+ padding-right: 25px;
+ padding-left: 25px;
+}
+
+.blocksContainer {
+ flex-grow: 1;
+ display: flex;
+ flex-direction: column;
+ padding: 25px;
+ background-color: #fff;
+}
+
+.blocks {
+ overflow-y: auto;
+ display: flex;
+ flex-wrap: wrap;
+ align-items: flex-start;
+ gap: 10px;
+}
+
+.block {
+ cursor: move;
+ opacity: 0.9;
+ transition: opacity 0.3s;
+}
+
+.block:hover {
+ opacity: 1;
+}
+
+.addButton {
+ width: auto;
+ padding: 8px 30px;
+ background-color: var(--white);
+ border: none;
+ border-radius: 20px;
+ box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.2);
+ cursor: pointer;
+ margin: 10px;
+ align-self: center;
+}
+
+.addButton:hover {
+ opacity: 0.9;
+}
diff --git a/src/components/SideBar/components/Prompt/Modal/CreatePromptModal.jsx b/src/components/SideBar/components/Prompt/Modal/CreatePromptModal.jsx
index 8c0e05e..40e0d62 100644
--- a/src/components/SideBar/components/Prompt/Modal/CreatePromptModal.jsx
+++ b/src/components/SideBar/components/Prompt/Modal/CreatePromptModal.jsx
@@ -7,30 +7,33 @@ import characterIcon from "../../../../../assets/images/characterIcon.svg";
import taskIcon from "../../../../../assets/images/taskIcon.svg";
import freeIcon from "../../../../../assets/images/freeIcon.svg";
import { useNavigate } from "react-router-dom";
-import { useSetRecoilState } from "recoil";
+import {useRecoilState} from "recoil";
import { promptMethodState } from "../../../../../recoil/prompt/promptRecoilState";
-import { setLocalPromptMethod } from "../../../../../util/localStorage";
-import { H5 } from "../../../../../styles/font-styles";
+import {setLocalPromptCategory, setLocalPromptMethod} from "../../../../../util/localStorage";
+import {B5, H5} from "../../../../../styles/font-styles";
import { t } from "i18next";
function CreatePromptModal({ isOpen, onClose }) {
const navigate = useNavigate();
- const setPromptMethod = useSetRecoilState(promptMethodState);
- const [selectedMethod, setSelectedMethod] = useState(null);
+ const [promptMethod, setPromptMethod] = useRecoilState(promptMethodState);
+
+ const allCategories = ["IT", "게임", "글쓰기", "건강", "교육", "예술", "기타"];
+ const [promptCategory, setPromptCategory] = useState("IT");
+
if (!isOpen) return null;
const handleCreateClick = () => {
- if (selectedMethod) {
- setPromptMethod(selectedMethod);
- setLocalPromptMethod(selectedMethod);
+ if (promptMethod) {
+ setLocalPromptCategory(promptCategory);
+ setLocalPromptMethod(promptMethod);
navigate(`/promptMaking/`);
onClose();
}
};
const handleMethodClick = (method) => {
- setSelectedMethod(method);
+ setPromptMethod(method);
};
return (
@@ -46,23 +49,51 @@ function CreatePromptModal({ isOpen, onClose }) {
handleMethodClick("Character")}
/>
handleMethodClick("Task/Research")}
/>
handleMethodClick("Free")}
/>
+
+ 카테고리
+
+
+ {allCategories.map((category) => (
+ - setPromptCategory(category)}
+ className={`${styles.option} ${
+ category === promptCategory
+ ? styles.active
+ : styles.none
+ }`}
+ >
+
+ {category}
+
+
+ ))}
+
+
+
{
const [combinations, setCombinations] = useRecoilState(combinationsState);
const [activeBlocks, setActiveBlocks] = useRecoilState(activeBlocksState);
+ const [activeAiBlocks, setActiveAiBlocks] = useRecoilState(activeAiBlocksState);
+ const [userHistory, setUserHistoryState] = useRecoilState(userHistoryState);
const blockDetails = useRecoilValue(blockDetailsState);
const activeCategory = useRecoilValue(activeCategoryState);
const { deleteBlock } = usePromptHook();
+ // useEffect(() => {
+ // const newActiveBlocks = { ...activeBlocks };
+ // for (const category in newActiveBlocks) {
+ // newActiveBlocks[category] = newActiveBlocks[category]?.filter(
+ // (blockId) => combinations[category] !== blockId,
+ // );
+ // }
+ // setActiveBlocks(newActiveBlocks);
+ // // eslint-disable-next-line react-hooks/exhaustive-deps
+ // }, [combinations]);
+
useEffect(() => {
const newActiveBlocks = { ...activeBlocks };
+ const newActiveAiBlocks = { ...activeAiBlocks };
for (const category in newActiveBlocks) {
newActiveBlocks[category] = newActiveBlocks[category]?.filter(
(blockId) => combinations[category] !== blockId,
);
+ newActiveAiBlocks[category] = newActiveAiBlocks[category]?.filter(
+ (blockId) => combinations[category] !== blockId,
+ );
}
setActiveBlocks(newActiveBlocks);
+ setActiveAiBlocks(newActiveAiBlocks);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [combinations]);
@@ -42,30 +61,66 @@ export const usePromptMaking = () => {
return;
}
+ // if (destination.droppableId === "deleteArea") {
+ // console.log(draggableId);
+ // handleDeleteBlock(
+ // source.droppableId,
+ // numericBlockId,
+ // isBlockDefault,
+ // );
+ // } else if (
+ // source.droppableId === "sidebar" &&
+ // destination.droppableId !== "sidebar"
+ // ) {
+ // handleSidebarToCombinationArea(
+ // destination.droppableId,
+ // numericBlockId,
+ // blockCategory,
+ // );
+ // } else if (
+ // source.droppableId !== "sidebar" &&
+ // destination.droppableId === "sidebar"
+ // ) {
+ // handleCombinationAreaToSidebar(source.droppableId, numericBlockId);
+ // } else if (
+ // source.droppableId !== "sidebar" &&
+ // destination.droppableId !== "sidebar"
+ // ) {
+ // handleWithinCombinationArea(
+ // source.droppableId,
+ // destination.droppableId,
+ // numericBlockId,
+ // );
+ // }
+
if (destination.droppableId === "deleteArea") {
- console.log(draggableId);
handleDeleteBlock(
source.droppableId,
numericBlockId,
isBlockDefault,
);
} else if (
- source.droppableId === "sidebar" &&
- destination.droppableId !== "sidebar"
+ (source.droppableId === "sidebar" || source.droppableId === "sidebar_ai") &&
+ destination.droppableId !== "sidebar" &&
+ destination.droppableId !== "sidebar_ai"
) {
handleSidebarToCombinationArea(
destination.droppableId,
numericBlockId,
blockCategory,
+ source.droppableId,
);
} else if (
source.droppableId !== "sidebar" &&
- destination.droppableId === "sidebar"
+ source.droppableId !== "sidebar_ai" &&
+ (destination.droppableId === "sidebar" || destination.droppableId === "sidebar_ai")
) {
- handleCombinationAreaToSidebar(source.droppableId, numericBlockId);
+ handleCombinationAreaToSidebar(source.droppableId, numericBlockId, destination.droppableId);
} else if (
source.droppableId !== "sidebar" &&
- destination.droppableId !== "sidebar"
+ source.droppableId !== "sidebar_ai" &&
+ destination.droppableId !== "sidebar" &&
+ destination.droppableId !== "sidebar_ai"
) {
handleWithinCombinationArea(
source.droppableId,
@@ -75,10 +130,39 @@ export const usePromptMaking = () => {
}
};
+ // const handleSidebarToCombinationArea = (
+ // category,
+ // blockId,
+ // blockCategory,
+ // ) => {
+ // if (category !== blockCategory) {
+ // enqueueSnackbar(
+ // `${t(`promptMaking.userPromptError`)} ${blockCategory} ${t(`promptMaking.userPromptError2`)}`,
+ // );
+ // return;
+ // }
+ //
+ // setCombinations((prev) => ({
+ // ...prev,
+ // [category]: blockId,
+ // }));
+ //
+ // setActiveBlocks((prev) => ({
+ // ...prev,
+ // [category]: prev[category].filter((id) => id !== blockId),
+ // }));
+ //
+ // handleCombinationChange({
+ // ...combinations,
+ // [category]: blockId,
+ // });
+ // };
+
const handleSidebarToCombinationArea = (
category,
blockId,
blockCategory,
+ sourceDroppableId,
) => {
if (category !== blockCategory) {
enqueueSnackbar(
@@ -92,10 +176,26 @@ export const usePromptMaking = () => {
[category]: blockId,
}));
- setActiveBlocks((prev) => ({
- ...prev,
- [category]: prev[category].filter((id) => id !== blockId),
- }));
+ setUserHistoryState((prev) => {
+ const prevEntries = typeof prev === 'string' ? prev.split('\n') : [];
+ const nextNumber = prevEntries.length + 1;
+ const description = blockDetails[blockId]?.blockDescription || 'Description not found';
+ const newEntry = `${nextNumber}. ${category}에서 ${description}을 선택했습니다`;
+ return prevEntries.length > 0 ? `${prevEntries.join('\n')}\n${newEntry}` : newEntry;
+ });
+
+
+ if (sourceDroppableId === "sidebar") {
+ setActiveBlocks((prev) => ({
+ ...prev,
+ [category]: prev[category].filter((id) => id !== blockId),
+ }));
+ } else if (sourceDroppableId === "sidebar_ai") {
+ setActiveAiBlocks((prev) => ({
+ ...prev,
+ [category]: prev[category].filter((id) => id !== blockId),
+ }));
+ }
handleCombinationChange({
...combinations,
@@ -103,16 +203,35 @@ export const usePromptMaking = () => {
});
};
- const handleCombinationAreaToSidebar = (category, blockId) => {
+ // const handleCombinationAreaToSidebar = (category, blockId) => {
+ // setCombinations((prev) => ({
+ // ...prev,
+ // [category]: null,
+ // }));
+ //
+ // setActiveBlocks((prev) => ({
+ // ...prev,
+ // [category]: [...prev[category], blockId],
+ // }));
+ // };
+
+ const handleCombinationAreaToSidebar = (category, blockId, destinationDroppableId) => {
setCombinations((prev) => ({
...prev,
[category]: null,
}));
- setActiveBlocks((prev) => ({
- ...prev,
- [category]: [...prev[category], blockId],
- }));
+ if (destinationDroppableId === "sidebar") {
+ setActiveBlocks((prev) => ({
+ ...prev,
+ [category]: [...prev[category], blockId],
+ }));
+ } else if (destinationDroppableId === "sidebar_ai") {
+ setActiveAiBlocks((prev) => ({
+ ...prev,
+ [category]: [...prev[category], blockId],
+ }));
+ }
};
const handleWithinCombinationArea = (
@@ -134,11 +253,12 @@ export const usePromptMaking = () => {
const handleCombinationChange = (newCombinations) => {
console.log("새로운 조합:", newCombinations);
console.log("조합 시도");
+ console.log(userHistory);
// 여기에 조합 변경에 따른 추가 로직을 구현할 수 있습니다.
};
const handleDeleteBlock = (sourceCategory, blockId, isDefault) => {
- if (sourceCategory === "sidebar") {
+ if (sourceCategory === "sidebar" || sourceCategory === "sidebar_ai") {
if (isDefault === "true") {
// isDefault는 문자열로 전달될 수 있으므로 문자열 비교
console.log("Cannot delete default block");
diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json
index 40ae43a..2789a52 100644
--- a/src/locales/en/translation.json
+++ b/src/locales/en/translation.json
@@ -64,7 +64,8 @@
"userPromptError3": "🚀 The migration between category is impossible! You can't move to ",
"userPromptError4": "to",
"blockDeleteFailed": "⚠️ Default Block can't be deleted",
- "blockDeleted": "Block is completely deleted! "
+ "blockDeleted": "Block is completely deleted! ",
+ "aiRecommend" : "Ai is recommending blocks!"
},
"introduce": {
"introduceOne": "Prompt Engineering for Everyone",
diff --git a/src/locales/ko/translation.json b/src/locales/ko/translation.json
index e561877..5f55545 100644
--- a/src/locales/ko/translation.json
+++ b/src/locales/ko/translation.json
@@ -63,7 +63,8 @@
"userPromptError3": "🚀 카테고리 간 이동은 불가능합니다!",
"userPromptError4": "에서 다음 카테고리로 이동 불가능합니다 :",
"blockDeleteFailed": "⚠️ 디폴트 블록은 삭제가 불가능합니다.",
- "blockDeleted": "블록 삭제가 완료되었습니다!"
+ "blockDeleted": "블록 삭제가 완료되었습니다!",
+ "aiRecommend" : "Ai가 블록을 추천중입니다!"
},
"introduce": {
"introduceOne": "모두를 위한 프롬프트 엔지니어링",
diff --git a/src/recoil/prompt/promptRecoilState.js b/src/recoil/prompt/promptRecoilState.js
index 831e357..6097ec4 100644
--- a/src/recoil/prompt/promptRecoilState.js
+++ b/src/recoil/prompt/promptRecoilState.js
@@ -125,6 +125,16 @@ export const activeBlocksState = atom({
),
});
+export const activeAiBlocksState = atom({
+ key: "activeAiBlocksState",
+ default: Object.fromEntries(
+ Object.keys(initialBlocks).map((category) => [
+ category,
+ initialBlocks[category].map((block) => block.blockId),
+ ]),
+ ),
+});
+
// 선택된 조합
export const combinationsState = atom({
key: "combinationsState",
@@ -219,6 +229,18 @@ export const promptEvaluationErrorState = atom({
key: "promptEvaluationErrorState",
default: null,
});
+
+export const fetchAiBlocksState = atom({
+ key: "fetchAiBlocksState",
+ default: null,
+});
+
+export const userHistoryState = atom({
+ key: "userHistoryState",
+ default: "",
+});
+
+
// // 각종 상태 초기화 함수
// export const useResetCategoriesOnTypeChange = () => {
// return useRecoilCallback(({ snapshot, set }) => async () => {
diff --git a/src/util/localStorage.js b/src/util/localStorage.js
index 680c7fd..3e8110c 100644
--- a/src/util/localStorage.js
+++ b/src/util/localStorage.js
@@ -33,3 +33,12 @@ export const getIsFirstVisited = () => {
export const setIsFirstVisited = (isFirstVisit) => {
localStorage.setItem("hasVisited", isFirstVisit.toString());
};
+
+export const setLocalPromptCategory = (type) => {
+ localStorage.setItem("LocalPromptCategory", type);
+};
+
+export const getLocalPromptCategory = () => {
+ const LocalPromptCategory = localStorage.getItem("LocalPromptCategory");
+ return LocalPromptCategory;
+};