Skip to content

Commit d3690ec

Browse files
authored
Merge pull request #97 from ASAP-Lettering/feat/#96
[Feat] 편지 등록, 쓰기 이미지 업로드 지연 문제 해결
2 parents 6992dcf + bcfe763 commit d3690ec

File tree

8 files changed

+254
-152
lines changed

8 files changed

+254
-152
lines changed

src/app/letter/register/page.tsx

Lines changed: 107 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,11 @@ const LetterRegisterPage = () => {
2020
const { showToast } = useToast();
2121
const [sender, setSender] = useState<string>("");
2222
const [content, setContent] = useState<string>("");
23-
const [images, setImages] = useState<string[]>([]);
23+
const [images, setImages] = useState<string[]>([]); // 서버 전송용
24+
const [previewImages, setPreviewImages] = useState<string[]>([]); // 미리보기용
2425
const [isButtonDisabled, setIsButtonDisabled] = useState<boolean>(false);
26+
const [isImageUploadLoading, setImageUploadLoading] =
27+
useState<boolean>(false); // 서버 이미지 업로드 상태
2528

2629
const [letterState, setLetterState] = useRecoilState(registerLetterState);
2730
const [isToastShown, setIsToastShown] = useState(false);
@@ -34,11 +37,16 @@ const LetterRegisterPage = () => {
3437
setSender(letterState.senderName);
3538
setContent(letterState.content);
3639
setImages(letterState.images);
40+
setPreviewImages(letterState.previewImages);
3741
}
3842
}, [letterState]);
3943

4044
const handleSenderChange = (newValue: string) => {
4145
setSender(newValue);
46+
setLetterState((prevState) => ({
47+
...prevState,
48+
senderName: newValue,
49+
}));
4250
};
4351

4452
const handleContentChange = (newValue: string) => {
@@ -48,65 +56,68 @@ const LetterRegisterPage = () => {
4856
} else {
4957
setContent(newValue);
5058
}
59+
setLetterState((prevState) => ({
60+
...prevState,
61+
content: newValue,
62+
}));
63+
};
64+
65+
const handleShowToast = () => {
66+
/* 토스트 메세지 보여지기 전*/
67+
if (previewImages.length >= 4 && !isToastShown) {
68+
showToast("사진 첨부는 최대 4장까지 가능해요.", {
69+
icon: true,
70+
close: false,
71+
bottom: "113px",
72+
});
73+
setIsToastShown(true);
74+
}
5175
};
5276

