nuxt ui notifications (#390)

* nuxt ui notifications

* use crispInit function

---------

Co-authored-by: Julien Nahum <julien@nahum.net>
This commit is contained in:
Favour Olayinka 2024-05-06 13:19:06 +01:00 committed by GitHub
parent 9f7cdd09fd
commit 49e6382bbb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 167 additions and 82 deletions

View File

@ -47,7 +47,7 @@
</NuxtLayout> </NuxtLayout>
<ToolsStopImpersonation /> <ToolsStopImpersonation />
<Notifications /> <NotificationsWrapper />
<feature-base /> <feature-base />
</div> </div>
</template> </template>
@ -125,6 +125,7 @@ export default {
}, },
mounted() { mounted() {
useCrisp().onCrispInit()
useCrisp().showChat() useCrisp().showChat()
}, },

View File

@ -0,0 +1,35 @@
<template>
<UNotifications
:ui="{
strategy: 'override',
position,
}"
>
<template #title="{ title }">
<span v-html="title" />
</template>
<template #description="{ description }">
<span v-html="description" />
</template>
</UNotifications>
</template>
<script setup>
// fixed flex flex-col justify-end z-[55] bottom-0 end-0 w-full sm:w-96
// fixed flex flex-col justify-end z-[55] top-auto bottom-0 w-full sm:w-96
const appStore = useAppStore()
const crispChatOpened = computed(() => appStore.crisp.chatOpened)
const crispHidden = computed(() => appStore.crisp.hidden)
const position = computed(() => {
if (crispHidden.value) {
return 'end-0 bottom-0'
} else {
if (crispChatOpened.value) {
return 'bottom-0'
}
return 'end-0 bottom-20'
}
})
</script>

View File

@ -1,50 +1,68 @@
const { notify } = useNotification() export function useAlert () {
export const useAlert = () => { function success (message, autoClose = 10000, options = {}) {
function success(message, autoClose = 10000) { return useToast().add({
notify({ icon: 'i-heroicons-check-circle',
title: "Success", title: options.title ?? 'Success',
text: message, description: message,
type: "success", color: 'green',
duration: autoClose, timeout: autoClose,
...options
}) })
} }
function error(message, autoClose = 10000) { function error (message, autoClose = 10000, options = {}) {
notify({ return useToast().add({
title: "Error", icon: 'i-heroicons-exclamation-circle',
text: message, title: options.title ?? 'Error',
type: "error", description: message,
duration: autoClose, color: 'red',
timeout: autoClose,
...options
}) })
} }
function warning(message, autoClose = 10000) { function warning (message, autoClose = 10000, options = {}) {
notify({ return useToast().add({
title: "Warning", icon: 'i-heroicons-exclamation-triangle',
text: message, title: options.title ?? 'Warning',
type: "warning", description: message,
duration: autoClose, color: 'yellow',
timeout: autoClose,
...options
}) })
} }
function confirm(message, success, failure = () => {}, autoClose = 10000) { function confirm (
notify({ message,
title: "Confirm", onSuccess,
text: message, onFailure = null,
type: "confirm", autoClose = 10000,
duration: autoClose, options = {}
data: { ) {
success, return useToast().add({
failure, icon: 'i-heroicons-question-mark-circle',
}, title: options.title ?? 'Are you sure?',
description: message,
color: 'blue',
timeout: autoClose,
actions: [
{ label: options.successLabel ?? 'Yes', click: onSuccess },
...(onFailure ? [{ label: options.failureLabel ?? 'No', click: onFailure }] : [])
],
...options
}) })
} }
function remove (id) {
useToast().remove(id)
}
return { return {
success, success,
error, error,
warning, warning,
confirm, confirm,
remove
} }
} }

View File

