fixed payout locks & time sensitive todos & minor ui updates on chores view

This commit is contained in:
JCEEE
2026-08-04 11:38:38 +01:00
parent 7603c3eb21
commit c38ca43f0b
11 changed files with 289 additions and 164 deletions
@@ -3,6 +3,7 @@
import { page } from '$app/state';
import { famStore } from '$lib/stores/fam.svelte';
import { ViewHeader, CardGrid, Card } from '$lib/components';
import { formatShortDate } from '$lib/format';
import type { ChoreTemplate, AssignedChore, Member, Season } from '$lib/types';
let { data, form } = $props();
@@ -143,7 +144,7 @@
let accordionState = $state<Record<string, { chores: boolean; todos: boolean }>>({});
function toggleAccordion(memberId: string, section: 'chores' | 'todos') {
const cur = accordionState[memberId] ?? { chores: false, todos: false };
const cur = accordionState[memberId] ?? { chores: true, todos: true };
accordionState[memberId] = { ...cur, [section]: !cur[section] };
}
@@ -168,16 +169,6 @@
});
}
// Format DDMMYY for todo deadline display
function formatDDMMYY(dateStr: string | undefined): string {
if (!dateStr) return '';
const d = new Date(dateStr + 'T00:00:00');
const day = String(d.getDate()).padStart(2, '0');
const mon = String(d.getMonth() + 1).padStart(2, '0');
const yr = String(d.getFullYear()).slice(2);
return `${day}${mon}${yr}`;
}
// 7 days from today as YYYY-MM-DD for the todo modal default
function defaultCompleteByDate(): string {
const d = new Date();
@@ -314,14 +305,8 @@
<Card cols={3}>
<div class="kanban">
<div class="column templates-col">
<h3>
Templates
<button
class="add-todo-btn"
title="New Chore Template"
onclick={() => (showCreateModal = true)}>+</button
>
</h3>
<h3>Templates</h3>
<button class="add-inline" onclick={() => (showCreateModal = true)}>+ New template</button>
{#each templates as t}
<div class="card template" draggable="true" ondragstart={(e) => handleDragStart(e, t.id)}>
<div class="card-body" onclick={() => openEditTemplate(t)} role="button" tabindex="0">
@@ -366,22 +351,22 @@
ondragover={handleDragOver}
ondrop={(e) => handleDrop(e, m.id)}
>
<h3>
<span class="dot" style="background:{m.color}"></span>
{m.name}
<button class="add-todo-btn" title="Add Todo" onclick={() => openTodo(m.id)}>+</button>
</h3>
<h3>
<span class="dot" style="background:{m.color}"></span>
{m.name}
</h3>
<!-- TODOS accordion -->
<button
class="accordion-head accordion-todos"
onclick={() => toggleAccordion(m.id, 'todos')}
>
<span class="accordion-label">📋 Todos ({todosForMember(m.id).length})</span>
<span class="accordion-arrow" class:open={accordionState[m.id]?.todos}> ▾ </span>
</button>
{#if accordionState[m.id]?.todos}
{#each sortedTodosForMember(m.id) as a}
<!-- TODOS accordion -->
<button
class="accordion-head accordion-todos"
onclick={() => toggleAccordion(m.id, 'todos')}
>
<span class="accordion-label">📋 Todos ({todosForMember(m.id).length})</span>
<span class="accordion-arrow" class:open={accordionState[m.id]?.todos ?? true}> ▾ </span>
</button>
{#if accordionState[m.id]?.todos ?? true}
<button class="add-inline" onclick={() => openTodo(m.id)}>+ Add a todo</button>
{#each sortedTodosForMember(m.id) as a}
{@const urgency = todoUrgency(a)}
<div
class="todo-admin-card"
@@ -403,7 +388,7 @@
<span class="todo-admin-type">{a.value} {a.type}</span>
{/if}
{#if a.completeBy}
<span class="todo-admin-deadline">due {formatDDMMYY(a.completeBy)}</span>
<span class="todo-admin-deadline">due {formatShortDate(a.completeBy)}</span>
{/if}
</div>
</div>
@@ -421,18 +406,15 @@
}}>×</button
>
</div>
{/each}
{#if todosForMember(m.id).length === 0}
<button class="empty empty-cta" onclick={() => openTodo(m.id)}>+ Add a todo</button>
{/if}
{/if}
{/each}
{/if}
<!-- CHORES accordion -->
<button class="accordion-head" onclick={() => toggleAccordion(m.id, 'chores')}>
<span class="accordion-label">Chores ({assignedForMember(m.id).length})</span>
<span class="accordion-arrow" class:open={accordionState[m.id]?.chores}> ▾ </span>
</button>
{#if accordionState[m.id]?.chores}
<!-- CHORES accordion -->
<button class="accordion-head" onclick={() => toggleAccordion(m.id, 'chores')}>
<span class="accordion-label">Chores ({assignedForMember(m.id).length})</span>
<span class="accordion-arrow" class:open={accordionState[m.id]?.chores ?? true}> ▾ </span>
</button>
{#if accordionState[m.id]?.chores ?? true}
{#each assignedForMember(m.id) as a}
{@const tName = templateName(a.templateId)}
<div class="card assigned" onclick={() => openEdit(a)} role="button" tabindex="0">
@@ -771,13 +753,19 @@
border: 1px dashed #d1d5db;
border-radius: 6px;
}
.empty-cta {
.add-inline {
width: 100%;
cursor: pointer;
margin-bottom: 0.5rem;
padding: 0.4rem;
background: transparent;
font: inherit;
border: 1px dashed #d1d5db;
border-radius: 6px;
color: #6b7280;
font-size: 0.8rem;
font-weight: 600;
cursor: pointer;
}
.empty-cta:hover {
.add-inline:hover {
border-color: #6366f1;
color: #6366f1;
background: #eef2ff;
@@ -1072,28 +1060,6 @@
font-weight: 700;
}
/* ── Add Todo button ── */
.add-todo-btn {
margin-left: auto;
background: #6366f1;
color: #fff;
border: none;
border-radius: 50%;
width: 22px;
height: 22px;
font-size: 1rem;
font-weight: 700;
line-height: 1;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
flex-shrink: 0;
}
.add-todo-btn:hover {
background: #4f46e5;
}
.todo-badge {
background: #fef3c7;
color: #b45309;