import { useNuxtApp } from 'nuxt/app'; import type { FetchOptions } from 'ofetch'; import { getCurrentInstance, h, render } from 'vue'; import DialogueBox from '../components/DialogueBox.vue'; import type { DialogueMessage } from '../components/DialogueBox.vue'; import type { Color, ModalSize } from '../src/bootstrap.ts'; export default (to: string = 'body') => { const { $translator: translator } = useNuxtApp(); const self = getCurrentInstance()!; const show = ( choice: boolean, message: string | DialogueMessage, colour: Color, value: string | string[] | undefined, size: ModalSize, ): Promise => { return new Promise((resolve, reject) => { if (typeof message === 'string') { message = { message }; } const vnode = h(DialogueBox, { choice, icon: message.icon || (choice ? 'map-marker-question' : undefined), header: message.header, message: message.message || (choice ? translator.translate('confirm.header') : undefined), margin: message.margin ?? true, colour, value, size: message.size ?? size, onConfirm: (value) => { hide(); resolve(value); }, onCancel: () => { hide(); reject(); }, }); vnode.key = Math.random(); vnode.appContext = self.appContext; render(vnode, document.querySelector(to)!); }); }; const hide = () => { render(null, document.querySelector(to)!); }; const alert = ( message: string | DialogueMessage, color: Color = 'primary', ): Promise => { return show(false, message, color, undefined, undefined).then(() => undefined); }; const confirm = ( message: string | DialogueMessage = '', colour: Color = 'primary', ): Promise => { return show(true, message, colour, undefined, undefined).then(() => undefined); }; const editor = ( value: string | string[], message: string | DialogueMessage = '', color: Color = 'primary', ): Promise => { return show(false, message, color, value, 'lg'); }; const alertRaw = ( message: string | DialogueMessage, color: Color = 'primary', ): Promise => { return show(false, `
${message}
`, color, undefined, 'lg').then(() => undefined); }; const postWithAlertOnError = async ( url: string, data: BodyInit | Record | null | undefined = undefined, options: Omit = {}, timeout = 30000, ): Promise => { return $fetch(url, { method: 'POST', body: data, timeout, ...options, }) .catch(async (error) => { let errorMessage = translator.translate('error.generic'); if (typeof error.data?.message === 'string') { errorMessage = error.data.message; } if (typeof error.data?.error === 'string') { errorMessage = translator.translate(error.data?.error); // in case no translatable key was provided if (errorMessage === undefined) { errorMessage = error.data?.error; } } await alert(errorMessage, 'danger'); throw new Error(`POST to ${url} failed: ${error.data?.error || 'unknown error'}`); }); }; return { alert, confirm, editor, alertRaw, postWithAlertOnError, }; };