Updated the task view and backend to handle more like a routine

This commit is contained in:
2026-03-08 22:10:46 -04:00
parent 4161ff9513
commit 9d3a277f45
14 changed files with 405 additions and 147 deletions

View File

@@ -75,6 +75,8 @@
}
let isFetching = false;
let lastKnownFirmware = null;
let lastKnownSlot = null;
async function fetchAll(silent = false) {
if (isFetching) return;
isFetching = true;
@@ -85,6 +87,16 @@
getOTAStatus(),
getUpcomingTasks().catch(() => ({ users: [] }))
]);
// Detect any OTA update: firmware version change OR www partition flip
const fwChanged = lastKnownFirmware && sys.firmware !== lastKnownFirmware;
const slotChanged = lastKnownSlot !== null && ota.active_slot !== lastKnownSlot;
if (fwChanged || slotChanged) {
console.log(`OTA detected (fw: ${fwChanged}, slot: ${slotChanged}). Reloading...`);
window.location.href = window.location.pathname + '?t=' + Date.now();
return;
}
lastKnownFirmware = sys.firmware;
lastKnownSlot = ota.active_slot;
systemInfo = sys;
otaStatus = ota;
upcomingData = upcoming;
@@ -180,7 +192,7 @@
<div class="w-full max-w-6xl mx-auto space-y-8">
<!-- Header -->
<div class="text-center">
<h1 class="text-2xl font-bold text-accent">Calendink Provider 📅📅🚀🚀⚡✨🌈</h1>
<h1 class="text-2xl font-bold text-accent">Calendink Provider 📅⚡✨🌈</h1>
<p class="text-text-secondary text-sm">ESP32-S3 System Dashboard v{__APP_VERSION__}</p>
<!-- Status Badge -->
@@ -214,29 +226,46 @@
<!-- Upcoming Tasks Section (top priority) -->
{#if upcomingData.users.length > 0}
{@const periodNames = ['Morning', 'Afternoon', 'Evening']}
{@const periodIcons = ['🌅', '☀️', '🌙']}
<div class="bg-bg-card border border-border rounded-xl overflow-hidden shadow-xl">
<div class="px-5 py-3 border-b border-border">
<h2 class="text-sm font-semibold text-text-primary uppercase tracking-wider">
📋 Upcoming Tasks
📋 Today's Routine
</h2>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-0 divide-y md:divide-y-0 md:divide-x divide-border">
{#each upcomingData.users as user}
{@const routineTasks = user.tasks.filter(t => t.recurrence > 0)}
<div class="p-4">
<h3 class="text-xs font-bold text-accent mb-3 uppercase tracking-wider">{user.name}</h3>
{#if user.tasks.length === 0}
<p class="text-[11px] text-text-secondary italic">No pending tasks</p>
{#if routineTasks.length === 0}
<p class="text-[11px] text-text-secondary italic">No routine tasks</p>
{:else}
<div class="space-y-2">
{#each user.tasks as task}
<div class="flex items-start gap-2">
<span class="text-[10px] mt-0.5 {isOverdue(task.due_date) ? 'text-danger' : 'text-text-secondary'} font-mono whitespace-nowrap">
{formatRelativeDate(task.due_date)}
</span>
<span class="text-xs text-text-primary leading-tight">{task.title}</span>
{#each [0, 1, 2] as periodIdx}
{@const tasksForPeriod = routineTasks.filter(t => t.period & (1 << periodIdx))}
{#if tasksForPeriod.length > 0}
<div class="mb-2">
<div class="text-[10px] uppercase tracking-wider text-text-secondary font-semibold mb-1">
{periodIcons[periodIdx]} {periodNames[periodIdx]}
</div>
{#each tasksForPeriod as task}
<div class="flex items-center gap-2 py-0.5 pl-3">
<span class="text-xs text-text-primary leading-tight">{task.title}</span>
{#if task.recurrence > 0}
<span class="text-[9px] text-accent font-mono">
{task.recurrence === 0x7F ? '∞' : task.recurrence === 0x1F ? 'wk' : ''}
</span>
{:else if task.due_date > 0}
<span class="text-[9px] {isOverdue(task.due_date) ? 'text-danger' : 'text-text-secondary'} font-mono">
{formatRelativeDate(task.due_date)}
</span>
{/if}
</div>
{/each}
</div>
{/each}
</div>
{/if}
{/each}
{/if}
</div>
{/each}