import { ref } from 'vue' import { defineStore } from 'pinia' import { z } from 'zod' import { API_BASE } from '@/utils/apiBase' export const setElementNodeSchema = z.object({ id: z.number().int().positive(), name: z.string().min(1), kind: z.string().min(1), levelId: z.number().int().positive(), get children() { return z.array(setElementNodeSchema) }, }) export const setLayoutResponseSchema = z.object({ set: z.object({ id: z.number().int().positive(), name: z.string().min(1), }), levels: z.array( z.object({ id: z.number().int().positive(), kind: z.string().min(1), depth: z.number().int().nonnegative(), elementCount: z.number().int().nonnegative(), }), ), elements: z.array(setElementNodeSchema), }) export type SetElementNode = z.infer export type SetLayoutResponse = z.infer const LOAD_ERROR = "We couldn't load this set's layout." export const useSetLayoutStore = defineStore('set-layout', () => { const layout = ref(null) const loading = ref(false) const error = ref(null) const notFound = ref(false) let activeRequestId = 0 async function fetchSetLayout(setId: number): Promise { const requestId = ++activeRequestId layout.value = null loading.value = true error.value = null notFound.value = false try { const response = await fetch(`${API_BASE}/api/sets/${setId}`, { method: 'GET', credentials: 'include', headers: { Accept: 'application/json', }, }) if (requestId !== activeRequestId) { return false } if (response.status === 404) { notFound.value = true return false } if (response.status !== 200) { error.value = LOAD_ERROR return false } const responseBody: unknown = await response.json() if (requestId !== activeRequestId) { return false } const parsedLayout = setLayoutResponseSchema.parse(responseBody) if (parsedLayout.set.id !== setId) { throw new Error('set response did not match requested set') } layout.value = parsedLayout return true } catch { if (requestId === activeRequestId) { layout.value = null error.value = LOAD_ERROR } return false } finally { if (requestId === activeRequestId) { loading.value = false } } } return { layout, loading, error, notFound, fetchSetLayout, } })