feat: live presence, delivery-tick sync, brand rollout, call fixes, desktop 0.1.3

Live presence (fixes stale in-call/status until refresh — impossible in apps):
- server broadcasts a user's status over the chat socket on connect/disconnect, call
  join/leave, and status change (chat.js broadcastPresence; signaling + routes hooks).
- client onPresence() updates the contact dot + open-chat header live.

Chat delivery ticks (#6): chat-list row now mirrors the thread (delivered→double grey,
read→blue) via a new 'with' field on the delivered relay + onChatRead/onChatDelivered.

Call fixes: no bogus 'host handed over' when a 1:1 call ends (leaveMeeting forced);
branded call-connecting + chat-thread loaders; header subtitle tracks live call state.

Notifications: web notify + sw.js use sender/group DP + brand icon (not old wordmark);
desktop shell drops Web Push so only the single native toast fires (#5).

Brand: master icon/splash/loaders wired everywhere (PWA/favicon/apple-touch/.ico),
branded login (blue + gold CTA), branded toasts (BZToast) on all pages, Electron splash.

Desktop: dev auto-targets localhost (packaged→prod); version 0.1.3 with new multi-size
icon; dropped unused node-notifier; removed home-mockup.html.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-02 15:43:02 +05:30
parent a152005b71
commit dc1915bb43
26 changed files with 411 additions and 338 deletions
+3 -2
View File
@@ -22,8 +22,9 @@ Output in `desktop/dist/`:
- `latest.yml` — the update manifest electron-updater reads
- `*.blockmap` — enables delta downloads
The release build points at production (`SERVER_URL` defaults to `https://remote.bizgaze.com`
in `main.js`).
A PACKAGED build points at production (`main.js` defaults `SERVER_URL` to
`https://remote.bizgaze.com` when `app.isPackaged`); running from source in dev defaults to
`http://localhost:8090`. `SERVER_URL` overrides either.
## Publish a release (self-hosted feed)
1. Bump `version` in `desktop/package.json` (semver — electron-updater compares this).
+6 -2
View File
@@ -3,11 +3,15 @@
Electron shell that loads the live Connect web UI and adds native screen capture. See the
overall plan in [../CLIENTS.md](../CLIENTS.md).
## Run (dev)
## Run (dev = local testing)
```bash
npm install
SERVER_URL=http://localhost:8090 npm start # default is https://remote.bizgaze.com
npm start # dev auto-targets http://localhost:8090 (your local server)
SERVER_URL=https://remote.bizgaze.com npm start # …or point dev at production to compare
```
`npm start` IS the local desktop test — no separate "local" installer needed. In dev (unpackaged)
the shell defaults to the local server; a PACKAGED installer defaults to production. `SERVER_URL`
overrides either. (Bash/Git-Bash syntax above; in PowerShell: `$env:SERVER_URL='…'; npm start`.)
## Build installers
```bash
+27 -2
View File
@@ -97,9 +97,26 @@ ipcMain.on('set-unread', (_e, { count, dataUrl } = {}) => {
} catch (_) {}
});
const SERVER_URL = (process.env.SERVER_URL || 'https://remote.bizgaze.com').replace(/\/+$/, '');
// Server origin: a PACKAGED build (the installer) points at production; running from source in dev
// (`npm start`, unpackaged) defaults to the local server so you can test the shell against localhost
// with no flags or separate "local" build. SERVER_URL always overrides (e.g. point dev at prod).
const SERVER_URL = (process.env.SERVER_URL || (app.isPackaged ? 'https://remote.bizgaze.com' : 'http://localhost:8090')).replace(/\/+$/, '');
let win;
let splash;
// A tiny brand-blue splash (splash.html) shown while the web UI loads, so launch feels instant
// and on-brand instead of a blank window. Closed as soon as the main window is ready to show.
function createSplash() {
splash = new BrowserWindow({
width: 440, height: 440, frame: false, resizable: false, center: true,
backgroundColor: '#1F3B73', skipTaskbar: true, alwaysOnTop: true, show: true,
webPreferences: { contextIsolation: true, nodeIntegration: false },
});
splash.loadFile(path.join(__dirname, 'splash.html'));
splash.on('closed', () => { splash = null; });
}
function closeSplash() { if (splash) { try { splash.close(); } catch (_) {} splash = null; } }
function createWindow() {
win = new BrowserWindow({
@@ -108,7 +125,8 @@ function createWindow() {
minWidth: 880,
minHeight: 600,
title: 'Biz Connect',
backgroundColor: '#0f1830',
backgroundColor: '#1F3B73',
show: false, // reveal only once the page is ready — the splash covers the gap
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true,
@@ -118,6 +136,12 @@ function createWindow() {
},
});
// Reveal the main window when its first paint is ready, and retire the splash. A fallback
// timer guarantees we never get stuck on the splash if the load stalls.
const reveal = () => { closeSplash(); if (win && !win.isVisible()) { win.show(); win.focus(); } };
win.once('ready-to-show', reveal);
setTimeout(reveal, 12000);
// Open the landing page (same entry as the website): the "before login" screen with the
// no-login "Share my screen" option + sign-in. It redirects logged-in users straight to /home.
win.loadURL(SERVER_URL + '/');
@@ -158,6 +182,7 @@ function configureSession() {
app.whenReady().then(() => {
configureSession();
createSplash();
createWindow();
Menu.setApplicationMenu(null); // hide the default menu bar; the web UI is the chrome
app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) createWindow(); });
+2 -6
View File
@@ -1,6 +1,6 @@
{
"name": "biz-connect-desktop",
"version": "0.1.2",
"version": "0.1.3",
"description": "Biz Connect technician desktop client — loads the Connect web UI with native screen capture",
"author": {
"name": "BizGaze",
@@ -12,8 +12,7 @@
"dist": "electron-builder"
},
"dependencies": {
"electron-updater": "^6.3.9",
"node-notifier": "^10.0.1"
"electron-updater": "^6.3.9"
},
"devDependencies": {
"electron": "^31.0.0",
@@ -26,9 +25,6 @@
"buildResources": "build",
"output": "dist"
},
"asarUnpack": [
"**/node_modules/node-notifier/**"
],
"publish": [
{
"provider": "generic",
+26
View File
@@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
html,body{margin:0;height:100%;overflow:hidden;}
body{background:#1F3B73;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:22px;
font-family:'Segoe UI',system-ui,sans-serif;-webkit-user-select:none;user-select:none;}
/* Branded orbit mark (white C + circling yellow dot) — matches the app icon/loader */
.mark{width:96px;height:96px;}
.mark .dot{transform-origin:50px 50px;animation:spin 1.1s linear infinite;}
@keyframes spin{to{transform:rotate(360deg);}}
.name{color:#fff;font-size:20px;font-weight:700;letter-spacing:.3px;}
.name b{color:#FFC708;font-weight:700;}
.sub{color:rgba(255,255,255,.66);font-size:12.5px;margin-top:-14px;}
</style>
</head>
<body>
<svg class="mark" viewBox="0 0 100 100" aria-label="Biz Connect">
<circle cx="50" cy="50" r="34" fill="none" stroke="#ffffff" stroke-width="9" stroke-linecap="round" stroke-dasharray="165 300" transform="rotate(38 50 50)"/>
<g class="dot"><circle cx="84" cy="50" r="7" fill="#FFC708"/></g>
</svg>
<div class="name">Biz <b>Connect</b></div>
<div class="sub">Starting…</div>
</body>
</html>