Skip to content

Commit

Permalink
Feat: 게시물수정 API 수정필요
Browse files Browse the repository at this point in the history
  • Loading branch information
LeHiHo committed Oct 24, 2023
1 parent 08f8a1d commit 8054388
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 67 deletions.
33 changes: 31 additions & 2 deletions src/api/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,37 @@ export const deleteProducts = async (id: number) => {
};

// 상품수정
export const putProducts = async (id: number) => {
const res = await client.put(`products/${id}`);
export const putProducts = async (
id: number,
title: string,
categoryName: string,
content: string,
price: string,
images?: FileList | string[] | null,
) => {
const formData = new FormData();
formData.append('title', title);
formData.append('categoryName', categoryName);
formData.append('content', content);
formData.append('price', price);

// 여러 이미지를 처리하는 경우
if (images) {
for (let i = 0; i < images.length; i++) {
formData.append('images', images[i]);
}
}

const config = {
headers: {
'Content-Type': 'multipart/form-data',
},
params: {
productId: id,
},
};

const res = await client.put(`products/${id}`, formData, config);
return res;
};

Expand Down
122 changes: 62 additions & 60 deletions src/templates/product/productPut.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@
import '@/styles/templates/write/write.scss';
import Header from '@/components/header';
import { useState, useEffect } from 'react';
import { postProducts } from '@/api/service';
import { putProducts, getProductDetail } from '@/api/service';
import CategoryModal from '@/templates/write/categoryModal';
import { useHandleImg } from '@/templates/write/useHandleImg';
import Btn from '@/components/btn';
import { useRouter, usePathname } from 'next/navigation';
import { getProductDetail } from '@/api/service';
import { AXIOSResponse } from '@/types/interface';

export default function ProductPut() {
Expand All @@ -17,13 +16,12 @@ export default function ProductPut() {
const [content, setContent] = useState<string>('');
const [price, setPrice] = useState<string>('');
const [isModal, setIsModal] = useState<boolean>(false);
const [product, setProduct] = useState<Product | null>(null);
const [initialFiles, setInitialFiles] = useState<File[]>([]);
const [imgFiles, setImgFiles] = useState<File[] | string[]>([]);

type Product = {
id: number;
title: string;
price: number;
price: string;
categoryName: string;
content: string;
images: string[];
Expand All @@ -36,56 +34,54 @@ export default function ProductPut() {
};

const router = useRouter();

const id = parseInt(usePathname().split('/')[2]);
console.log(id);

const urlToFile = async (
url: string,
filename: string,
mimeType: string,
): Promise<File> => {
const res = await fetch(url);
const blob = await res.blob();
return new File([blob], filename, { type: mimeType });
};

const handleEdit = async () => {
try {
const res: AXIOSResponse<Product> = await getProductDetail(id);
if (res.statusCode === 200) {
setProduct(res.data);
const imageUrls = res.data.images;
console.log(imageUrls);
const files = await Promise.all(
imageUrls.map((url) => urlToFile(url, 'filename', 'image/*')), // filename과 mimeType은 적절하게 설정
);
setInitialFiles(files);
} else {
console.error('get failed:', res);
}
} catch (error: any) {
if (error.res) {
const errorData = error.res?.data;
console.error('get failed:', errorData);
} else {
console.error('An unexpected error occurred:', error);
}
}
};

useEffect(() => {
handleEdit();
}, []);
// const urlToFile = async (
// url: string,
// filename: string,
// mimeType: string,
// ): Promise<File> => {
// const res = await fetch(url, { mode: 'no-cors' });
// const blob = await res.blob();
// return new File([blob], filename, { type: mimeType });
// };

useEffect(() => {
if (product) {
setTitle(product.title || '');
setCategory(product.categoryName || '');
setContent(product.content || '');
setPrice(product.price ? String(product.price) : '');
}
}, [product]);
const fetchData = async () => {
try {
const res: AXIOSResponse<Product> = await getProductDetail(id);
if (res.statusCode === 200) {
const {
title = '',
categoryName = '',
content = '',
price = '',
} = res.data;

setTitle(title);
setCategory(categoryName);
setContent(content);
setPrice(price);
const imageUrls = res.data.images; // 먼저 images를 가져온다
setImgFiles(imageUrls);
// if (imageUrls) {
// const files = await Promise.all(
// imageUrls.map((url) => urlToFile(url, 'filename', 'image/*')), // filename과 mimeType은 적절하게 설정
// );
// setImgFiles(files);
// }
}
} catch (error: any) {
if (error.res) {
const errorData = error.res?.data;
console.error('get failed:', errorData);
} else {
console.error('An unexpected error occurred:', error);
}
}
};
fetchData();
}, [id]);

const generateUniqueId = (image: File, index: number): string => {
return `${image.lastModified}-${image.name}-${index}`;
Expand All @@ -99,24 +95,26 @@ export default function ProductPut() {
setCategory(selectedCategory);
};

// console.log('imgFiles', imgFiles);
const { imageArray, images, removeImage, handleImageChange } =
useHandleImg(initialFiles);
useHandleImg(imgFiles);

const handleWrite = async () => {
const handleEdit = async () => {
try {
if (images) {
const response = await postProducts(
const res = await putProducts(
id,
title,
category,
content,
price,
images,
);
if (response.data.statusCode === 200) {
if (res.data.statusCode === 200) {
router.push('/main');
console.log('Post success', response);
console.log('수정완료');
} else {
console.error('Post failed:', response);
console.error('Post failed:', res);
}
}
} catch (error: any) {
Expand Down Expand Up @@ -157,12 +155,16 @@ export default function ProductPut() {
multiple
/>
</label>
{imageArray.map((image, index) => (
{imageArray.map((image: any, index: number) => (
<div
className="previewImg-item"
key={generateUniqueId(image, index)}>
<img
src={URL.createObjectURL(image)}
src={
image instanceof Blob || image instanceof File
? URL.createObjectURL(image)
: image
}
alt={`Uploaded ${index}`}
/>
<div className="x_btn" onClick={() => removeImage(index)}>
Expand Down Expand Up @@ -224,7 +226,7 @@ export default function ProductPut() {
<Btn
type="button"
disabled={!title || !category || !content || !price || !images}
onClick={handleWrite}
onClick={handleEdit}
label="작성완료"
/>
</footer>
Expand Down
54 changes: 49 additions & 5 deletions src/templates/write/useHandleImg.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,67 @@
import { useState, useEffect } from 'react';

export const useHandleImg = (initialFiles?: File[]) => {
// const [imageArray, setImageArray] = useState<File[]>([]);
const [imageArray, setImageArray] = useState<File[]>(initialFiles || []);
async function urlToFile(
url: string,
filename: string,
mimeType: string,
): Promise<File> {
const res = await fetch(url, { mode: 'no-cors' });
const buf = await res.arrayBuffer();
return new File([buf], filename, { type: mimeType });
}

// const urlToFile = async (
// url: string,
// filename: string,
// mimeType: string,
// ): Promise<File> => {
// const res = await fetch(url, { mode: 'no-cors' });
// const blob = await res.blob();
// return new File([blob], filename, { type: mimeType });
// };

export const useHandleImg = (initialFiles?: (File | string)[]) => {
const [imageArray, setImageArray] = useState<(File | string)[]>(
initialFiles || [],
);
const [images, setImages] = useState<FileList | null>(null);

useEffect(() => {
if (initialFiles) {
const filePromises = initialFiles.map(async (item, index) => {
if (typeof item === 'string') {
return urlToFile(item, `file-${index}.jpg`, 'image/jpeg');
}
return item;
});

Promise.all(filePromises).then((files) => {
setImageArray(files);
});
}
}, [initialFiles]);

useEffect(() => {
if (imageArray.length === 0) {
setImages(null);
return;
}

const fileArray = imageArray.filter(
(item): item is File => item instanceof File,
);

const dataTransfer = new DataTransfer();
imageArray.forEach((file) => dataTransfer.items.add(file));
fileArray.forEach((file) => dataTransfer.items.add(file));
setImages(dataTransfer.files);
}, [imageArray]);

const removeImage = (index: number) => {
URL.revokeObjectURL(URL.createObjectURL(imageArray[index]));
const target = imageArray[index];
if (target instanceof File) {
URL.revokeObjectURL(URL.createObjectURL(target));
}

const updatedImages = [...imageArray];
updatedImages.splice(index, 1);
setImageArray(updatedImages);
Expand Down

0 comments on commit 8054388

Please sign in to comment.