diff --git a/client/app.vue b/client/app.vue
index a5cd1846..2bb02f04 100644
--- a/client/app.vue
+++ b/client/app.vue
@@ -47,7 +47,7 @@
-
+
@@ -125,6 +125,7 @@ export default {
},
mounted() {
+ useCrisp().onCrispInit()
useCrisp().showChat()
},
diff --git a/client/components/global/NotificationsWrapper.vue b/client/components/global/NotificationsWrapper.vue
new file mode 100644
index 00000000..646007bf
--- /dev/null
+++ b/client/components/global/NotificationsWrapper.vue
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/client/composables/useAlert.js b/client/composables/useAlert.js
index e0357d3b..015778c8 100644
--- a/client/composables/useAlert.js
+++ b/client/composables/useAlert.js
@@ -1,50 +1,68 @@
-const { notify } = useNotification()
+export function useAlert () {
-export const useAlert = () => {
- function success(message, autoClose = 10000) {
- notify({
- title: "Success",
- text: message,
- type: "success",
- duration: autoClose,
+ function success (message, autoClose = 10000, options = {}) {
+ return useToast().add({
+ icon: 'i-heroicons-check-circle',
+ title: options.title ?? 'Success',
+ description: message,
+ color: 'green',
+ timeout: autoClose,
+ ...options
})
}
- function error(message, autoClose = 10000) {
- notify({
- title: "Error",
- text: message,
- type: "error",
- duration: autoClose,
+ function error (message, autoClose = 10000, options = {}) {
+ return useToast().add({
+ icon: 'i-heroicons-exclamation-circle',
+ title: options.title ?? 'Error',
+ description: message,
+ color: 'red',
+ timeout: autoClose,
+ ...options
})
}
- function warning(message, autoClose = 10000) {
- notify({
- title: "Warning",
- text: message,
- type: "warning",
- duration: autoClose,
+ function warning (message, autoClose = 10000, options = {}) {
+ return useToast().add({
+ icon: 'i-heroicons-exclamation-triangle',
+ title: options.title ?? 'Warning',
+ description: message,
+ color: 'yellow',
+ timeout: autoClose,
+ ...options
})
}
- function confirm(message, success, failure = () => {}, autoClose = 10000) {
- notify({
- title: "Confirm",
- text: message,
- type: "confirm",
- duration: autoClose,
- data: {
- success,
- failure,
- },
+ function confirm (
+ message,
+ onSuccess,
+ onFailure = null,
+ autoClose = 10000,
+ options = {}
+ ) {
+ return useToast().add({
+ 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 {
success,
error,
warning,
confirm,
+ remove
}
}
diff --git a/client/composables/useCrisp.js b/client/composables/useCrisp.js
index 308c8f2d..58613246 100644
--- a/client/composables/useCrisp.js
+++ b/client/composables/useCrisp.js
@@ -1,80 +1,106 @@
-export const useCrisp = () => {
- let crisp = import.meta.client ? window.Crisp : null
+export function useCrisp () {
+ const crisp = import.meta.client ? window.Crisp : null
- function openChat() {
- if (!crisp) return
+ function onCrispInit () {
+ if (!crisp)
+ return
+ crisp.chat.onChatOpened(() => {
+ useAppStore().crisp.chatOpened = true
+ })
+ crisp.chat.onChatClosed(() => {
+ useAppStore().crisp.chatOpened = false
+ })
+ }
+
+ function openChat () {
+ if (!crisp)
+ return
showChat()
crisp.chat.open()
}
- function showChat() {
- if (!crisp) return
+ function showChat () {
+ if (!crisp)
+ return
crisp.chat.show()
+ useAppStore().crisp.hidden = false
}
- function hideChat() {
- if (!crisp) return
+ function hideChat () {
+ if (!crisp)
+ return
crisp.chat.hide()
+ useAppStore().crisp.hidden = true
}
- function closeChat() {
- if (!crisp) return
+ function closeChat () {
+ if (!crisp)
+ return
crisp.chat.close()
}
- function openAndShowChat(message = null) {
- if (!crisp) return
+ function openAndShowChat (message = null) {
+ if (!crisp)
+ return
openChat()
- if (message) sendTextMessage(message)
+ if (message)
+ sendTextMessage(message)
}
- function openHelpdesk() {
- if (!crisp) return
+ function openHelpdesk () {
+ if (!crisp)
+ return
openChat()
crisp.chat.setHelpdeskView()
}
- function openHelpdeskArticle(articleSlug, locale = "en") {
- if (!crisp) return
+ function openHelpdeskArticle (articleSlug, locale = 'en') {
+ if (!crisp)
+ return
crisp.chat.openHelpdeskArticle(locale, articleSlug)
}
- function sendTextMessage(message) {
- if (!crisp) return
- crisp.message.send("text", message)
+ function sendTextMessage (message) {
+ if (!crisp)
+ return
+ crisp.message.send('text', message)
}
- function setUser(user) {
- if (!crisp) return
+ function setUser (user) {
+ if (!crisp)
+ return
crisp.user.setEmail(user.email)
crisp.user.setNickname(user.name)
crisp.session.setData({
- user_id: user.id,
- "pro-subscription": user?.is_subscribed ?? false,
- "stripe-id": user?.stripe_id ?? "",
- subscription: user?.has_enterprise_subscription ? "enterprise" : "pro",
+ 'user_id': user.id,
+ 'pro-subscription': user?.is_subscribed ?? false,
+ 'stripe-id': user?.stripe_id ?? '',
+ 'subscription': user?.has_enterprise_subscription ? 'enterprise' : 'pro'
})
if (user?.is_subscribed ?? false) {
setSegments([
- "subscribed",
- user?.has_enterprise_subscription ? "enterprise" : "pro",
+ 'subscribed',
+ user?.has_enterprise_subscription ? 'enterprise' : 'pro'
])
}
}
- function pushEvent(event, data = {}) {
- if (!crisp) return
+ function pushEvent (event, data = {}) {
+ if (!crisp)
+ return
crisp.session.pushEvent(event, data)
}
- function setSegments(segments, overwrite = false) {
- if (!crisp) return
+ function setSegments (segments, overwrite = false) {
+ if (!crisp)
+ return
crisp.session.setSegments(segments, overwrite)
}
return {
crisp,
+ onCrispInit,
openChat,
showChat,
hideChat,
@@ -84,6 +110,7 @@ export const useCrisp = () => {
openHelpdeskArticle,
sendTextMessage,
pushEvent,
- setUser,
+ setSegments,
+ setUser
}
}
diff --git a/client/nuxt.config.ts b/client/nuxt.config.ts
index 88919a77..39e7faca 100644
--- a/client/nuxt.config.ts
+++ b/client/nuxt.config.ts
@@ -11,7 +11,6 @@ export default defineNuxtConfig({
'@pinia/nuxt',
'@vueuse/nuxt',
'@vueuse/motion/nuxt',
- 'nuxt3-notifications',
'nuxt-simple-sitemap',
'@nuxt/ui',
...process.env.NUXT_PUBLIC_GOOGLE_ANALYTICS_CODE ? ['nuxt-gtag'] : [],
diff --git a/client/package.json b/client/package.json
index 44bc0d3d..47bb8ece 100644
--- a/client/package.json
+++ b/client/package.json
@@ -49,7 +49,6 @@
"fuse.js": "^6.4.6",
"js-sha256": "^0.10.0",
"libphonenumber-js": "^1.10.44",
- "nuxt3-notifications": "^1.1.9",
"object-to-formdata": "^4.5.1",
"pinia": "^2.1.7",
"prismjs": "^1.24.1",
diff --git a/client/pages/forms/[slug]/edit.vue b/client/pages/forms/[slug]/edit.vue
index 5e468fcc..9b9a443a 100644
--- a/client/pages/forms/[slug]/edit.vue
+++ b/client/pages/forms/[slug]/edit.vue
@@ -74,14 +74,12 @@ watch(form, (form) => {
onBeforeRouteLeave((to, from, next) => {
if (isDirty()) {
- return useAlert().confirm(
- "Changes you made may not be saved. Are you sure want to leave?",
- () => {
- window.onbeforeunload = null
- next()
- },
- () => {},
- )
+ if (window.confirm('Changes you made may not be saved. Are you sure want to leave?')) {
+ window.onbeforeunload = null
+ next()
+ } else {
+ next(false)
+ }
}
next()
})
diff --git a/client/pages/forms/create/index.vue b/client/pages/forms/create/index.vue
index a69bebda..a54446e8 100644
--- a/client/pages/forms/create/index.vue
+++ b/client/pages/forms/create/index.vue
@@ -42,16 +42,14 @@ useOpnSeoMeta({
})
onBeforeRouteLeave((to, from, next) => {
- if (isDirty()) {
- return useAlert().confirm(
- "Changes you made may not be saved. Are you sure want to leave?",
- () => {
+ if (this.isDirty()) {
+ if (window.confirm('Changes you made may not be saved. Are you sure want to leave?')) {
window.onbeforeunload = null
next()
- },
- () => {},
- )
- }
+ } else {
+ next(false)
+ }
+ }
next()
})
diff --git a/client/stores/app.js b/client/stores/app.js
index 853285f7..37016c44 100644
--- a/client/stores/app.js
+++ b/client/stores/app.js
@@ -5,6 +5,10 @@ export const useAppStore = defineStore("app", {
state: () => ({
layout: "default",
navbarHidden: false,
+ crisp: {
+ chatOpened: false,
+ hidden: false
+ },
// App Loader
loader: {
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 00000000..e4c309cd
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,6 @@
+{
+ "name": "opnform",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {}
+}