const { app, BrowserWindow, ipcMain, Menu, Tray } = require('electron') const path = require('path') const { spawn } = require('child_process') const isDev = process.env.NODE_ENV === 'development' || (!app.isPackaged && !process.env.NODE_ENV) let mainWindow let tray let backendProcess function createWindow() { mainWindow = new BrowserWindow({ width: 1400, height: 900, minWidth: 1200, minHeight: 700, webPreferences: { nodeIntegration: false, contextIsolation: true, preload: path.join(__dirname, 'preload.js') }, icon: path.join(__dirname, '../public/icon.png'), titleBarStyle: 'hiddenInset', frame: process.platform !== 'win32', backgroundColor: '#F8FAFC' }) if (isDev) { mainWindow.loadURL('http://localhost:5173') mainWindow.webContents.openDevTools() } else { // In production, load the built files const indexPath = path.join(__dirname, '../dist/index.html') console.log('Loading:', indexPath) mainWindow.loadFile(indexPath) // DevTools nur öffnen wenn explizit gewünscht // mainWindow.webContents.openDevTools() // Log any errors mainWindow.webContents.on('did-fail-load', (event, errorCode, errorDescription) => { console.error('Failed to load:', errorCode, errorDescription) }) mainWindow.webContents.on('console-message', (event, level, message) => { console.log('Console:', message) }) // Warte bis Seite geladen ist mainWindow.webContents.on('did-finish-load', () => { console.log('Page loaded successfully') }) } mainWindow.on('closed', () => { mainWindow = null }) // Custom window controls for Windows if (process.platform === 'win32') { mainWindow.on('maximize', () => { mainWindow.webContents.send('window-maximized') }) mainWindow.on('unmaximize', () => { mainWindow.webContents.send('window-unmaximized') }) } } function createTray() { // Tray-Funktion vorerst deaktiviert, da Icon fehlt // TODO: Tray-Icon hinzufügen return tray = new Tray(path.join(__dirname, '../public/tray-icon.png')) const contextMenu = Menu.buildFromTemplate([ { label: 'SkillMate öffnen', click: () => { if (mainWindow) { mainWindow.show() } else { createWindow() } } }, { type: 'separator' }, { label: 'Beenden', click: () => { app.quit() } } ]) tray.setToolTip('SkillMate') tray.setContextMenu(contextMenu) tray.on('click', () => { if (mainWindow) { mainWindow.isVisible() ? mainWindow.hide() : mainWindow.show() } else { createWindow() } }) } function startBackend() { // Backend nur im Development-Modus automatisch starten // In Production wird es extern gestartet return if (!isDev) { // In production, backend is bundled with the app const backendPath = app.isPackaged ? path.join(process.resourcesPath, 'backend', 'index.js') : path.join(__dirname, '../../backend/dist/index.js') console.log('Starting backend from:', backendPath) // Check if backend exists const fs = require('fs') if (!fs.existsSync(backendPath)) { console.error('Backend not found at:', backendPath) // Try alternative path const altPath = path.join(__dirname, '../backend/index.js') console.log('Trying alternative path:', altPath) if (fs.existsSync(altPath)) { backendPath = altPath } } backendProcess = spawn('node', [backendPath], { env: { ...process.env, NODE_ENV: 'production', PORT: '3001', DATABASE_PATH: path.join(app.getPath('userData'), 'skillmate.db'), LOG_PATH: path.join(app.getPath('userData'), 'logs') }, stdio: ['pipe', 'pipe', 'pipe'] }) backendProcess.stdout.on('data', (data) => { console.log(`Backend: ${data}`) }) backendProcess.stderr.on('data', (data) => { console.error(`Backend Error: ${data}`) }) backendProcess.on('error', (error) => { console.error('Failed to start backend:', error) }) backendProcess.on('exit', (code) => { console.log(`Backend exited with code ${code}`) }) } } app.whenReady().then(() => { createWindow() createTray() startBackend() }) app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit() } }) app.on('before-quit', () => { if (backendProcess) { backendProcess.kill() } }) app.on('activate', () => { if (mainWindow === null) { createWindow() } }) // IPC handlers ipcMain.handle('app:minimize', () => { mainWindow.minimize() }) ipcMain.handle('app:maximize', () => { if (mainWindow.isMaximized()) { mainWindow.unmaximize() } else { mainWindow.maximize() } }) ipcMain.handle('app:close', () => { mainWindow.close() }) ipcMain.handle('app:getVersion', () => { return app.getVersion() }) ipcMain.handle('app:getPath', (event, name) => { return app.getPath(name) })