diff --git a/src/component/ImageDiary/Canvas.js b/src/component/ImageDiary/Canvas.js
index 9898a61..b706ac9 100644
--- a/src/component/ImageDiary/Canvas.js
+++ b/src/component/ImageDiary/Canvas.js
@@ -1,117 +1,216 @@
-import { IoTrashOutline } from "react-icons/io5";
-import { AiOutlineRollback } from "react-icons/ai";
-import { HiOutlinePaintBrush } from "react-icons/hi2";
-import { TfiEraser } from "react-icons/tfi";
-import { useEffect, useState } from "react";
-import { useDispatch, useSelector } from "react-redux";
-import { BRUSH_SIZE, SELECT_COLOR } from "../../redux/modules/ImageDiary";
-
-const Canvas = ({ isVisible, canvasRef }) => {
- const [getCtx, setGetCtx] = useState(null); //드로잉 영역
- const [painting, setPainting] = useState(false); //그리기 모드
- const [erasing, setErasing] = useState(false); //지우기 모드
- const [history, setHistory] = useState([]); //실행 취소
- const brushSize = useSelector((state) => state.ImageDiary.brushSize);
- const selectedColor = useSelector((state) => state.ImageDiary.selectedColor);
- const dispatch = useDispatch();
+import React, { useEffect, useRef, useState } from "react";
+import { imageState } from "../../recoil/keywordState";
+import { useRecoilState, useRecoilValue } from "recoil";
+import { brushSizeState, selectedColorState } from "../../recoil/canvasState";
+import {
+ BRUSH_MODE,
+ BrushButton,
+ ChangeBrushSizeRangeComp,
+ EraserButton,
+ SelectedColor,
+ TrashButton,
+ UnDoButton,
+} from "./DrawTools";
+import { INPUT_END, useDrawInputEvents } from "./useDrawInputEvents";
+
+export const CanvasList = ({ Keywords, canvasRefs, canvasBgRefs, index }) => {
+ return (
+
+ {Keywords.map((cur, i) => (
+
+ ))}
+
+ );
+};
+
+const Canvas = ({
+ isVisible,
+ canvasRef,
+ canvasBgRef,
+ canvasKeyword,
+ arrIdx,
+}) => {
+ const [screenInputMode, setScreenInputMode] = useState(INPUT_END); // 입력 모드
+ const [drawMode, setDrawMode] = useState(BRUSH_MODE); // 그리기 모드
+ const [history, setHistory] = useState([]);
+
//드로잉 영역 초기 세팅
- useEffect(() => {
- const canvas = canvasRef.current;
- const ctx = canvas.getContext("2d");
+ let { clearCanvas } = useInitializeCanvas({
+ canvasRef,
+ canvasBgRef,
+ canvasKeyword,
+ });
- ctx.lineJoin = "round"; //선이 꺽이는 부분의 스타일
- ctx.fillStyle = "white"; //캔버스 배경색
- ctx.fillRect(0, 0, canvas.width, canvas.height);
- ctx.lineWidth = 1; //선의 두께
- ctx.strokeStyle = "#000000"; //선의 색
-
- dispatch({ type: SELECT_COLOR, selectedColor: "#000000" });
- dispatch({ type: BRUSH_SIZE, brushSize: 1 });
- setGetCtx(ctx);
- clearCanvas();
- }, []);
+ const width = useGetScreenWidth();
+
+ return (
+
+
+
+ {/* 전체삭제, 뒤로가기, 브러쉬, 지우개 */}
+
+
+
+
+
+
+
+ {/* 브러쉬 크기 조정 */}
+
+
+ );
+};
+
+const DrawCanvas = ({
+ canvasRef,
+ screenInputMode,
+ setScreenInputMode,
+ setHistory,
+ drawMode,
+ width,
+ arrIdx,
+}) => {
+ const {
+ handleTouchStart,
+ handleTouchMove,
+ handleTouchEnd,
+ handleMouseDown,
+ handleMouseMove,
+ handleMouseUp,
+ } = useDrawInputEvents({
+ canvasRef,
+ drawMode,
+ screenInputMode,
+ setScreenInputMode,
+ setHistory,
+ });
+
+ return (
+
+ );
+};
+
+const BackGroundCanvas = ({ bgCanvasRef, width, canvasKeyword, arrIdx }) => {
+ const images = useRecoilValue(imageState);
- // 브러쉬 크기, 펜 색상 변경 시 호출됨
useEffect(() => {
- if (getCtx) {
- getCtx.lineWidth = brushSize;
- getCtx.strokeStyle = selectedColor;
+ const bgCtx = bgCanvasRef.current.getContext("2d");
+
+ const findAiImages = images.find((cur) => {
+ return cur.keyword === canvasKeyword;
+ });
+ if (findAiImages) {
+ console.log(findAiImages.bgOpacity);
+ bgCtx.globalAlpha = findAiImages.bgOpacity;
}
- }, [brushSize, selectedColor]);
-
- //그리기, 지우기 기능
- const drawFn = (x, y) => {
- if (!painting) {
- getCtx.beginPath();
- getCtx.moveTo(x, y);
- } else {
- if (erasing) {
- getCtx.clearRect(
- x - brushSize,
- y - brushSize,
- brushSize * 2,
- brushSize * 2
- );
- } else {
- getCtx.lineTo(x, y);
- getCtx.stroke();
+ }, [images]);
+
+ return (
+
+ );
+};
- //canvas 화면 전체 지우기
- const clearCanvas = () => {
- const canvas = canvasRef.current;
- const ctx = canvas.getContext("2d");
- ctx.clearRect(0, 0, canvas.width, canvas.height);
- };
+const useInitializeCanvas = ({ canvasRef, canvasBgRef, canvasKeyword }) => {
+ const [brushSize, _] = useRecoilState(brushSizeState); //브러쉬 크기
+ const [selectedColor, setSelectedColor] = useRecoilState(selectedColorState); //선택된 색상
+ const aiImages = useRecoilValue(imageState);
- // 캔버스 상태를 히스토리에 업데이트하는 함수
- const updateCanvasState = () => {
+ useEffect(() => {
+ //드로잉 영역 초기 세팅
const canvas = canvasRef.current;
+ const bgCanvas = canvasBgRef.current;
const ctx = canvas.getContext("2d");
- const currentState = ctx.getImageData(0, 0, canvas.width, canvas.height);
- setHistory((prevHistory) => [...prevHistory, currentState]);
- };
+ const bgCtx = canvasBgRef.current.getContext("2d");
- //실행 취소
- const unDo = () => {
- const canvas = canvasRef.current;
- const ctx = canvas.getContext("2d");
- if (history.length > 1) {
- history.pop(); // 현재 상태 제거
- const prevState = history[history.length - 1];
- ctx.putImageData(prevState, 0, 0);
- } else {
- history.pop();
- clearCanvas();
+ ctx.lineJoin = "round"; //선이 꺽이는 부분의 스타일
+ ctx.lineWidth = brushSize; //선의 두께
+ ctx.strokeStyle = selectedColor; //선의 색
+
+ setSelectedColor("#000000");
+
+ bgCtx.fillStyle = "white";
+ bgCtx.fillRect(0, 0, canvas.width, canvas.height);
+
+ // ai 가 제시한 image url 찾기
+ let findAiSuggest = aiImages.find((i) => i.keyword === canvasKeyword);
+
+ // 있다면 이미지를 배경에 그려줌
+ if (findAiSuggest) {
+ console.log(findAiSuggest);
+ const backgroundImage = new Image();
+ backgroundImage.crossOrigin = "anonymous";
+ backgroundImage.src =
+ findAiSuggest.imageUrl + `?v=${new Date().getTime()}`;
+ backgroundImage.onload = () => {
+ bgCtx.drawImage(backgroundImage, 0, 0, bgCanvas.width, bgCanvas.height);
+ canvasBgRef.current.globalAlpha = findAiSuggest.bgOpacity;
+ };
}
- };
+ }, []);
- // 터치 이벤트 핸들러 함수
- const handleTouchStart = (e) => {
- const touch = e.touches[0];
- const rect = canvasRef.current.getBoundingClientRect();
- const x = touch.clientX - rect.left + window.scrollX;
- const y = touch.clientY - rect.top + window.scrollY;
- setPainting(true);
- drawFn(x, y);
+ //canvas 화면 전체 지우기
+ const clearCanvas = () => {
+ const canvas = canvasRef.current;
+ const ctx = canvas.getContext("2d");
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
};
- const handleTouchMove = (e) => {
- const touch = e.touches[0];
- const rect = canvasRef.current.getBoundingClientRect();
- const x = touch.clientX - rect.left + window.scrollX;
- const y = touch.clientY - rect.top + window.scrollY;
- drawFn(x, y);
- };
+ return { clearCanvas };
+};
- const handleTouchEnd = () => {
- setPainting(false);
- updateCanvasState();
- };
+const useGetScreenWidth = () => {
// 캔버스 크기를 반응형으로 조절하기 위해 화면의 크기를 받아와서 조정
- const [width, setWidth] = useState();
+ const [width, setWidth] = useState(window.innerWidth);
const resizeListener = () => {
const size = window.innerWidth > 450 ? 450 : window.innerWidth;
setWidth(Math.ceil(size * 0.9));
@@ -123,110 +222,7 @@ const Canvas = ({ isVisible, canvasRef }) => {
return () => {
window.removeEventListener("resize", resizeListener);
};
- }, []);
- // 마우스 클릭 이벤트 핸들러 함수
- const handleMouseDown = (e) => {
- const rect = canvasRef.current.getBoundingClientRect();
- const x = e.clientX - rect.left + window.scrollX;
- const y = e.clientY - rect.top + window.scrollY;
- setPainting(true);
- drawFn(x, y);
- };
-
- const handleMouseMove = (e) => {
- if (painting) {
- const rect = canvasRef.current.getBoundingClientRect();
- const x = e.clientX - rect.left + window.scrollX;
- const y = e.clientY - rect.top + window.scrollY;
- drawFn(x, y);
- }
- };
-
- const handleMouseUp = () => {
- setPainting(false);
- updateCanvasState();
- };
+ }, [window.innerWidth]);
- //브러쉬 크기 변경
- const changeLineWidth = (event) => {
- console.log(brushSize);
- dispatch({ type: BRUSH_SIZE, brushSize: parseInt(event.target.value, 10) });
- };
-
- useEffect(() => {
- console.log("painting: ", painting, " erasing: ", erasing);
- }, [painting, erasing]);
-
- return (
-
-
- {/* 전체삭제, 뒤로가기, 브러쉬, 지우개 */}
-
-
-
-
-
{
- setErasing(false);
- }}
- color={erasing ? "black" : "red"}
- />
- setErasing(true)}
- color={erasing ? "red" : "black"}
- />
-
- {/* 브러쉬 크기 조정 */}
-
-
- 브러쉬 크기 {brushSize}
-
-
-
-
- );
+ return width;
};
-
-export default Canvas;
diff --git a/src/component/ImageDiary/Color.js b/src/component/ImageDiary/Color.js
index 97078bb..d0f4cff 100644
--- a/src/component/ImageDiary/Color.js
+++ b/src/component/ImageDiary/Color.js
@@ -1,11 +1,10 @@
import React from "react";
-import { connect, useDispatch } from "react-redux";
-import { SELECT_COLOR } from "../../redux/modules/ImageDiary";
+import { useSetRecoilState } from "recoil";
+import { selectedColorState } from "../../recoil/canvasState";
const Color = ({ color }) => {
- const dispatch = useDispatch();
- // const selectedcolor = useSelector((state) => state.ImageDiary.selectedColor);
const borderColor = color === "#FFFFFF" ? "1px solid black" : "none";
+ const setSelectedColor = useSetRecoilState(selectedColorState);
return (
{
backgroundColor: color,
border: borderColor,
}}
- onClick={() => dispatch({ type: SELECT_COLOR, selectedColor: color })}
+ onClick={() => setSelectedColor(color)}
>
);
};
diff --git a/src/component/ImageDiary/DrawTools.js b/src/component/ImageDiary/DrawTools.js
new file mode 100644
index 0000000..38bacf2
--- /dev/null
+++ b/src/component/ImageDiary/DrawTools.js
@@ -0,0 +1,103 @@
+import { IoTrashOutline } from "react-icons/io5";
+import { AiOutlineRollback } from "react-icons/ai";
+import { HiOutlinePaintBrush } from "react-icons/hi2";
+import { TfiEraser } from "react-icons/tfi";
+import React, { useEffect } from "react";
+import { useRecoilState } from "recoil";
+import { brushSizeState, selectedColorState } from "../../recoil/canvasState";
+
+export const BRUSH_MODE = "brush";
+export const ERASER_MODE = "eraser";
+
+export const TrashButton = ({ clearCanvas }) => {
+ return (
+
+ );
+};
+
+export const UnDoButton = ({ canvasRef, history, clearCanvas }) => {
+ //실행 취소
+ const unDo = () => {
+ const canvas = canvasRef.current;
+ const ctx = canvas.getContext("2d");
+
+ history.pop(); // 현재 상태 제거
+
+ if (history.length > 1) {
+ const prevState = history[history.length - 1];
+ ctx.putImageData(prevState, 0, 0);
+ return;
+ }
+
+ clearCanvas();
+ };
+
+ return
;
+};
+
+export const SelectedColor = () => {
+ const [selectedColor, _] = useRecoilState(selectedColorState); //선택된 색상
+ return (
+
+ );
+};
+
+export const BrushButton = ({ drawMode, setDrawMode }) => {
+ return (
+
setDrawMode(BRUSH_MODE)}
+ color={drawMode === BRUSH_MODE ? "red" : "black"}
+ />
+ );
+};
+
+export const EraserButton = ({ drawMode, setDrawMode }) => {
+ return (
+ setDrawMode(ERASER_MODE)}
+ color={drawMode === ERASER_MODE ? "red" : "black"}
+ />
+ );
+};
+
+export const ChangeBrushSizeRangeComp = () => {
+ const [brushSize, setBrushSize] = useRecoilState(brushSizeState); //브러쉬 크기
+ useEffect(() => {
+ setBrushSize(brushSize);
+ }, []);
+
+ const changeLineWidth = (event) => {
+ setBrushSize(parseInt(event.target.value));
+ };
+
+ return (
+
+
+ 브러쉬 크기 {brushSize}
+
+
+
+ );
+};
diff --git a/src/component/ImageDiary/Palette.js b/src/component/ImageDiary/Palette.js
index 754eb56..7550654 100644
--- a/src/component/ImageDiary/Palette.js
+++ b/src/component/ImageDiary/Palette.js
@@ -16,11 +16,16 @@ const Palette = ({}) => {
"#E500FF",
];
return (
-
- {colors.map((item, idx) => (
-
- ))}
-
+ <>
+
+ 옆으로 넘겨서 더 많은 색상을 볼 수 있어요!
+
+
+ {colors.map((item, idx) => (
+
+ ))}
+
+ >
);
};
diff --git a/src/component/ImageDiary/useDrawInputEvents.js b/src/component/ImageDiary/useDrawInputEvents.js
new file mode 100644
index 0000000..100743e
--- /dev/null
+++ b/src/component/ImageDiary/useDrawInputEvents.js
@@ -0,0 +1,117 @@
+import { BRUSH_MODE, ERASER_MODE } from "./DrawTools";
+import { useRecoilState } from "recoil";
+import { brushSizeState, selectedColorState } from "../../recoil/canvasState";
+import { useEffect, useState } from "react";
+
+export const INPUT_START = "start";
+export const INPUT_MOVE = "move";
+export const INPUT_END = "end";
+
+export const useDrawInputEvents = ({
+ canvasRef,
+ screenInputMode,
+ drawMode,
+ setScreenInputMode,
+ setHistory,
+}) => {
+ const [brushSize, _] = useRecoilState(brushSizeState); //브러쉬 크기
+ const [selectedColor, __] = useRecoilState(selectedColorState); //선택된 색상
+
+ //브러쉬 크기, 펜 색상 변경 시 호출됨
+ useEffect(() => {
+ let canvas = canvasRef.current;
+ let ctx = canvas.getContext("2d");
+ ctx.lineWidth = brushSize;
+ ctx.strokeStyle = selectedColor;
+ }, [brushSize, selectedColor]);
+
+ const drawFn = (x, y) => {
+ let canvas = canvasRef.current;
+ let ctx = canvas.getContext("2d");
+ // 그리기전이라면 그리기 시작
+ if (screenInputMode === INPUT_END) {
+ ctx.beginPath();
+ ctx.moveTo(x, y);
+ return;
+ }
+
+ // 그리기 모드에 따라 그리기 또는 지우기
+ if (drawMode === ERASER_MODE) {
+ ctx.clearRect(x - brushSize, y - brushSize, brushSize * 2, brushSize * 2);
+ }
+
+ if (drawMode === BRUSH_MODE) {
+ ctx.lineTo(x, y);
+ ctx.stroke();
+ }
+ };
+
+ // 캔버스 상태를 히스토리에 업데이트하는 함수
+ const updateCanvasState = () => {
+ let canvas = canvasRef.current;
+ let ctx = canvas.getContext("2d");
+ const currentState = ctx.getImageData(0, 0, canvas.width, canvas.height);
+ setHistory((prevHistory) => [...prevHistory, currentState]);
+ };
+
+ // 터치 이벤트 핸들러 함수
+ const handleTouchStart = (e) => {
+ let canvas = canvasRef.current;
+ let rect = canvas.getBoundingClientRect();
+ const touch = e.touches[0];
+ const x = touch.clientX - rect.left + window.scrollX;
+ const y = touch.clientY - rect.top + window.scrollY;
+ setScreenInputMode(INPUT_START);
+ drawFn(x, y);
+ };
+
+ const handleTouchMove = (e) => {
+ let canvas = canvasRef.current;
+ let rect = canvas.getBoundingClientRect();
+ const touch = e.touches[0];
+ const x = touch.clientX - rect.left + window.scrollX;
+ const y = touch.clientY - rect.top + window.scrollY;
+ setScreenInputMode(INPUT_MOVE);
+ drawFn(x, y);
+ };
+
+ const handleTouchEnd = () => {
+ setScreenInputMode(INPUT_END);
+ updateCanvasState();
+ };
+
+ // 마우스 클릭 이벤트 핸들러 함수
+ const handleMouseDown = (e) => {
+ let canvas = canvasRef.current;
+ let rect = canvas.getBoundingClientRect();
+ const x = e.clientX - rect.left + window.scrollX;
+ const y = e.clientY - rect.top + window.scrollY;
+ setScreenInputMode(INPUT_START);
+ drawFn(x, y);
+ };
+
+ const handleMouseMove = (e) => {
+ if (screenInputMode === INPUT_END) return;
+
+ let canvas = canvasRef.current;
+ let rect = canvas.getBoundingClientRect();
+ const x = e.clientX - rect.left + window.scrollX;
+ const y = e.clientY - rect.top + window.scrollY;
+ setScreenInputMode(INPUT_MOVE);
+ drawFn(x, y);
+ };
+
+ const handleMouseUp = () => {
+ setScreenInputMode(INPUT_END);
+ updateCanvasState();
+ };
+
+ return {
+ handleTouchStart,
+ handleTouchMove,
+ handleTouchEnd,
+ handleMouseDown,
+ handleMouseMove,
+ handleMouseUp,
+ };
+};
diff --git a/src/component/MyPageList.js b/src/component/MyPageItem.js
similarity index 75%
rename from src/component/MyPageList.js
rename to src/component/MyPageItem.js
index fcd2e20..dbe65ab 100644
--- a/src/component/MyPageList.js
+++ b/src/component/MyPageItem.js
@@ -1,4 +1,4 @@
-const MyPageList = ({ src, text, onClick }) => {
+const MyPageItem = ({ src, text, onClick }) => {
return (
{
);
};
-export default MyPageList;
+export default MyPageItem;
diff --git a/src/index.js b/src/index.js
index f542046..95f9d43 100644
--- a/src/index.js
+++ b/src/index.js
@@ -5,9 +5,9 @@ import "./index.css";
import store from "./redux/config/configStore";
import { Provider } from "react-redux";
import { BrowserRouter } from "react-router-dom";
+import { RecoilRoot } from "recoil";
const root = ReactDOM.createRoot(document.getElementById("root"));
-
const render = () => {
const state = store.getState();
const fontSize = state.fontSize;
@@ -15,11 +15,13 @@ const render = () => {
document.documentElement.style.fontSize = fontSize;
root.render(
-
-
-
-
-
+
+
+
+
+
+
+
);
};
diff --git a/src/pages/Calendar/Calendar.js b/src/pages/Calendar/Calendar.js
index d6475e1..72092c5 100644
--- a/src/pages/Calendar/Calendar.js
+++ b/src/pages/Calendar/Calendar.js
@@ -13,11 +13,13 @@ import {
import { CHANGE_DIARY } from "../../redux/modules/DiaryInfo.js";
import DiaryController from "../../api/diary.controller.js";
import { SET_PAGENAME } from "../../redux/modules/PageName.js";
+import diaryController from "../../api/diary.controller.js";
const Calendar = () => {
const location = useLocation();
const dispatch = useDispatch();
const [isOpen, setIsOpen] = useState(false);
+ const [mark, setMark] = useState([]);
useEffect(() => {
// 페이지 이름 설정
@@ -42,6 +44,7 @@ const Calendar = () => {
day: currentDate.getDate(),
});
}
+ checkDiaryList();
}, [location.state, dispatch]);
const navigate = useNavigate();
@@ -68,6 +71,25 @@ const Calendar = () => {
);
};
+ //일기 유무 리스트 가져오기
+ const checkDiaryList = async () => {
+ try {
+ const response = await diaryController.checkDiaryList({
+ userId,
+ year: reduxYear,
+ month: reduxMonth,
+ });
+ const { result } = response.data;
+ const currentMonthData = result[`${reduxYear}-${reduxMonth}`];
+ const filteredDates = Object.keys(currentMonthData).filter(
+ (date) => currentMonthData[date].isExist
+ );
+ setMark(filteredDates);
+ } catch (error) {
+ console.error("일기 유무 리스트 가져오기 중 오류", error);
+ setMark([]);
+ }
+ };
//선택한 날의 일기 가져오기
const getDiary = async () => {
setIsGetDiaryComplete(false);
@@ -89,7 +111,6 @@ const Calendar = () => {
userId: userId,
date: dateFormat(),
});
- console.log(res.data);
//일기가 존재하지 않음
if (res.data.result.length == 0) {
@@ -105,8 +126,9 @@ const Calendar = () => {
type: CHANGE_DIARY,
diaryId: diaryInfo.diaryId,
content: diaryInfo.content,
- imgUrl: diaryInfo.imgUrl,
date: diaryInfo.createDate,
+ keywords: diaryInfo.keywords,
+ imgUrl: diaryInfo.imgUrl,
});
setIsDiaryExist(true);
} catch (error) {
@@ -116,6 +138,10 @@ const Calendar = () => {
setIsGetDiaryComplete(true);
};
+ useEffect(() => {
+ // 첫 렌더링 시와 연도, 달이 변경될 때마다 일기 유무 리스트를 가져옵니다.
+ checkDiaryList();
+ }, [reduxYear, reduxMonth]);
useEffect(() => {
// 일기 데이터 가져오기
getDiary();
@@ -124,11 +150,13 @@ const Calendar = () => {
// 이전 달로 이동
const prevMonth = () => {
dispatch({ type: CHANGE_MONTH, number: -1 });
+ setMark([]);
};
// 다음 달로 이동
const nextMonth = () => {
dispatch({ type: CHANGE_MONTH, number: 1 });
+ setMark([]);
};
// 현재 달의 첫째 날의 요일을 반환합니다. (0: 일요일, 1: 월요일, ...)
@@ -176,34 +204,36 @@ const Calendar = () => {
days.forEach((selectDay, index) => {
const isSelected = selectDay !== "" && reduxDay === selectDay;
+ // 현재 선택한 날짜의 날짜 문자열을 생성합니다.
+ const dateStr = `${selectDay.toString()}`;
+
+ // mark 배열에 포함된 숫자들과 일치하는지 확인합니다.
+ const isDiaryExistForDay = mark.includes(dateStr);
+
+ let cellClassNames = "";
if (index % 7 !== 0) {
- cells.push(
- handleDateClick(selectDay)}
- >
- {selectDay}
- |
- );
+ cellClassNames = `${selectDay === "" ? "empty" : ""} ${isSelected ? "selected" : ""}`;
} else {
rows.push(cells);
cells = [];
- cells.push(
- handleDateClick(selectDay)}
- >
- {selectDay}
- |
- );
+ cellClassNames = `${selectDay === "" ? "empty" : ""} ${isSelected ? "selected" : ""}`;
}
+ cells.push(
+ handleDateClick(selectDay)}
+ >
+ {selectDay}
+ {isDiaryExistForDay && (
+
+ )}
+ |
+ );
+
if (index === days.length - 1) {
rows.push(cells);
}
diff --git a/src/pages/Calendar/Diary.js b/src/pages/Calendar/Diary.js
index f8aa22f..4264331 100644
--- a/src/pages/Calendar/Diary.js
+++ b/src/pages/Calendar/Diary.js
@@ -5,18 +5,20 @@ import DiaryController from "../../api/diary.controller.js";
import { useDispatch, useSelector } from "react-redux";
import Loading from "../../component/Loading.js";
import { CHANGE_DIARY } from "../../redux/modules/DiaryInfo.js";
+import SimpleImageSlider from "react-simple-image-slider";
-const Diary = ({ data }) => {
+const Diary = () => {
const navigate = useNavigate();
const dispatch = useDispatch();
const textRef = useRef();
- const [isImage, setIsImage] = useState(false);
const [isSaving, setIsSaving] = useState(false);
- const { diaryId, content, date, imgUrl } = useSelector(
+ const { diaryId, content, date, keywords, imgUrl } = useSelector(
(state) => state.DiaryInfo
);
+ const [diaryImages, setDiaryImages] = useState([]);
+
const userId = useSelector((state) => state.UserInfo.userId);
const [newContent, setNewContent] = useState(content);
@@ -26,7 +28,6 @@ const Diary = ({ data }) => {
textarea.style.height = "auto"; // Reset height to auto
textarea.style.height = textarea.scrollHeight + "px";
}, []);
-
useEffect(() => {
handleResizeHeight();
}, [handleResizeHeight]);
@@ -57,8 +58,9 @@ const Diary = ({ data }) => {
type: CHANGE_DIARY,
diaryId: diaryInfo.diaryId,
content: diaryInfo.content,
- imgUrl: diaryInfo.imgUrl,
date: diaryInfo.createDate,
+ keywords: diaryInfo.keywords,
+ imgUrl: diaryInfo.imgUrl,
});
setIsSaving(false);
} catch (error) {
@@ -80,26 +82,51 @@ const Diary = ({ data }) => {
}
};
+ useEffect(() => {
+ if (imgUrl) {
+ setDiaryImages([imgUrl]);
+ return;
+ }
+
+ if (keywords.length === 0 || keywords[0].imgUrl == null) {
+ setDiaryImages([]);
+ return;
+ }
+
+ setDiaryImages(
+ keywords.map((keyword) => {
+ return keyword.imgUrl;
+ })
+ );
+ }, []);
+
return (
{isSaving ?
: null}
-
- {imgUrl !== null ? (
-

- ) : (
+
+ {diaryImages.length === 0 && (
{
- navigate("/draw", { state: data });
+ navigate("/draw");
}}
>
그림 그리기
)}
+ {diaryImages.length > 0 && (
+
+ )}
{
const [showDiary, setShowDiary] = useState(false);
@@ -14,8 +16,8 @@ const DiaryEdit = ({ isOpen }) => {
(state) => state.DiaryInfo
);
- const [data, setData] = useState([]);
-
+ const setKeywordState = useSetRecoilState(keywordState);
+ const resetKeywordState = useSetRecoilState(keywordState);
const fetchData = async () => {
try {
const response = await DiaryController.getQuiz({
@@ -45,6 +47,7 @@ const DiaryEdit = ({ isOpen }) => {
const navigate = useNavigate();
useEffect(() => {
+ resetKeywordState();
setShowDiary(false);
}, [diaryId]);
@@ -56,15 +59,11 @@ const DiaryEdit = ({ isOpen }) => {
try {
const response = await keywordController.getKeyword(diaryId);
const { isSuccess, result } = response.data;
+ setKeywordState(result);
if (result.length == 0) {
return;
}
- setData(
- result.map((item, index) => {
- return { keywordId: item.keywordId, keyword: item.keyword };
- })
- );
console.log(result);
} catch (error) {
console.error("Error fetching quiz data:", error);
@@ -111,7 +110,7 @@ const DiaryEdit = ({ isOpen }) => {
일기닫기
- {showDiary &&
}
+ {showDiary &&
}
);
};
diff --git a/src/pages/Calendar/Draw.js b/src/pages/Calendar/Draw.js
index 2e8130b..ad8447a 100644
--- a/src/pages/Calendar/Draw.js
+++ b/src/pages/Calendar/Draw.js
@@ -1,262 +1,301 @@
import React, { useEffect, useRef, useState } from "react";
-import { useDispatch } from "react-redux";
+import { useDispatch, useSelector } from "react-redux";
import { SET_PAGENAME } from "../../redux/modules/PageName";
-import { useLocation, useNavigate } from "react-router-dom";
import {
IoIosArrowBack,
IoIosArrowDown,
- IoIosArrowUp,
IoIosArrowForward,
+ IoIosArrowUp,
} from "react-icons/io";
import { AiOutlineExclamationCircle } from "react-icons/ai";
-import Canvas from "../../component/ImageDiary/Canvas";
+import { CanvasList } from "../../component/ImageDiary/Canvas";
import Palette from "../../component/ImageDiary/Palette";
import Button from "../../component/Button";
import keywordController from "../../api/keyword.controller";
import imgController from "../../api/img.controller";
import InfiniteScroll from "../../component/ImageDiary/InfiniteScroll";
-import SkyButton from "../../component/BackGroundSkyButton";
import AIModal from "../../component/ImageDiary/AIModal";
+import { useRecoilState } from "recoil";
+import { keywordState } from "../../recoil/keywordState";
+import diaryController from "../../api/diary.controller";
+import { useNavigate } from "react-router-dom";
+import DiaryController from "../../api/diary.controller";
+
const Draw = () => {
const dispatch = useDispatch();
- useEffect(() => {
- dispatch({ type: SET_PAGENAME, pageName: "그림일기" });
- }, []);
- const location = useLocation();
- const navigate = useNavigate();
const [index, setIndex] = useState(0);
+ const [keywordInfo, _] = useRecoilState(keywordState);
//키워드
- const [keyword, setKeyword] = useState([]);
- //키워드 아이디
- const [keywordId, setKeywordId] = useState([]);
+ const [keyword, setKeyword] = useState(
+ keywordInfo.map((item) => item.keyword)
+ );
//캔버스들 저장
- const canvasRefs = useRef({});
- //키워드별 사진 저장(base64 형태) -> photoedit으로 넘겨줌
- const [savedImages, setSavedImages] = useState([]);
- //키워드가 존재하는 지의 여부
- const [isKeywordExist, setIsKeywordExist] = useState();
- //다른 사람 그림 보기
- const [showOtherDraw, setShowOtherDraw] = useState(false);
- const [isModalOpen, setIsModalOpen] = useState(false);
-
- //다른 사람 그림 보기 클릭
- const handleClickShowDraw = () => {
- setShowOtherDraw(!showOtherDraw);
- console.log(showOtherDraw);
- };
-
- const handleModal = () => {
- setIsModalOpen(!isModalOpen);
- };
+ const canvasRefs = useRef(keywordInfo.map((_) => React.createRef()));
+ const canvasBgRefs = useRef(keywordInfo.map((_) => React.createRef()));
useEffect(() => {
+ dispatch({ type: SET_PAGENAME, pageName: "그림일기" });
+
//키워드가 없는 경우
- if (location.state.length == 0) {
+ if (keywordInfo.length === 0) {
setKeyword(["자유롭게 그려주세요"]);
- setIsKeywordExist(false);
- }
-
- //키워드가 있는 경우
- if (location.state.length !== 0) {
- setIsKeywordExist(true);
- setKeyword(location.state.map((item) => item.keyword));
- setKeywordId(location.state.map((item) => item.keywordId));
+ canvasRefs.current.push(React.createRef());
+ canvasBgRefs.current.push(React.createRef());
}
}, []);
+ return (
+
+
+ {/* AI 도움 */}
+
+ {/* 다른 사람의 키워드 사진 띄워줄 부분 */}
+
+ {/* Canvas */}
+
+ {/* 색상팔레트 */}
+
+ {/* 저장 버튼 */}
+
+
+ );
+};
+
+const KeywordNavigation = ({ keywords, index, setIndex }) => {
+ const isFirstIndex = index === 0;
+ const isLastIndex = index === keywords.length - 1;
+
//다음 키워드 제시
const getNextKeyword = () => {
- if (index == keyword.length - 1) return;
+ if (index === keywords.length - 1) return;
setIndex((index) => index + 1);
};
//이전 키워드 제시
const getPrevKeyword = () => {
- if (index == 0) return;
+ if (keywords === 0) return;
setIndex((index) => index - 1);
};
- // 캔버스 렌더링
- const renderCanvas = () => {
- canvasRefs.current = keyword.map(() => React.createRef());
- return keyword.map((cur, i) => (
-
+ );
+};
- const saveImage = async () => {
- try {
- const photos = await postImg(); // postImg 함수의 반환값을 받아옴
- if (!isKeywordExist) return;
- console.log(photos);
- await saveKeywordImg(photos); // saveKeywordImg 함수에 이미지 URL 배열 전달
- } catch (err) {
- console.log(err);
- }
- };
+const AISuggestionTextAndIconAndModal = ({ keywords, index }) => {
+ const [isModalOpen, setIsModalOpen] = useState(false);
- const handleClickAIButton = () => {
- navigate("/draw/help", {
- state: {
- keyword: keyword[index],
- },
- });
+ const handleModal = () => {
+ setIsModalOpen(!isModalOpen);
};
return (
-
- {/* 키워드 */}
-
- {keyword.length > 0 ? (
- index === 0 ? (
-
- ) : (
-
- )
- ) : null}
-
{keyword[index]}
- {keyword.length > 0 && index !== keyword.length - 1 && (
-
- )}
- {keyword.length > 0 && index === keyword.length - 1 && (
-
- )}
-
- {/* AI 도움 */}
+ <>
+ {isModalOpen && (
+
+ )}
혹시 그림 그리기 어려우신가요?
handleModal()} />
+ >
+ );
+};
+
+const ShowOtherDrawSlider = ({ keywords, index, isKeywordExist }) => {
+ //다른 사람 그림 보기
+ const [showOtherDraw, setShowOtherDraw] = useState(false);
+
+ //다른 사람 그림 보기 클릭
+ const handleClickShowDraw = () => {
+ setShowOtherDraw(!showOtherDraw);
+ };
+
+ if (!isKeywordExist) {
+ return null;
+ }
+
+ return (
+ <>
handleClickShowDraw()}
>
다른 사람 그림 보기
- {showOtherDraw ? (
-
- ) : (
-
- )}
+ {showOtherDraw && }
+ {!showOtherDraw && }
- {/* 사진 띄워줄 부분 */}
- {isKeywordExist && showOtherDraw && renderPhoto()}
- {/* Canvas */}
-
- {renderCanvas()}
-
- {/* 색상팔레트 */}
-
- 옆으로 넘겨서 더 많은 색상을 볼 수 있어요!
-
-
-
- {keyword.length - 1 === index || keyword.length === 0 ? (
-
- {isModalOpen && (
-
+ );
+};
+
+const SaveImageButton = ({ index, canvasRefs, canvasBgRefs, keywordInfo }) => {
+ const isKeywordExist = keywordInfo.length !== 0;
+ const { saveAllCanvasDrawToKeywordImage } = useSaveCanvasImage({
+ canvasRefs,
+ canvasBgRefs,
+ keywordInfo,
+ isKeywordExist,
+ });
+
+ return (
+
+ {canvasRefs.current.length - 1 === index && (
+
);
};
+const useSaveCanvasImage = ({
+ canvasRefs,
+ canvasBgRefs,
+ keywordInfo,
+ isKeywordExist,
+}) => {
+ let navigate = useNavigate();
+ const diaryId = useSelector((state) => state.DiaryInfo.diaryId);
+ //키워드 별 사진을 서버로 전송
+ const saveAllCanvasDrawToKeywordImage = async () => {
+ const uploadCanvasDrawRequests = [];
+
+ for (let i = 0; i < canvasRefs.current.length; i++) {
+ uploadCanvasDrawRequests.push(
+ uploadCanvasImageToUrl({
+ canvas: canvasRefs.current[i].current,
+ bgCanvas: canvasBgRefs.current[i].current,
+ })
+ );
+ }
+
+ let uploadedImageUrls = await Promise.all(uploadCanvasDrawRequests);
+
+ let saveKeywordRequests = [];
+
+ for (let i = 0; i < canvasRefs.current.length; i++) {
+ saveKeywordRequests.push(
+ saveKeywordImageUrl({
+ keywordInfo: keywordInfo[i],
+ uploadedImageUrl: uploadedImageUrls[i],
+ })
+ );
+ }
+
+ await Promise.all(saveKeywordRequests);
+ navigate("/calendar");
+ };
+
+ const uploadCanvasImageToUrl = async ({ canvas, bgCanvas }) => {
+ const formData = new FormData();
+
+ let resultCanvas = mergeCanvas({ canvas, bgCanvas });
+ const blob = await canvasToBlob({ canvas: resultCanvas });
+
+ formData.append("image", blob, "image.png");
+
+ const response = await imgController.uploadImg(formData);
+
+ return response.data.result.imageUrl;
+ };
+
+ const saveKeywordImageUrl = async ({ keywordInfo, uploadedImageUrl }) => {
+ //키워드가 있는 경우 키워드별 이미지 저장
+ if (isKeywordExist) {
+ return await keywordController.saveKeywordImg(keywordInfo.keywordId, {
+ imgUrl: uploadedImageUrl,
+ });
+ }
+ // 키워드가 없는 경우 다이어리 이미지 저장
+ else {
+ return await DiaryController.saveDiaryImg(diaryId, {
+ imgUrl: uploadedImageUrl,
+ });
+ }
+ };
+
+ return { saveAllCanvasDrawToKeywordImage };
+};
+
+const mergeCanvas = ({ canvas, bgCanvas }) => {
+ // resultCanvas 컴포넌트 생성
+ const resultCanvas = document.createElement("canvas");
+ resultCanvas.width = canvas.width;
+ resultCanvas.height = canvas.height;
+
+ const resultCtx = resultCanvas.getContext("2d");
+
+ resultCtx.drawImage(bgCanvas, 0, 0, canvas.width, canvas.height);
+ resultCtx.drawImage(canvas, 0, 0, canvas.width, canvas.height);
+ resultCtx.globalAlpha = 1.0;
+
+ return resultCanvas;
+};
+
+const canvasToBlob = async ({ canvas }) => {
+ return new Promise((resolve, reject) => {
+ canvas.toBlob((blob) => {
+ console.log(blob);
+ if (blob) {
+ resolve(blob);
+ } else {
+ reject();
+ }
+ });
+ });
+};
+
export default Draw;
diff --git a/src/pages/DiaryManagement.js b/src/pages/DiaryManagement.js
deleted file mode 100644
index 95ae4f0..0000000
--- a/src/pages/DiaryManagement.js
+++ /dev/null
@@ -1,180 +0,0 @@
-import React, { useEffect, useState } from "react";
-import { useDispatch, useSelector } from "react-redux";
-import { SET_PAGENAME } from "../redux/modules/PageName";
-import { useNavigate, useLocation } from "react-router-dom";
-import Button from "../component/Button";
-import diaryController from "../api/diary.controller";
-import queryString from "query-string";
-
-function DiaryListCop({ diaryDates }) {
- const navigate = useNavigate();
- const formattedDates = diaryDates.map((dateStr) => {
- const date = new Date(dateStr);
- const formattedDate = `${date.getFullYear()}년 ${date.getMonth() + 1}월 ${date.getDate()}일`;
- return formattedDate;
- });
- const handleClick = (index) => {
- navigate("/calendar", { state: diaryDates[index] });
- };
- return (
-
- {diaryDates.length > 0 ? (
-
- {formattedDates.map((date, index) => (
-
handleClick(index)}
- key={index}
- >
-
- {date}
-
-
- 일기 확인하기 {">"}
-
-
- ))}
-
- ) : (
-
- 일기가 존재하지 않습니다.
-
- )}
-
- );
-}
-
-function SearchDiary({ id, setDiaries }) {
- const [startDate, setStartDate] = useState("");
- const [endDate, setEndDate] = useState("");
- const [option, setOption] = useState("");
-
- const navigate = useNavigate();
- const location = useLocation();
-
- const query = queryString.parse(location.search);
-
- const currentDate = new Date();
- const currentYear = currentDate.getFullYear();
- const currentMonth = String(currentDate.getMonth() + 1).padStart(2, "0");
- const currentDay = String(currentDate.getDate()).padStart(2, "0");
-
- const previousDate = new Date(currentDate);
- previousDate.setDate(currentDate.getDate() - 1);
- const previousYear = previousDate.getFullYear();
- const previousMonth = String(previousDate.getMonth() + 1).padStart(2, "0");
- const previousDay = String(previousDate.getDate()).padStart(2, "0");
-
- const defaultDate = `${currentYear}-${currentMonth}-${currentDay}`;
- const defaultPreviousDate = `${previousYear}-${previousMonth}-${previousDay}`;
-
- useEffect(() => {
- setStartDate(query.startDate || defaultPreviousDate);
- setEndDate(query.endDate || defaultDate);
- setOption(query.sortBy || "DES_CREATE_DATE");
- if (query.startDate && query.endDate) {
- searchDiaryList(query.startDate, query.endDate, query.sortBy);
- }
- }, [query.startDate, query.endDate, query.sortBy]);
-
- useEffect(() => {
- searchDiaryList(startDate, endDate, option);
- }, [option]);
-
- const handleStartDateChange = (event) => {
- const newStartDate = event.target.value;
- setStartDate(newStartDate);
- if (newStartDate > endDate) {
- setEndDate("");
- }
- };
-
- const handleEndDateChange = (event) => {
- setEndDate(event.target.value);
- };
-
- const handleOptionChange = (event) => {
- setOption(event.target.value);
- };
-
- const searchDiaryList = async (
- start = startDate,
- end = endDate,
- sortBy = option
- ) => {
- try {
- const response = await diaryController.searchDiaryList({
- userId: id,
- startDate: start,
- finishDate: end,
- sortBy: sortBy,
- });
- const diaries = response.data.result.diaries;
- const createDateList = diaries.map((diary) => diary.createDate);
- setDiaries(createDateList);
-
- navigate(
- `${location.pathname}?startDate=${start}&endDate=${end}&sortBy=${sortBy}`,
- { replace: true }
- );
- } catch (error) {
- console.error("기간별 일기 조회 중 오류", error);
- }
- };
-
- return (
-
-
-
-
-
-
-
- );
-}
-
-const DiaryManagement = () => {
- const dispatch = useDispatch();
- const userInfo = useSelector((state) => state.UserInfo);
- const [diaries, setDiaries] = useState([]);
-
- useEffect(() => {
- dispatch({ type: SET_PAGENAME, pageName: "일기 관리" });
- }, [dispatch]);
-
- return (
-
-
-
-
- );
-};
-
-export default DiaryManagement;
diff --git a/src/pages/ImageDiary/HelpForAi.js b/src/pages/ImageDiary/HelpForAi.js
index fe40c7a..a1f9663 100644
--- a/src/pages/ImageDiary/HelpForAi.js
+++ b/src/pages/ImageDiary/HelpForAi.js
@@ -4,6 +4,9 @@ import Button from "../../component/Button";
import imgController from "../../api/img.controller";
import SimpleImageSlider from "react-simple-image-slider";
import Modal from "../../component/Modal";
+import Loading from "../../component/Loading";
+import { useRecoilState, useRecoilValue } from "recoil";
+import { apiKeyStore } from "../../recoil/apiKeyStore";
const HelpForAi = () => {
const location = useLocation();
@@ -11,23 +14,31 @@ const HelpForAi = () => {
const navigate = useNavigate();
// AI가 생성한 이미지
const [aiImages, setAiImages] = useState([]);
+ const [isLoading, setIsLoading] = useState(false);
+ const apiKeyState = useRecoilValue(apiKeyStore);
+
const getImageForAI = async () => {
- // prompt가 비어 있거나 keyword를 포함하지 않으면 모달을 표시
- if (!prompt || !prompt.includes(keyword)) {
+ // keyword가 "자유롭게 그려주세요"이거나, prompt가 keyword를 포함하는 경우
+ if (
+ (keyword === "자유롭게 그려주세요" && prompt) ||
+ (prompt && prompt.includes(keyword))
+ ) {
+ try {
+ setIsLoading(true);
+ const res = await imgController.generateImage({
+ password: apiKeyState.apiKey,
+ prompt: prompt,
+ n: 3,
+ });
+ console.log(res.data);
+ setAiImages(res.data.result.urls);
+ } catch (error) {
+ console.error(error);
+ }
+ setIsLoading(false);
+ } else {
+ // 그 외의 경우 모달을 표시
handleModal();
- return;
- }
-
- try {
- const res = await imgController.generateImage({
- password: "password",
- prompt: prompt,
- n: 3,
- });
- console.log(res.data);
- setAiImages(res.data.result.urls);
- } catch (error) {
- console.error(error);
}
};
@@ -66,7 +77,7 @@ const HelpForAi = () => {
if (aiImages.length === 0) return;
navigate("/draw/help/result", {
state: {
- keyword: prompt,
+ keyword: keyword,
image: aiImages[currentIndex],
fullWidth: fullWidth,
},
@@ -102,7 +113,7 @@ const HelpForAi = () => {
onChange={handlePromptChange}
/>
);
};
diff --git a/src/pages/ImageDiary/ShowAiResult.js b/src/pages/ImageDiary/ShowAiResult.js
index 55d5b5d..544da06 100644
--- a/src/pages/ImageDiary/ShowAiResult.js
+++ b/src/pages/ImageDiary/ShowAiResult.js
@@ -1,26 +1,54 @@
import React, { useEffect, useState } from "react";
import { useLocation, useNavigate } from "react-router-dom";
+import { useRecoilState } from "recoil";
import BackGroundSkyButton from "../../component/BackGroundSkyButton";
-import Button from "../../component/Button";
-import { style } from "d3";
+import { imageState } from "../../recoil/keywordState";
const ShowAiResult = () => {
const location = useLocation();
+ const navigate = useNavigate();
+ const [image, setImage] = useRecoilState(imageState);
+
const keyword = location.state.keyword;
const imageUrl = location.state.image;
const fullWidth = location.state.fullWidth;
- const navigate = useNavigate();
// 배경 투명도
+ const [bgOpacity, setBgOpacity] = useState(1);
const bgOpacityList = ["30", "50", "70", "100"];
- const [bgOpacity, setBgOpacity] = useState("1");
const [selectedOpacityIndex, setSelectedOpacityIndex] = useState(3);
+
// 투명도 변경
const changeOpacity = (item, index) => {
setBgOpacity(parseInt(item) * 0.01);
setSelectedOpacityIndex(index);
};
+ // 이미지 저장
+ const saveEditImage = () => {
+ const newImage = {
+ keyword: keyword,
+ imageUrl: imageUrl,
+ bgOpacity: bgOpacity,
+ };
- const saveEditImage = () => {};
+ setImage((prevImage) => {
+ // 같은 키워드에 2번 도움받는 경우, 기존 키워드의 이미지 덮어쓰기
+ const existingIndex = prevImage.findIndex(
+ (image) => image.keyword === keyword
+ );
+
+ if (existingIndex !== -1) {
+ // 같은 keyword를 가진 항목이 이미 존재하는 경우, 해당 항목을 업데이트
+ const updatedImages = [...prevImage];
+ updatedImages[existingIndex] = newImage;
+ return updatedImages;
+ } else {
+ // 같은 keyword를 가진 항목이 존재하지 않는 경우, 새 항목 추가
+ return [...prevImage, newImage];
+ }
+ });
+
+ navigate("/draw");
+ };
return (
diff --git a/src/pages/MyPages/APIKeyInput.js b/src/pages/MyPages/APIKeyInput.js
new file mode 100644
index 0000000..2e54caa
--- /dev/null
+++ b/src/pages/MyPages/APIKeyInput.js
@@ -0,0 +1,49 @@
+import { useRecoilState } from "recoil";
+import { apiKeyStore } from "../../recoil/apiKeyStore";
+
+export const API_KEY_INPUT_PAGE_PATH = "/mypage/apikey";
+
+export const APIKeyInput = () => {
+ return (
+
+
+
API KEY 입력하기
+
+ API KEY를 입력하면, OpenAI 의 이미지 생성 API를 사용할 수 있습니다.
+
+
+
+
+ );
+};
+
+const APIKeyInputForm = () => {
+ const [apiKeyState, setApiKeyState] = useRecoilState(apiKeyStore);
+
+ const handleInput = (e) => {
+ setApiKeyState((preState) => {
+ return {
+ ...preState,
+ apiKey: e.target.value,
+ };
+ });
+ };
+
+ return (
+
+ );
+};
diff --git a/src/pages/MyPage.js b/src/pages/MyPages/MyPage.js
similarity index 69%
rename from src/pages/MyPage.js
rename to src/pages/MyPages/MyPage.js
index a94f7a1..245a6e8 100644
--- a/src/pages/MyPage.js
+++ b/src/pages/MyPages/MyPage.js
@@ -1,35 +1,53 @@
-import User from "../assets/user.png";
-import MyPageList from "../component/MyPageList";
-import Diary from "../assets/diary.png";
-import { useState } from "react";
+import User from "../../assets/user.png";
+import Left from "../../assets/left.png";
+import MyPageItem from "../../component/MyPageItem";
+import Diary from "../../assets/diary.png";
+import { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
-import { useEffect } from "react";
-import { SET_PAGENAME } from "../redux/modules/PageName";
+import { SET_PAGENAME } from "../../redux/modules/PageName";
import { useNavigate } from "react-router-dom";
-import { setFontSize } from "../redux/modules/fontSize";
+import { setFontSize } from "../../redux/modules/fontSize";
+import { USER_UPDATE_PAGE_PATH } from "./UserUpdate";
+import { DIARY_MANAGEMENT_PAGE_PATH } from "./DiaryManagement";
+import { API_KEY_INPUT_PAGE_PATH } from "./APIKeyInput";
-const UserProfile = () => {
+const MyPage = () => {
+ const dispatch = useDispatch();
let navigate = useNavigate();
+ useEffect(() => {
+ dispatch({ type: SET_PAGENAME, pageName: "마이페이지" });
+ }, []);
- let userInfo = useSelector((state) => state.UserInfo);
-
- const LogOutButton = () => {
- const logout = () => {
- localStorage.clear();
- navigate("/login");
- };
+ return (
+
+ {/* 사진, 이름, 닉네임 */}
+
- return (
-
-
+ {/* 마이페이지 리스트 */}
+
+ navigate(USER_UPDATE_PAGE_PATH)}
+ />
+ navigate(API_KEY_INPUT_PAGE_PATH)}
+ />
+ navigate(DIARY_MANAGEMENT_PAGE_PATH)}
+ />
+
- );
- };
+
+ );
+};
+
+const UserProfile = () => {
+ let userInfo = useSelector((state) => state.UserInfo);
return (
{
);
};
-const Toggle = () => {
+const LogOutButton = () => {
+ let navigate = useNavigate();
+
+ const logout = () => {
+ localStorage.clear();
+ navigate("/login");
+ };
+
+ return (
+
+
+
+ );
+};
+
+const FontSizeToggleButton = () => {
const dispatch = useDispatch();
const currentFontSize = useSelector((state) => state.fontSize);
const [isDrop, setIsDrop] = useState(false);
@@ -103,32 +138,4 @@ const Toggle = () => {
);
};
-const MyPage = () => {
- const dispatch = useDispatch();
- let navigate = useNavigate();
- useEffect(() => {
- dispatch({ type: SET_PAGENAME, pageName: "마이페이지" });
- }, []);
- return (
-
- {/* 사진, 이름, 닉네임 */}
-
-
- {/* 마이페이지 리스트 */}
-
- navigate("/userupdate")}
- />
- navigate("/diarymanagement")}
- />
-
-
-
- );
-};
export default MyPage;
diff --git a/src/pages/MyPages/UserUpdate.js b/src/pages/MyPages/UserUpdate.js
index cd6c138..0d1d391 100644
--- a/src/pages/MyPages/UserUpdate.js
+++ b/src/pages/MyPages/UserUpdate.js
@@ -5,12 +5,7 @@ import Button from "../../component/Button";
import Modal from "../../component/Modal";
import { useNavigate } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
-<<<<<<< HEAD:src/pages/UserUpdate.js
-import { SET_PAGENAME } from "../redux/modules/PageName";
-=======
import { SET_PAGENAME } from "../../redux/modules/PageName";
-import axios from "axios";
->>>>>>> develop:src/pages/MyPages/UserUpdate.js
export const USER_UPDATE_PAGE_PATH = "/userupdate";
diff --git a/src/pages/UserUpdate.js b/src/pages/UserUpdate.js
deleted file mode 100644
index 7c22b79..0000000
--- a/src/pages/UserUpdate.js
+++ /dev/null
@@ -1,208 +0,0 @@
-import React, { useEffect, useState } from "react";
-import UserController from "../api/users.controller";
-import { useForm } from "react-hook-form";
-import Button from "../component/Button";
-import Modal from "../component/Modal";
-import { useNavigate } from "react-router-dom";
-import { useDispatch, useSelector } from "react-redux";
-import { SET_PAGENAME } from "../redux/modules/PageName";
-
-const UserUpdate = () => {
- const dispatch = useDispatch();
- const userInfo = useSelector((state) => state.UserInfo);
- const navigate = useNavigate();
-
- const {
- register,
- handleSubmit,
- watch,
- formState: { errors },
- reset,
- } = useForm();
-
- useEffect(() => {
- dispatch({ type: SET_PAGENAME, pageName: "정보 수정" });
- }, [dispatch]);
-
- useEffect(() => {
- reset(userInfo);
- console.log(userInfo);
- }, [userInfo, reset]);
-
- const onSubmit = async (data) => {
- const accessToken = localStorage.getItem("AccessToken");
- if (!accessToken) {
- console.error("엑세스 토큰이 없습니다.");
- return;
- }
-
- const userData = {
- id: userInfo.userId,
- username: data.username,
- nickname: data.nickname,
- email: data.email,
- password: data.password,
- birth: data.birth,
- };
-
- try {
- await UserController.updateUser({ userData, accessToken });
- console.log("성공");
- navigate("/mypage");
- } catch (error) {
- console.log("정보 수정 중 오류", error);
- }
- };
-
- const [nickname, setNickname] = useState("");
- const nicknameRegister = register("nickname", {
- required: "빈 칸 없이 작성해주세요.",
- });
-
- const handleChange = (event) => {
- setNickname(event.target.value);
- nicknameRegister.onChange(event);
- };
-
- const checkNickname = async () => {
- if (nickname === "") return;
- try {
- const res = await UserController.checkNickname({ nickname });
- setIsNicknameExist(false);
- } catch (error) {
- console.log(error);
- setIsNicknameExist(true);
- }
- setIsModalOpen(true);
- };
-
- const [isModalOpen, setIsModalOpen] = useState(false);
- const closeModal = () => {
- setIsModalOpen(false);
- };
- const [isNicknameExist, setIsNicknameExist] = useState(false);
-
- if (!userInfo) return null;
-
- return (
-
-
- {isModalOpen && isNicknameExist && (
-
- )}
- {isModalOpen && !isNicknameExist && (
-
- )}
-
- );
-};
-
-export default UserUpdate;
diff --git a/src/recoil/apiKeyStore.js b/src/recoil/apiKeyStore.js
new file mode 100644
index 0000000..c9e8b66
--- /dev/null
+++ b/src/recoil/apiKeyStore.js
@@ -0,0 +1,8 @@
+import { atom } from "recoil";
+
+export const apiKeyStore = atom({
+ key: "apiKeyState",
+ default: {
+ apiKey: "",
+ },
+});
diff --git a/src/recoil/canvasState.js b/src/recoil/canvasState.js
new file mode 100644
index 0000000..324a46c
--- /dev/null
+++ b/src/recoil/canvasState.js
@@ -0,0 +1,10 @@
+import { atom } from "recoil";
+
+export const selectedColorState = atom({
+ key: "selectedColorState",
+ default: "#000000",
+});
+export const brushSizeState = atom({
+ key: "brushSizeState",
+ default: 3,
+});
diff --git a/src/recoil/keywordState.js b/src/recoil/keywordState.js
new file mode 100644
index 0000000..e4728bb
--- /dev/null
+++ b/src/recoil/keywordState.js
@@ -0,0 +1,17 @@
+import { atom } from "recoil";
+
+export const keywordState = atom({
+ key: "keywordState",
+ default: [],
+});
+
+const defaultImageState = {
+ keyword: "Keyword",
+ imageUrl: "ImageUrl",
+ bgOpacity: "numBgOpacity",
+};
+
+export const imageState = atom({
+ key: "imageState",
+ default: [],
+});
diff --git a/src/redux/config/configStore.js b/src/redux/config/configStore.js
index 9521ef5..5af27ed 100644
--- a/src/redux/config/configStore.js
+++ b/src/redux/config/configStore.js
@@ -1,6 +1,5 @@
import { createStore } from "redux";
import { combineReducers } from "redux";
-import ImageDiary from "../modules/ImageDiary.js";
import DiaryDate from "../modules/DiaryDate.js";
import DiaryInfo from "../modules/DiaryInfo.js";
import UserInfo from "../modules/UserInfo.js";
@@ -8,7 +7,6 @@ import PageName from "../modules/PageName.js";
import fontSizeReducer from "../modules/fontSize.js";
const rootReducer = combineReducers({
- ImageDiary,
DiaryDate,
DiaryInfo,
UserInfo,
diff --git a/src/redux/modules/DiaryInfo.js b/src/redux/modules/DiaryInfo.js
index f2a4d36..06fd189 100644
--- a/src/redux/modules/DiaryInfo.js
+++ b/src/redux/modules/DiaryInfo.js
@@ -7,7 +7,8 @@ const initialState = {
diaryId: 0,
content: "",
date: 0,
- imgUrl: null,
+ keywords: [],
+ imgUrl: "",
};
export default function DiaryInfo(state = initialState, action) {
@@ -18,6 +19,7 @@ export default function DiaryInfo(state = initialState, action) {
diaryId: action.diaryId,
content: action.content,
date: action.date,
+ keywords: action.keywords,
imgUrl: action.imgUrl,
};
diff --git a/src/redux/modules/ImageDiary.js b/src/redux/modules/ImageDiary.js
deleted file mode 100644
index 228f657..0000000
--- a/src/redux/modules/ImageDiary.js
+++ /dev/null
@@ -1,24 +0,0 @@
-export const SELECT_COLOR = "SELECT_COLOR";
-export const BRUSH_SIZE = "BRUSH_SIZE";
-
-export const initialState = {
- selectedColor: "#000000",
- brushSize: 1,
-};
-
-export default function ImageDiary(state = initialState, action) {
- switch (action.type) {
- case SELECT_COLOR:
- return {
- ...state,
- selectedColor: action.selectedColor,
- };
- case BRUSH_SIZE:
- return {
- ...state,
- brushSize: action.brushSize,
- };
- default:
- return state;
- }
-}