feat(web): Phase 3b — medication/health/interactions feature UIs

Build the three core feature UIs on top of the now-wired stores + corrected API
client from Phase 3a, turning the runnable shell into a usable app.

Dashboard (pages/Dashboard.tsx): AppBar (Normogen + username + logout) over an
MUI Tabs container (Medications | Health | Interactions), widened to lg. User
loads on mount (needed for profile_id in medication create).

MedicationManager (components/medication/): full CRUD.
* List of medication cards (name, dosage·frequency, active chip, instructions)
  with edit/delete actions and an empty state.
* Create dialog: name/dosage/frequency/route(select)/instructions. profile_id
  sourced from user.profile_id with a 'default' fallback (TODO: real profiles).
  Payload typed to CreateMedicationRequest.
* Edit dialog (UpdateMedicationRequest shape) + delete confirm. Guards the
  optional medication_id field.

HealthStats (components/health/): trend cards + chart + add + table.
* Trend summary cards from /health-stats/trends (avg/min/max + trend arrow).
* recharts LineChart of a selected stat type over measured_at, with a type
  selector. Timestamp field is measured_at (not timestamp).
* Record dialog (stat_type/value/unit/measured_at/notes) + recent-readings table
  (date-fns formatted).

InteractionsChecker (components/interactions/): multi-select medication names
(chips) -> POST /interactions/check. Results rendered as cards with a
SeverityChip, description, and disclaimer. Success/empty states.

Shared SeverityChip (components/common/): maps InteractionSeverity ->
MUI Chip color (severe=error, moderate=warning, mild=success, unknown=default).

Added @mui/icons-material@7 (pinned to match @mui/material 7; npm tried to grab
v9 which needs material ^9).

Verified: npm run build clean (TS5 strict), dev server serves the app + all
component modules transform. Solaria round-trip confirmed every contract the UIs
call: medication create/list (200), interactions warfarin+aspirin -> severe,
health-stat create (201).
This commit is contained in:
goose 2026-06-28 04:31:16 -03:00
parent ef1bb9f4be
commit 1515923996
7 changed files with 886 additions and 60 deletions

View file

