Type-checks every link against the real route tree. Caught a dead one: the
book page linked tags to /tag/{id}, a route that has never existed.
87 lines
2.7 KiB
TypeScript
87 lines
2.7 KiB
TypeScript
import { resolve } from '$app/paths';
|
|
import { browser } from '$app/environment';
|
|
import { goto, invalidate } from '$app/navigation';
|
|
import { page } from '$app/state';
|
|
import { deleteLibrary } from '$lib/api';
|
|
import type { Library } from '$lib/schema';
|
|
import { getContext, setContext } from 'svelte';
|
|
import { toast } from 'svelte-sonner';
|
|
|
|
export class LibraryState {
|
|
libraries = $state<Library[]>([]);
|
|
activeLibrary = $state<Library | undefined>(undefined);
|
|
createDialogOpen = $state(false);
|
|
|
|
constructor(libraries: Library[]) {
|
|
this.libraries = libraries;
|
|
|
|
const activeLibrary = this.libraries.find((lib) => lib.id.toString() === page.params.libraryId);
|
|
|
|
let previousLibrary: Library | undefined;
|
|
|
|
if (browser) {
|
|
previousLibrary = this.libraries.find(
|
|
(lib) => lib.id.toString() === localStorage.getItem('previousLibraryId')
|
|
);
|
|
}
|
|
|
|
this.activeLibrary = activeLibrary || previousLibrary || libraries[0];
|
|
}
|
|
|
|
async setActive(libraryId: number) {
|
|
this.activeLibrary = this.libraries.find((lib) => lib.id === libraryId) || this.libraries[0];
|
|
if (browser) {
|
|
localStorage.setItem('previousLibraryId', this.activeLibrary.id.toString());
|
|
await goto(resolve('/(root)/(library)/library/[libraryId]/view', { libraryId: String(libraryId) }), {
|
|
invalidate: ['app:libraries']
|
|
});
|
|
}
|
|
}
|
|
|
|
updateLibraries(libraries: Library[]) {
|
|
this.libraries = libraries;
|
|
|
|
// Update the current library as it may have been removed
|
|
if (!this.libraries.find((lib) => this.activeLibrary?.id === lib.id))
|
|
this.activeLibrary = libraries[0] || undefined;
|
|
}
|
|
|
|
async deleteLibrary(libraryId: number) {
|
|
// Store library with its original index
|
|
const libIndex = this.libraries.findIndex((lib) => lib.id === libraryId);
|
|
const deletionSnapshot = { library: this.libraries[libIndex], index: libIndex };
|
|
|
|
// Optimistically delete the library
|
|
this.libraries = this.libraries.filter((lib) => lib.id !== libraryId);
|
|
|
|
try {
|
|
// Delete library via API
|
|
await deleteLibrary(libraryId);
|
|
toast.success(`Deleted library '${deletionSnapshot.library}'`);
|
|
} catch (err) {
|
|
// Delete failed; restore library at its original position
|
|
this.libraries.splice(deletionSnapshot.index, 0, deletionSnapshot.library);
|
|
toast.error('Failed to delete library');
|
|
console.error('Failed to delete library: ', err);
|
|
}
|
|
}
|
|
|
|
addLibrary(library: Library) {
|
|
this.libraries.push(library);
|
|
}
|
|
|
|
openLibraryCreateDialog() {
|
|
this.createDialogOpen = true;
|
|
}
|
|
}
|
|
|
|
const LIBRARY_KEY = Symbol('LIBRARY');
|
|
|
|
export function setLibraryState(libraries: Library[]) {
|
|
return setContext(LIBRARY_KEY, new LibraryState(libraries));
|
|
}
|
|
|
|
export function getLibraryState() {
|
|
return getContext<ReturnType<typeof setLibraryState>>(LIBRARY_KEY);
|
|
}
|