Fix bugs, add auto-refresh, quick-complete tasks, and every-N-day routines

- Fix bot auth: merge duplicate on_ready handlers so session restore runs (#13)
- Fix push notifications: pass Uint8Array directly as applicationServerKey (#6)
- Show specific conflict reason on schedule save instead of generic error (#17)
- Add inline checkmark button to complete tasks on routines timeline (#18)
- Add visibility-change + 60s polling auto-refresh to routines, meds, tasks (#15)
- Add every-N-day routine scheduling: schema, API, scheduler, and UI (#16)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-19 19:04:52 -06:00
parent 24a1d18b25
commit ecb79af44e
10 changed files with 288 additions and 96 deletions

View File

@@ -91,24 +91,36 @@ export default function MedicationsPage() {
const [isLoading, setIsLoading] = useState(true);
const [tick, setTick] = useState(0);
const fetchData = async () => {
try {
const [medsData, todayData, adherenceData] = await Promise.all([
api.medications.list(),
api.medications.getToday().catch(() => []),
api.medications.getAdherence(30).catch(() => []),
]);
setMedications(medsData);
setTodayMeds(todayData);
setAdherence(adherenceData);
} catch (err) {
console.error('Failed to fetch medications:', err);
}
};
useEffect(() => {
const fetchData = async () => {
try {
const [medsData, todayData, adherenceData] = await Promise.all([
api.medications.list(),
api.medications.getToday().catch(() => []),
api.medications.getAdherence(30).catch(() => []),
]);
setMedications(medsData);
setTodayMeds(todayData);
setAdherence(adherenceData);
} catch (err) {
console.error('Failed to fetch medications:', err);
} finally {
setIsLoading(false);
}
fetchData().finally(() => setIsLoading(false));
}, []);
// Re-fetch when tab becomes visible or every 60s
useEffect(() => {
const onVisible = () => {
if (document.visibilityState === 'visible') fetchData();
};
document.addEventListener('visibilitychange', onVisible);
const poll = setInterval(fetchData, 60_000);
return () => {
document.removeEventListener('visibilitychange', onVisible);
clearInterval(poll);
};
fetchData();
}, []);
// Auto-refresh grouping every 60s