Attainly/frontend/website/src/stores/setLayout.ts
2026-08-08 23:38:31 +03:00

102 lines
2.3 KiB
TypeScript

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),
get children() {
return z.array(setElementNodeSchema)
},
})
export const setLayoutResponseSchema = z.object({
set: z.object({
id: z.number().int().positive(),
name: z.string().min(1),
}),
elements: z.array(setElementNodeSchema),
})
export type SetElementNode = z.infer<typeof setElementNodeSchema>
export type SetLayoutResponse = z.infer<typeof setLayoutResponseSchema>
const LOAD_ERROR = "We couldn't load this set's layout."
export const useSetLayoutStore = defineStore('set-layout', () => {
const layout = ref<SetLayoutResponse | null>(null)
const loading = ref(false)
const error = ref<string | null>(null)
const notFound = ref(false)
let activeRequestId = 0
async function fetchSetLayout(setId: number): Promise<boolean> {
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,
}
})