@ -10,6 +10,7 @@
"dependencies": {
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@mui/icons-material": "^7.3.11",
"@mui/material": "^7.3.9",
"@mui/x-charts": "^8.27.4",
"axios": "^1.13.6",
@ -1127,26 +1128,52 @@
}
},
"node_modules/@mui/core-downloads-tracker": {
"version": "7.3.9",
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.9.tgz",
"integrity": "sha512-MOkOCTfbMJwLshlBCKJ59V2F/uaLYfmKnN76kksj6jlGUVdI25A9Hzs08m+zjBRdLv+sK7Rqdsefe8X7h/6PCw==",
"version": "7.3.11",
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.11.tgz",
"integrity": "sha512-a7I/b/nBTdXYz2cOSlEmkQ9WWE1x8FHpqMhFPp+Y1VPFxcOw91G5ELOHARQAGSPy5V+UCgJua6K/1x70bAtQPw==",
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
}
},
"node_modules/@mui/icons-material": {
"version": "7.3.11",
"resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-7.3.11.tgz",
"integrity": "sha512-+hz5ilwHZ3djd5es3sCErLioqe/NhZcYTsV/TNXZAMdJdb23F4xzJjqnnZdnurc3S1+ietcssRNqieOhPQLZ7Q==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.28.6"
},
"engines": {
"node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui-org"
},
"peerDependencies": {
"@mui/material": "^7.3.11",
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/material": {
"version": "7.3.9",
"resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.9.tgz",
"integrity": "sha512-I8yO3t4T0y7bvDiR1qhIN6iBWZOTBfVOnmLlM7K6h3dx5YX2a7rnkuXzc2UkZaqhxY9NgTnEbdPlokR1RxCNRQ==",
"version": "7.3.11",
"resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.11.tgz",
"integrity": "sha512-yq8bPc3LxOwKRWpcjRgDkYFmpM6aKlARfESTmOQcvLYFeJwtHte2tw6hJDrb8sk8wcvpDprHEHVaoUU0MslIkw==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.28.6",
"@mui/core-downloads-tracker": "^7.3.9",
"@mui/system": "^7.3.9",
"@mui/core-downloads-tracker": "^7.3.11",
"@mui/system": "^7.3.11",
"@mui/types": "^7.4.12",
"@mui/utils": "^7.3.9",
"@mui/utils": "^7.3.11",
"@popperjs/core": "^2.11.8",
"@types/react-transition-group": "^4.4.12",
"clsx": "^2.1.1",
@ -1165,7 +1192,7 @@
"peerDependencies": {
"@emotion/react": "^11.5.0",
"@emotion/styled": "^11.3.0",
"@mui/material-pigment-css": "^7.3.9",
"@mui/material-pigment-css": "^7.3.11",
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
@ -1192,13 +1219,13 @@
"license": "MIT"
},
"node_modules/@mui/private-theming": {
"version": "7.3.9",
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.3.9.tgz",
"integrity": "sha512-ErIyRQvsiQEq7Yvcvfw9UDHngaqjMy9P3JDPnRAaKG5qhpl2C4tX/W1S4zJvpu+feihmZJStjIyvnv6KDbIrlw==",
"version": "7.3.11",
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.3.11.tgz",
"integrity": "sha512-9B+YKms0fRHbNrqp9tOT/DNbNnU5gyvJ1o3qAGXfq8GmZcbJnE3At9x07Zr/o0pkhzg4aDdwXVqe4+AcgtOCPA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.28.6",
"@mui/utils": "^7.3.9",
"@mui/utils": "^7.3.11",
"prop-types": "^15.8.1"
},
"engines": {
@ -1219,9 +1246,9 @@
}
},
"node_modules/@mui/styled-engine": {
"version": "7.3.9",
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.3.9.tgz",
"integrity": "sha512-JqujWt5bX4okjUPGpVof/7pvgClqh7HvIbsIBIOOlCh2u3wG/Bwp4+E1bc1dXSwkrkp9WUAoNdI5HEC+5HKvMw==",
"version": "7.3.10",
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.3.10.tgz",
"integrity": "sha512-WxE9SiF8xskAQqGjsp0poXCkCqsoXFEsSr0HBXfApmGHR+DBnXRp+z46Vsltg4gpPM4Z96DeAQRpeAOnhNg7Ng==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.28.6",
@ -1253,16 +1280,16 @@
}
},
"node_modules/@mui/system": {
"version": "7.3.9",
"resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.9.tgz",
"integrity": "sha512-aL1q9am8XpRrSabv9qWf5RHhJICJql34wnrc1nz0MuOglPRYF/liN+c8VqZdTvUn9qg+ZjRVbKf4sJVFfIDtmg==",
"version": "7.3.11",
"resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.11.tgz",
"integrity": "sha512-7izwGWdNawAKpBKcRlx7f2gFnAAjmASBWvMcyX4YYEeLOFsbfGRbUYGInvnAcUeql3rPxI7F9Ft4oY2OLRz44g==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.28.6",
"@mui/private-theming": "^7.3.9",
"@mui/styled-engine": "^7.3.9",
"@mui/private-theming": "^7.3.11",
"@mui/styled-engine": "^7.3.10",
"@mui/types": "^7.4.12",
"@mui/utils": "^7.3.9",
"@mui/utils": "^7.3.11",
"clsx": "^2.1.1",
"csstype": "^3.2.3",
"prop-types": "^15.8.1"
@ -1310,9 +1337,9 @@
}
},
"node_modules/@mui/utils": {
"version": "7.3.9",
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.9.tgz",
"integrity": "sha512-U6SdZaGbfb65fqTsH3V5oJdFj9uYwyLE2WVuNvmbggTSDBb8QHrFsqY8BN3taK9t3yJ8/BPHD/kNvLNyjwM7Yw==",
"version": "7.3.11",
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.11.tgz",
"integrity": "sha512-XTjGnifwteg71/ij+0e7Y7d+hwyntMYP5wPoA/g2drdGH+Flkvjwy0OfrVpKBbaOvofq4zU/LIyUZyKgmWu18g==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.28.6",