Skip to content

Commit 7e7316c

Browse files
committed
fix: 저장하기 버튼 활성화/비활성화 로직 수정,
- createHint atom에 selectedHint의 initial값 import - DrawerHint/Answer에서 중복되는 로직을 useImages로 분리
1 parent 9e15805 commit 7e7316c

File tree

6 files changed

+249
-277
lines changed

6 files changed

+249
-277
lines changed

app/admin-new/(components)/ThemeDrawer/Container.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,15 @@ const ThemeDrawer = ({
8181
</div>
8282

8383
<ThemeDrawerHint
84-
hintImages={hintImages}
85-
setHintImages={setHintImages}
84+
imageType={"hint"}
85+
images={hintImages}
86+
setImages={setHintImages}
8687
/>
8788

8889
<ThemeDrawerAnswer
89-
answerImages={answerImages}
90-
setAnswerImages={setAnswerImages}
90+
imageType={"answer"}
91+
images={answerImages}
92+
setImages={setAnswerImages}
9193
/>
9294
</div>
9395

app/admin-new/(components)/ThemeDrawer/ThemeDrawerAnswer.tsx

Lines changed: 33 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -1,125 +1,29 @@
11
import Image from "next/image";
2-
import {
3-
ChangeEvent,
4-
Dispatch,
5-
MouseEvent,
6-
SetStateAction,
7-
useEffect,
8-
useRef,
9-
useState,
10-
} from "react";
2+
import { Dispatch, SetStateAction } from "react";
113

124
import { useSelectedHint } from "@/components/atoms/selectedHint.atom";
13-
import { useToastWrite } from "@/components/atoms/toast.atom";
14-
import { subscribeLinkURL } from "@/admin-new/(consts)/sidebar";
15-
import { useCreateHint } from "@/components/atoms/createHint.atom";
16-
import { getStatus } from "@/utils/localStorage";
175

18-
import { compressImage, convertToPng } from "./helpers/imageHelpers";
196
import { GalleryImageProps } from "./consts/themeDrawerProps";
7+
import useImages from "./hooks/useImages";
208
const ThemeDrawerAnswer = ({
21-
answerImages,
22-
setAnswerImages,
9+
imageType,
10+
images,
11+
setImages,
2312
}: {
24-
answerImages: File[];
25-
setAnswerImages: Dispatch<SetStateAction<File[]>>;
13+
imageType: string;
14+
images: File[];
15+
setImages: Dispatch<SetStateAction<File[]>>;
2616
}) => {
27-
const status = getStatus();
28-
29-
const [selectedHint, setSelectedHint] = useSelectedHint();
30-
const [, setCreateHint] = useCreateHint();
31-
const [imgCnt, setImgCnt] = useState<number>(3);
32-
const setToast = useToastWrite();
33-
const answerRef = useRef<string>("");
34-
35-
// 가지고 있던 이미지 갯수를 빼줘서 남은 imgCnt 계산
36-
useEffect(() => {
37-
if (selectedHint.answerImageUrlList) {
38-
setImgCnt(
39-
3 - answerImages.length - selectedHint.answerImageUrlList.length
40-
);
41-
return;
42-
}
43-
setImgCnt(3 - answerImages.length);
44-
}, [answerImages, selectedHint.answerImageUrlList]);
45-
46-
// 이미지 파일 핸들러
47-
const handleHintFileClick = (e: MouseEvent<HTMLInputElement>) => {
48-
if (imgCnt === 0) {
49-
e.preventDefault();
50-
setToast({
51-
isOpen: true,
52-
title: "이미지는 3개까지 추가할 수 있습니다.",
53-
text: "",
54-
});
55-
return;
56-
}
57-
};
58-
const handleAnswerFileChange = async (e: ChangeEvent<HTMLInputElement>) => {
59-
if (!e.target.files) {
60-
return;
61-
}
62-
const files: File[] = [];
63-
const file = e.target.files[0];
64-
if (file.size > 5 * 1024 * 1024) {
65-
try {
66-
const compressedFile = await compressImage(file);
67-
68-
if (compressedFile.type !== "image/png") {
69-
const pngFile = await convertToPng(compressedFile);
70-
files.push(pngFile);
71-
} else {
72-
files.push(compressedFile);
73-
}
74-
} catch (error) {
75-
console.error("Image compression failed", error);
76-
files.push(file);
77-
}
78-
} else {
79-
files.push(file);
80-
}
81-
setAnswerImages((prev) => [...prev, ...files]);
82-
};
83-
84-
const answerInputRef = useRef<HTMLInputElement>(null);
85-
86-
const handleAnswerClick = (e: MouseEvent<HTMLButtonElement>) => {
87-
if (!status?.includes("SUBSCRIPTION")) {
88-
e.preventDefault();
89-
window.open(subscribeLinkURL, "_blank", "noopener,noreferrer");
90-
return;
91-
}
92-
answerInputRef.current?.click(); // 숨겨진 input 클릭 트리거
93-
};
94-
95-
const handleAnswerChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
96-
answerRef.current = e.target.value;
97-
setCreateHint((prev) => ({ ...prev, answer: answerRef.current }));
98-
};
99-
100-
// 힌트 추가 중 삭제 (로컬 이미지)
101-
const deleteLocalAnswerImg = (index: number) => {
102-
const newImages = [
103-
...answerImages.slice(0, index),
104-
...answerImages.slice(index + 1),
105-
];
106-
setAnswerImages(newImages);
107-
if (answerInputRef.current) {
108-
answerInputRef.current.value = "";
109-
}
110-
};
111-
// 수정 시 삭제
112-
const deleteServerAnswerImg = (index: number) => {
113-
const answerServerImages = selectedHint.answerImageUrlList;
114-
const newImages = [
115-
...answerServerImages.slice(0, index),
116-
...answerServerImages.slice(index + 1),
117-
];
118-
setSelectedHint((prev) => ({ ...prev, answerImageUrlList: newImages }));
119-
if (answerInputRef.current) {
120-
answerInputRef.current.value = "";
121-
}
122-
};
17+
const [selectedHint] = useSelectedHint();
18+
const {
19+
handleFileInputClick,
20+
handleFileInputChange,
21+
handleAddImageBtnClick,
22+
handleTextAreaChange,
23+
deleteLocalImage,
24+
deleteServerImage,
25+
answerInputRef,
26+
} = useImages({ imageType, images, setImages });
12327

12428
return (
12529
<div className="drawer-answer">
@@ -128,67 +32,64 @@ const ThemeDrawerAnswer = ({
12832
<button
12933
className="secondary_button28"
13034
type="button"
131-
onClick={handleAnswerClick}
35+
onClick={handleAddImageBtnClick}
13236
>
13337
<Image {...GalleryImageProps} />
13438
<input
13539
type="file"
13640
multiple
137-
onClick={handleHintFileClick}
138-
onChange={handleAnswerFileChange}
41+
onClick={handleFileInputClick}
42+
onChange={handleFileInputChange}
13943
accept="image/*"
14044
style={{ display: "none" }}
14145
ref={answerInputRef}
14246
/>
14347
이미지 추가
144-
{(answerImages.length > 0 ||
48+
{(images.length > 0 ||
14549
selectedHint?.answerImageUrlList?.length > 0) &&
14650
`(${
147-
(answerImages.length || 0) +
51+
(images.length || 0) +
14852
(selectedHint.answerImageUrlList?.length || 0)
14953
}/3)`}
15054
</button>
15155
</div>
152-
{selectedHint?.answerImageUrlList?.map((src, idx) => (
153-
<div className="drawer-images" key={src}>
154-
<div className="drawer-image-box">
56+
<div className="drawer-images">
57+
{selectedHint?.answerImageUrlList?.map((src, idx) => (
58+
<div className="drawer-image-box" key={src}>
15559
<img src={src} alt={`answer-preview-${src}`} />
15660
<div
15761
className="drawer-image-dimmed"
158-
onClick={() => deleteServerAnswerImg(idx)}
62+
onClick={() => deleteServerImage(idx)}
15963
>
16064
<button className="button28" type="button">
16165
삭제하기
16266
</button>
16367
</div>
16468
</div>
165-
</div>
166-
))}
167-
{answerImages.length > 0 && (
168-
<div className="drawer-images">
169-
{answerImages.map((file, index) => (
69+
))}
70+
{images.length > 0 &&
71+
images.map((file, index) => (
17072
<div key={file.name} className="drawer-image-box">
17173
<img
17274
src={URL.createObjectURL(file)}
17375
alt={`answer-preview-${index}`}
17476
/>
17577
<div
17678
className="drawer-image-dimmed"
177-
onClick={() => deleteLocalAnswerImg(index)}
79+
onClick={() => deleteLocalImage(index)}
17880
>
17981
<button className="button28" type="button">
18082
삭제하기
18183
</button>
18284
</div>
18385
</div>
18486
))}
185-
</div>
186-
)}
87+
</div>
18788

18889
<textarea
18990
className="drawer-content-textarea"
19091
placeholder="정답 내용을 입력해 주세요."
191-
onChange={handleAnswerChange}
92+
onChange={handleTextAreaChange}
19293
defaultValue={selectedHint.answer}
19394
/>
19495
</div>

0 commit comments

Comments
 (0)