diff --git a/src/components/ToastRenderer.vue b/src/components/ToastRenderer.vue
new file mode 100644
index 0000000..65e9587
--- /dev/null
+++ b/src/components/ToastRenderer.vue
@@ -0,0 +1,106 @@
+
+
+
+
+
+
handleOpenUpdate(toast.id, val)"
+ >
+
+
+
+
+ {{ toast.content.text }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/layouts/default.vue b/src/layouts/default.vue
index be7b6e7..5b751a0 100644
--- a/src/layouts/default.vue
+++ b/src/layouts/default.vue
@@ -11,6 +11,7 @@ useHead({
id="root"
class="main-body"
>
+
diff --git a/src/pages/account/login.vue b/src/pages/account/login.vue
index 3dbc949..fada313 100644
--- a/src/pages/account/login.vue
+++ b/src/pages/account/login.vue
@@ -2,6 +2,7 @@
const route = useRoute();
const auth = useAuthStore();
const authUtils = useAuthUtils();
+const toasts = useToasts();
const redirect = computed(() => route.query.redirect?.toString() ?? null);
const registerURI = computed(() => {
if (redirect.value) {
@@ -14,7 +15,6 @@ const registerURI = computed(() => {
});
const loginForm = reactive({ username: '', password: '' });
-const errorMessage = ref();
async function loginSubmission() {
try {
@@ -32,11 +32,10 @@ async function loginSubmission() {
await authUtils.safelyRedirectAfterLogin(redirect.value);
} catch (error: unknown) {
const err = getApiError(error);
- errorMessage.value = err.code;
-
- setTimeout(() => { // TODO: replace this toast
- errorMessage.value = null;
- }, 5000);
+ toasts.publish({
+ type: 'error',
+ text: err.message
+ });
}
}
@@ -85,14 +84,6 @@ async function loginSubmission() {
-
diff --git a/src/pages/account/register.vue b/src/pages/account/register.vue
index 752a4d2..284345a 100644
--- a/src/pages/account/register.vue
+++ b/src/pages/account/register.vue
@@ -4,6 +4,7 @@ import type { ApiAuthRegisterRequest } from '~~/shared/api-types';
const route = useRoute();
const auth = useAuthStore();
const authUtils = useAuthUtils();
+const toasts = useToasts();
const redirect = computed(() => route.query.redirect?.toString() ?? null);
const loginURI = computed(() => {
if (redirect.value) {
@@ -16,8 +17,6 @@ const loginURI = computed(() => {
});
const registerForm = reactive({ email: '', username: '', mii_name: '', password: '', password_confirm: '' });
-
-const errorMessage = ref();
const captchaRef = useTemplateRef('captcha');
async function registerSubmission() {
@@ -47,10 +46,10 @@ async function registerSubmission() {
await authUtils.safelyRedirectAfterLogin(redirect.value);
} catch (error: unknown) {
const err = getApiError(error);
- errorMessage.value = err.code;
- setTimeout(() => { // TODO: replace this toast
- errorMessage.value = null;
- }, 5000);
+ toasts.publish({
+ type: 'error',
+ text: err.message
+ });
}
}
@@ -137,14 +136,6 @@ async function registerSubmission() {
-
diff --git a/src/stores/toasts.ts b/src/stores/toasts.ts
new file mode 100644
index 0000000..d908ca8
--- /dev/null
+++ b/src/stores/toasts.ts
@@ -0,0 +1,30 @@
+export type ToastContent = {
+ type: 'success' | 'error';
+ text: string;
+};
+
+export type ToastItem = {
+ id: number;
+ content: ToastContent;
+};
+
+export const useToasts = defineStore('toasts', () => {
+ let idCounter = 0;
+ const toasts = ref([]);
+ const readonlyToasts = computed(() => toasts.value);
+
+ return {
+ getAll() {
+ return readonlyToasts.value;
+ },
+ remove(id: number) {
+ toasts.value = toasts.value.filter(v => v.id !== id);
+ },
+ publish(item: ToastContent) {
+ toasts.value.push({
+ id: idCounter++,
+ content: item
+ });
+ }
+ };
+});