production-taskbar-client / src / main / ipc / helpdeskChannel.js
helpdeskChannel.js
Raw
import { ipcMain, BrowserWindow, app, screen } from "electron";
import path from "path";
import _ from "lodash";

import settings from "../settings";
import { createBarcodeHandler, parseUserId } from "../utils/barcodeHandler";
import { findWindow } from "../utils/winapi/getWindowData";
import openDevToolsWindow from "../utils/openDevToolsWindow";

const isDev = process.env.NODE_ENV === "development";

const kInputEventChannel = "input-event";
const kHelpdeskChannel = "helpdesk-channel";
const kSupportWindow = "openSupportWindow";
const kOverlayWindow = "openOverlayWindow";
const kHelpdeskRoute = "helpdesk";
const kHelpdeskOverlayRoute = "helpdesk-overlay";
const kOpenIssues = "open-issues";

const readIssuesFromSettings = () => {
  const array = settings.get(kOpenIssues);
  return (
    array?.map((id) => {
      return { id };
    }) || []
  );
};

const saveIssueToSettings = (issues) => {
  return settings.set(
    kOpenIssues,
    issues.map((i) => i.id)
  );
};

export default async function initHelpdeskChannel(mainWindow) {
  //* Handle support window
  let supportWin;
  let overlayWin;
  let supportDevToolsWin;
  let overlayDevToolsWin;
  const cachedOpenIssues = readIssuesFromSettings();

  // Open Helpdesk window
  ipcMain.handle(kSupportWindow, async () => {
    if (supportWin) {
      supportWin.focus();
      return;
    }

    mainWindow.webContents.send(kHelpdeskChannel, {
      event: "helpdesk-form-opened",
    });

    const { height: screenHeight } = isDev
      ? screen.getPrimaryDisplay().workAreaSize
      : screen.getPrimaryDisplay().size;

    let width = 900;
    let height = 700;

    if (screenHeight <= 600) {
      width = 700;
      height = 500;
    } else if (screenHeight <= 768) {
      width = 800;
      height = 600;
    }

    const win = new BrowserWindow({
      width,
      height,
      center: true,
      show: true,
      alwaysOnTop: false,
      resizable: isDev,
      minimizable: false,
      maximizable: false,
      backgroundColor: "#2e2c29",
      webPreferences: {
        preload: path.join(app.getAppPath(), "./dist/preload.js"),
        nodeIntegration: true,
        contextIsolation: false,
        backgroundThrottling: false,
        devTools: isDev,
        additionalArguments: ["helpdesk-form"],
      },
    });
    win.setMenu(null);
    supportWin = win;

    const barcodeProcessor = (barcode) => {
      const userId = parseUserId(barcode);
      if (userId) win.webContents.send(kInputEventChannel, userId);
    };

    const barcodeHandler = createBarcodeHandler(barcodeProcessor, 200, 4);

    const inputEventCallback = (message) => {
      if (message.event === "key-down") {
        const { char } = message.data;
        barcodeHandler(char);
      }
    };

    ipcMain.on(kInputEventChannel, inputEventCallback);

    win.on("close", () => {
      supportWin = null;
      if (!supportDevToolsWin?.isDestroyed()) supportDevToolsWin?.close();
      supportDevToolsWin = null;
      ipcMain.removeListener(kInputEventChannel, inputEventCallback);
      mainWindow.webContents.send(kHelpdeskChannel, {
        event: "helpdesk-form-closed",
      });
    });

    win.once("ready-to-show", () => {
      win.title = "Helpdesk";
      win.setAlwaysOnTop(true, "screen-saver"); // prevents from overlapping in some cases
    });

    if (isDev) {
      win.loadURL(`http://localhost:4000#/${kHelpdeskRoute}`);
      supportDevToolsWin = openDevToolsWindow({
        window: win,
        title: "Helpdesk form",
      });
    } else {
      win.loadURL(
        `file://${app.getAppPath()}/dist/renderer/index.html#/${kHelpdeskRoute}`
      );
    }
  });

  // Open helpdesk overlay window
  ipcMain.on(kOverlayWindow, () => {
    if (overlayWin) {
      overlayWin.focus();
      return;
    }

    const { width: screenW, height: screenH } =
      screen.getPrimaryDisplay().workAreaSize;

    let ratio = 5;
    if (screenW <= 1600) ratio = 4;
    if (screenW <= 1280) ratio = 3.5;
    if (screenW <= 1024) ratio = 3;

    const winWidth = Math.round(screenW / ratio);
    const winHeight = screenH;
    const winX = Math.round(screenW - winWidth);
    const winY = 0;

    const win = new BrowserWindow({
      x: winX,
      y: winY,
      width: winWidth,
      height: winHeight,
      show: false,
      alwaysOnTop: true,
      skipTaskbar: true,
      transparent: true,
      frame: false,
      resizable: false,
      minimizable: false,
      maximizable: false,
      webPreferences: {
        preload: path.join(app.getAppPath(), "./dist/preload.js"),
        nodeIntegration: true,
        contextIsolation: false,
        backgroundThrottling: false,
        devTools: isDev,
        additionalArguments: ["helpdesk-overlay"],
      },
    });
    win.setMenu(null);
    overlayWin = win;

    win.once("ready-to-show", () => {
      win.setAlwaysOnTop(true, "screen-saver");
      win.showInactive();
      setTimeout(() => win.setIgnoreMouseEvents(true), 500);
    });

    win.on("close", () => {
      if (!overlayDevToolsWin?.isDestroyed()) overlayDevToolsWin?.close();
      overlayWin = null;
      overlayDevToolsWin = null;
    });

    if (isDev) {
      win.loadURL(`http://localhost:4000#/${kHelpdeskOverlayRoute}`);
      overlayDevToolsWin = openDevToolsWindow({
        window: win,
        title: "Helpdesk overlay",
      });
    } else {
      win.loadURL(
        `file://${app.getAppPath()}/dist/renderer/index.html#/${kHelpdeskOverlayRoute}`
      );
    }
  });

  // Handle helpdesk actions
  ipcMain.handle(kHelpdeskChannel, async (_e, { event, data }) => {
    if (event === "add-issue") {
      cachedOpenIssues.push(data);
      saveIssueToSettings(cachedOpenIssues);

      if (overlayWin) {
        overlayWin.webContents.send(kHelpdeskChannel, {
          event: "overlay-add-issue",
          data,
        });
      } else {
        ipcMain.emit(kOverlayWindow);
      }

      return cachedOpenIssues;
    }

    if (event === "remove-issue-id") {
      _.remove(cachedOpenIssues, (i) => i.id === data);
      saveIssueToSettings(cachedOpenIssues);
      return cachedOpenIssues;
    }

    if (event === "remove-all-issues") {
      settings.set(kOpenIssues, []);
      cachedOpenIssues.splice(0, cachedOpenIssues.length);
      if (overlayWin) overlayWin.close();
    }

    if (event === "get-open-issues") {
      return readIssuesFromSettings();
    }

    if (event === "get-winkhmman-path") {
      const result = findWindow({ exeName: "WinKHM.exe" }, () => {});
      if (result) {
        return path.join(path.dirname(result.path), "WinKHMMan.exe");
      }
    }

    if (event === "helpdesk-form-close") {
      supportWin.close();
    }

    if (event === "helpdesk-form-show") {
      supportWin.show();
      return true;
    }
    if (event === "helpdesk-form-hide") {
      supportWin.hide();
      return true;
    }

    return null;
  });

  if (!_.isEmpty(cachedOpenIssues))
    setTimeout(() => ipcMain.emit(kOverlayWindow), 10_000);
}