{#if form?.error}
{form.error}
{/if}
Templates โ Drag to assign
openCreateChore()}>๏ผ Create a chore
{#each templates as t}
handleDragStart(e, t.id)} style="border-left-color:{outlineColor(t.color)}; background:{accentBg(t.color)}" >
{t.name}
{t.defaultFrequency}
{t.defaultType}
{t.defaultType === 'money' ? `ยฃ${Number(t.defaultValue).toFixed(2)}` : t.defaultValue}
{/each} {#if templates.length === 0}
No templates yet
{/if}
Season:
All Chores
{#each activeSeasons as s}
{s.name}
{/each}
{#each members as m}
handleDrop(e, m.id)} >
{m.name}
toggleAccordion(m.id, 'todos')}>
{@html todoIcon}
Todos
{@html (accordionState[m.id]?.todos ?? true) ? CHEVRON_UP : CHEVRON_DOWN}
{visibleTodosForMember(m.id).length}
{#if accordionState[m.id]?.todos ?? true}
{#each visibleTodosForMember(m.id) as a} {@const completed = isTodoCompleted(a.id)} {@const expired = isTodoExpired(a)} {@const urgency = todoUrgency(a)}
!completed && !expired && openEdit(a)} role="button" tabindex={completed || expired ? -1 : 0} >
{a.customName || 'Todo'}
{#if a.type === 'emoji'}
{a.emoji || '๐'} celebration
{:else if a.type === 'money'}
ยฃ{Number(a.value).toFixed(2)} cash
{:else}
{a.value} pts
{/if} {#if a.completeBy}
due {formatHumanDate(a.completeBy)}
{/if}
{#if completed}
{@html checkCircleIcon} TBC completed
{:else if expired}
EXPIRED
{:else}
{ e.stopPropagation(); const s = page.data.session as any; if (!s) return; await fetch(`/api/admin/${s.famId}/assigned-chores/${a.id}`, { method: 'DELETE', headers: { 'x-session-famid': s.famId, 'x-session-userid': s.userId } }); }}>ร
{/if}
{/each}
openTodo(m.id)} >๏ผ Add a todo
{/if}
toggleAccordion(m.id, 'chores')}>
{@html choresIcon}
Chores
{@html (accordionState[m.id]?.chores ?? true) ? CHEVRON_UP : CHEVRON_DOWN}
{assignedForMember(m.id).length}
{#if accordionState[m.id]?.chores ?? true}
{#each assignedForMember(m.id) as a} {@const tName = templateName(a.templateId)}
openEdit(a)} role="button" tabindex="0" style="border-left-color:{outlineColor(a.color)}; background:{accentBg( a.color )}" >
{a.customName || tName}
{a.frequency}
{#each a.seasonIds || [] as sid}
{/each} {#if (a.seasonIds || []).length === 0}
All year
{/if}
{a.type === 'money' ? `ยฃ${Number(a.value).toFixed(2)}` : `${a.value} pts`}
{ e.stopPropagation(); const s = page.data.session as any; if (!s) return; await fetch(`/api/admin/${s.famId}/assigned-chores/${a.id}`, { method: 'DELETE', headers: { 'x-session-famid': s.famId, 'x-session-userid': s.userId } }); }}>ร
{/each} {#if assignedForMember(m.id).length === 0}
Drop a chore here
{/if}
openCreateChore(m.id)} >๏ผ Create a chore
{/if}
{/each}
handleDrop(e, '')} >
Everyone
toggleAccordion('shared', 'chores')}>
{@html choresIcon}
Competitive Chores
{@html (accordionState.shared?.chores ?? true) ? CHEVRON_UP : CHEVRON_DOWN}
{sharedChoresFiltered().length}
{#if accordionState.shared?.chores ?? true}
{#each sharedChoresFiltered() as a} {@const tName = templateName(a.templateId)}
openEdit(a)} role="button" tabindex="0" style="border-left-color:{outlineColor(a.color)}; background:{accentBg(a.color)}" >
{a.customName || tName}
{a.frequency}
{#each a.seasonIds || [] as sid}
{/each} {#if (a.seasonIds || []).length === 0}
All year
{/if}
{a.type === 'money' ? `ยฃ${Number(a.value).toFixed(2)}` : `${a.value} pts`}
{ e.stopPropagation(); const s = page.data.session as any; if (!s) return; await fetch(`/api/admin/${s.famId}/assigned-chores/${a.id}`, { method: 'DELETE', headers: { 'x-session-famid': s.famId, 'x-session-userid': s.userId } }); }}>ร
{:else}
Drop a chore here
{/each}
openCreateChore('')} >๏ผ Create a chore
{/if}
{#if members.length < 3} {#each Array(3 - members.length) as _}
{/each} {/if}
{#snippet seasonPills(list: Season[] = [], selected: string[] = [], set: (v: string[]) => void)}
set([])}>Any
{#each list as s}
set([s.id])}>{s.name}
{/each}
{/snippet} {#if assignModal}
{ if (e.target === e.currentTarget) { assignModal = null; assignStep = 1; } }} role="presentation" >
e.stopPropagation()} role="dialog">
{assignModal.t ? `Assign: ${assignModal.t.name}` : 'Create a chore'}
(assignStep = 1)}> {@html STEP_SVG(1)}
Who
(assignStep = 2)}> {@html STEP_SVG(2)}
How
(assignStep = 3)}> {@html STEP_SVG(3)}
What
{#if assignStep === 1}
Name
Description
Assign to
{ if (assignTarget === 'member' && !assignModal?.memberId && members.length) { assignModal = { ...assignModal!, memberId: members[0].id }; } }} >
A specific member
Shared (all members)
{#if assignTarget === 'member'}
Member
{#each members as m}
{m.name}
{/each}
{/if} {:else if assignStep === 2}
Frequency
Daily
Weekly
Type
Points
Money
Value
Seasons
{@render seasonPills(seasons, assignSeasonIds, (v: string[]) => (assignSeasonIds = v))}
{:else}
Colour
{#each TEMPLATE_COLORS as c}
(assignColor = c.value)} >
{/each}
None
{#each ICON_NAMES as n}
{n}
{/each}
{/if}
{#if assignStep > 1}
assignStep--}>Back
{:else}
{ assignModal = null; assignStep = 1; }}>Cancel
{/if} {#if assignStep < 3}
assignStep++}>Next
{:else}
Assign
{/if}
{/if} {#if showEditModal && editingAssignment}
{ if (e.target === e.currentTarget) closeEdit(); }} role="presentation" >
e.stopPropagation()} role="dialog">
{#if editingAssignment.isTodo} Edit Todo: {editingAssignment.customName || 'Todo'} {:else} Edit: {editingAssignment.customName || templateName(editingAssignment.templateId)} {/if}
Name
Description
{#if editingAssignment.isTodo}
Type
Points
Cash
Celebration
{#if editType === 'points'}
Points value
{:else if editType === 'money'}
Cash amount (ยฃ)
{:else}
{editEmoji}
(showTodoEmojiPicker = !showTodoEmojiPicker)} > {showTodoEmojiPicker ? 'Hide' : 'Choose'}
{#if showTodoEmojiPicker}
{#each EMOJI_CHOICES as e}
{ editEmoji = e; showTodoEmojiPicker = false; }}>{e}
{/each}
{/if} {/if}
Start date
Complete by
{:else}
Colour
{#each TEMPLATE_COLORS as c}
(editColor = c.value)} >
{/each}
None
{#each ICON_NAMES as n}
{n}
{/each}
Frequency
Daily
Weekly
Type
Points
Money
Value
Seasons
{@render seasonPills(seasons, editSeasonIds, (v: string[]) => (editSeasonIds = v))}
{/if}
Cancel
Save
{/if} {#if showTodoModal && todoMemberId}
{ if (e.target === e.currentTarget) showTodoModal = false; }} role="presentation" >
e.stopPropagation()} role="dialog">
Add Todo for {members.find((m) => m.id === todoMemberId)?.name || 'Member'}
{ return async ({ result }: any) => { if (result.type === 'success') { showTodoModal = false; todoMemberId = ''; } }; }} >
Name
Type
Points
Cash
Celebration
{#if todoType === 'points'}
Points value
{:else if todoType === 'money'}
Cash amount (ยฃ)
{:else}
{todoEmoji}
(showTodoEmojiPicker = !showTodoEmojiPicker)} > {showTodoEmojiPicker ? 'Hide' : 'Choose'}
{#if showTodoEmojiPicker}
{#each EMOJI_CHOICES as e}
{ todoEmoji = e; showTodoEmojiPicker = false; }}>{e}
{/each}
{/if} {/if}
Starts
Now
Next week
Complete by
Next week
Custom date
{#if todoCompleteBy === 'custom'}
Due date
{/if}
(showTodoModal = false)}>Cancel
Add Todo
{/if}