diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 8a39d5e..919eace 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -30,11 +30,9 @@ dependencies:
specifier: ^8.9.2
version: 8.9.2
react:
- specifier: ^18.2.0
specifier: ^18.2.0
version: 18.2.0
react-dom:
- specifier: ^18.2.0
specifier: ^18.2.0
version: 18.2.0(react@18.2.0)
react-icons:
diff --git a/src/api/service.ts b/src/api/service.ts
index a693548..3200d1a 100644
--- a/src/api/service.ts
+++ b/src/api/service.ts
@@ -32,7 +32,7 @@ export const postProducts = async (
formData.append('title', title);
formData.append('categoryName', categoryName);
formData.append('content', content);
- formData.append('price', price.toString());
+ formData.append('price', price);
// 여러 이미지를 처리하는 경우
if (images) {
@@ -51,11 +51,47 @@ export const deleteProducts = async (id: number) => {
return res;
};
+// 상품수정
+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;
+};
+
export const getProductCategory = async () => {
const res = await client.get(`/products/categories`);
return res.data;
};
+// 상품정보 불러오기
export const getProducts = async (searchWord?: string, category?: string) => {
const res = await client.get('/products?pageSize=100', {
params: {
diff --git a/src/app/product/[id]/edit/page.tsx b/src/app/product/[id]/edit/page.tsx
new file mode 100644
index 0000000..4464d90
--- /dev/null
+++ b/src/app/product/[id]/edit/page.tsx
@@ -0,0 +1,9 @@
+import ProductPut from '@/templates/product/productPut';
+
+export default function Page() {
+ return (
+ <>
+
+ >
+ );
+}
diff --git a/src/templates/product/productDetail.tsx b/src/templates/product/productDetail.tsx
index 796598e..3ed12c2 100644
--- a/src/templates/product/productDetail.tsx
+++ b/src/templates/product/productDetail.tsx
@@ -19,6 +19,7 @@ import 'slick-carousel/slick/slick-theme.css';
import 'slick-carousel/slick/slick.css';
import ProductDelete from './productDelete';
+import ProductPut from './productPut';
type Seller = {
sellerId: number;
@@ -173,9 +174,10 @@ export const ProductDetail = () => {
role="button"
ref={menuRef}
className="product-detail__menu">
-
router.push('/product/edit')}>
+
router.push(`/product/${id}/edit`)}>
게시글 수정
+
삭제
)}
diff --git a/src/templates/product/productPut.tsx b/src/templates/product/productPut.tsx
new file mode 100644
index 0000000..a81951c
--- /dev/null
+++ b/src/templates/product/productPut.tsx
@@ -0,0 +1,236 @@
+'use client';
+
+import '@/styles/templates/write/write.scss';
+import Header from '@/components/header';
+import { useState, useEffect } from 'react';
+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 { AXIOSResponse } from '@/types/interface';
+
+export default function ProductPut() {
+ const [title, setTitle] = useState('');
+ const [category, setCategory] = useState('');
+ const [content, setContent] = useState('');
+ const [price, setPrice] = useState('');
+ const [isModal, setIsModal] = useState(false);
+ const [imgFiles, setImgFiles] = useState([]);
+
+ type Product = {
+ id: number;
+ title: string;
+ price: string;
+ categoryName: string;
+ content: string;
+ images: string[];
+ status: string;
+ likes: number;
+ myProduct: boolean;
+ seller: Seller;
+ sellerProductInfos: sellerProductInfos[];
+ like: boolean;
+ };
+
+ const router = useRouter();
+ const id = parseInt(usePathname().split('/')[2]);
+
+ // const urlToFile = async (
+ // url: string,
+ // filename: string,
+ // mimeType: string,
+ // ): Promise => {
+ // const res = await fetch(url, { mode: 'no-cors' });
+ // const blob = await res.blob();
+ // return new File([blob], filename, { type: mimeType });
+ // };
+
+ useEffect(() => {
+ const fetchData = async () => {
+ try {
+ const res: AXIOSResponse = 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}`;
+ };
+
+ const toggleModal = () => {
+ setIsModal(!isModal);
+ };
+
+ const handleSelectCategory = (selectedCategory: string) => {
+ setCategory(selectedCategory);
+ };
+
+ // console.log('imgFiles', imgFiles);
+ const { imageArray, images, removeImage, handleImageChange } =
+ useHandleImg(imgFiles);
+
+ const handleEdit = async () => {
+ try {
+ if (images) {
+ const res = await putProducts(
+ id,
+ title,
+ category,
+ content,
+ price,
+ images,
+ );
+ if (res.data.statusCode === 200) {
+ router.push('/main');
+ console.log('수정완료');
+ } else {
+ console.error('Post failed:', res);
+ }
+ }
+ } catch (error: any) {
+ if (error.response) {
+ const errorData = error.response?.data;
+ console.error('Post failed:', errorData);
+ } else {
+ console.error('An unexpected error occurred:', error);
+ }
+ }
+ };
+
+ const imgCount = imageArray?.length;
+
+ return (
+ <>
+ 임시저장}
+ />
+
+ >
+ );
+}
diff --git a/src/templates/write/useHandleImg.ts b/src/templates/write/useHandleImg.ts
index f510794..faa1bde 100644
--- a/src/templates/write/useHandleImg.ts
+++ b/src/templates/write/useHandleImg.ts
@@ -1,22 +1,67 @@
import { useState, useEffect } from 'react';
-export const useHandleImg = () => {
- const [imageArray, setImageArray] = useState([]);
+async function urlToFile(
+ url: string,
+ filename: string,
+ mimeType: string,
+): Promise {
+ 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 => {
+// 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(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);