mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-09-24 05:05:20 -04:00

the #shared alias used by Nuxt cannot be easily disabled and to prevent breackage with jiti, we make use of it
122 lines
4.0 KiB
TypeScript
122 lines
4.0 KiB
TypeScript
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 '#shared/bootstrap.ts';
|
|
import { random } from '#shared/helpers.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<string | string[] | undefined> => {
|
|
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 = 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<void> => {
|
|
return show(false, message, color, undefined, undefined).then(() => undefined);
|
|
};
|
|
|
|
const confirm = (
|
|
message: string | DialogueMessage = '',
|
|
colour: Color = 'primary',
|
|
): Promise<void> => {
|
|
return show(true, message, colour, undefined, undefined).then(() => undefined);
|
|
};
|
|
|
|
const editor = (
|
|
value: string | string[],
|
|
message: string | DialogueMessage = '',
|
|
color: Color = 'primary',
|
|
): Promise<string | string[] | undefined> => {
|
|
return show(false, message, color, value, 'lg');
|
|
};
|
|
|
|
const alertRaw = (
|
|
message: string | DialogueMessage,
|
|
color: Color = 'primary',
|
|
): Promise<void> => {
|
|
return show(false, `<pre class="text-start"><code>${message}</code></pre>`, color, undefined, 'lg').then(() => undefined);
|
|
};
|
|
|
|
const postWithAlertOnError = async <T = unknown>(
|
|
url: string,
|
|
data: BodyInit | Record<string, unknown> | null | undefined = undefined,
|
|
options: Omit<FetchOptions, 'method' | 'data' | 'timeout'> = {},
|
|
timeout = 30000,
|
|
): Promise<T> => {
|
|
return $fetch<T>(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,
|
|
};
|
|
};
|