Skip to content

Commit e7eb8a7

Browse files
Merge pull request #57 from umc-hackaton-4team/dev
fix : 캔디 SVG 파일명 공백 제거 및 기능 개선
2 parents 62659b2 + c10c1a3 commit e7eb8a7

File tree

8 files changed

+80
-23
lines changed

8 files changed

+80
-23
lines changed

src/constants/candyImages.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import RedCandy from "../assets/candy/red 1.svg";
2-
import OrangeCandy from "../assets/candy/orange 1.svg";
3-
import YellowCandy from "../assets/candy/yellow 1.svg";
4-
import GreenCandy from "../assets/candy/green 1.svg";
5-
import BlueCandy from "../assets/candy/blue 1.svg";
1+
import RedCandy from "../assets/candy/red.svg";
2+
import OrangeCandy from "../assets/candy/orange.svg";
3+
import YellowCandy from "../assets/candy/yellow.svg";
4+
import GreenCandy from "../assets/candy/green.svg";
5+
import BlueCandy from "../assets/candy/blue.svg";
66

77
export const CANDY_MAP: Record<string, string> = {
88
RED: RedCandy,

src/pages/ArchivePage/ArchivePage.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ import CandyOrange from "../../assets/icons/candy-orange.svg";
1313
import CandyPink from "../../assets/icons/candy-pink.svg";
1414
import CandyGreen from "../../assets/icons/candy-green.svg";
1515
import CandyBlue from "../../assets/icons/candy-blue.svg";
16+
import CandySpecial from "../../assets/icons/specialcandy.svg";
1617

1718
const CANDY_ICON_BY_COLOR: Partial<Record<CandyColor, string>> = {
1819
YELLOW: CandyYellow,
1920
ORANGE: CandyOrange,
2021
PINK: CandyPink,
2122
GREEN: CandyGreen,
2223
BLUE: CandyBlue,
24+
SPECIAL: CandySpecial,
2325
};
2426

2527
export default function ArchivePage() {

src/pages/RecommendPage/AchievementPage.tsx

Lines changed: 73 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import { useState } from "react";
1+
import { useState, useRef } from "react";
22
import { useLocation, useNavigate } from "react-router-dom";
33
import { api } from "../../api/axios";
44
import { API_ENDPOINTS } from "../../api/endpoints";
5-
import { useToastStore } from "../../store/toastStore";
5+
import { toast } from "../../store/toastStore";
66
import { Spinner } from "../../components/common/Spinner";
77
import specialcandy from "../../assets/icons/specialcandy.svg";
8+
import imageCompression from "browser-image-compression";
89
import type { Recommendation } from "../../types/recommendation";
910

1011
// 이미지 추가 아이콘 컴포넌트
@@ -26,35 +27,65 @@ const ImageAddIcon = () => (
2627
export default function AchievementPage() {
2728
const location = useLocation();
2829
const navigate = useNavigate();
29-
const { addToast } = useToastStore();
3030

3131
const item = location.state?.item as Recommendation | undefined;
3232
const [memo, setMemo] = useState("");
33+
const [images, setImages] = useState<File[]>([]);
3334
const [loading, setLoading] = useState(false);
35+
const fileInputRef = useRef<HTMLInputElement | null>(null);
3436

3537
// 현재 날짜 포맷
3638
const today = new Date();
3739
const dateStr = `${today.getMonth() + 1}. ${today.getDate()}.`;
3840
const dayNames = ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일"];
3941
const dayStr = dayNames[today.getDay()];
4042

43+
const handleImageChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
44+
const files = e.target.files;
45+
if (!files) return;
46+
47+
const compressedFiles: File[] = [];
48+
for (let i = 0; i < files.length; i++) {
49+
try {
50+
const compressed = await imageCompression(files[i], {
51+
maxSizeMB: 0.5,
52+
maxWidthOrHeight: 1024,
53+
useWebWorker: true,
54+
});
55+
compressedFiles.push(compressed);
56+
} catch (err) {
57+
console.error("이미지 압축 실패:", err);
58+
}
59+
}
60+
61+
if (compressedFiles.length + images.length > 4) {
62+
toast.warning("이미지는 최대 4장까지 업로드 가능합니다!");
63+
}
64+
65+
setImages((prev) => [...prev, ...compressedFiles].slice(0, 4));
66+
e.target.value = "";
67+
};
68+
4169
const handleSubmit = async () => {
4270
if (!item) {
43-
addToast("추천 정보가 없습니다.", "error");
71+
toast.error("추천 정보가 없습니다.");
4472
return;
4573
}
4674

4775
setLoading(true);
4876
try {
49-
// 완료 API 호출
50-
await api.post(API_ENDPOINTS.RECOMMENDATIONS.COMPLETE(item.id), {
51-
memo,
77+
const formData = new FormData();
78+
formData.append("request", JSON.stringify({ memo }));
79+
images.forEach((img) => formData.append("images", img));
80+
81+
await api.post(API_ENDPOINTS.RECOMMENDATIONS.COMPLETE(item.id), formData, {
82+
headers: { "Content-Type": "multipart/form-data" },
5283
});
53-
addToast("사탕이 만들어졌어요!", "success");
84+
toast.success("사탕이 만들어졌어요!");
5485
navigate("/archive");
5586
} catch (err) {
5687
console.error(err);
57-
addToast("저장에 실패했습니다.", "error");
88+
toast.error("저장에 실패했습니다.");
5889
} finally {
5990
setLoading(false);
6091
}
@@ -109,15 +140,39 @@ export default function AchievementPage() {
109140
</div>
110141

111142
{/* 이미지 업로드 영역 */}
112-
<div className="flex gap-3 mt-4">
113-
{[0, 1, 2, 3].map((index) => (
114-
<button
115-
key={index}
116-
className="w-[80px] h-[80px] rounded-[8px] border border-[#D5D5D5] bg-[#F8F8F8] flex items-center justify-center"
117-
>
118-
{index === 0 && <ImageAddIcon />}
119-
</button>
120-
))}
143+
<div className="mt-4">
144+
<input
145+
ref={fileInputRef}
146+
type="file"
147+
accept="image/*"
148+
multiple
149+
onChange={handleImageChange}
150+
className="hidden"
151+
/>
152+
153+
<div className="grid grid-cols-4 gap-3">
154+
{images.map((file, idx) => (
155+
<div
156+
key={idx}
157+
className="relative h-20 overflow-hidden rounded-xl border"
158+
>
159+
<img
160+
src={URL.createObjectURL(file)}
161+
className="h-full w-full object-cover"
162+
/>
163+
</div>
164+
))}
165+
166+
{images.length < 4 && (
167+
<button
168+
type="button"
169+
onClick={() => fileInputRef.current?.click()}
170+
className="flex h-20 items-center justify-center rounded-xl border border-[#D5D5D5] bg-[#F8F8F8]"
171+
>
172+
<ImageAddIcon />
173+
</button>
174+
)}
175+
</div>
121176
</div>
122177
</div>
123178
</div>

0 commit comments

Comments
 (0)