1- const { app, BrowserWindow, protocol, net } = require ( 'electron' ) ;
1+ const { app, BrowserWindow, protocol, net, Notification , ipcMain , session } = require ( 'electron' ) ;
22const path = require ( 'path' ) ;
33const url = require ( 'url' ) ;
44
@@ -31,9 +31,9 @@ function createWindow() {
3131 icon : path . join ( __dirname , '../assets/icon.png' ) ,
3232 webPreferences : {
3333 preload : path . join ( __dirname , 'preload.js' ) ,
34- nodeIntegration : isDev ,
35- contextIsolation : ! isDev ,
36- webSecurity : ! isDev ,
34+ nodeIntegration : false ,
35+ contextIsolation : true ,
36+ webSecurity : true ,
3737 } ,
3838 } ) ;
3939
@@ -55,6 +55,43 @@ function createWindow() {
5555}
5656
5757app . whenReady ( ) . then ( ( ) => {
58+ // ── Content Security Policy ───────────────────────────────────────
59+ // Set a proper CSP to silence the Electron security warning about
60+ // "unsafe-eval" / missing CSP. In development we allow the local
61+ // dev-server origin; in production only the custom app:// scheme.
62+ session . defaultSession . webRequest . onHeadersReceived ( ( details , callback ) => {
63+ let csp ;
64+ if ( isDev ) {
65+ // Dev mode: Metro/webpack needs 'unsafe-eval' for source maps
66+ // and hot-reload, blob: for dynamic chunks, ws: for HMR.
67+ csp =
68+ "default-src 'self' http://localhost:8081;" +
69+ " script-src 'self' http://localhost:8081 'unsafe-inline' 'unsafe-eval' blob:;" +
70+ " style-src 'self' http://localhost:8081 'unsafe-inline';" +
71+ " img-src 'self' http://localhost:8081 data: https: blob:;" +
72+ " font-src 'self' http://localhost:8081 data:;" +
73+ " connect-src 'self' http://localhost:8081 https: wss: ws:;" +
74+ " media-src 'self' http://localhost:8081 data: blob:;" +
75+ " worker-src 'self' blob:;" ;
76+ } else {
77+ csp =
78+ "default-src 'self' app:;" +
79+ " script-src 'self' app: 'unsafe-inline';" +
80+ " style-src 'self' app: 'unsafe-inline';" +
81+ " img-src 'self' app: data: https:;" +
82+ " font-src 'self' app: data:;" +
83+ " connect-src 'self' app: https: wss:;" +
84+ " media-src 'self' app: data:;" +
85+ " worker-src 'self' blob:;" ;
86+ }
87+
88+ callback ( {
89+ responseHeaders : {
90+ ...details . responseHeaders ,
91+ 'Content-Security-Policy' : [ csp ] ,
92+ } ,
93+ } ) ;
94+ } ) ;
5895 // Register the custom app:// protocol handler for production builds.
5996 // This serves all files from the dist/ directory so that absolute asset
6097 // paths in the bundled HTML/JS/CSS resolve correctly.
@@ -77,6 +114,47 @@ app.whenReady().then(() => {
77114
78115 createWindow ( ) ;
79116
117+ // ── Notification IPC handlers ──────────────────────────────────────
118+ // Allow the renderer to request native Electron Notification objects
119+ // which map to macOS Notification Center, Windows Toast & Linux
120+ // libnotify/notify-send automatically.
121+
122+ ipcMain . handle ( 'notifications:isSupported' , ( ) => {
123+ return Notification . isSupported ( ) ;
124+ } ) ;
125+
126+ ipcMain . handle ( 'notifications:show' , ( _event , payload ) => {
127+ if ( ! Notification . isSupported ( ) ) {
128+ console . warn ( 'Native notifications are not supported on this platform' ) ;
129+ return false ;
130+ }
131+
132+ try {
133+ const notification = new Notification ( {
134+ title : payload . title || 'Resgrid Dispatch' ,
135+ body : payload . body || '' ,
136+ icon : path . join ( __dirname , '../assets/icon.png' ) ,
137+ silent : false ,
138+ } ) ;
139+
140+ notification . on ( 'click' , ( ) => {
141+ // Focus / restore the main window when the notification is clicked
142+ const windows = BrowserWindow . getAllWindows ( ) ;
143+ if ( windows . length > 0 ) {
144+ const win = windows [ 0 ] ;
145+ if ( win . isMinimized ( ) ) win . restore ( ) ;
146+ win . focus ( ) ;
147+ }
148+ } ) ;
149+
150+ notification . show ( ) ;
151+ return true ;
152+ } catch ( err ) {
153+ console . error ( 'Failed to show native notification:' , err ) ;
154+ return false ;
155+ }
156+ } ) ;
157+
80158 app . on ( 'activate' , ( ) => {
81159 if ( BrowserWindow . getAllWindows ( ) . length === 0 ) {
82160 createWindow ( ) ;
0 commit comments