1- import React , { useState } from "react" ;
1+ import React , { useState , useEffect } from "react" ;
22import "./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