replace alerts with notifications using DaisyUI toasts
This commit is contained in:
@@ -69,7 +69,7 @@ Demo site [here](https://nuxt3-saas-boilerplate.netlify.app/)
|
|||||||
### Look and Feel, Design System and Customisation
|
### Look and Feel, Design System and Customisation
|
||||||
- [x] Default UI isn't too crap
|
- [x] Default UI isn't too crap
|
||||||
- [x] Integrated Design system including theming (Tailwind + daisyUI)
|
- [x] Integrated Design system including theming (Tailwind + daisyUI)
|
||||||
- [ ] Toasts for things like reset email sent
|
- [x] Toasts for things like reset email sent
|
||||||
- [ ] Modals, just because people like modals
|
- [ ] Modals, just because people like modals
|
||||||
|
|
||||||
### Demo Software (Notes)
|
### Demo Software (Notes)
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
const user = useSupabaseUser();
|
const user = useSupabaseUser();
|
||||||
const accountStore = useAccountStore()
|
const accountStore = useAccountStore()
|
||||||
const { dbUser, activeAccountId } = storeToRefs(accountStore);
|
const { dbUser, activeAccountId } = storeToRefs(accountStore);
|
||||||
|
const notifyStore = useNotifyStore();
|
||||||
|
const { notifications } = storeToRefs(notifyStore);
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await accountStore.init()
|
await accountStore.init()
|
||||||
@@ -21,6 +23,21 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="navbar bg-base-100">
|
<div class="navbar bg-base-100">
|
||||||
|
<div class="toast toast-end toast-top">
|
||||||
|
<div v-for="notification in notifications" :class="notification.type">
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
@click.prevent="notifyStore.removeNotification(notification)"
|
||||||
|
type="button"
|
||||||
|
class="ml-auto -mx-1.5 -my-1.5 bg-white text-gray-400 hover:text-gray-900 rounded-lg focus:ring-2 focus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex h-8 w-8 dark:text-gray-500 dark:hover:text-white dark:bg-gray-800 dark:hover:bg-gray-700"
|
||||||
|
aria-label="Close">
|
||||||
|
<span class="sr-only">Close</span>
|
||||||
|
<svg aria-hidden="true" class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
|
||||||
|
</button>
|
||||||
|
<span> {{notification.message}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="navbar-start">
|
<div class="navbar-start">
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
<label tabindex="0" class="btn btn-ghost lg:hidden">
|
<label tabindex="0" class="btn btn-ghost lg:hidden">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const supabase = useSupabaseAuthClient();
|
const supabase = useSupabaseAuthClient();
|
||||||
const config = useRuntimeConfig();
|
const config = useRuntimeConfig();
|
||||||
|
const notifyStore = useNotifyStore();
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const email = ref('')
|
const email = ref('')
|
||||||
@@ -12,9 +13,9 @@
|
|||||||
redirectTo: `${config.public.siteRootUrl}/resetpassword`,
|
redirectTo: `${config.public.siteRootUrl}/resetpassword`,
|
||||||
})
|
})
|
||||||
if (error) throw error
|
if (error) throw error
|
||||||
else alert('Password Reset link sent, check your email.');
|
else notifyStore.notify("Password Reset link sent, check your email.", NotificationType.Success);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
alert(error)
|
notifyStore.notify(error, NotificationType.Error);
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const supabase = useSupabaseAuthClient();
|
const supabase = useSupabaseAuthClient();
|
||||||
|
|
||||||
|
const notifyStore = useNotifyStore();
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const password = ref('')
|
const password = ref('')
|
||||||
const confirmPassword = ref('')
|
const confirmPassword = ref('')
|
||||||
@@ -13,11 +15,11 @@
|
|||||||
});
|
});
|
||||||
if (error) throw error
|
if (error) throw error
|
||||||
else {
|
else {
|
||||||
alert('password changed');
|
notifyStore.notify("password changed", NotificationType.Success);
|
||||||
navigateTo('/signin', {replace: true}); // navigate to signin because it is best practice although the auth session seems to be valid so it immediately redirects to dashboard
|
navigateTo('/signin', {replace: true}); // navigate to signin because it is best practice although the auth session seems to be valid so it immediately redirects to dashboard
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
alert(error)
|
notifyStore.notify(error, NotificationType.Error);
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
const supabase = useSupabaseAuthClient();
|
const supabase = useSupabaseAuthClient();
|
||||||
|
|
||||||
const accountStore = useAccountStore()
|
const accountStore = useAccountStore()
|
||||||
|
const notifyStore = useNotifyStore();
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const email = ref('')
|
const email = ref('')
|
||||||
@@ -15,7 +16,7 @@
|
|||||||
const { error } = await supabase.auth.signInWithPassword({ email: email.value, password: password.value })
|
const { error } = await supabase.auth.signInWithPassword({ email: email.value, password: password.value })
|
||||||
if (error) throw error
|
if (error) throw error
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
alert(error)
|
notifyStore.notify(error, NotificationType.Error);
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
@@ -28,7 +29,7 @@
|
|||||||
const { error } = await supabase.auth.signInWithOAuth({ provider: 'google' })
|
const { error } = await supabase.auth.signInWithOAuth({ provider: 'google' })
|
||||||
if (error) throw error
|
if (error) throw error
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
alert(error)
|
notifyStore.notify(error, NotificationType.Error);
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
const user = useSupabaseUser()
|
const user = useSupabaseUser()
|
||||||
const supabase = useSupabaseAuthClient();
|
const supabase = useSupabaseAuthClient();
|
||||||
|
|
||||||
|
const notifyStore = useNotifyStore();
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const email = ref('')
|
const email = ref('')
|
||||||
const password = ref('')
|
const password = ref('')
|
||||||
@@ -19,7 +21,7 @@
|
|||||||
signUpOk.value = true;
|
signUpOk.value = true;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
alert(error)
|
notifyStore.notify(error, NotificationType.Error);
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
|
|||||||
45
stores/notify.store.ts
Normal file
45
stores/notify.store.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import { defineStore } from "pinia"
|
||||||
|
|
||||||
|
/*
|
||||||
|
This store manages User and Account state including the ActiveAccount
|
||||||
|
It is used in the Account administration page and the header due to it's account switching features.
|
||||||
|
*/
|
||||||
|
export interface Notification{
|
||||||
|
message: string;
|
||||||
|
type: NotificationType;
|
||||||
|
notifyTime: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum NotificationType{
|
||||||
|
Info = "alert alert-info",
|
||||||
|
Success = "alert alert-success",
|
||||||
|
Warning = "alert alert-warning",
|
||||||
|
Error = "alert alert-error",
|
||||||
|
}
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
notifications: Notification[],
|
||||||
|
notificationsArchive: Notification[],
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useNotifyStore = defineStore('notify', {
|
||||||
|
state: (): State => {
|
||||||
|
return {
|
||||||
|
notifications: [],
|
||||||
|
notificationsArchive: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
notify(messageOrError: unknown, type:NotificationType){
|
||||||
|
let message: string = "";
|
||||||
|
if (messageOrError instanceof Error) message = messageOrError.message;
|
||||||
|
if (typeof messageOrError === "string") message = messageOrError;
|
||||||
|
const notification: Notification = {message, type, notifyTime: Date.now()};
|
||||||
|
this.notifications.push(notification);
|
||||||
|
setTimeout(this.removeNotification.bind(this), 5000, notification);
|
||||||
|
},
|
||||||
|
removeNotification(notification: Notification){
|
||||||
|
this.notifications = this.notifications.filter(n => n.notifyTime != notification.notifyTime);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user