UNPKG

@ozmos/viper-vue

Version:

Vue plugin for Viper

219 lines 8.57 kB
import { useMutation, useQuery } from "@tanstack/vue-query"; import { inject, ref, toValue } from "vue"; import { useRouter } from "vue-router"; export class Page { params = ref({}); formatTitle = (title) => title; props = {}; actions = {}; hashes = {}; queryClient; constructor(config) { this.queryClient = config.queryClient; if (config.formatTitle) { this.formatTitle = config.formatTitle; } } updateFromPageJson(json) { this.props = json.props; this.actions = json.actions; this.hashes = json.hashes; this.setPageTitle(json.title || ""); this.params.value = json.params; for (const key in this.props) { this.queryClient.setQueryData([this.hashes[key]], () => this.props[key]); } } setPageTitle(title) { document.title = this.formatTitle(title || ""); } } export function usePage() { const page = inject("viperPage"); const router = useRouter(); return { setPageTitle: page.setPageTitle, params: page.params, useQuery(key) { const enabled = ref(false); const query = useQuery({ enabled, initialData: () => page.props[key], queryKey: [page.hashes[key]], queryFn: async () => { const res = await fetch(router.currentRoute.value.path, { headers: { Accept: "application/json", "Content-Type": "application/json", "X-Viper-Request": "true", "X-Viper-Only": key, }, }); enabled.value = true; if (!res.ok) { throw await res.json(); } const data = await res.json(); return data.props[key]; }, }); return { ...query, data: query.data, }; }, useMutation(key, options = {}) { return useMutation({ ...options, mutationFn: async (data = {}) => { const res = await fetch(router.currentRoute.value.path, { method: "POST", credentials: "include", body: JSON.stringify(data), headers: { Accept: "application/json", "Content-Type": "application/json", "X-Viper-Request": "true", "X-Viper-Action": key, "X-XSRF-TOKEN": decodeURIComponent(getXsrfToken() || ""), }, }); if (!res.ok) { if (res.status === 422) { const data = (await res.json()); throw data.errors; } throw await res.json(); } return (await res.json()); }, }); }, useForm(key, options) { const _initialState = { ...toValue(options.state ?? {}) }; const state = ref(options.state); const errors = ref({}); const mutation = useMutation({ ...options, mutationFn: async (data = {}) => { errors.value = {}; const res = await fetch(router.currentRoute.value.path, { method: "POST", credentials: "include", body: JSON.stringify({ ...toValue(state), ...toValue(data ?? {}), }), headers: { Accept: "application/json", "Content-Type": "application/json", "X-Viper-Request": "true", "X-Viper-Action": key, "X-XSRF-TOKEN": decodeURIComponent(getXsrfToken() || ""), }, }); if (!res.ok) { if (res.status === 422) { const data = (await res.json()); errors.value = Object.entries(data.errors).reduce( // biome-ignore lint/performance/noAccumulatingSpread: it's fine here (acc, [key, value]) => ({ ...acc, [key]: value[0] }), {}); throw data.errors; } throw await res.json(); } return (await res.json()); }, }); return { ...mutation, mutate(override = {}) { return mutation.mutate(override); }, mutateAsync(override = {}) { return mutation.mutateAsync(override); }, reset: () => { state.value = { ..._initialState }; }, errors, state, }; }, useFormData(key, options) { const _initialState = { ...toValue(options.state ?? {}) }; const state = ref(options.state); const errors = ref({}); const mutation = useMutation({ ...options, mutationFn: async (data = {}) => { errors.value = {}; const json = { ...toValue(state), ...toValue(data ?? {}), }; const formData = new FormData(); for (const key of options.files) { if (Array.isArray(json[key])) { for (const file of json[key]) { formData.append(key, file); } } else if (json[key]) { formData.set(key, json[key]); } delete json[key]; } formData.set("state", JSON.stringify(json)); const res = await fetch(router.currentRoute.value.path, { method: "POST", credentials: "include", body: formData, headers: { Accept: "application/json", "X-Viper-Request": "true", "X-Viper-Action": key, "X-XSRF-TOKEN": decodeURIComponent(getXsrfToken() || ""), }, }); if (!res.ok) { if (res.status === 422) { const data = (await res.json()); errors.value = Object.entries(data.errors).reduce( // biome-ignore lint/performance/noAccumulatingSpread: it's fine here (acc, [key, value]) => ({ ...acc, [key]: value[0] }), {}); throw data.errors; } throw await res.json(); } return (await res.json()); }, }); return { ...mutation, mutate(override = {}) { return mutation.mutate(override); }, mutateAsync(override = {}) { return mutation.mutateAsync(override); }, reset: () => { state.value = { ..._initialState }; }, errors, state, }; }, }; } function getXsrfToken() { const cookies = document.cookie.split(";"); for (let i = 0; i < cookies.length; i++) { const cookie = cookies[i].trim(); if (cookie.startsWith("XSRF-TOKEN=")) { return cookie.substring("XSRF-TOKEN=".length, cookie.length); } } return null; } //# sourceMappingURL=page.js.map