summaryrefslogblamecommitdiffstatshomepage
path: root/frontend/src/lib/Utils.ts
blob: 1a07be1d230358852b6a5986760cba81a60a5d6e (plain) (tree)











































































































                                                                                                         
import { isError } from '$gql/Utils';
import type { ImageFragment } from '$gql/graphql';
import type { BeforeNavigate } from '@sveltejs/kit';
import type { OperationResultState } from '@urql/svelte';
import { openModal } from 'svelte-modals';
import ConfirmDeletion from './dialogs/ConfirmDeletion.svelte';

export function range(from: number, to: number) {
	return Array.from({ length: to - from + 1 }, (_, k) => k + from);
}

export function getRandomInt(min: number, max: number) {
	const minCeiled = Math.ceil(min);
	const maxFloored = Math.floor(max);

	return Math.floor(Math.random() * (maxFloored - minCeiled) + minCeiled);
}

export interface ListItem {
	id: number | string;
	name: string;
}

export interface ResultState {
	fetching: boolean;
	message?: string;
}

export function getResultState(state: OperationResultState): ResultState {
	let message: string | undefined;

	if (state.error) {
		message = `${state.error.name}: ${state.error.message}`;
	} else if (state.data) {
		// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
		const obj = Object.values(state.data)[0];
		if (isError(obj)) {
			message = obj.message;
		}
	}

	return { fetching: state.fetching, message: message };
}

export function src(image: ImageFragment, type: 'full' | 'thumb' = 'thumb') {
	const dir = image.hash.slice(0, 2);
	const file = image.hash.slice(2);

	return `/objects/${dir}/${file}_${type}.webp`;
}

export function numKeys(obj?: object | null, ignore: string[] = []) {
	if (!obj) return 0;

	const len = Object.keys(obj).length;
	let ignored = 0;

	for (const i of ignore) {
		if (Object.hasOwn(obj, i)) ignored++;
	}

	return len - ignored;
}

export function confirmDeletion(
	typename: string,
	names: string | string[],
	callback: () => void,
	warning?: string
) {
	openModal(
		ConfirmDeletion,
		{ names: Array.isArray(names) ? names : [names], typename, callback: callback, warning },
		{ replace: true }
	);
}

export function idFromLabel(label: string) {
	return label.toLowerCase().replaceAll(' ', '-');
}

export function pluralize(singular: string, size: number) {
	return `${singular}${size > 1 ? 's' : ''}`;
}

export function formatListSize(word: string, size: number) {
	return `${size} ${pluralize(word, size)}`;
}

export function joinText(items: string[], separator = ', ') {
	return items.filter((i) => i).join(separator);
}

export function confirmPending() {
	return confirm('There are pending changes. Click Cancel to keep editing or OK to dismiss them.');
}

export function preventOnPending({ to, cancel }: BeforeNavigate, pending: boolean) {
	if (!pending) return;

	if (to) {
		if (confirmPending()) {
			return;
		}
	}

	cancel();
}