Skip to content

Commit 770d5b7

Browse files
author
bu2000
committed
냉장고에 수기 방식으로 재료 등록 백앤드 프런트 완료
1 parent 28feac3 commit 770d5b7

8 files changed

Lines changed: 1007 additions & 565 deletions

File tree

.screen-graph.json

Lines changed: 352 additions & 208 deletions
Large diffs are not rendered by default.
Lines changed: 104 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,142 +1,133 @@
1-
import React, { useState } from "react";
1+
import React, { useState, useEffect } from "react";
22
import "./style.css";
33

4-
// 카테고리 상수는 제거하거나, 백엔드 전송용으로 내부에서만 기본값 처리하면 됩니다.
4+
const DEFAULT_IMAGE_URL =
5+
"https://c.animaapp.com/sjWITF5i/img/ingredientimage-7@2x.png";
56

6-
export const AddIngredientPopup = ({ onClose, onAdd }) => {
7-
const [isReceiptProcessed, setIsReceiptProcessed] = useState(false);
8-
const [items, setItems] = useState([]);
7+
export const AddIngredientPopup = ({ onClose, onAdd, items }) => {
8+
const [editingItems, setEditingItems] = useState([]);
99

10-
// 1단계: 영수증 분석 시뮬레이션
11-
const handleAnalyzeReceipt = (e) => {
12-
e.preventDefault();
13-
console.log("영수증 분석 시작...");
10+
useEffect(() => {
11+
const today = new Date().toISOString().split("T")[0];
1412

15-
const mockAnalyzedData = [
16-
{ id: 1, name: "양파", expiryDays: 7 },
17-
{ id: 2, name: "삼겹살", expiryDays: 3 },
18-
{ id: 3, name: "우유", expiryDays: 10 },
19-
{ id: 4, name: "종량제봉투", expiryDays: 0 },
20-
];
21-
22-
setItems(mockAnalyzedData);
23-
setIsReceiptProcessed(true);
24-
};
13+
if (items && items.length > 0) {
14+
const initializedItems = items.map((item) => ({
15+
...item,
16+
purchaseDate: item.purchaseDate
17+
? item.purchaseDate.split("T")[0]
18+
: today,
19+
expiredDate: item.expiredDate ? item.expiredDate.split("T")[0] : "",
20+
image: item.image || DEFAULT_IMAGE_URL,
21+
}));
22+
setEditingItems(initializedItems);
23+
}
24+
}, [items]);
2525

2626
const handleItemChange = (id, field, value) => {
27-
setItems(items.map(item =>
28-
item.id === id ? { ...item, [field]: value } : item
29-
));
27+
setEditingItems((prev) =>
28+
prev.map((item) => (item.id === id ? { ...item, [field]: value } : item))
29+
);
3030
};
3131

3232
const handleDeleteItem = (id) => {
33-
setItems(items.filter(item => item.id !== id));
34-
};
35-
36-
const handleAddItem = () => {
37-
const newItem = {
38-
id: Date.now(),
39-
name: "",
40-
expiryDays: ""
41-
};
42-
setItems([...items, newItem]);
33+
setEditingItems((prev) => prev.filter((item) => item.id !== id));
4334
};
4435

4536
const handleFinalSubmit = () => {
46-
const isValid = items.every(item => item.name && item.expiryDays !== "");
37+
const isValid = editingItems.every(
38+
(item) => item.name && item.purchaseDate && item.expiredDate
39+
);
40+
4741
if (!isValid) {
48-
alert("모든 재료의 정보를 입력해주세요.");
42+
alert("모든 재료의 이름, 구매일자, 유통기한을 입력해주세요.");
4943
return;
5044
}
5145

52-
items.forEach(item => {
53-
onAdd({
54-
...item,
55-
category: "기타", // 백엔드에서 필요하다면 기본값으로 '기타'나 '미분류' 전송
56-
expiryDays: parseInt(item.expiryDays),
57-
image: "https://c.animaapp.com/sjWITF5i/img/ingredientimage-7@2x.png"
58-
});
59-
});
46+
if (editingItems.length === 0) {
47+
alert("등록할 재료가 없습니다.");
48+
return;
49+
}
6050

61-
onClose();
51+
onAdd(editingItems);
6252
};
6353

6454
return (
6555
<div className="add-ingredient-popup-overlay" onClick={onClose}>
66-
<div className="add-ingredient-popup-container" onClick={(e) => e.stopPropagation()}>
67-
<button className="add-ingredient-popup-close" onClick={onClose}>×</button>
68-
56+
<div
57+
className="add-ingredient-popup-container"
58+
onClick={(e) => e.stopPropagation()}
59+
>
60+
<button className="add-ingredient-popup-close" onClick={onClose}>
61+
×
62+
</button>
63+
6964
<div className="add-ingredient-popup-header">
70-
<h2 className="add-ingredient-popup-title">
71-
{isReceiptProcessed ? "분석 결과 확인" : "영수증 등록"}
72-
</h2>
65+
<h2 className="add-ingredient-popup-title">재료 확인 및 수정</h2>
66+
<p style={{ color: "#666", marginTop: "5px", fontSize: "14px" }}>
67+
자동 계산된 유통기한을 확인하고 필요하면 수정해주세요.
68+
</p>
7369
</div>
7470

75-
{!isReceiptProcessed ? (
76-
<form className="add-ingredient-popup-form" onSubmit={handleAnalyzeReceipt}>
77-
<div className="add-ingredient-popup-input-group">
78-
<label className="add-ingredient-popup-label">영수증 업로드</label>
79-
<input
80-
type="file"
81-
className="add-ingredient-popup-input file-input"
82-
accept="image/*"
83-
required
84-
/>
85-
<p className="helper-text">선명한 영수증 사진을 올려주세요.</p>
86-
</div>
87-
<button type="submit" className="add-ingredient-popup-submit-btn">
88-
분석 시작
89-
</button>
90-
</form>
91-
) : (
92-
<div className="processed-list-container">
93-
{/* 카테고리 헤더 삭제 */}
94-
<div className="processed-list-header">
95-
<span style={{ flex: 3 }}>재료명</span>
96-
<span style={{ flex: 1, textAlign: 'center' }}>기한(일)</span>
97-
<span style={{ width: '28px' }}></span> {/* 삭제버튼 자리 */}
98-
</div>
99-
100-
<div className="processed-list-body">
101-
{items.map((item) => (
102-
<div key={item.id} className="processed-item-row">
103-
{/* 카테고리 Select 삭제, 이름 입력창 확장 */}
104-
<input
105-
type="text"
106-
className="item-input name-input"
107-
value={item.name}
108-
onChange={(e) => handleItemChange(item.id, "name", e.target.value)}
109-
placeholder="재료명"
110-
/>
111-
112-
<input
113-
type="number"
114-
className="item-input date-input"
115-
value={item.expiryDays}
116-
onChange={(e) => handleItemChange(item.id, "expiryDays", e.target.value)}
117-
placeholder="일"
118-
/>
119-
<button
120-
className="item-delete-btn"
121-
onClick={() => handleDeleteItem(item.id)}
122-
title="삭제"
123-
>
124-
125-
</button>
126-
</div>
127-
))}
128-
129-
<button className="add-row-btn" onClick={handleAddItem}>
130-
+ 직접 추가하기
131-
</button>
132-
</div>
133-
134-
<button onClick={handleFinalSubmit} className="add-ingredient-popup-submit-btn">
135-
{items.length}개 재료 등록하기
136-
</button>
71+
<div className="processed-list-container">
72+
<div className="processed-list-header">
73+
<span style={{ flex: 1.5 }}>재료명</span>
74+
<span style={{ flex: 1.2, textAlign: "center" }}>구매일자</span>
75+
<span style={{ flex: 1.2, textAlign: "center" }}>유통기한</span>
76+
<span style={{ width: "30px" }}></span>
13777
</div>
138-
)}
78+
79+
<div className="processed-list-body">
80+
{editingItems.map((item) => (
81+
<div key={item.id} className="processed-item-row">
82+
<input
83+
type="text"
84+
className="item-input name-input"
85+
value={item.name}
86+
onChange={(e) =>
87+
handleItemChange(item.id, "name", e.target.value)
88+
}
89+
placeholder="재료명"
90+
/>
91+
92+
<input
93+
type="date"
94+
className="item-input date-input"
95+
value={item.purchaseDate}
96+
onChange={(e) =>
97+
handleItemChange(item.id, "purchaseDate", e.target.value)
98+
}
99+
/>
100+
101+
<input
102+
type="date"
103+
className="item-input date-input"
104+
value={item.expiredDate}
105+
onChange={(e) =>
106+
handleItemChange(item.id, "expiredDate", e.target.value)
107+
}
108+
/>
109+
110+
<button
111+
className="item-delete-btn"
112+
onClick={() => handleDeleteItem(item.id)}
113+
title="삭제"
114+
>
115+
116+
</button>
117+
</div>
118+
))}
119+
</div>
120+
121+
<button
122+
onClick={handleFinalSubmit}
123+
className="add-ingredient-popup-submit-btn"
124+
>
125+
{editingItems.length}개 재료 저장하기
126+
</button>
127+
</div>
139128
</div>
140129
</div>
141130
);
142-
};
131+
};
132+
133+
export default AddIngredientPopup;

0 commit comments

Comments
 (0)