main
ts 117 lines 2.96 KB
Raw
1 import type { NotificationObject } from "./useGlobalActions"
2 import { useStorage } from "@vueuse/core"
3 import _uniqBy from "lodash/uniqBy"
4 import { NButton } from "naive-ui"
5 import { computed, h } from "vue"
6 import { useSettingsStore } from "@/stores/settings"
7 import dayjs from "@/utils/dayjs"
8 import { secureLocalStorage } from "@/utils/secure-storage"
9 import { useGlobalActions } from "./useGlobalActions"
10
11 export type NotificationCategory = "alert"
12 export type NotificationType = "success" | "info" | "warning" | "error" | "default" | undefined
13 export interface Notification {
14 id: number | string
15 category: NotificationCategory
16 type: NotificationType
17 title: string
18 description: string
19 read: boolean
20 date: string | Date
21 action?: () => void
22 actionTitle?: string
23 }
24
25 export interface PrependOptions {
26 /** prepend and send a notification */
27 sendNotify?: boolean
28 /** send a notification only if there isn't any item with match id/type/category */
29 autoNotify?: boolean
30 }
31
32 const list = useStorage<Notification[]>("notifications-list", [], secureLocalStorage({ session: true }))
33
34 export function useNotifications() {
35 const hasUnread = computed(() => list.value.filter(o => !o.read).length !== 0)
36 const hasNotifications = computed(() => list.value.length !== 0)
37 const dFormats = useSettingsStore().dateFormat
38
39 function formatDatetime(date: Date | string) {
40 const datejs = dayjs(date)
41 if (!datejs.isValid()) return date
42
43 if (dayjs().isSame(datejs, "day")) {
44 return datejs.format(dFormats.time)
45 }
46 return datejs.format("D MMM")
47 }
48
49 return {
50 list,
51 hasUnread,
52 hasNotifications,
53 formatDatetime,
54 setRead: (id: string | number) => {
55 const item = list.value.find(o => o.id === id)
56 if (item) {
57 item.read = true
58 }
59 },
60 setAllRead: () => {
61 for (const item of list.value) {
62 item.read = true
63 }
64 },
65 deleteOne: (id: string | number) => {
66 list.value = list.value.filter(o => o.id !== id)
67 },
68 deleteAll: () => {
69 list.value = []
70 },
71 prepend: (newItem: Notification, options?: PrependOptions) => {
72 let sendNotify = options?.sendNotify || false
73 const autoNotify = options?.autoNotify || false
74
75 if (autoNotify) {
76 const item = list.value.find(
77 o => o.id === newItem.id && o.type === newItem.type && o.category === newItem.category
78 )
79
80 if (!item) {
81 sendNotify = true
82 }
83 }
84
85 if (sendNotify) {
86 const notify: NotificationObject = {
87 title: newItem.title,
88 content: newItem.description,
89 type: newItem.type,
90 meta: formatDatetime(newItem.date).toString(),
91 action: undefined,
92 duration: 3000,
93 keepAliveOnHover: true
94 }
95
96 if (newItem.action) {
97 notify.action = () =>
98 h(
99 NButton,
100 {
101 text: true,
102 type: newItem.type,
103 onClick: newItem.action
104 },
105 {
106 default: () => newItem.actionTitle || "Details"
107 }
108 )
109 }
110
111 useGlobalActions().notification(notify)
112 }
113
114 list.value = _uniqBy([newItem, ...list.value], o => o.id)
115 }
116 }
117 }