Skip to content

Commit 461bcc2

Browse files
committed
설문조사 및 재료 추가 폼 수정
1 parent 28ba77e commit 461bcc2

7 files changed

Lines changed: 241 additions & 97 deletions

File tree

package-lock.json

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"dependencies": {
1212
"react": "^18.2.0",
1313
"react-dom": "^18.2.0",
14+
"react-icons": "^5.5.0",
1415
"react-router-dom": "^6.8.1"
1516
},
1617
"devDependencies": {

src/components/AddIngredientPopup/AddIngredientPopup.jsx

Lines changed: 66 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,27 @@ export const AddIngredientPopup = ({ onClose, onAdd }) => {
77
const [name, setName] = useState("");
88
const [category, setCategory] = useState("채소류");
99
const [expiryDays, setExpiryDays] = useState("");
10+
11+
// 영수증 분석(1단계) 완료 여부를 체크하는 상태
12+
const [isReceiptProcessed, setIsReceiptProcessed] = useState(false);
1013

1114
const handleSubmit = (e) => {
1215
e.preventDefault();
16+
17+
// 1단계: 영수증 등록 버튼을 눌렀을 때 (아직 분석 결과가 안 나왔을 때)
18+
if (!isReceiptProcessed) {
19+
// TODO: 백엔드로 영수증 이미지를 보내고 분석 결과를 받아오는 로직이 들어갈 자리
20+
console.log("영수증 분석 시작...");
21+
22+
// [가상 시나리오] 백엔드에서 분석된 결과가 자동으로 채워진다고 가정
23+
// setName("분석된 양파");
24+
// setExpiryDays("7");
25+
26+
setIsReceiptProcessed(true); // 입력 필드를 보여주도록 상태 변경
27+
return;
28+
}
1329

30+
// 2단계: 최종 등록 버튼을 눌렀을 때
1431
if (!name || !expiryDays) {
1532
alert("모든 필드를 입력해주세요.");
1633
return;
@@ -36,54 +53,69 @@ export const AddIngredientPopup = ({ onClose, onAdd }) => {
3653
<button className="add-ingredient-popup-close" onClick={onClose}>×</button>
3754

3855
<div className="add-ingredient-popup-header">
39-
<h2 className="add-ingredient-popup-title">식재료 추가</h2>
56+
<h2 className="add-ingredient-popup-title">영수증 등록</h2>
4057
</div>
4158

4259
<form className="add-ingredient-popup-form" onSubmit={handleSubmit}>
4360
<div className="add-ingredient-popup-input-group">
44-
<label className="add-ingredient-popup-label">식재료 이름</label>
61+
<label className="add-ingredient-popup-label">영수증</label>
4562
<input
46-
type="text"
63+
type="file"
4764
className="add-ingredient-popup-input"
48-
value={name}
49-
onChange={(e) => setName(e.target.value)}
50-
placeholder="예: 양파"
51-
required
65+
required={!isReceiptProcessed} // 분석 전에는 필수 입력
66+
disabled={isReceiptProcessed} // 분석 후에는 수정 불가 (선택 사항)
5267
/>
5368
</div>
69+
70+
{/* isReceiptProcessed가 true일 때만 아래 내용 표시 백앤드에서 분석한 결과 표시해주는 곳 사용자 확인용 마음에 안들면 여기서 수정가능 */}
71+
{isReceiptProcessed && (
72+
<>
73+
<div className="add-ingredient-popup-input-group">
74+
<label className="add-ingredient-popup-label">재료명</label>
75+
<input
76+
type="text"
77+
className="add-ingredient-popup-input"
78+
value={name}
79+
onChange={(e) => setName(e.target.value)}
80+
placeholder="예: 양파"
81+
required
82+
/>
83+
</div>
5484

55-
<div className="add-ingredient-popup-input-group">
56-
<label className="add-ingredient-popup-label">카테고리</label>
57-
<select
58-
className="add-ingredient-popup-select"
59-
value={category}
60-
onChange={(e) => setCategory(e.target.value)}
61-
required
62-
>
63-
{CATEGORIES.map((cat) => (
64-
<option key={cat} value={cat}>{cat}</option>
65-
))}
66-
</select>
67-
</div>
85+
<div className="add-ingredient-popup-input-group">
86+
<label className="add-ingredient-popup-label">카테고리</label>
87+
<select
88+
className="add-ingredient-popup-select"
89+
value={category}
90+
onChange={(e) => setCategory(e.target.value)}
91+
required
92+
>
93+
{CATEGORIES.map((cat) => (
94+
<option key={cat} value={cat}>{cat}</option>
95+
))}
96+
</select>
97+
</div>
6898

69-
<div className="add-ingredient-popup-input-group">
70-
<label className="add-ingredient-popup-label">유통기한 (일)</label>
71-
<input
72-
type="number"
73-
className="add-ingredient-popup-input"
74-
value={expiryDays}
75-
onChange={(e) => setExpiryDays(e.target.value)}
76-
placeholder="예: 7"
77-
min="1"
78-
required
79-
/>
80-
</div>
99+
<div className="add-ingredient-popup-input-group">
100+
<label className="add-ingredient-popup-label">유통기한 (일)</label>
101+
<input
102+
type="number"
103+
className="add-ingredient-popup-input"
104+
value={expiryDays}
105+
onChange={(e) => setExpiryDays(e.target.value)}
106+
placeholder="예: 7"
107+
min="1"
108+
required
109+
/>
110+
</div>
111+
</>
112+
)}
81113

82114
<button type="submit" className="add-ingredient-popup-submit-btn">
83-
추가하기
115+
{isReceiptProcessed ? "최종 등록" : "추가하기"}
84116
</button>
85117
</form>
86118
</div>
87119
</div>
88120
);
89-
};
121+
};

src/components/PreferencesPopup/PreferencesPopup.jsx

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,15 @@ import "./style.css";
44
const HEALTH_GOALS = [
55
{ id: 1, name: "체중 감량" },
66
{ id: 2, name: "근육 증가" },
7-
{ id: 3, name: "건강 유지" },
8-
{ id: 4, name: "면역력 강화" },
9-
{ id: 5, name: "소화 개선" },
7+
{ id: 3, name: "체중 유지" },
8+
{ id: 4, name: "저염 식단" },
9+
{ id: 5, name: "혈압 관리" },
10+
{ id: 6, name: "당뇨 관리" },
11+
{ id: 7, name: "콜레스테롤 관리" },
12+
{ id: 8, name: "채식(비건)" },
13+
{ id: 9, name: "채식(락토-오보)" },
14+
{ id: 10, name: "임산부 식단" },
15+
{ id: 11, name: "키토제닉 (고지방 저탄수화물)" },
1016
];
1117

1218
const ALLERGIES = [
@@ -19,7 +25,7 @@ const ALLERGIES = [
1925
{ id: 7, name: "대두" },
2026
];
2127

22-
const SPICE_LEVELS = ["안매움", "약간매움", "매움", "아주매움"];
28+
const SPICE_LEVELS = ["안매움", "보통", "매움"];
2329
const CUISINE_TYPES = ["한식", "중식", "일식", "양식", "기타"];
2430

2531
export const PreferencesPopup = ({ onClose, userData }) => {
@@ -45,6 +51,12 @@ export const PreferencesPopup = ({ onClose, userData }) => {
4551
);
4652
};
4753

54+
const toggleCuisine = (cuisine) => {
55+
setPreferredCuisine((prev) =>
56+
prev.includes(cuisine) ? prev.filter((item) => item !== cuisine) : [...prev, cuisine]
57+
);
58+
};
59+
4860
const handleSubmit = (e) => {
4961
e.preventDefault();
5062

@@ -143,21 +155,22 @@ export const PreferencesPopup = ({ onClose, userData }) => {
143155
/>
144156
</div>
145157

146-
<div className="preferences-popup-input-group">
147-
<label className="preferences-popup-label">선호 요리</label>
148-
<select
149-
className="preferences-popup-select"
150-
value={preferredCuisine}
151-
onChange={(e) => setPreferredCuisine(e.target.value)}
152-
required
153-
>
154-
<option value="">선택하세요</option>
158+
<div className="preferences-popup-section">
159+
<label className="preferences-popup-section-label">선호 요리 (다중 선택)</label>
160+
161+
{/* 중요: chips 클래스로 감싸야 가로로 배치됩니다 */}
162+
<div className="preferences-popup-chips">
155163
{CUISINE_TYPES.map((cuisine) => (
156-
<option key={cuisine} value={cuisine}>
164+
<button
165+
key={cuisine}
166+
type="button"
167+
className={`preferences-chip ${preferredCuisine.includes(cuisine) ? "active" : ""}`}
168+
onClick={() => toggleCuisine(cuisine)}
169+
>
157170
{cuisine}
158-
</option>
171+
</button>
159172
))}
160-
</select>
173+
</div>
161174
</div>
162175

163176
<div className="preferences-popup-input-group">

src/screens/AddIngredientPage/AddIngredientPage.jsx

Lines changed: 51 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import React, { useState, useEffect } from "react";
2-
import { Link, useNavigate } from "react-router-dom"; // Removed useLocation
1+
import React, { useState, useRef } from "react";
2+
import { Link, useNavigate } from "react-router-dom";
33
import { UnifiedHeader } from "../../components/UnifiedHeader";
4+
import { BiSolidRightArrow, BiSolidLeftArrow } from "react-icons/bi";
45
import "./style.css";
56

67
const CATEGORIES = ["전체", "육류", "채소류", "가공류", "유제품", "기타"];
78

89
const MOCK_INGREDIENT_DATABASE = [
9-
// TODO: Backend Integration: Replace with API call to fetch all available ingredients from DB
1010
{ id: 1, name: "양파", category: "채소류", image: "https://c.animaapp.com/sjWITF5i/img/ingredientimage-1.png" },
1111
{ id: 2, name: "닭고기", category: "육류", image: "https://c.animaapp.com/sjWITF5i/img/ingredientimage-7@2x.png" },
1212
{ id: 3, name: "돼지고기", category: "육류", image: "https://c.animaapp.com/sjWITF5i/img/ingredientimage-7@2x.png" },
@@ -27,9 +27,7 @@ const MOCK_INGREDIENT_DATABASE = [
2727

2828
export const AddIngredientPage = () => {
2929
const navigate = useNavigate();
30-
// Removed useLocation and onAddMultipleIngredients here
31-
// const location = useLocation();
32-
// const onAddMultipleIngredients = location.state?.onAddMultipleIngredients;
30+
const scrollRef = useRef(null); // 스크롤 DOM 제어
3331

3432
const [selectedCategory, setSelectedCategory] = useState("전체");
3533
const [searchQuery, setSearchQuery] = useState("");
@@ -47,7 +45,7 @@ export const AddIngredientPage = () => {
4745
if (exists) {
4846
return prev.filter((item) => item.id !== ingredient.id);
4947
} else {
50-
return [...prev, { ...ingredient, expiryDays: 7 }]; // Default expiry days
48+
return [...prev, { ...ingredient, expiryDays: 7 }];
5149
}
5250
});
5351
};
@@ -58,15 +56,23 @@ export const AddIngredientPage = () => {
5856
return;
5957
}
6058

61-
// Directly update localStorage for userIngredients
6259
const currentIngredients = JSON.parse(localStorage.getItem("userIngredients") || "[]");
6360
const updatedIngredients = [...currentIngredients, ...selectedIngredients];
6461
localStorage.setItem("userIngredients", JSON.stringify(updatedIngredients));
65-
66-
// TODO: Backend Integration: Send selectedIngredients to backend
67-
console.log("Adding ingredients to mock DB:", selectedIngredients);
6862

69-
navigate("/desktop"); // Navigate back to desktop
63+
navigate("/desktop");
64+
};
65+
66+
const scroll = (direction) => {
67+
if (scrollRef.current) {
68+
const { current } = scrollRef;
69+
const scrollAmount = 300;
70+
if (direction === "left") {
71+
current.scrollBy({ left: -scrollAmount, behavior: "smooth" });
72+
} else {
73+
current.scrollBy({ left: scrollAmount, behavior: "smooth" });
74+
}
75+
}
7076
};
7177

7278
return (
@@ -101,28 +107,38 @@ export const AddIngredientPage = () => {
101107
))}
102108
</div>
103109

104-
<div className="add-ingredient-grid">
105-
{filteredIngredients.map((ingredient) => {
106-
const isSelected = selectedIngredients.find((item) => item.id === ingredient.id);
107-
return (
108-
<button
109-
key={ingredient.id}
110-
className={`add-ingredient-card ${isSelected ? "selected" : ""}`}
111-
onClick={() => toggleIngredient(ingredient)}
112-
>
113-
<img
114-
src={ingredient.image}
115-
alt={ingredient.name}
116-
className="add-ingredient-card-image"
117-
/>
118-
<div className="add-ingredient-card-name">{ingredient.name}</div>
119-
<div className="add-ingredient-card-category">{ingredient.category}</div>
120-
{isSelected && (
121-
<div className="add-ingredient-card-check"></div>
122-
)}
123-
</button>
124-
);
125-
})}
110+
<div className="add-ingredient-grid-wrapper">
111+
<button className="scroll-arrow-btn left" onClick={() => scroll("left")}>
112+
<BiSolidLeftArrow />
113+
</button>
114+
115+
<div className="add-ingredient-grid" ref={scrollRef}>
116+
{filteredIngredients.map((ingredient) => {
117+
const isSelected = selectedIngredients.find((item) => item.id === ingredient.id);
118+
return (
119+
<button
120+
key={ingredient.id}
121+
className={`add-ingredient-card ${isSelected ? "selected" : ""}`}
122+
onClick={() => toggleIngredient(ingredient)}
123+
>
124+
<img
125+
src={ingredient.image}
126+
alt={ingredient.name}
127+
className="add-ingredient-card-image"
128+
/>
129+
<div className="add-ingredient-card-name">{ingredient.name}</div>
130+
<div className="add-ingredient-card-category">{ingredient.category}</div>
131+
{isSelected && (
132+
<div className="add-ingredient-card-check"></div>
133+
)}
134+
</button>
135+
);
136+
})}
137+
</div>
138+
139+
<button className="scroll-arrow-btn right" onClick={() => scroll("right")}>
140+
<BiSolidRightArrow />
141+
</button>
126142
</div>
127143

128144
<div className="add-ingredient-footer">
@@ -145,4 +161,4 @@ export const AddIngredientPage = () => {
145161
</div>
146162
</div>
147163
);
148-
};
164+
};

0 commit comments

Comments
 (0)