diff --git a/src/components/_admin/products/editProduct.jsx b/src/components/_admin/products/editProduct.jsx
index d0d85ee..98cb0a8 100644
--- a/src/components/_admin/products/editProduct.jsx
+++ b/src/components/_admin/products/editProduct.jsx
@@ -29,6 +29,7 @@ export default function EditProduct({ brands, categories, slug, shops, isVendor
+
{isInitialized ? (
) : (
diff --git a/src/components/upload/UploadMultiFile.jsx b/src/components/upload/UploadMultiFile.jsx
index ec5c38d..83c64c5 100644
--- a/src/components/upload/UploadMultiFile.jsx
+++ b/src/components/upload/UploadMultiFile.jsx
@@ -39,10 +39,11 @@ UploadMultiFile.propTypes = {
isInitialized: PropTypes.bool.isRequired,
isEdit: PropTypes.bool.isRequired,
loading: PropTypes.bool.isRequired,
- onAnnotationsChange: PropTypes.func.isRequired
+ onAnnotationsChange: PropTypes.func.isRequired,
+ metaDescription: PropTypes.string
};
-export default function UploadMultiFile({ onAnnotationsChange, ...props }) {
+export default function UploadMultiFile({ onAnnotationsChange, metaDescription, ...props }) {
const { error, files, onRemove, blob, isEdit, onRemoveAll, loading, sx, ...other } = props;
const [modalOpen, setModalOpen] = useState(false);
@@ -53,6 +54,9 @@ export default function UploadMultiFile({ onAnnotationsChange, ...props }) {
const [image, setImage] = useState('');
const [predictions, setPredictions] = useState([]); // Roboflow 결과 저장
+ const [selectedAnnotation, setSelectedAnnotation] = useState(null);
+ const [editPrice, setEditPrice] = useState('');
+ const [showAnnotations, setShowAnnotations] = useState(false);
const canvasRef = useRef(null); // 캔버스 참조
const hasFile = files.length > 0;
const { getRootProps, getInputProps, isDragActive, isDragReject } = useDropzone({
@@ -80,40 +84,43 @@ export default function UploadMultiFile({ onAnnotationsChange, ...props }) {
const blob = await response.blob();
// API 호출
- const formData = new FormData();
- formData.append('file', blob);
- const apiEndpoint = `https://detect.roboflow.com/picup/1?api_key=s9OJq0UPljSqkPsJY6xP`;
+ if (!isEdit) {
+ const formData = new FormData();
+ formData.append('file', blob);
- try {
- const apiResponse = await fetch(apiEndpoint, {
- method: 'POST',
- body: formData
- });
+ const apiEndpoint = `https://detect.roboflow.com/picup/1?api_key=s9OJq0UPljSqkPsJY6xP`;
- const result = await apiResponse.json();
- console.log('Roboflow Predictions:', result);
-
- if (result.predictions) {
- setPredictions(result.predictions);
-
- // 바운딩 박스와 라벨 표시
- result.predictions.forEach((prediction) => {
- const { x, y, width, height, class: label, confidence } = prediction;
-
- // 바운딩 박스
- ctx.strokeStyle = 'red';
- ctx.lineWidth = 1;
- ctx.strokeRect(x - 50, y - 80, width, height);
-
- // 라벨
- ctx.fillStyle = 'red';
- ctx.font = '16px Arial';
- ctx.fillText(`${label} (${(confidence * 100).toFixed(2)}%)`, x - 50, y - 80 > 10 ? y - 5 : 10);
+ try {
+ const apiResponse = await fetch(apiEndpoint, {
+ method: 'POST',
+ body: formData
});
+
+ const result = await apiResponse.json();
+ console.log('Roboflow Predictions:', result);
+
+ if (result.predictions) {
+ setPredictions(result.predictions);
+
+ // 바운딩 박스와 라벨 표시
+ result.predictions.forEach((prediction) => {
+ const { x, y, width, height, class: label, confidence } = prediction;
+
+ // 바운딩 박스
+ ctx.strokeStyle = 'red';
+ ctx.lineWidth = 1;
+ ctx.strokeRect(x - 50, y - 80, width, height);
+
+ // 라벨
+ ctx.fillStyle = 'red';
+ ctx.font = '16px Arial';
+ ctx.fillText(`${label} (${(confidence * 100).toFixed(2)}%)`, x - 50, y - 80 > 10 ? y - 5 : 10);
+ });
+ }
+ } catch (error) {
+ console.error('Error detecting objects:', error);
}
- } catch (error) {
- console.error('Error detecting objects:', error);
}
};
};
@@ -121,6 +128,7 @@ export default function UploadMultiFile({ onAnnotationsChange, ...props }) {
// AI 상품 검출 트리거
const objectDetect = () => {
detectWithRoboflow();
+ setShowAnnotations(true);
};
// 캔버스 클릭 시 실행되는 핸들러
@@ -133,30 +141,40 @@ export default function UploadMultiFile({ onAnnotationsChange, ...props }) {
setPriceModalOpen(true); // 금액 입력 모달 열기
};
- // 금액 입력 후 저장
- // const handleSavePrice = () => {
- // const updatedAnnotations = [...annotations, { x: clientPosition.x, y: clientPosition.y, price }];
- // setAnnotations(updatedAnnotations);
- // setPriceModalOpen(false); // 모달 닫기
- // setPrice(''); // 입력 초기화
-
- // if (onAnnotationsChange) {
- // onAnnotationsChange(updatedAnnotations); // 부모 컴포넌트에 알림
- // }
-
- // };
-
const handleSavePrice = () => {
- const newId = annotations.length > 0 ? annotations[annotations.length - 1].id + 1 : 1;
+ if (selectedAnnotation) {
+ const updatedAnnotations = annotations.map((ann) =>
+ ann.id === selectedAnnotation.id ? { ...ann, price: editPrice } : ann
+ );
+ setAnnotations(updatedAnnotations);
+ } else {
+ const newId = annotations.length > 0 ? annotations[annotations.length - 1].id + 1 : 1;
+ const updatedAnnotations = [...annotations, { id: newId, x: clientPosition.x, y: clientPosition.y, price }];
+ setAnnotations(updatedAnnotations);
+ }
- const updatedAnnotations = [...annotations, { id: newId, x: clientPosition.x, y: clientPosition.y, price }];
+ setPriceModalOpen(false);
+ setPrice('');
+ setSelectedAnnotation(null);
+ if (onAnnotationsChange) {
+ onAnnotationsChange(annotations);
+ }
+ };
+ const handleEditAnnotation = (annotation) => {
+ setSelectedAnnotation(annotation);
+ setEditPrice(annotation.price);
+ setPriceModalOpen(true);
+ };
+
+ const handleDeleteAnnotation = (id) => {
+ const updatedAnnotations = annotations.filter((ann) => ann.id !== id);
setAnnotations(updatedAnnotations);
- setPriceModalOpen(false); // 모달 닫기
- setPrice(''); // 입력 초기화
+ setPriceModalOpen(false);
+ setSelectedAnnotation(null);
if (onAnnotationsChange) {
- onAnnotationsChange(updatedAnnotations); // 부모 컴포넌트에 알림
+ onAnnotationsChange(updatedAnnotations);
}
};
@@ -166,6 +184,21 @@ export default function UploadMultiFile({ onAnnotationsChange, ...props }) {
}
}, [annotations, onAnnotationsChange, other.metaDescription]);
+ useEffect(() => {
+ if (metaDescription) {
+ try {
+ const parsedAnnotations = JSON.parse(metaDescription);
+ setAnnotations(parsedAnnotations);
+ } catch (error) {
+ console.error('Failed to parse metaDescription:', error);
+ }
+ }
+ }, [metaDescription]);
+
+
+ console.log(showAnnotations)
+
+
return (
{
setModalOpen(true);
- setImage(file.url);
+ if (isEdit) {
+ setImage(files[0].url);
+ } else {
+ setImage(file.url);
+ }
}}
src={!file.blob ? file.url : file.blob}
sx={{
@@ -271,6 +308,7 @@ export default function UploadMultiFile({ onAnnotationsChange, ...props }) {
sx={{ position: 'absolute;', right: 0, top: 0 }}
onClick={() => {
setModalOpen(false);
+ setShowAnnotations(false);
setImage('');
}}
>
@@ -280,7 +318,7 @@ export default function UploadMultiFile({ onAnnotationsChange, ...props }) {
sx={{ position: 'absolute', bottom: 0, left: '50%', transform: 'translate(-50%, -30px)' }}
onClick={() => objectDetect()}
>
- AI 상품 검출
+ {isEdit ? '상품 보기' : 'AI 상품 검출 '}
{/* 금액 입력 모달 */}
setPriceModalOpen(false)}>
@@ -300,14 +338,27 @@ export default function UploadMultiFile({ onAnnotationsChange, ...props }) {
Enter Price
setPrice(e.target.value)}
+ value={editPrice || price}
+ onChange={(e) => {
+ isEdit ? setEditPrice(e.target.value) : setPrice(e.target.value);
+ }}
placeholder="Enter price"
style={{ padding: '8px', borderRadius: '4px', border: '1px solid #ddd' }}
/>
-
+
+
+ {selectedAnnotation && (
+
+ )}
+