5377
const handleAddImages = async (
5478
event: React.ChangeEvent<HTMLInputElement>
5579
) => {
5680
const files = event.target.files;
5781
if (files) {
58-
const selectedImages: File[] = Array.from(files).slice(0, 4);
59-
const totalImages = images.length + selectedImages.length;
60-
61-
/* 토스트 메세지 이미 보여짐 */
62-
if (isToastShown) {
63-
if (totalImages >= 4) {
64-
setIsButtonDisabled(true);
65-
return;
66-
}
82+
const selectedImages: File[] = Array.from(files);
83+
const existingImageCount = (previewImages || []).length;
6784

68-
if (totalImages > 4) {
69-
const additionalImagesNeeded = 4 - images.length;
70-
const newImages = [
71-
...images,
72-
...selectedImages
73-
.slice(0, additionalImagesNeeded)
74-
.map((file) => URL.createObjectURL(file)),
75-
];
76-
setImages(newImages);
77-
return;
78-
}
79-
} else {
80-
/* 토스트 메세지 보여지기 전*/
81-
if (totalImages > 4) {
82-
showToast("사진 첨부는 최대 4장까지 가능해요.", {
83-
icon: true,
84-
close: false,
85-
bottom: "113px",
86-
});
87-
setIsToastShown(true);
88-
setIsButtonDisabled(true);
89-
const newImages = [
90-
...images,
91-
...selectedImages
92-
.slice(0, 4 - images.length)
93-
.map((file) => URL.createObjectURL(file)),
94-
];
95-
setImages(newImages);
96-
return;
97-
}
98-
}
85+
// 총 이미지 개수를 4개로 제한
86+
const additionalImagesNeeded = Math.max(0, 4 - existingImageCount);
9987

100-
setIsButtonDisabled(false);
88+
// 초과된 이미지는 제외한 업로드 가능한 이미지
89+
const validImages = selectedImages.slice(0, additionalImagesNeeded);
90+
91+
// 미리보기 이미지 업데이트
92+
const newPreviewImages = [
93+
...(previewImages || []),
94+
...validImages.map((file) => URL.createObjectURL(file)),
95+
];
96+
97+
setPreviewImages(newPreviewImages);
98+
99+
// 총 이미지가 4개를 초과하려고 할 때 (토스트 메세지 보여지기 전)
100+
if (selectedImages.length > additionalImagesNeeded && !isToastShown) {
101+
showToast("사진 첨부는 최대 4장까지 가능해요.", {
102+
icon: true,
103+
close: false,
104+
bottom: "113px",
105+
});
106+
setIsToastShown(true);
107+
setIsButtonDisabled(false);
108+
}
101109

102110
const imageUrls: string[] = [];
103-
for (const file of selectedImages) {
111+
for (const file of validImages) {
104112
const compressedFile = await imageCompression(file, {
105-
maxSizeMB: 1,
106-
maxWidthOrHeight: 1024,
113+
maxSizeMB: 0.1,
114+
maxWidthOrHeight: 512,
107115
useWebWorker: true,
108116
});
117+
109118
try {
119+
setImageUploadLoading(true);
120+
110121
const response = await postImage(compressedFile);
111122
console.log("이미지 업로드 성공", response.data);
112123
imageUrls.push(response.data.imageUrl);
@@ -115,23 +126,51 @@ const LetterRegisterPage = () => {
115126
}
116127
}
117128
setImages((prevImages) => [...prevImages, ...imageUrls]);
129+
setImageUploadLoading(false);
130+
131+
setLetterState((prevState) => ({
132+
...prevState,
133+
images: [...(prevState.images || []), ...imageUrls],
134+
previewImages: newPreviewImages,
135+
}));
118136
}
119137
};
120138

121139
const handleDeleteImages = (id: number) => {
122-
if (images.length - 1 < 4) {
140+
const updatedImages = images.filter((_, index) => index !== id);
141+
const updatedPreviewImages = previewImages.filter(
142+
(_, index) => index !== id
143+
);
144+
145+
if (previewImages.length - 1 < 4) {
123146
setIsButtonDisabled(false);
124147
}
125-
setImages((prevImages) => prevImages.filter((_, index) => index !== id));
148+
149+
// 상태 업데이트
150+
setImages(updatedImages);
151+
setPreviewImages(updatedPreviewImages);
152+
153+
// setLetterState에 변경된 상태 반영
154+
setLetterState((prevState) => ({
155+
...prevState,
156+
images: updatedImages,
157+
previewImages: updatedPreviewImages,
158+
}));
126159
};
127160

128-
const handleAddNext = () => {
161+
useEffect(() => {
162+
console.log("images", images);
163+
console.log("previewImages", previewImages);
164+
}, [images, previewImages]);
165+
166+
const handleAddNext = async () => {
129167
/* 다음 페이지 */
130168
setLetterState((prevState) => ({
131169
...prevState,
132170
senderName: sender,
133171
content: content,
134172
images: images,
173+
previewImages: previewImages,
135174
}));
136175
if (letterId) {
137176
if (independent === "true") {
@@ -176,7 +215,7 @@ const LetterRegisterPage = () => {
176215
placeholder="최대 1000자까지 입력이 가능해요"
177216
height="228px"
178217
/>
179-
{images.length === 0 ? (
218+
{(previewImages || []).length === 0 ? (
180219
<AddImageLabel>
181220
<input
182221
type="file"
@@ -189,20 +228,22 @@ const LetterRegisterPage = () => {
189228
</AddImageLabel>
190229
) : (
191230
<ImagesList>
192-
<AddImagesLabel>
193-
<input
194-
type="file"
195-
accept="image/*"
196-
multiple
197-
onChange={handleAddImages}
198-
style={{ display: "none" }}
199-
disabled={isButtonDisabled}
200-
/>
231+
<AddImagesLabel onClick={handleShowToast}>
232+
{previewImages.length < 4 && (
233+
<input
234+
type="file"
235+
accept="image/*"
236+
multiple
237+
onChange={handleAddImages}
238+
style={{ display: "none" }}
239+
disabled={isButtonDisabled}
240+
/>
241+
)}
201242
+<br />
202-
{images.length}/4
243+
{previewImages.length}/4
203244
</AddImagesLabel>
204245
<ImagesWrapper>
205-
{images.map((image, index) => (
246+
{previewImages.map((image, index) => (
206247
<ImageDiv>
207248
<Image
208249
src={image}
@@ -229,8 +270,12 @@ const LetterRegisterPage = () => {
229270
<Button
230271
buttonType="primary"
231272
size="large"
232-
text="다음"
233-
disabled={!sender || (!content && images.length === 0)}
273+
text={isImageUploadLoading ? "Loading..." : "다음"}
274+
disabled={
275+
!sender ||
276+
(!content && previewImages?.length === 0) ||
277+
isImageUploadLoading
278+
}
234279
onClick={handleAddNext}
235280
/>
236281
</ButtonWrapper>

src/app/planet/add/page.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client";
22

3-
import React, { useEffect, useState } from "react";
3+
import React, { useState } from "react";
44
import styled from "styled-components";
55
import { theme } from "@/styles/theme";
66
import NavigatorBar from "@/components/common/NavigatorBar";
@@ -20,6 +20,12 @@ const PlanetAddPage = () => {
2020
setTemplateType(id);
2121
};
2222

23+
const handleChangePlanet = (value: string) => {
24+
if (value.length <= 10) {
25+
setPlanet(value);
26+
}
27+
};
28+
2329
const handleAddPlanet = async () => {
2430
/* 새 행성 추가하기 */
2531
try {
@@ -46,7 +52,7 @@ const PlanetAddPage = () => {
4652
<Input
4753
inputType="boxText"
4854
value={planet}
49-
onChange={setPlanet}
55+
onChange={handleChangePlanet}
5056
placeholder="최대 10자까지 입력할 수 있어요"
5157
/>
5258
<Add>내 스페이스에 {planet} 행성이 추가돼요</Add>

src/app/planet/page.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,15 @@ const PlanetPage = () => {
7070
senderName: "",
7171
content: "",
7272
images: [],
73+
previewImages: [],
7374
templateType: 0,
7475
});
7576
setSendState({
7677
draftId: null,
7778
receiverName: "",
7879
content: "",
7980
images: [] as string[],
81+
previewImages: [] as string[],
8082
templateType: 0,
8183
});
8284
}, []);

0 commit comments

Comments
 (0)