121 lines
3.0 KiB
TypeScript
121 lines
3.0 KiB
TypeScript
import { writable, derived } from 'svelte/store';
|
|
import { liveQuery } from 'dexie';
|
|
import { db } from '$lib/db/schema';
|
|
import type { AgendaContext, Topic, HistoryEntry, ContextType } from '@ka-note/shared';
|
|
|
|
// --- Writable UI state ---
|
|
export const currentContextId = writable<string>('daily-log');
|
|
export const currentMode = writable<'prep' | 'meeting'>('prep');
|
|
export const currentView = writable<string>('agenda');
|
|
|
|
// --- Session-only state (resets on tab close) ---
|
|
const isBrowser = typeof sessionStorage !== 'undefined';
|
|
|
|
function createSessionSet(key: string) {
|
|
const stored = isBrowser ? sessionStorage.getItem(key) : null;
|
|
const initial = stored ? new Set<string>(JSON.parse(stored)) : new Set<string>();
|
|
const { subscribe, set, update } = writable(initial);
|
|
|
|
return {
|
|
subscribe,
|
|
add(id: string) {
|
|
update(s => {
|
|
s.add(id);
|
|
if (isBrowser) sessionStorage.setItem(key, JSON.stringify([...s]));
|
|
return new Set(s);
|
|
});
|
|
},
|
|
remove(id: string) {
|
|
update(s => {
|
|
s.delete(id);
|
|
if (isBrowser) sessionStorage.setItem(key, JSON.stringify([...s]));
|
|
return new Set(s);
|
|
});
|
|
},
|
|
clear() {
|
|
set(new Set());
|
|
if (isBrowser) sessionStorage.removeItem(key);
|
|
}
|
|
};
|
|
}
|
|
|
|
export const processedTopicIds = createSessionSet('ka-note-processed');
|
|
|
|
// --- UI-only state ---
|
|
export const collapsedTopicIds = writable(new Set<string>());
|
|
|
|
// --- Reactive Dexie queries ---
|
|
|
|
export function contextsByType(type: ContextType) {
|
|
return liveQuery(() =>
|
|
db.contexts
|
|
.where('type').equals(type)
|
|
.filter(c => !c.deletedAt)
|
|
.sortBy('sortOrder')
|
|
);
|
|
}
|
|
|
|
export function allActiveContexts() {
|
|
return liveQuery(() =>
|
|
db.contexts.filter(c => !c.deletedAt).sortBy('sortOrder')
|
|
);
|
|
}
|
|
|
|
export function contextById(id: string) {
|
|
return liveQuery(() => db.contexts.get(id));
|
|
}
|
|
|
|
export function topicsForContext(contextId: string) {
|
|
return liveQuery(() =>
|
|
db.topics
|
|
.where('contextId').equals(contextId)
|
|
.filter(t => !t.deletedAt)
|
|
.sortBy('sortOrder')
|
|
);
|
|
}
|
|
|
|
export function historyForTopic(topicId: string) {
|
|
return liveQuery(() =>
|
|
db.historyEntries
|
|
.where('topicId').equals(topicId)
|
|
.filter(h => !h.deletedAt)
|
|
.sortBy('sortOrder')
|
|
);
|
|
}
|
|
|
|
export function allHistoryForContext(contextId: string) {
|
|
return liveQuery(async () => {
|
|
const topics = await db.topics
|
|
.where('contextId').equals(contextId)
|
|
.filter(t => !t.deletedAt)
|
|
.toArray();
|
|
const topicIds = topics.map(t => t.id);
|
|
const entries = await db.historyEntries
|
|
.where('topicId').anyOf(topicIds)
|
|
.filter(h => !h.deletedAt)
|
|
.toArray();
|
|
return entries.map(e => ({
|
|
...e,
|
|
topicTitle: topics.find(t => t.id === e.topicId)?.title ?? ''
|
|
}));
|
|
});
|
|
}
|
|
|
|
export function ratingsForHistoryEntry(historyEntryId: string) {
|
|
return liveQuery(() =>
|
|
db.ratings
|
|
.where('historyEntryId').equals(historyEntryId)
|
|
.filter(r => !r.deletedAt)
|
|
.toArray()
|
|
);
|
|
}
|
|
|
|
export function ratingsForPerson(personName: string) {
|
|
return liveQuery(() =>
|
|
db.ratings
|
|
.where('personName').equals(personName)
|
|
.filter(r => !r.deletedAt)
|
|
.toArray()
|
|
);
|
|
}
|