@ -1,80 +1,106 @@
export const useCrisp = () => { export function useCrisp () {
let crisp = import.meta.client ? window.Crisp : null const crisp = import.meta.client ? window.Crisp : null
function openChat() { function onCrispInit () {
if (!crisp) return if (!crisp)
return
crisp.chat.onChatOpened(() => {
useAppStore().crisp.chatOpened = true
})
crisp.chat.onChatClosed(() => {
useAppStore().crisp.chatOpened = false
})
}
function openChat () {
if (!crisp)
return
showChat() showChat()
crisp.chat.open() crisp.chat.open()
} }
function showChat() { function showChat () {
if (!crisp) return if (!crisp)
return
crisp.chat.show() crisp.chat.show()
useAppStore().crisp.hidden = false
} }
function hideChat() { function hideChat () {
if (!crisp) return if (!crisp)
return
crisp.chat.hide() crisp.chat.hide()
useAppStore().crisp.hidden = true
} }
function closeChat() { function closeChat () {
if (!crisp) return if (!crisp)
return
crisp.chat.close() crisp.chat.close()
} }
function openAndShowChat(message = null) { function openAndShowChat (message = null) {
if (!crisp) return if (!crisp)
return
openChat() openChat()
if (message) sendTextMessage(message) if (message)
sendTextMessage(message)
} }
function openHelpdesk() { function openHelpdesk () {
if (!crisp) return if (!crisp)
return
openChat() openChat()
crisp.chat.setHelpdeskView() crisp.chat.setHelpdeskView()
} }
function openHelpdeskArticle(articleSlug, locale = "en") { function openHelpdeskArticle (articleSlug, locale = 'en') {
if (!crisp) return if (!crisp)
return
crisp.chat.openHelpdeskArticle(locale, articleSlug) crisp.chat.openHelpdeskArticle(locale, articleSlug)
} }
function sendTextMessage(message) { function sendTextMessage (message) {
if (!crisp) return if (!crisp)
crisp.message.send("text", message) return
crisp.message.send('text', message)
} }
function setUser(user) { function setUser (user) {
if (!crisp) return if (!crisp)
return
crisp.user.setEmail(user.email) crisp.user.setEmail(user.email)
crisp.user.setNickname(user.name) crisp.user.setNickname(user.name)
crisp.session.setData({ crisp.session.setData({
user_id: user.id, 'user_id': user.id,
"pro-subscription": user?.is_subscribed ?? false, 'pro-subscription': user?.is_subscribed ?? false,
"stripe-id": user?.stripe_id ?? "", 'stripe-id': user?.stripe_id ?? '',
subscription: user?.has_enterprise_subscription ? "enterprise" : "pro", 'subscription': user?.has_enterprise_subscription ? 'enterprise' : 'pro'
}) })
if (user?.is_subscribed ?? false) { if (user?.is_subscribed ?? false) {
setSegments([ setSegments([
"subscribed", 'subscribed',
user?.has_enterprise_subscription ? "enterprise" : "pro", user?.has_enterprise_subscription ? 'enterprise' : 'pro'
]) ])
} }
} }
function pushEvent(event, data = {}) { function pushEvent (event, data = {}) {
if (!crisp) return if (!crisp)
return
crisp.session.pushEvent(event, data) crisp.session.pushEvent(event, data)
} }
function setSegments(segments, overwrite = false) { function setSegments (segments, overwrite = false) {
if (!crisp) return if (!crisp)
return
crisp.session.setSegments(segments, overwrite) crisp.session.setSegments(segments, overwrite)
} }
return { return {
crisp, crisp,
onCrispInit,
openChat, openChat,
showChat, showChat,
hideChat, hideChat,
@ -84,6 +110,7 @@ export const useCrisp = () => {
openHelpdeskArticle, openHelpdeskArticle,
sendTextMessage, sendTextMessage,
pushEvent, pushEvent,
setUser, setSegments,
setUser
} }
} }

View File

@ -11,7 +11,6 @@ export default defineNuxtConfig({
'@pinia/nuxt', '@pinia/nuxt',
'@vueuse/nuxt', '@vueuse/nuxt',
'@vueuse/motion/nuxt', '@vueuse/motion/nuxt',
'nuxt3-notifications',
'nuxt-simple-sitemap', 'nuxt-simple-sitemap',
'@nuxt/ui', '@nuxt/ui',
...process.env.NUXT_PUBLIC_GOOGLE_ANALYTICS_CODE ? ['nuxt-gtag'] : [], ...process.env.NUXT_PUBLIC_GOOGLE_ANALYTICS_CODE ? ['nuxt-gtag'] : [],

View File

@ -49,7 +49,6 @@
"fuse.js": "^6.4.6", "fuse.js": "^6.4.6",
"js-sha256": "^0.10.0", "js-sha256": "^0.10.0",
"libphonenumber-js": "^1.10.44", "libphonenumber-js": "^1.10.44",
"nuxt3-notifications": "^1.1.9",
"object-to-formdata": "^4.5.1", "object-to-formdata": "^4.5.1",
"pinia": "^2.1.7", "pinia": "^2.1.7",
"prismjs": "^1.24.1", "prismjs": "^1.24.1",

View File

@ -74,14 +74,12 @@ watch(form, (form) => {
onBeforeRouteLeave((to, from, next) => { onBeforeRouteLeave((to, from, next) => {
if (isDirty()) { if (isDirty()) {
return useAlert().confirm( if (window.confirm('Changes you made may not be saved. Are you sure want to leave?')) {
"Changes you made may not be saved. Are you sure want to leave?", window.onbeforeunload = null
() => { next()
window.onbeforeunload = null } else {
next() next(false)
}, }
() => {},
)
} }
next() next()
}) })

View File

@ -42,16 +42,14 @@ useOpnSeoMeta({
}) })
onBeforeRouteLeave((to, from, next) => { onBeforeRouteLeave((to, from, next) => {
if (isDirty()) { if (this.isDirty()) {
return useAlert().confirm( if (window.confirm('Changes you made may not be saved. Are you sure want to leave?')) {
"Changes you made may not be saved. Are you sure want to leave?",
() => {
window.onbeforeunload = null window.onbeforeunload = null
next() next()
}, } else {
() => {}, next(false)
) }
} }
next() next()
}) })

View File

@ -5,6 +5,10 @@ export const useAppStore = defineStore("app", {
state: () => ({ state: () => ({
layout: "default", layout: "default",
navbarHidden: false, navbarHidden: false,
crisp: {
chatOpened: false,
hidden: false
},
// App Loader // App Loader
loader: { loader: {

6
package-lock.json generated Normal file
View File

@ -0,0 +1,6 @@
{
"name": "opnform",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}