source: frontend/src/pages/Grocery.jsx

Last change on this file was 98cd519, checked in by Acko <lavurovski.a65@…>, 17 hours ago

Shema update + project push

  • Property mode set to 100644
File size: 4.0 KB
RevLine 
[2e0035f]1import { useEffect, useState } from 'react'
2import { api } from '../lib/api.js'
3
4export default function Grocery() {
5 const [lists, setLists] = useState([])
6 const [recipes, setRecipes] = useState([])
7 const [catalog, setCatalog] = useState([])
8 const [open, setOpen] = useState(null)
9 const [error, setError] = useState(null)
10 const [notes, setNotes] = useState('')
11 const [bulk, setBulk] = useState([])
12 const [item, setItem] = useState({ ingredientName: '', buyQuantity: '' })
13
14 const load = () => api.get('/grocery-lists').then(setLists).catch(e => setError(e.message))
15
16 useEffect(() => {
17 load()
18 api.get('/recipes').then(setRecipes).catch(() => {})
19 api.get('/catalog/ingredients').then(setCatalog).catch(() => {})
20 }, [])
21
22 const create = async () => {
23 setError(null)
24 try {
25 const created = await api.post('/grocery-lists', {
26 notes,
27 bulkRecipeIds: bulk.map(Number),
28 singleItems: item.ingredientName && item.buyQuantity
29 ? [{ ingredientName: item.ingredientName, buyQuantity: Number(item.buyQuantity) }]
30 : []
31 })
32 setOpen(created)
33 setNotes(''); setBulk([]); setItem({ ingredientName: '', buyQuantity: '' })
34 load()
35 } catch (e) { setError(e.message) }
36 }
37
38 return (
39 <div>
40 {error && <div className="error">{error}</div>}
41
42 <div className="card">
43 <h3>New grocery list</h3>
44 <div className="stack" style={{ maxWidth: 520 }}>
45 <input placeholder="notes" value={notes} onChange={e => setNotes(e.target.value)} />
46 <span className="muted">Add whole recipes:</span>
47 <select multiple size={5} value={bulk}
48 onChange={e => setBulk(Array.from(e.target.selectedOptions, o => o.value))}>
49 {recipes.map(r => <option key={r.id} value={r.id}>{r.name}</option>)}
50 </select>
51 <span className="muted">Plus one item on its own:</span>
52 <div className="row">
53 <select style={{ flex: 1 }} value={item.ingredientName}
54 onChange={e => setItem({ ...item, ingredientName: e.target.value })}>
55 <option value="">— ingredient —</option>
56 {catalog.map(c => <option key={c.name} value={c.name}>{c.name}</option>)}
57 </select>
58 <input type="number" placeholder="grams" style={{ width: 110 }}
59 value={item.buyQuantity}
60 onChange={e => setItem({ ...item, buyQuantity: e.target.value })} />
61 </div>
62 <button className="primary" onClick={create}>Create list</button>
63 </div>
64 </div>
65
66 {open && (
67 <div className="card">
68 <h3>Shopping list #{open.id}</h3>
69 <div className="muted">
70 {open.notes} · total <span className="kcal">{open.kcal} kcal</span>
71 {open.bulkRecipes.length > 0 && <> · from: {open.bulkRecipes.join(', ')}</>}
72 </div>
73 <table>
74 <thead><tr><th>category</th><th>ingredient</th><th>grams</th></tr></thead>
75 <tbody>
76 {open.shoppingLines.map(l => (
77 <tr key={l.ingredient}>
78 <td className="muted">{l.category}</td>
79 <td>{l.ingredient}</td>
80 <td>{l.totalGrams}</td>
81 </tr>
82 ))}
83 </tbody>
84 </table>
85 </div>
86 )}
87
88 <div className="card">
89 <h3>My lists</h3>
90 <table>
91 <tbody>
92 {lists.map(l => (
93 <tr key={l.id}>
94 <td>{new Date(l.dateTime).toLocaleDateString()}</td>
95 <td>{l.notes}</td>
96 <td className="kcal">{l.kcal} kcal</td>
97 <td>{l.bought ? 'bought' : 'open'}</td>
98 <td style={{ width: 1 }}>
99 <button className="small" onClick={() => api.get(`/grocery-lists/${l.id}`).then(setOpen)}>
100 open
101 </button>
102 </td>
103 </tr>
104 ))}
105 </tbody>
106 </table>
107 </div>
108 </div>
109 )
110}
Note: See TracBrowser for help on using the repository browser.