From 6995b7630e665a675274ea41df8bb475997ff283 Mon Sep 17 00:00:00 2001 From: denis0001-dev Date: Sun, 26 Jul 2026 18:33:22 +0300 Subject: [PATCH] Remove the Electron version --- .cursor/rules/general.mdc | 3 +- .dockerignore | 1 - .github/workflows/build.yml | 171 ------------------ .vscode/tasks.json | 35 +--- README.en.md | 11 +- README.md | 11 +- package.json | 26 +-- src/electron/electron.d.ts | 25 --- src/electron/forge.config.ts | 45 ----- src/electron/main.ts | 65 ------- src/electron/preload.ts | 11 -- src/main/App.tsx | 2 - src/main/Electron.tsx | 11 -- src/main/core/electron/electron.scss | 41 ----- src/main/core/electron/electron.ts | 17 -- src/main/core/init.ts | 3 +- .../push-notifications/push-notifications.ts | 144 ++------------- src/main/main.tsx | 1 - src/main/pages/auth/LoginForm.tsx | 8 +- .../ui/left/settings/NotificationsPanel.tsx | 8 +- src/main/state/user.ts | 7 +- tsconfig.json | 2 +- vite.config.ts | 43 +---- 23 files changed, 37 insertions(+), 654 deletions(-) delete mode 100644 .github/workflows/build.yml delete mode 100644 src/electron/electron.d.ts delete mode 100644 src/electron/forge.config.ts delete mode 100644 src/electron/main.ts delete mode 100644 src/electron/preload.ts delete mode 100644 src/main/Electron.tsx delete mode 100644 src/main/core/electron/electron.scss delete mode 100644 src/main/core/electron/electron.ts diff --git a/.cursor/rules/general.mdc b/.cursor/rules/general.mdc index 6328741..745bdfe 100644 --- a/.cursor/rules/general.mdc +++ b/.cursor/rules/general.mdc @@ -39,9 +39,8 @@ When working with this project, follow these rules: - NEVER create database migrations, they are auto-generated. ## Project Structure Awareness -- This is a React/TypeScript frontend with Python FastAPI backend +- This is a React/TypeScript browser frontend (desktop is Compose Multiplatform in the Android/KMP repo) - Uses MDUI components for UI -- Has Electron support for desktop app - Uses Zustand for state management - Uses use-immer for immutable state updates - Uses React Router for navigation diff --git a/.dockerignore b/.dockerignore index 2275e13..a2993bf 100644 --- a/.dockerignore +++ b/.dockerignore @@ -17,7 +17,6 @@ node_modules npm-debug.log .vite dist -dist-electron build out coverage diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 03009be..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,171 +0,0 @@ -name: Build Electron app - -on: - workflow_dispatch: - inputs: - apiBaseUrl: - description: "API base URL" - required: false - default: "fromchat.ru" - type: string - push: - tags: ["v**"] - paths: - - 'frontend/**' - - 'package.json' - - '.github/workflows/build.yml' - -concurrency: - group: build-${{ github.ref }} - cancel-in-progress: true - -permissions: - contents: read - -jobs: - build-linux: - name: Build Linux - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '24' - - - name: Cache dependencies - uses: actions/cache@v4 - with: - path: node_modules - key: npm-ubuntu-latest-node-24-${{ hashFiles('package.json') }} - restore-keys: | - npm-ubuntu-latest-node-24- - - - name: Install dependencies - run: npm install --ignore-scripts --no-audit --no-fund - - - name: Cache Electron downloads - uses: actions/cache@v4 - with: - path: | - ~/.cache/electron - ~/.cache/electron-builder - key: electron-ubuntu-latest-${{ hashFiles('package.json', 'package.json') }} - restore-keys: | - electron-ubuntu-latest- - - - name: Build Electron app - shell: bash - env: - VITE_API_BASE_URL: ${{ inputs.apiBaseUrl }} - run: npm run build:electron - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: FromChat-linux - path: | - frontend/build/electron/forge/make/*/** - if-no-files-found: error - - build-macos: - name: Build macOS - runs-on: macos-latest - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '24' - - - name: Cache dependencies - uses: actions/cache@v4 - with: - path: node_modules - key: npm-macos-latest-node-24-${{ hashFiles('package.json') }} - restore-keys: | - npm-macos-latest-node-24- - - - name: Install dependencies - run: npm install --ignore-scripts --no-audit --no-fund - - # - name: Cache Electron downloads - # uses: actions/cache@v4 - # with: - # path: | - # ~/.cache/electron - # ~/.cache/electron-builder - # key: electron-macos-latest-${{ hashFiles('package.json') }} - # restore-keys: | - # electron-macos-latest- - - - name: Build Electron app - shell: bash - env: - VITE_API_BASE_URL: ${{ inputs.apiBaseUrl }} - run: npm run build:electron - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: FromChat-macOS - path: | - frontend/build/electron/forge/make/zip/darwin/*/**.zip - if-no-files-found: error - - build-windows: - name: Build Windows - runs-on: windows-latest - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Force npm to use Bash - run: npm config set script-shell "C:\Program Files\Git\bin\bash.exe" - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '24' - - - name: Cache dependencies - uses: actions/cache@v4 - with: - path: node_modules - key: npm-windows-latest-node-24-${{ hashFiles('package.json') }} - restore-keys: | - npm-windows-latest-node-24- - - - name: Install dependencies - run: npm install --ignore-scripts --no-audit --no-fund - - - name: Cache Electron downloads - uses: actions/cache@v4 - with: - path: | - ~\AppData\Local\electron\Cache - ~\AppData\Local\electron-builder\Cache - key: electron-windows-latest-${{ hashFiles('package.json') }} - restore-keys: | - electron-windows-latest- - - - name: Build Electron app - shell: bash - env: - VITE_API_BASE_URL: ${{ inputs.apiBaseUrl }} - run: npm run build:electron - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: FromChat-windows - path: | - frontend/build/electron/forge/make/zip/win32/x64 - if-no-files-found: error \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 3c6d252..48b01d0 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -19,25 +19,6 @@ }, "isBackground": true }, - { - "label": "Frontend (Electron)", - "type": "shell", - "command": "npm run frontend:electron:dev", - "options": { - "cwd": "${workspaceFolder}" - }, - "presentation": { - "echo": true, - "reveal": "always", - "focus": false, - "panel": "shared" - }, - "group": { - "kind": "build" - }, - "isBackground": true - }, - { "label": "Web", "dependsOn": ["Frontend (Web)"], @@ -51,20 +32,6 @@ "focus": false, "panel": "shared" } - }, - { - "label": "Electron", - "dependsOn": ["Frontend (Electron)"], - "dependsOrder": "parallel", - "group": { - "kind": "build" - }, - "presentation": { - "echo": true, - "reveal": "always", - "focus": false, - "panel": "shared" - } } ] -} \ No newline at end of file +} diff --git a/README.en.md b/README.en.md index 6a2e203..a65bd6e 100644 --- a/README.en.md +++ b/README.en.md @@ -7,14 +7,14 @@ **Web client for FromChat messenger** - [🌐 Web Client](https://github.com/fromchat-messenger/web) • [🖥️ Backend](https://github.com/fromchat-messenger/backend) • [📱 Android](https://github.com/fromchat-messenger/android) • [🌍 Website](https://github.com/fromchat-messenger/site) + [🌐 Web Client](https://github.com/fromchat-messenger/web) • [🖥️ Backend](https://github.com/fromchat-messenger/backend) • [📱 Android / Desktop](https://github.com/fromchat-messenger/android) • [🌍 Website](https://github.com/fromchat-messenger/site) --- ## 📝 Description -FromChat Web is a React/TypeScript client (browser and Electron) for the FromChat server. +FromChat Web is a React/TypeScript browser client for the FromChat server. The desktop client is Compose Multiplatform in the [Android/KMP repository](https://github.com/fromchat-messenger/android). **Note:** Landing pages and legal documents live in [fromchat-messenger/site](https://github.com/fromchat-messenger/site). @@ -43,7 +43,6 @@ FromChat Web is a React/TypeScript client (browser and Electron) for the FromCha - Device management - WebSocket real-time updates - Dark mode -- Optional Electron desktop build --- @@ -58,7 +57,6 @@ FromChat Web is a React/TypeScript client (browser and Electron) for the FromCha | Zustand + use-immer | state | | Motion | animations | | TweetNaCl.js | cryptography | -| Electron | desktop (optional) | --- @@ -98,8 +96,6 @@ npm run frontend:dev # Vite on :8301 npm run frontend:typecheck # TypeScript npm run frontend:build # typecheck + production build → build/normal npm run frontend:preview # preview built frontend -npm run frontend:electron:dev # Electron + Vite -npm run frontend:electron:build # Electron package ``` ### Project structure @@ -114,7 +110,6 @@ web/ │ │ ├── state/ # Zustand stores │ │ ├── utils/ │ │ └── css/ # SCSS (Material Design) -│ ├── electron/ # Electron main/preload │ └── protocol/ # shared protocol (@fromchat/protocol) ├── plugins/ # Vite plugins ├── vite.config.ts @@ -157,7 +152,7 @@ GNU Affero General Public License v3.0 — see [LICENSE](./LICENSE). ## 🔗 Related Repositories - [Backend API](https://github.com/fromchat-messenger/backend) -- [Android Client](https://github.com/fromchat-messenger/android) +- [Android / Desktop (KMP)](https://github.com/fromchat-messenger/android) - [Website](https://github.com/fromchat-messenger/site) - [Deployment](https://github.com/fromchat-messenger/deployment) diff --git a/README.md b/README.md index 322d448..676ea22 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ _Написано ИИ. Могут быть ошибки._ ## 📝 Описание -Веб-клиент FromChat — React/TypeScript приложение (браузер и Electron) для работы с сервером FromChat. +Веб-клиент FromChat — React/TypeScript приложение для браузера. Десктоп-клиент — Compose Multiplatform в [Android/KMP репозитории](https://github.com/fromchat-messenger/android). ## Развернуть в 1 клик @@ -23,7 +23,6 @@ docker run -d --restart always -p 8301:80 fromchat/web:latest - Управление устройствами - WebSocket для реал-тайма - Тёмный режим -- Сборка Electron (опционально) ## 🏗️ Технологический стек @@ -36,7 +35,6 @@ docker run -d --restart always -p 8301:80 fromchat/web:latest | Zustand + use-immer | состояние | | Motion | анимации | | TweetNaCl.js | криптография | -| Electron | десктоп (опционально) | ## 🔧 Разработка @@ -65,8 +63,6 @@ npm run frontend:dev # Vite на :8301 npm run frontend:typecheck # TypeScript npm run frontend:build # typecheck + production build → build/normal npm run frontend:preview # preview собранного фронта -npm run frontend:electron:dev # Electron + Vite -npm run frontend:electron:build # сборка Electron ``` ### Структура проекта @@ -81,7 +77,6 @@ web/ │ │ ├── state/ # Zustand stores │ │ ├── utils/ │ │ └── css/ # SCSS (Material Design) -│ ├── electron/ # main/preload Electron │ └── protocol/ # общий протокол (@fromchat/protocol) ├── plugins/ # Vite-плагины ├── vite.config.ts @@ -112,6 +107,6 @@ GNU Affero General Public License v3.0 — см. [LICENSE](./LICENSE). ## 🔗 Связанные репозитории - [Backend API](https://github.com/fromchat-messenger/backend) -- [Android Client](https://github.com/fromchat-messenger/android) +- [Android / Desktop (KMP)](https://github.com/fromchat-messenger/android) - [Website](https://github.com/fromchat-messenger/site) -- [Deployment](https://github.com/fromchat-messenger/deployment) \ No newline at end of file +- [Deployment](https://github.com/fromchat-messenger/deployment) diff --git a/package.json b/package.json index cc7b920..ad84273 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,6 @@ "private": true, "version": "0.0.0", "type": "module", - "main": "build/electron/core/main.js", "description": "A 100% Open Source Messenger", "license": "GPL-3.0", "authors": "denis0001-dev", @@ -11,38 +10,23 @@ "frontend:dev": "vite", "frontend:typecheck": "tsc --project tsconfig.json", "frontend:build": "npm run frontend:typecheck && vite build", - "frontend:electron:dev": "VITE_ELECTRON=true npm run frontend:dev", - "frontend:electron:build": "VITE_ELECTRON=true npm run frontend:build && rm -rf out && electron-forge make --force --arch arm64,x64", "frontend:preview": "vite preview", "frontend:dependencies": "npm install --ignore-scripts", "frontend:clean": "rm -rf build", - "build:electron": "npm run frontend:electron:build", - "build": "npm run frontend:build && npm run build:electron", + "build": "npm run frontend:build", "preview": "docker compose -f docker-compose.yml up --build --watch", "preview:clean": "docker compose -f docker-compose.yml down -v --remove-orphans", "prepare": "husky", "install": "if [ ! -e .env ]; then cp .env.example .env; fi" }, - "files": [ - "build/electron" - ], "devDependencies": { - "@electron-forge/cli": "^7.9.0", - "@electron-forge/maker-deb": "^7.9.0", - "@electron-forge/maker-dmg": "^7.9.0", - "@electron-forge/maker-rpm": "^7.9.0", - "@electron-forge/maker-squirrel": "^7.9.0", - "@electron-forge/maker-zip": "^7.9.0", - "@electron-forge/plugin-auto-unpack-natives": "^7.9.0", - "@electron-forge/plugin-fuses": "^7.9.0", - "@electron/fuses": "^1.0.0", "@types/he": "^1.2.3", + "@types/node": "^26.1.1", "@types/react": "^19.1.13", "@types/react-dom": "^19.1.9", "@vitejs/plugin-react": "^5.0.3", "autoprefixer": "^10.4.21", "dotenv-cli": "^11.0.0", - "electron": "^39.2.7", "husky": "^9.1.7", "postcss": "^8.5.6", "rollup-plugin-visualizer": "^6.0.4", @@ -51,13 +35,10 @@ "terser": "^5.44.0", "typescript": "~5.9.2", "vite": "^7.1.6", - "vite-plugin-electron": "^0.29.0", - "vite-plugin-electron-renderer": "^0.14.6", "vite-plugin-html": "^3.2.2", "vite-plugin-sass-dts": "^1.3.34" }, "dependencies": { - "electron-squirrel-startup": "^1.0.1", "escape-string-regexp": "^5.0.0", "he": "^1.2.0", "idb": "^8.0.3", @@ -70,8 +51,5 @@ "tweetnacl": "^1.0.3", "use-immer": "^0.11.0", "zustand": "^5.0.8" - }, - "config": { - "forge": "src/electron/forge.config.ts" } } diff --git a/src/electron/electron.d.ts b/src/electron/electron.d.ts deleted file mode 100644 index 5dd2c3c..0000000 --- a/src/electron/electron.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -export type Platform = "win32" | "darwin" | "linux" - -export interface NotificationShowOptions { - title: string; - body: string; - icon?: string; - tag?: string; -} - -export interface ElectronNotifications { - requestPermission: () => Promise; - show: (options: NotificationShowOptions) => Promise; -} - -export interface ElectronInterface { - desktop: true, - platform: Platform, - notifications: ElectronNotifications -} - -declare global { - interface Window { - electronInterface: ElectronInterface - } -} \ No newline at end of file diff --git a/src/electron/forge.config.ts b/src/electron/forge.config.ts deleted file mode 100644 index 4280750..0000000 --- a/src/electron/forge.config.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { FusesPlugin } from '@electron-forge/plugin-fuses'; -import { FuseV1Options, FuseVersion } from '@electron/fuses'; -import type { ForgeConfig } from '@electron-forge/shared-types'; - -export default { - packagerConfig: { - asar: true, - }, - outDir: "build/electron/forge", - rebuildConfig: {}, - makers: [ - { - name: '@electron-forge/maker-zip', - config: {}, - platforms: ['win32', 'darwin'], - }, - { - name: '@electron-forge/maker-deb', - config: {}, - platforms: ['linux'], - }, - { - name: '@electron-forge/maker-rpm', - config: {}, - platforms: ['linux'], - }, - ], - plugins: [ - { - name: '@electron-forge/plugin-auto-unpack-natives', - config: {}, - }, - // Fuses are used to enable/disable various Electron functionality - // at package time, before code signing the application - new FusesPlugin({ - version: FuseVersion.V1, - [FuseV1Options.RunAsNode]: false, - [FuseV1Options.EnableCookieEncryption]: true, - [FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false, - [FuseV1Options.EnableNodeCliInspectArguments]: false, - [FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true, - [FuseV1Options.OnlyLoadAppFromAsar]: true, - }), - ], -} satisfies ForgeConfig; \ No newline at end of file diff --git a/src/electron/main.ts b/src/electron/main.ts deleted file mode 100644 index 38da357..0000000 --- a/src/electron/main.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { app, BrowserWindow, Notification, ipcMain } from 'electron'; -import path from "path"; -import type { NotificationShowOptions } from "./electron.d.ts"; - -let mainWindow: BrowserWindow | null = null; - -app.whenReady().then(() => { - mainWindow = new BrowserWindow({ - title: 'Main window', - minWidth: 800, - minHeight: 420, - webPreferences: { - preload: path.join(import.meta.dirname, "preload.mjs") - }, - titleBarStyle: "hidden", - trafficLightPosition: { - x: 16 - 4, - y: 16 - 4 - }, - titleBarOverlay: process.platform !== "darwin" - }); - - if (process.env.VITE_DEV_SERVER_URL) { - mainWindow.loadURL(process.env.VITE_DEV_SERVER_URL); - } else { - mainWindow.loadFile('build/electron/dist/index.html'); - } - - // Handle notification permission requests - ipcMain.handle('request-notification-permission', async () => { - if (Notification.isSupported()) { - return 'granted'; - } - return 'denied'; - }); - - // Handle showing notifications - ipcMain.handle("show-notification", async (_event, options: NotificationShowOptions) => { - if (Notification.isSupported()) { - try { - const notification = new Notification({ - title: options.title, - body: options.body, - icon: options.icon, - silent: false, - urgency: 'normal' - }); - - notification.on('click', () => { - if (mainWindow) { - mainWindow.show(); - mainWindow.focus(); - } - }); - - notification.show(); - return true; - } catch (error) { - console.error('Error creating notification:', error); - return false; - } - } - return false; - }); -}); \ No newline at end of file diff --git a/src/electron/preload.ts b/src/electron/preload.ts deleted file mode 100644 index 50b98b7..0000000 --- a/src/electron/preload.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { contextBridge, ipcRenderer } from "electron"; -import type { ElectronInterface, NotificationShowOptions, Platform } from "./electron.d.ts"; - -contextBridge.exposeInMainWorld("electronInterface", { - desktop: true, - platform: process.platform as Platform, - notifications: { - requestPermission: () => ipcRenderer.invoke("request-notification-permission"), - show: (options: NotificationShowOptions) => ipcRenderer.invoke("show-notification", options) - } -} satisfies ElectronInterface); \ No newline at end of file diff --git a/src/main/App.tsx b/src/main/App.tsx index f82dbba..f0f49a1 100644 --- a/src/main/App.tsx +++ b/src/main/App.tsx @@ -1,6 +1,5 @@ import { BrowserRouter, Routes, Route, useNavigate, useLocation, matchRoutes, Navigate, type RouteObject } from "react-router-dom"; import { AnimatePresence, motion } from "motion/react"; -import { ElectronTitleBar } from "./Electron"; import { useUserStore } from "./state/user"; import { lazy, useEffect, useRef, useState } from "react"; import { parseProfileLink } from "./core/profileLinks"; @@ -133,7 +132,6 @@ export default function App() { return authReady && ( -
diff --git a/src/main/Electron.tsx b/src/main/Electron.tsx deleted file mode 100644 index 03c2522..0000000 --- a/src/main/Electron.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { PRODUCT_NAME } from "./core/config"; -import { isElectron } from "./core/electron/electron"; - -export function ElectronTitleBar() { - return isElectron && ( -
- {window.electronInterface.platform == "darwin" &&
} -
{PRODUCT_NAME}
-
- ) -} \ No newline at end of file diff --git a/src/main/core/electron/electron.scss b/src/main/core/electron/electron.scss deleted file mode 100644 index 9f45831..0000000 --- a/src/main/core/electron/electron.scss +++ /dev/null @@ -1,41 +0,0 @@ -@use "../../css/material" as *; - -#electron-title-bar { - display: none; -} - -html.electron { - #electron-title-bar { - display: flex; - flex-direction: row; - gap: 8px; - min-height: 40px; - background-color: $color-dark-surface-container; - width: 100%; - -webkit-app-region: drag; - user-select: none; - z-index: 10; - transition: background-color 0.5s ease; - flex-shrink: 0; - - &.color-surface { - background-color: $color-dark-surface; - } - } - - #window-title { - flex: 1; - display: flex; - align-items: center; - font-weight: 500; - } - - #main-wrapper { - flex: 1; - min-height: 0; - } - - &.platform-darwin .macos-padding { - width: 80px; - } -} \ No newline at end of file diff --git a/src/main/core/electron/electron.ts b/src/main/core/electron/electron.ts deleted file mode 100644 index c69cce2..0000000 --- a/src/main/core/electron/electron.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @fileoverview Electron-specific code - * @description This module initializes Electron-specific functionality. - * @author denis0001-dev - * @version 1.0.0 - */ - -import "./electron.scss"; - -export const isElectron = import.meta.env.VITE_ELECTRON && window.electronInterface != undefined; - -if (isElectron) { - console.log("Running in Electron"); - document.documentElement.classList.add("electron", `platform-${window.electronInterface.platform}`); -} else { - console.log("Running in normal browser"); -} \ No newline at end of file diff --git a/src/main/core/init.ts b/src/main/core/init.ts index a59aa57..631ea94 100644 --- a/src/main/core/init.ts +++ b/src/main/core/init.ts @@ -7,7 +7,8 @@ import { PRODUCT_NAME } from "./config"; import { enableMapSet } from "immer"; -import type { Platform } from "../../electron/electron.d"; + +type Platform = "win32" | "darwin" | "linux"; function detectPlatform(): Platform { const userAgent = navigator.userAgent.toLowerCase(); diff --git a/src/main/core/push-notifications/push-notifications.ts b/src/main/core/push-notifications/push-notifications.ts index 7ca24cb..c8d1265 100644 --- a/src/main/core/push-notifications/push-notifications.ts +++ b/src/main/core/push-notifications/push-notifications.ts @@ -1,9 +1,5 @@ import api from "@/core/api"; -import { isElectron } from "@/core/electron/electron"; -import { websocket } from "@/core/websocket"; -import type { NewMessageWebSocketMessage, WebSocketMessage } from "@/core/types"; import serviceWorker from "./service-worker?worker&url"; -import logo from "@/images/logo.svg"; export interface PushSubscriptionData { endpoint: string; @@ -26,8 +22,6 @@ export interface NotificationPayload { let isInitialized = false; let registration: ServiceWorkerRegistration | null = null; let subscription: PushSubscription | null = null; -let isElectronReceiverRunning = false; -let messageListener: ((event: MessageEvent) => void) | null = null; // Helper functions function urlBase64ToUint8Array(base64String: string): Uint8Array { @@ -97,35 +91,6 @@ async function sendSubscriptionToServer(token: string): Promise { } } -async function showMessageNotification(message: any): Promise { - try { - await showNotification({ - title: `New message from ${message.username}`, - body: message.content.length > 100 - ? message.content.substring(0, 100) + "..." - : message.content, - icon: message.profile_picture || logo, - tag: `message_${message.id}`, - data: { - type: "public_message", - message_id: message.id, - sender_id: message.user_id, - sender_username: message.username - } - }); - } catch (error) { - console.error("Failed to show message notification:", error); - } -} - -async function handleWebSocketMessage(response: WebSocketMessage): Promise { - // Handle notifications for new messages - if (response.type === "newMessage" && response.data) { - const newResponse = response as NewMessageWebSocketMessage; - await showMessageNotification(newResponse.data); - } -} - // Public API functions export async function initialize(): Promise { if (isInitialized) { @@ -133,32 +98,24 @@ export async function initialize(): Promise { } try { - if (isElectron) { - // For Electron, we just need to request permission - const permission = await window.electronInterface.notifications.requestPermission(); - isInitialized = permission === "granted"; + if (!("serviceWorker" in navigator) || !("PushManager" in window)) { + console.log("Push messaging is not supported"); + return false; + } + + try { + registration = await navigator.serviceWorker.register(serviceWorker, { type: "module" }); + console.log("Service Worker registered successfully"); + + const permission = await Notification.requestPermission(); + if (permission === "granted") { + await subscribeToWebPush(); + isInitialized = true; + } return isInitialized; - } else { - // For web browsers, initialize service worker and push manager - if (!("serviceWorker" in navigator) || !("PushManager" in window)) { - console.log("Push messaging is not supported"); - return false; - } - - try { - registration = await navigator.serviceWorker.register(serviceWorker, { type: "module" }); - console.log("Service Worker registered successfully"); - - const permission = await Notification.requestPermission(); - if (permission === "granted") { - await subscribeToWebPush(); - isInitialized = true; - } - return isInitialized; - } catch (error) { - console.error("Service Worker registration failed:", error); - return false; - } + } catch (error) { + console.error("Service Worker registration failed:", error); + return false; } } catch (error) { console.error("Failed to initialize notification service:", error); @@ -171,11 +128,6 @@ export async function subscribe(token: string): Promise { return false; } - if (isElectron) { - // In Electron, we don't need server-side subscription - return true; - } - // If subscription doesn't exist, try to get it from the push manager or create a new one if (!subscription && registration) { try { @@ -194,32 +146,12 @@ export async function subscribe(token: string): Promise { return await sendSubscriptionToServer(token); } -export async function showNotification(payload: NotificationPayload): Promise { - if (isElectron) { - try { - return await window.electronInterface.notifications.show({ - title: payload.title, - body: payload.body, - icon: payload.icon, - tag: payload.tag - }); - } catch (error) { - console.error("Failed to show Electron notification:", error); - return false; - } - } - - // For web browsers, notifications are handled by the service worker - // when push messages are received from the server +export async function showNotification(_payload: NotificationPayload): Promise { + // Notifications are handled by the service worker when push messages are received from the server return false; } export async function unsubscribe(): Promise { - if (isElectron) { - // In Electron, we don't need to unsubscribe from server - return true; - } - if (!subscription) { return true; } @@ -235,43 +167,5 @@ export async function unsubscribe(): Promise { } export function isSupported(): boolean { - if (isElectron) { - return true; // Electron always supports notifications - } return "serviceWorker" in navigator && "PushManager" in window; } - -// Electron-specific functions -export async function startElectronReceiver(): Promise { - if (!isElectron || isElectronReceiverRunning) { - return; - } - - isElectronReceiverRunning = true; - - // Add our own message listener to the existing WebSocket - messageListener = (event: MessageEvent) => { - try { - const response: WebSocketMessage = JSON.parse(event.data); - handleWebSocketMessage(response); - } catch (error) { - console.error('Failed to parse WebSocket message:', error); - } - }; - - websocket.addEventListener('message', messageListener); -} - -export function stopElectronReceiver(): void { - if (!isElectron) { - return; - } - - isElectronReceiverRunning = false; - - // Remove our message listener - if (messageListener) { - websocket.removeEventListener('message', messageListener); - messageListener = null; - } -} \ No newline at end of file diff --git a/src/main/main.tsx b/src/main/main.tsx index 83eec38..ba9d3ad 100644 --- a/src/main/main.tsx +++ b/src/main/main.tsx @@ -9,7 +9,6 @@ import './css/style.scss'; import "./utils/material"; import "./core/init"; -import "./core/electron/electron"; import { createRoot } from 'react-dom/client'; import App from './App'; import { StrictMode } from 'react'; diff --git a/src/main/pages/auth/LoginForm.tsx b/src/main/pages/auth/LoginForm.tsx index 4484f07..2de10ae 100644 --- a/src/main/pages/auth/LoginForm.tsx +++ b/src/main/pages/auth/LoginForm.tsx @@ -7,8 +7,7 @@ import { useUserStore } from "@/state/user"; import { MaterialButton } from "@/utils/material"; import api from "@/core/api"; import { AuthTextField, type AuthTextFieldHandle } from "./AuthTextField"; -import { initialize, isSupported, startElectronReceiver, subscribe } from "@/core/push-notifications/push-notifications"; -import { isElectron } from "@/core/electron/electron"; +import { initialize, isSupported, subscribe } from "@/core/push-notifications/push-notifications"; import type { Alert, AlertType } from "./Auth"; import { AuthHeader, AlertsContainer } from "./Auth"; import styles from "./auth.module.scss"; @@ -115,11 +114,6 @@ export function LoginForm({ onSwitchMode }: LoginFormProps) { const initialized = await initialize(); if (initialized) { await subscribe(data.token); - - if (isElectron) { - await startElectronReceiver(); - } - console.log("Notifications enabled"); } else { console.log("Notification permission denied"); diff --git a/src/main/pages/chat/ui/left/settings/NotificationsPanel.tsx b/src/main/pages/chat/ui/left/settings/NotificationsPanel.tsx index ea84bf7..ca105c5 100644 --- a/src/main/pages/chat/ui/left/settings/NotificationsPanel.tsx +++ b/src/main/pages/chat/ui/left/settings/NotificationsPanel.tsx @@ -2,7 +2,6 @@ import { useState, useRef } from "react"; import { MaterialList, MaterialListItem, MaterialSwitch, type MDUISwitch } from "@/utils/material"; import { useUserStore } from "@/state/user"; import { initialize, subscribe, unsubscribe, isSupported } from "@/core/push-notifications/push-notifications"; -import { isElectron } from "@/core/electron/electron"; import api from "@/core/api"; import styles from "@/pages/chat/css/settings-dialog.module.scss"; @@ -23,12 +22,7 @@ export function NotificationsPanel() { setChecking(true); try { - let permission: string; - if (isElectron) { - permission = await window.electronInterface.notifications.requestPermission(); - } else { - permission = Notification.permission; - } + const permission = Notification.permission; console.log("checkPushStatus", permission); setPushEnabled(permission === "granted"); } catch (error) { diff --git a/src/main/state/user.ts b/src/main/state/user.ts index c927f08..fe9f017 100644 --- a/src/main/state/user.ts +++ b/src/main/state/user.ts @@ -2,8 +2,7 @@ import { create } from "zustand"; import type { User } from "@/core/types"; import api from "@/core/api"; import { API_BASE_URL } from "@/core/config"; -import { initialize, subscribe, startElectronReceiver, isSupported } from "@/core/push-notifications/push-notifications"; -import { isElectron } from "@/core/electron/electron"; +import { initialize, subscribe, isSupported } from "@/core/push-notifications/push-notifications"; import { onlineStatusManager } from "@/core/onlineStatusManager"; import { typingManager } from "@/core/typingManager"; import type { UserState } from "./types"; @@ -126,10 +125,6 @@ export const useUserStore = create((set) => ({ const initialized = await initialize(); if (initialized) { await subscribe(token); - - if (isElectron) { - await startElectronReceiver(); - } } } } catch (e) { diff --git a/tsconfig.json b/tsconfig.json index 4ac21a3..f045adc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -31,6 +31,6 @@ "jsx": "react-jsx", "jsxImportSource": "react" }, - "include": ["src", "src/electron/electron.d.ts", "src/protocol"], + "include": ["src", "src/protocol"], "exclude": ["**/__*/**", "__*"] } \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index 9b77086..4a25d69 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,7 +1,6 @@ import { defineConfig, PluginOption } from "vite"; import { createHtmlPlugin } from "vite-plugin-html"; import autoprefixer from "autoprefixer"; -import electron from "vite-plugin-electron/simple"; import react from "@vitejs/plugin-react"; import path from "path"; import { visualizer } from 'rollup-plugin-visualizer'; @@ -10,7 +9,7 @@ import { optimizeCssModules } from './plugins/optimizeCssModules'; import { optimizeSvg } from './plugins/optimizeSvg'; const currentDir = path.resolve(__dirname); -const outDir = process.env.VITE_ELECTRON ? `${currentDir}/build/electron` : `${currentDir}/build/normal`; +const outDir = `${currentDir}/build/normal`; const plugins: PluginOption[] = [ react({ @@ -42,34 +41,6 @@ const plugins: PluginOption[] = [ }) ] -if (process.env.VITE_ELECTRON) { - plugins.push( - electron({ - main: { - entry: "src/electron/main.ts", - vite: { - build: { - outDir: `${outDir}/core` - } - } - }, - preload: { - input: "src/electron/preload.ts", - vite: { - build: { - outDir: `${outDir}/core` - } - } - }, - renderer: {}, - }) - ); -} - -const apiProxyTarget = process.env.VITE_API_BASE_URL?.startsWith("http") - ? process.env.VITE_API_BASE_URL - : "http://127.0.0.1:8300"; - export default defineConfig({ root: path.resolve(__dirname, "src"), envDir: currentDir, @@ -80,20 +51,10 @@ export default defineConfig({ "@fromchat/protocol": path.resolve(__dirname, "./src/protocol/index.ts") } }, - // Dev entry on 8301: browser uses same-origin `/api` (HTTP + WebSocket, e.g. `/api/chat/ws`). server: { host: '0.0.0.0', port: 8301, strictPort: true, - proxy: { - "/api": { - target: apiProxyTarget, - changeOrigin: true, - rewrite: (path) => path.replace(/^\/api/, ""), - ws: true, - proxyTimeout: 0, - } - }, allowedHosts: ["beta.fromchat.ru"] }, appType: "spa", @@ -125,4 +86,4 @@ export default defineConfig({ chunkSizeWarningLimit: 1024 }, cacheDir: `${currentDir}/build/cache` -}); \ No newline at end of file +});