feat: reports, timeline toggles, and stock correction improvements (#236)

* refactor(frontend): modularize styles and polish modal/ui interactions

* feat: add report workflow and timeline/settings improvements

* fix: resolve CI failures for backend typing, lint, and playwright config
This commit is contained in:
Daniel Volz
2026-02-20 18:52:59 +01:00
committed by GitHub
parent 89d565bc9d
commit 052751b2ba
74 changed files with 8815 additions and 4027 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+16 -6
View File
@@ -192,8 +192,12 @@ export function SchedulePage() {
<div key={dose.id} className="dose-item past">
<span className="dose-time">{dose.timeStr}</span>
<span className="dose-usage">
{dose.usage} {dose.usage !== 1 ? t("common.pills") : t("common.pill")}
{med?.pillWeightMg && ` (${dose.usage * med.pillWeightMg} ${med.doseUnit ?? "mg"})`}
<span className="dose-usage-main">
{dose.usage} {dose.usage !== 1 ? t("common.pills") : t("common.pill")}
</span>
{med?.pillWeightMg && (
<span className="dose-usage-weight">{`${dose.usage * med.pillWeightMg} ${med.doseUnit ?? "mg"}`}</span>
)}
</span>{" "}
{dose.intakeRemindersEnabled && (
<span
@@ -235,7 +239,8 @@ export function SchedulePage() {
disabled={isEmpty}
title={t("dose.markAsTaken")}
>
<span className="dose-btn-label">{t("dose.take")}</span>
<span aria-hidden="true"></span>
</button>
)}
</div>
@@ -348,8 +353,12 @@ export function SchedulePage() {
<div key={dose.id} className="dose-item">
<span className="dose-time">{dose.timeStr}</span>
<span className="dose-usage">
{dose.usage} {dose.usage !== 1 ? t("common.pills") : t("common.pill")}
{med?.pillWeightMg && ` (${dose.usage * med.pillWeightMg} ${med.doseUnit ?? "mg"})`}
<span className="dose-usage-main">
{dose.usage} {dose.usage !== 1 ? t("common.pills") : t("common.pill")}
</span>
{med?.pillWeightMg && (
<span className="dose-usage-weight">{`${dose.usage * med.pillWeightMg} ${med.doseUnit ?? "mg"}`}</span>
)}
</span>
{dose.intakeRemindersEnabled && (
<span
@@ -395,7 +404,8 @@ export function SchedulePage() {
disabled={isEmpty}
title={t("dose.markAsTaken")}
>
<span className="dose-btn-label">{t("dose.take")}</span>
<span aria-hidden="true"></span>
</button>
)}
</div>
+71 -2
View File
@@ -34,7 +34,6 @@ export function SettingsPage() {
} = useAppContext();
const hasExistingData = meds.length > 0;
return (
<section className="grid">
{settingsLoading ? (
@@ -674,8 +673,62 @@ export function SettingsPage() {
<p className="threshold-validation-error">{t("settings.stock.thresholdValidation")}</p>
)}
</div>
</article>
{/* General UI */}
<article className="card">
<div className="card-head">
<h2>{t("settings.timeline.title")}</h2>
</div>
<div className="setting-section">
<div className="section-header">
<h3>{t("settings.timeline.dashboardSectionOrder")}</h3>
</div>
<div className="setting-row compact">
<div className="setting-label">
<span>{t("settings.timeline.swapDashboardSections")}</span>
<span className="info-tooltip small" data-tooltip={t("settings.timeline.swapDashboardSectionsDesc")}>
</span>
</div>
<label className="toggle-switch small">
<input
type="checkbox"
checked={settings.swapDashboardMainSections}
onChange={(e) => setSettings({ ...settings, swapDashboardMainSections: e.target.checked })}
/>
<span className="toggle-slider"></span>
</label>
</div>
</div>
<div className="setting-section">
<div className="section-header">
<h3>{t("settings.timeline.upcomingSection")}</h3>
</div>
<div className="setting-row compact">
<div className="setting-label">
<span>{t("settings.timeline.upcomingTodayOnly")}</span>
<span className="info-tooltip small" data-tooltip={t("settings.timeline.upcomingTodayOnlyDesc")}>
</span>
</div>
<label className="toggle-switch small">
<input
type="checkbox"
checked={settings.upcomingTodayOnly}
onChange={(e) => setSettings({ ...settings, upcomingTodayOnly: e.target.checked })}
/>
<span className="toggle-slider"></span>
</label>
</div>
</div>
<div className="setting-section">
<div className="section-header">
<h3>{t("settings.timeline.sharedSection")}</h3>
</div>
<div className="setting-row compact">
<div className="setting-label">
<span>{t("settings.stock.shareStockStatus")}</span>
@@ -692,6 +745,22 @@ export function SettingsPage() {
<span className="toggle-slider"></span>
</label>
</div>
<div className="setting-row compact" style={{ marginTop: "10px" }}>
<div className="setting-label">
<span>{t("settings.timeline.shareScheduleTodayOnly")}</span>
<span className="info-tooltip small" data-tooltip={t("settings.timeline.shareScheduleTodayOnlyDesc")}>
</span>
</div>
<label className="toggle-switch small">
<input
type="checkbox"
checked={settings.shareScheduleTodayOnly}
onChange={(e) => setSettings({ ...settings, shareScheduleTodayOnly: e.target.checked })}
/>
<span className="toggle-slider"></span>
</label>
</div>
</div>
</article>
@@ -737,6 +806,7 @@ export function SettingsPage() {
<button
type="button"
onClick={() => setImportResult(null)}
aria-label={t("common.close")}
style={{
background: "none",
border: "none",
@@ -747,7 +817,6 @@ export function SettingsPage() {
color: "inherit",
opacity: 0.7,
}}
aria-label="Close"
>
×
</button>