All files / src/entities/layer/model layer.service.ts

71.87% Statements 23/32
53.84% Branches 7/13
71.42% Functions 5/7
75% Lines 21/28

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89            31x   1x                   12x 12x 12x   12x 12x 3x 3x 3x 3x       12x                       12x 12x       2x 2x 2x 2x 2x       3x 3x                                                              
import { nanoid } from 'nanoid';
import type { EditorSnapshot, Layer } from '@/shared/types';
import { layerRepository } from '@/entities/layer/api';
import { LAYER, LAYER_DEFAULTS, LAYER_ERROR_MESSAGES } from '@/shared/constants';
import Dexie from 'dexie';
 
export const layerService = {
	async getLayers(projectId: string): Promise<Layer[]> {
		return layerRepository.getAllByProject(projectId);
	},
 
	async createLayer({
		projectId,
		name,
	}: {
		projectId: string;
		name?: string;
	}): Promise<Layer> {
		const layers = await layerRepository.getAllByProject(projectId);
		const maxZ = layers.length > 0 ? Math.max(...layers.map((l) => l.zIndex)) : -1;
		const nextZ = maxZ + 1;
 
		let nextIndex = 1;
		for (const l of layers) {
			const match = l.name.match(/(\d+)$/);
			Eif (match) {
				const num = parseInt(match[1], 10);
				Eif (num >= nextIndex) nextIndex = num + 1;
			}
		}
 
		const layer: Layer = {
			id: nanoid(),
			projectId,
			name: name?.trim() || `${LAYER.NAME(nextIndex)}`,
			visible: true,
			opacity: 1,
			zIndex: nextZ,
			createdAt: Date.now(),
			updatedAt: Date.now(),
			snapshot: '',
		};
 
		await layerRepository.add(layer);
		return layer;
	},
 
	async updateLayer(args: { id: string; changes: Partial<Layer> }): Promise<Layer> {
		const { id, changes } = args;
		await layerRepository.update(id, { ...changes, updatedAt: Date.now() });
		const updated = await layerRepository.getById(id);
		Iif (!updated) throw new Error(`${LAYER_ERROR_MESSAGES.LAYER_NOT_FOUND(id)}`);
		return updated;
	},
 
	async deleteLayer(id: string): Promise<string> {
		await layerRepository.remove(id);
		return id;
	},
 
	async ensureBaseLayer(
		projectId: string,
		defaultName = `${LAYER_DEFAULTS.INITIAL_NAME}`,
	): Promise<Layer | null> {
		const layers = await layerRepository.getAllByProject(projectId);
		if (layers.length > 0) return null;
		return this.createLayer({ projectId, name: defaultName });
	},
	async replaceAll(projectId: string, layers: EditorSnapshot['layers']) {
		// remove all layers from project
		await layerRepository.removeByProject(projectId);
		await Dexie.waitFor(Promise.resolve());
		// add layers from a snapshot
		for (const l of layers) {
			await layerRepository.add({
				id: l.id,
				projectId,
				name: l.name,
				visible: l.visible,
				opacity: l.opacity,
				zIndex: l.zIndex,
				snapshot: l.snapshot,
				createdAt: Date.now(),
				updatedAt: Date.now(),
			});
		}
	},
};