diff --git a/src/pages/WriteEdit/WriteEdit.page.tsx b/src/pages/WriteEdit/WriteEdit.page.tsx index 373fdc2..8050474 100644 --- a/src/pages/WriteEdit/WriteEdit.page.tsx +++ b/src/pages/WriteEdit/WriteEdit.page.tsx @@ -28,9 +28,11 @@ import TitleAndIntroduceSection from './components/TitleAndIntroduceSection'; import UpdateImages from './components/UpdateImages'; import { usePutIdea } from './hooks/mutations/usePutIdea'; import { useWritingEditInfoQuery } from './hooks/queries/useWritingInfoQuery'; -import { ImageResponse, Info, PutFormData } from './types'; +import { AddedImage, ImageResponse, Info, PutFormData } from './types'; import { get2DepthCountsBy1Depth } from './utils/get2DepthCountsBy1Depth'; +type ImageType = AddedImage | ImageResponse; + const WriteEditPage = () => { const openAlert = useAlert(); const location = useLocation(); @@ -42,11 +44,7 @@ const WriteEditPage = () => { const [title, setTitle] = useState(ideaDetail.title); const [introduce, setIntroduce] = useState(ideaDetail.introduce); const [isOpenBottomSheet, setIsOpenBottomSheet] = useState(false); - const [images, setImages] = useState(ideaDetail.imageResponses); // 서버에서 받아온거 화면 보여주는용 - const [imageFiles, setImageFiles] = useState([]); // 새롭게 수정해서 올린거 서버에 보낼거 - const [notDeletedImageIds, setNotDeletedImageIds] = useState( - ideaDetail.imageResponses.map((image) => image.id), - ); // images 에서 삭제되지 않은 id를 기록해서 서버로 보낼거 + const [images, setImages] = useState(ideaDetail.imageResponses); const [selectedTeamRecruitment1Depth, setSelectedTeamRecruitment1Depth] = useState(skillCategoryResponses[0].name); const [selectedSkillResponses, setSelectedSkillResponses] = useState( skillCategoryResponses @@ -105,6 +103,9 @@ const WriteEditPage = () => { const formData = new FormData(); + const alreadyUploadedImages = images.filter((image) => image.id > 0) as ImageResponse[]; + const justUploadedImages = images.filter((image) => image.id < 0) as AddedImage[]; + const userData = { title, introduce, @@ -113,10 +114,10 @@ const WriteEditPage = () => { branchIds: selectedCheckboxId.branches, purposeIds: selectedCheckboxId.purposes, skillCategoryIds: selectedSkillResponses.map((selectedSkillResponse) => selectedSkillResponse.id), - imageIds: notDeletedImageIds, + imageIds: alreadyUploadedImages.map((image) => image.id), }; - imageFiles.forEach((imageFile) => { + justUploadedImages.forEach(({ imageFile }) => { formData.append('images', imageFile); }); @@ -153,22 +154,14 @@ const WriteEditPage = () => { setSelectedSkillResponses((prev) => prev.filter((item) => item.id !== id)); }; - const addImages = (addedImages: File[]) => { - setImageFiles([...imageFiles, ...addedImages]); + const addImages = (addedImages: AddedImage[]) => { + setImages([...images, ...addedImages]); }; - // server 에서 기존에 있던 이미지 제거 시 - const deleteImage = (id: number) => { - const filteredImages = images.filter((image) => image.id !== id); - const filteredImageIds = filteredImages.map((image) => image.id); + const deleteImages = (id: number) => { + const deletedImages = images.filter((image) => image.id !== id); - setImages(filteredImages); - setNotDeletedImageIds(filteredImageIds); - }; - - // client 에서 새롭게 추가한 이미지 제거 시 - const deleteImageFiles = (index: number) => { - setImageFiles(imageFiles.filter((_, idx) => idx + notDeletedImageIds.length !== index)); + setImages(deletedImages); }; return ( @@ -185,13 +178,7 @@ const WriteEditPage = () => { - + diff --git a/src/pages/WriteEdit/components/UpdateImages.tsx b/src/pages/WriteEdit/components/UpdateImages.tsx index c3a3ad5..ebdfe03 100644 --- a/src/pages/WriteEdit/components/UpdateImages.tsx +++ b/src/pages/WriteEdit/components/UpdateImages.tsx @@ -1,46 +1,29 @@ import styled from '@emotion/styled'; import { Box, Flex, SVGCancel, theme } from 'concept-be-design-system'; -import { useState } from 'react'; import useAlert from '../../../hooks/useAlert'; import useCompressImage from '../../Write/hooks/useCompressImage'; -import { ImageResponse } from '../types'; +import { AddedImage, ImageResponse } from '../types'; -interface Props { - images: ImageResponse[]; - imageFiles: File[]; - onAddImages: (images: File[]) => void; - onDeleteImage: (id: number) => void; // 서버에 있는 이미지 - onDeleteImageFiles: (index: number) => void; // 클라이언트에서 추가한 이미지 -} +type ImageType = AddedImage | ImageResponse; -type ImageUrls = - | { - id: number; - ideaId: number; - imageUrl: string; - } - | string; - -interface DeleteProps { - id?: number; - index: number; - imageUrl: string; +interface Props { + images: ImageType[]; + onAddImages: (images: AddedImage[]) => void; + onDeleteImage: (id: number) => void; } -const FROM_SERVER_IMAGE = 'cloudfront'; +let CLIENT_IMAGE_ADJUST_VALUE = -1; -// let addId = -1; - -const UpdateImages = ({ images, imageFiles, onAddImages, onDeleteImage, onDeleteImageFiles }: Props) => { +const UpdateImages = ({ images, onAddImages, onDeleteImage }: Props) => { const openAlert = useAlert(); const { compressImages } = useCompressImage(); - const [imageUrls, setImageUrls] = useState(images); - const onChangeImage = async (e: React.ChangeEvent) => { + const onClickAddImage = async (e: React.ChangeEvent) => { const imageFileList = e.target.files; if (!imageFileList) return; - if (images.length + imageFiles.length + imageFileList.length > 3) { + + if (images.length + imageFileList.length > 3) { openAlert({ content: '이미지는 최대 3개까지 업로드 가능합니다.' }); } @@ -48,70 +31,42 @@ const UpdateImages = ({ images, imageFiles, onAddImages, onDeleteImage, onDelete const compressedImages = await compressImages(updatedImages); const imageObjectUrls = compressedImages.map((image) => URL.createObjectURL(image)); - onAddImages(compressedImages); - setImageUrls([...imageUrls, ...imageObjectUrls]); - }; + const willAddedImages = compressedImages.map((image, idx) => ({ + id: CLIENT_IMAGE_ADJUST_VALUE--, + imageUrl: imageObjectUrls[idx], + imageFile: image, + })); - const onClickDeleteImage = ({ id, index, imageUrl }: DeleteProps) => { - if (imageUrl.includes(FROM_SERVER_IMAGE) && id) { - onDeleteImage(id); - setImageUrls(imageUrls.filter((_, idx) => idx !== index)); - return; - } + onAddImages(willAddedImages); + }; - onDeleteImageFiles(index); - setImageUrls(imageUrls.filter((_, idx) => idx !== index)); + const onClickDeleteImage = (id: number) => { + onDeleteImage(id); }; return ( + - - {imageUrls.map((image, index) => { - if (typeof image === 'string') { - return ( - - - onClickDeleteImage({ index, imageUrl: image })} /> - - {`이미지 - - ); - } - - return ( - - - onClickDeleteImage({ id: image.id, index, imageUrl: image.imageUrl })} - /> - - {`이미지 - - ); - })} + + {images.map(({ id, imageUrl }, index) => ( + onClickDeleteImage(id)}> + + + + {`이미지 + + ))} ); diff --git a/src/pages/WriteEdit/types/index.ts b/src/pages/WriteEdit/types/index.ts index 87a600c..6f95ad8 100644 --- a/src/pages/WriteEdit/types/index.ts +++ b/src/pages/WriteEdit/types/index.ts @@ -44,6 +44,12 @@ export interface ImageResponse { imageUrl: string; } +export interface AddedImage { + id: number; + imageUrl: string; + imageFile: File; +} + export type IdeaDetail = { imageUrl: string; nickname: string;