feat: global attendance store persists between views
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
import { EventsOn, EventsOff, WindowSetSize, ScreenGetAll } from '../wailsjs/runtime/runtime'
|
||||
import { GetParticipants, StartMeeting, GetSettings, SkipSpeaker, RemoveFromQueue, SwitchToSpeaker } from '../wailsjs/go/app/App'
|
||||
import { t, initLocale } from './lib/i18n'
|
||||
import { attendance } from './lib/stores'
|
||||
|
||||
let currentView = 'main'
|
||||
let timerState = null
|
||||
@@ -222,6 +223,7 @@
|
||||
async function loadParticipants() {
|
||||
try {
|
||||
participants = await GetParticipants() || []
|
||||
attendance.init(participants)
|
||||
} catch (e) {
|
||||
console.error('Failed to load participants:', e)
|
||||
participants = []
|
||||
@@ -231,12 +233,16 @@
|
||||
async function handleQuickStart() {
|
||||
if (participants.length === 0) return
|
||||
|
||||
const ids = participants.map(p => p.id)
|
||||
const attendance = {}
|
||||
participants.forEach(p => { attendance[p.id] = true })
|
||||
const att = attendance.get()
|
||||
const presentIds = participants.filter(p => att[p.id]).map(p => p.id)
|
||||
|
||||
if (presentIds.length === 0) {
|
||||
alert($t('setup.noParticipants'))
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await StartMeeting(ids, attendance)
|
||||
await StartMeeting(presentIds, att)
|
||||
meetingActive = true
|
||||
} catch (e) {
|
||||
console.error('Failed to start meeting:', e)
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
import { onMount, createEventDispatcher } from 'svelte'
|
||||
import { GetParticipants, GetMeeting, StartMeeting, AddParticipant, DeleteParticipant, ReorderParticipants, UpdateParticipant, UpdateMeeting } from '../../wailsjs/go/app/App'
|
||||
import { t } from '../lib/i18n'
|
||||
import { attendance } from '../lib/stores'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let participants = []
|
||||
let meeting = null
|
||||
let selectedOrder = []
|
||||
let attendance = {}
|
||||
let loading = true
|
||||
let newName = ''
|
||||
let newTimeLimitMin = 2
|
||||
@@ -37,10 +37,7 @@
|
||||
meeting = await GetMeeting()
|
||||
|
||||
selectedOrder = participants.map(p => p.id)
|
||||
attendance = {}
|
||||
participants.forEach(p => {
|
||||
attendance[p.id] = true
|
||||
})
|
||||
attendance.init(participants)
|
||||
} catch (e) {
|
||||
console.error('Failed to load data:', e)
|
||||
}
|
||||
@@ -95,8 +92,7 @@
|
||||
}
|
||||
|
||||
function toggleAttendance(id) {
|
||||
attendance[id] = !attendance[id]
|
||||
attendance = attendance
|
||||
attendance.toggle(id)
|
||||
}
|
||||
|
||||
// Drag and drop state
|
||||
@@ -152,14 +148,15 @@
|
||||
}
|
||||
|
||||
async function handleStart() {
|
||||
const presentIds = selectedOrder.filter(id => attendance[id])
|
||||
const att = attendance.get()
|
||||
const presentIds = selectedOrder.filter(id => att[id])
|
||||
if (presentIds.length === 0) {
|
||||
alert($t('setup.noParticipants'))
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await StartMeeting(presentIds, attendance)
|
||||
await StartMeeting(presentIds, att)
|
||||
dispatch('started')
|
||||
} catch (e) {
|
||||
console.error('Failed to start meeting:', e)
|
||||
@@ -314,7 +311,7 @@
|
||||
{@const p = getParticipant(id)}
|
||||
{#if p}
|
||||
<li
|
||||
class:absent={!attendance[id]}
|
||||
class:absent={!$attendance[id]}
|
||||
class:drag-over={dragOverId === id}
|
||||
draggable="true"
|
||||
on:dragstart={(e) => handleDragStart(e, id)}
|
||||
@@ -329,10 +326,10 @@
|
||||
|
||||
<button
|
||||
class="attendance-toggle"
|
||||
class:present={attendance[id]}
|
||||
class:present={$attendance[id]}
|
||||
on:click={() => toggleAttendance(id)}
|
||||
>
|
||||
{attendance[id] ? '✓' : '✗'}
|
||||
{$attendance[id] ? '✓' : '✗'}
|
||||
</button>
|
||||
|
||||
<span class="name">{p.name}</span>
|
||||
@@ -375,8 +372,8 @@
|
||||
{/if}
|
||||
|
||||
<div class="summary">
|
||||
<span>{$t('setup.participants')}: {Object.values(attendance).filter(Boolean).length} / {participants.length}</span>
|
||||
<span>≈ {formatTime(selectedOrder.filter(id => attendance[id]).reduce((acc, id) => acc + (getParticipant(id)?.timeLimit || 0), 0))}</span>
|
||||
<span>{$t('setup.participants')}: {Object.values($attendance).filter(Boolean).length} / {participants.length}</span>
|
||||
<span>≈ {formatTime(selectedOrder.filter(id => $attendance[id]).reduce((acc, id) => acc + (getParticipant(id)?.timeLimit || 0), 0))}</span>
|
||||
</div>
|
||||
|
||||
<button class="start-btn" on:click={handleStart}>
|
||||
|
||||
56
frontend/src/lib/stores.js
Normal file
56
frontend/src/lib/stores.js
Normal file
@@ -0,0 +1,56 @@
|
||||
import { writable, get } from 'svelte/store';
|
||||
|
||||
function createAttendanceStore() {
|
||||
const { subscribe, set, update } = writable({});
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
|
||||
// Initialize attendance for all participants (default: true)
|
||||
init(participants) {
|
||||
const current = get({ subscribe });
|
||||
const newAttendance = {};
|
||||
|
||||
for (const p of participants) {
|
||||
// Keep existing value or default to true
|
||||
newAttendance[p.id] = current[p.id] !== undefined ? current[p.id] : true;
|
||||
}
|
||||
|
||||
set(newAttendance);
|
||||
},
|
||||
|
||||
// Toggle attendance for a participant
|
||||
toggle(id) {
|
||||
update((att) => {
|
||||
att[id] = !att[id];
|
||||
return { ...att };
|
||||
});
|
||||
},
|
||||
|
||||
// Set attendance for a participant
|
||||
set(id, present) {
|
||||
update((att) => {
|
||||
att[id] = present;
|
||||
return { ...att };
|
||||
});
|
||||
},
|
||||
|
||||
// Get current attendance object
|
||||
get() {
|
||||
return get({ subscribe });
|
||||
},
|
||||
|
||||
// Reset all to true
|
||||
resetAll() {
|
||||
update((att) => {
|
||||
const reset = {};
|
||||
for (const id in att) {
|
||||
reset[id] = true;
|
||||
}
|
||||
return reset;
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export const attendance = createAttendanceStore();
|
||||
Reference in New Issue
Block a user