source: frontend/src/pages/Planner.jsx@ 2e0035f

Last change on this file since 2e0035f was 2e0035f, checked in by Acko <lavurovski.a65@…>, 8 days ago

Initial Commit

  • Property mode set to 100644
File size: 3.4 KB
RevLine 
[2e0035f]1import { useEffect, useState } from 'react'
2import { api } from '../lib/api.js'
3
4/** UseCase1002 - log a meal and see the daily totals. */
5export default function Planner() {
6 const [entries, setEntries] = useState([])
7 const [feed, setFeed] = useState([])
8 const [daily, setDaily] = useState([])
9 const [macros, setMacros] = useState([])
10 const [error, setError] = useState(null)
11 const [pick, setPick] = useState([])
12 const [notes, setNotes] = useState('')
13
14 const today = new Date().toISOString().slice(0, 10)
15 const weekAgo = new Date(Date.now() - 7 * 864e5).toISOString().slice(0, 10)
16
17 const load = () => {
18 api.get('/planner').then(setEntries).catch(e => setError(e.message))
19 api.get(`/planner/daily?from=${weekAgo}&to=${today}`).then(setDaily).catch(() => {})
20 api.get(`/planner/macros?from=${weekAgo}&to=${today}`).then(setMacros).catch(() => {})
21 }
22
23 useEffect(() => {
24 load()
25 api.get('/posts/feed').then(setFeed).catch(() => {})
26 }, [])
27
28 const log = async () => {
29 setError(null)
30 try {
31 await api.post('/planner', {
32 notes,
33 postIds: pick.map(Number),
34 consumed: true
35 })
36 setNotes('')
37 setPick([])
38 load()
39 } catch (e) { setError(e.message) }
40 }
41
42 return (
43 <div>
44 {error && <div className="error">{error}</div>}
45
46 <div className="card">
47 <h3>Log a meal</h3>
48 <div className="stack" style={{ maxWidth: 520 }}>
49 <input placeholder="notes, e.g. Lunch at home"
50 value={notes} onChange={e => setNotes(e.target.value)} />
51 <select multiple size={5} value={pick}
52 onChange={e => setPick(Array.from(e.target.selectedOptions, o => o.value))}>
53 {feed.map(p => (
54 <option key={p.id} value={p.id}>
55 {p.recipeName} — {p.kcalPerServing} kcal / portion
56 </option>
57 ))}
58 </select>
59 <span className="muted">One portion is counted per selected meal.</span>
60 <button className="primary" onClick={log}>Log it</button>
61 </div>
62 </div>
63
64 <div className="card">
65 <h3>Last 7 days</h3>
66 <table>
67 <thead><tr><th>day</th><th>kcal</th><th>meals</th></tr></thead>
68 <tbody>
69 {daily.map(d => (
70 <tr key={d.day}>
71 <td>{d.day}</td><td className="kcal">{d.kcalConsumed}</td><td>{d.mealsLogged}</td>
72 </tr>
73 ))}
74 </tbody>
75 </table>
76 {daily.length === 0 && <p className="muted">Nothing logged in the last week.</p>}
77 </div>
78
79 {macros.length > 0 && (
80 <div className="card">
81 <h3>Macronutrients supplied this week</h3>
82 <table>
83 <tbody>
84 {macros.map(m => (
85 <tr key={m.nutrient}><td>{m.nutrient}</td><td>{m.total} {m.unit}</td></tr>
86 ))}
87 </tbody>
88 </table>
89 </div>
90 )}
91
92 <div className="card">
93 <h3>Diary</h3>
94 <table>
95 <tbody>
96 {entries.map(e => (
97 <tr key={e.id}>
98 <td>{new Date(e.dateTime).toLocaleString()}</td>
99 <td>{e.notes}</td>
100 <td className="muted">{e.meals.join(', ')}</td>
101 <td className="kcal">{e.kcal}</td>
102 <td>{e.consumed ? 'eaten' : 'planned'}</td>
103 </tr>
104 ))}
105 </tbody>
106 </table>
107 </div>
108 </div>
109 )
110}
Note: See TracBrowser for help on using the repository browser.