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