From b6627d322b5900cb76b6431761cf4a34ca93a00f Mon Sep 17 00:00:00 2001 From: MathieuG-P <40181755+Zagrios@users.noreply.github.com> Date: Sun, 3 Jul 2022 22:57:54 +0200 Subject: [PATCH] notification system --- package-lock.json | 8 ++- package.json | 1 + src/renderer/App.tsx | 3 +- .../notification-item.component.tsx | 46 ++++++++++++ .../notification-overlay.component.tsx | 20 ++++++ .../components/svgs/bsm-icon.component.tsx | 4 +- .../components/svgs/cross-icon.component.tsx | 7 ++ src/renderer/services/notification.service.ts | 70 +++++++++++++++++++ 8 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 src/renderer/components/notification/notification-item.component.tsx create mode 100644 src/renderer/components/notification/notification-overlay.component.tsx create mode 100644 src/renderer/components/svgs/cross-icon.component.tsx create mode 100644 src/renderer/services/notification.service.ts diff --git a/package-lock.json b/package-lock.json index 92072d3b..021375af 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "electron-react-boilerplate", + "name": "bs-manager", "requires": true, "lockfileVersion": 1, "dependencies": { @@ -1911,6 +1911,12 @@ "@types/jest": "*" } }, + "@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "dev": true + }, "@types/verror": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.5.tgz", diff --git a/package.json b/package.json index 46ad9003..e41131fb 100644 --- a/package.json +++ b/package.json @@ -160,6 +160,7 @@ "@types/react-outside-click-handler": "^1.3.1", "@types/react-test-renderer": "^17.0.2", "@types/terser-webpack-plugin": "^5.0.4", + "@types/uuid": "^8.3.4", "@types/webpack-bundle-analyzer": "^4.4.1", "@types/webpack-env": "^1.17.0", "@typescript-eslint/eslint-plugin": "^5.29.0", diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index 506644cd..7ad3a866 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -8,7 +8,7 @@ import { SettingsPage } from "./pages/settings-page.component"; import { BsmProgressBar } from "./components/progress-bar/bsm-progress-bar.component"; import { useEffect } from "react"; import { ThemeService } from "./services/theme.service"; -import { ThemeConfig } from "./config/default-configuration.config"; +import { NotificationOverlay } from "./components/notification/notification-overlay.component"; export default function App() { @@ -26,6 +26,7 @@ export default function App() {
+
diff --git a/src/renderer/components/notification/notification-item.component.tsx b/src/renderer/components/notification/notification-item.component.tsx new file mode 100644 index 00000000..f2c6e6cd --- /dev/null +++ b/src/renderer/components/notification/notification-item.component.tsx @@ -0,0 +1,46 @@ +import { NotificationResult, NotificationType, Notification } from "renderer/services/notification.service" +import { motion } from "framer-motion" +import { BsmImage } from "../shared/bsm-image.component"; +import BeatRunningImg from "../../../../assets/images/apngs/beat-running.png"; +import BeatConflictImg from "../../../../assets/images/apngs/beat-conflict.png"; +import BeatWaitingImg from "../../../../assets/images/apngs/beat-waiting.png"; +import BeatImpatientImg from "../../../../assets/images/apngs/beat-impatient.png"; +import { BsmButton } from "../shared/bsm-button.component"; + +export function NotificationItem({resolver, index, notification}: {resolver?: (value: NotificationResult|string) => void, index: number, notification: Notification}) { + + const renderImage = () => { + if(notification.type === NotificationType.SUCCESS){ return ; } + if(notification.type === NotificationType.WARNING){ return ; } + if(notification.type === NotificationType.ERROR){ return ; } + return + } + + const renderNeonColors = () => { + if(notification.type === NotificationType.SUCCESS){ return "bg-green-400 shadow-green-400"; } + if(notification.type === NotificationType.WARNING){ return "bg-yellow-400 shadow-yellow-400"; } + if(notification.type === NotificationType.ERROR){ return "bg-red-500 shadow-red-500"; } + return "bg-gray-800 shadow-gray-800 dark:bg-white dark:shadow-white"; + } + + return ( + +
+
+ {renderImage()} +
+

{notification.title}

+ {notification.desc &&

{notification.desc}

} +
+
+ {notification.actions && ( +
+ {notification.actions.map(a => {a.title})} +
+ )} +
+ + +
+ ) +} diff --git a/src/renderer/components/notification/notification-overlay.component.tsx b/src/renderer/components/notification/notification-overlay.component.tsx new file mode 100644 index 00000000..f1398aaa --- /dev/null +++ b/src/renderer/components/notification/notification-overlay.component.tsx @@ -0,0 +1,20 @@ +import { useObservable } from "renderer/hooks/use-observable.hook" +import { NotificationService } from "renderer/services/notification.service" +import { NotificationItem } from "./notification-item.component"; +import { AnimatePresence, AnimateSharedLayout, motion } from "framer-motion"; + +export function NotificationOverlay() { + + const notificationService = NotificationService.getInstance(); + + const notifications = useObservable(notificationService.notifications$); + + + return ( + + + {notifications?.map((n, index) => )} + + + ) +} diff --git a/src/renderer/components/svgs/bsm-icon.component.tsx b/src/renderer/components/svgs/bsm-icon.component.tsx index 9ebc927a..8401ccfc 100644 --- a/src/renderer/components/svgs/bsm-icon.component.tsx +++ b/src/renderer/components/svgs/bsm-icon.component.tsx @@ -7,8 +7,9 @@ import { TerminalIcon } from "./terminal-icon.component"; import { DesktopIcon } from "./desktop-icon.component"; import { OculusIcon } from "./oculus-icon.component"; import { AddIcon } from "./add-icon.component"; +import CrossIcon from "./cross-icon.component"; -export type BsmIconType = "settings"|"trash"|"favorite"|"folder"|"bsNote"|"terminal"|"desktop"|"oculus"|"add"; +export type BsmIconType = "settings"|"trash"|"favorite"|"folder"|"bsNote"|"terminal"|"desktop"|"oculus"|"add"|"cross"; export function BsmIcon({className, icon}: {className?: string, icon: BsmIconType}) { @@ -22,6 +23,7 @@ export function BsmIcon({className, icon}: {className?: string, icon: BsmIconTyp if(icon === "desktop"){ return } if(icon === "oculus"){ return } if(icon === "add"){ return } + if(icon === "cross"){ return } } return ( diff --git a/src/renderer/components/svgs/cross-icon.component.tsx b/src/renderer/components/svgs/cross-icon.component.tsx new file mode 100644 index 00000000..4defa13e --- /dev/null +++ b/src/renderer/components/svgs/cross-icon.component.tsx @@ -0,0 +1,7 @@ +export default function CrossIcon(props: {className: string}){ + return ( + + + + ) +} diff --git a/src/renderer/services/notification.service.ts b/src/renderer/services/notification.service.ts new file mode 100644 index 00000000..d12b7082 --- /dev/null +++ b/src/renderer/services/notification.service.ts @@ -0,0 +1,70 @@ +import { BehaviorSubject } from "rxjs"; +import { v4 as uuidv4 } from 'uuid'; + +export class NotificationService{ + + private static instance: NotificationService; + + public readonly notifications$: BehaviorSubject; + + public static getInstance(): NotificationService{ + if(!NotificationService.instance){ NotificationService.instance = new NotificationService(); } + return NotificationService.instance; + } + + private constructor(){ + this.notifications$ = new BehaviorSubject([]); + + setInterval(() => { + this.notify({title: "coucou le testaze aze azeazeaze", desc: "ceci est un test de notification ne rien faire", actions:[{id: "1",title: "Continuer"}, {id: "1",title: "Faire autre"}, {id: "1",title: "Annuler", cancel: true}]}); + }, 5000) + } + + public notify(notification: Notification): Promise{ + let resovableNotification: ResolvableNotification; + const promise = new Promise(resolve => { + resovableNotification = {id: uuidv4(), notification: notification, resolver: resolve } + setTimeout(() => resolve(NotificationResult.NO_CHOICE), notification.duration || 10000); + }); + + this.notifications$.next([...this.notifications$.value, resovableNotification]); + + promise.then(() => { + this.notifications$.next(this.notifications$.value.filter(n => n.id !== resovableNotification.id)); + }) + + return promise; + } + +} + +export interface Notification { + title: string, + type?: NotificationType + desc?: string, + actions?: NotificationAction[], + duration?: number, +} + +export enum NotificationType { + SUCCESS = 0, + WARNING = 1, + ERROR = 2, +} + +export interface NotificationAction { + id: string, + title: string, + cancel?: boolean +} + +export enum NotificationResult { + NO_CHOICE = "no_choice", + CLOSE = "close", +} + +interface ResolvableNotification{ + id: string, + resolver: (value: NotificationResult|string) => void, + notification: Notification +} \ No newline at end of file