① Frontend
- 상품 생성 시 JSON 대신 FromData 형식으로 전달 (image 때문에)
const submitHandler = async (evt) => {
evt.preventDefault();
try {
const sendData = new FormData();
sendData.append('name', formData.name);
sendData.append('description', formData.description);
sendData.append('image', evt.target.image.files[0]);
sendData.append('category', formData.category);
sendData.append('price', formData.price);
sendData.append('stock', formData.stock);
await sendRequest(
process.env.REACT_APP_BACKEND_URL + '/products',
'POST',
sendData
/*JSON.stringify({
name: formData.name,
description: formData.description,
image: formData.image,
category: formData.category,
price: formData.price,
stock: formData.stock
}),
{
'Content-Type': 'application/json'
}*/
);
window.location.href = "/";
} catch (err) {
setIsError(true);
setErrorMessage(err.message);
}
};
- 상품 수정 시 기존 데이터를 useEffect로 넣기
useEffect(() => {
setFormData({
name: product?.name || "",
description: product?.description || "",
category: product?.category || "",
price: product?.price || 0,
stock: product?.stock || 0
});
}, [product]);
- Data를 불러올 때 useEffect안에 함수를 작성하여 불러오기
useEffect(() => {
const fetchProducts = async () => {
try {
const responseData = await sendRequest(
process.env.REACT_APP_BACKEND_URL + '/products'
);
setProducts(responseData.products);
} catch (err) {
setIsError(true);
setErrorMessage(err.message);
}
};
fetchProducts();
}, [sendRequest]);
② Backend
상품의 Image를 올리면 내부 파일에 저장되고 상품 삭제 시 같이 삭제되도록 함
- Image upload
const MIME_TYPE_MAP = {
'image/png': 'png',
'image/jpeg': 'jpeg',
'image/jpg': 'jpg'
};
const fileUpload = multer({
limits: 500000,
storage: multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads/images');
},
filename: (req, file, cb) => {
const ext = MIME_TYPE_MAP[file.mimetype];
cb(null, uuid() + '.' + ext);
}
}),
fileFilter: (req, file, cb) => {
const isValid = !!MIME_TYPE_MAP[file.mimetype];
let error = isValid ? null : new Error('Invalid mime type!');
cb(error, isValid);
}
});
- Controller
const getHomeProduct = async (req, res, next) => {
let products;
try {
products = await Product.find({});
} catch (err) {
const error = new Error('something went wrong');
error.code = 500;
return next(error);
}
res.status(200).json({products: products.map(product => product.toObject({ getters: true }))});
};
const getProduct = async (req, res, next) => {
const productId = req.params.pid;
let product;
try {
product = await Product.findById(productId);
} catch (err) {
const error = new Error('something went wrong');
error.code = 500;
return next(error);
}
if (!product) {
const error = new Error('can not find product');
error.code = 404;
return next(error);
}
res.status(200).json({ product: product.toObject({ getters: true }) });
};
const getCategory = async (req, res, next) => {
const categoryId = req.params.cid;
let products;
try {
products = await Product.find({category: categoryId});
} catch (err) {
const error = new Error('something went wrong');
error.code = 500;
return next(error);
}
if (!products || products.length === 0) {
const error = new Error('can not find product');
error.code = 404;
return next(error);
}
res.status(200).json({
products: products.map(product =>
product.toObject({ getters: true })
)
});
};
const createProduct = async (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
const error = new Error("Invalid inputs");
error.code = 422;
return next(error);
}
const { name, description, category, price, stock } = req.body;
const createdProduct = new Product({
name,
description,
category,
price,
stock,
image: process.env.BACKEND_URL + req.file.path,
review: []
});
try {
await createdProduct.save();
} catch (err) {
const error = new Error('something went wrong');
error.code = 500;
return next(error);
}
res.status(201).json({ product: createdProduct });
};
const editProduct = async (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
const error = new Error("Invalid inputs");
error.code = 422;
return next(error);
}
const { name, description, category, price, stock } = req.body;
const productId = req.params.pid;
let product;
try {
product = await Product.findById(productId);
} catch (err) {
const error = new Error('something went wrong');
error.code = 500;
return next(error);
}
product.name = name;
product.description = description;
product.category = category;
product.price = price;
product.stock = stock;
try {
await product.save();
} catch (err) {
const error = new Error('something went wrong');
error.code = 500;
return next(error);
}
res.status(200).json({ product: product.toObject({ getters: true }) });
};
const deleteProduct = async (req, res, next) => {
const productId = req.params.pid;
let product;
try {
product = await Product.findById(productId);
} catch (err) {
const error = new Error('something went wrong');
error.code = 500;
return next(error);
}
if (!product) {
const error = new Error('can not find product');
error.code = 404;
return next(error);
}
const imagePath = product.image.replace(process.env.BACKEND_URL, '');
try {
await product.deleteOne();
} catch (err) {
const error = new Error('something went wrong');
error.code = 500;
return next(error);
}
fs.unlink(imagePath, err => {
console.log(err);
});
res.status(200).json({ message: 'Delete product.' });
};
'쇼핑몰 구현 프로젝트' 카테고리의 다른 글
[쇼핑몰 구현 프로젝트] 08. 리뷰 관련 기능 (0) | 2024.06.23 |
---|---|
[쇼핑몰 구현 프로젝트] 07. 장바구니 관련 기능 (0) | 2024.06.23 |
[쇼핑몰 구현 프로젝트] 05. 회원가입/로그인 (0) | 2024.06.23 |
[쇼핑몰 구현 프로젝트] 04. Backend, Database 틀잡기 (0) | 2024.06.22 |
[쇼핑몰 구현 프로젝트] 03. Frontend 틀잡기 (0) | 2024.06.22 |