Files
kiosco_desk/main/background.ts
T
2025-11-27 11:02:45 -06:00

317 lines
9.1 KiB
TypeScript

import path, { resolve } from "path";
import { app, ipcMain } from "electron";
import serve from "electron-serve";
import { createWindow } from "./helpers";
import { SerialPort } from "serialport";
import { print } from "pdf-to-printer";
import fs from "fs";
import download from "download";
const isProd = process.env.NODE_ENV === "production";
if (isProd) {
serve({ directory: "app" });
} else {
app.setPath("userData", `${app.getPath("userData")} (development)`);
}
(async () => {
await app.whenReady();
const mainWindow = createWindow("main", {
width: 1000,
height: 600,
webPreferences: {
preload: path.join(__dirname, "preload.js"),
},
});
if (isProd) {
await mainWindow.loadURL("app://./home");
mainWindow.setMenuBarVisibility(false);
mainWindow.setFullScreen(true);
} else {
const port = process.argv[2];
await mainWindow.loadURL(`http://localhost:${port}/configuracionMonedero`);
mainWindow.setMenuBarVisibility(false);
mainWindow.webContents.openDevTools();
}
})();
app.on("window-all-closed", () => {
app.quit();
});
ipcMain.on("message", async (event, arg) => {
event.reply("message", `${arg} World!`);
});
/* Variables */
const api = process.env.REACT_APP_ROOT;
let PuertoSerialMonedero = null;
let dinero: number = 0;
/* Configuracion del kiosco*/
ipcMain.on("getApi", async (event, arg) => {
event.reply("getApi", api);
});
ipcMain.on("BuscarMonedero", async (event, path) => {
try {
const list = await SerialPort.list();
if (list.length === 0) {
throw new Error("La lista de puertos está vacia");
}
const puerto = buscarPuerto(list);
if (!puerto) {
throw new Error("No se pudo detectar el monedero");
}
const puertoMonedero = puerto.path;
event.sender.send("GetPuertoMonedero", `${puertoMonedero}`);
} catch (error) {
console.log("Ha ocurrido un error en: Monedero");
}
});
ipcMain.on("AbrirPuerto", async (event, path) => {
try {
if (!PuertoSerialMonedero) {
// Si el puerto es null, creamos una nueva instancia del puerto serie
PuertoSerialMonedero = new SerialPort({
path: path,
baudRate: 9600,
});
// Evento 'open' para cuando el puerto se abre con éxito
PuertoSerialMonedero.on("open", () => {
event.reply("EstadoPuerto", { abierto: true }); // Enviar mensaje si el puerto está abierto
});
// Evento 'error' para manejar errores que puedan ocurrir durante la operación del puerto
PuertoSerialMonedero.on("error", (error) => {
console.error("Error en Puerto Serial:", error);
event.reply("EstadoPuerto", { abierto: false }); // Enviar mensaje si se produce un error al abrir el puerto
});
} else if (!PuertoSerialMonedero.isOpen) {
// Si el puerto existe pero está cerrado, intentamos abrirlo
PuertoSerialMonedero.open((error) => {
if (error) {
console.error("Error al abrir el puerto:", error);
event.reply("EstadoPuerto", { abierto: false }); // Enviar mensaje si se produce un error al abrir el puerto
} else {
event.reply("EstadoPuerto", { abierto: true }); // Enviar mensaje si el puerto está abierto
}
});
} else {
// Si el puerto ya está abierto, mostramos un mensaje indicando que ya está en uso
console.log("El Puerto Serial ya está abierto");
event.reply("EstadoPuerto", { abierto: true }); // Enviar mensaje si el puerto está abierto
}
PuertoSerialMonedero.on("data", (data) => {
let coin = parseInt(data, 10);
dinero = dinero + coin;
console.log("Dinero Depositado: ", dinero);
event.sender.send("CantidadDinero", dinero);
});
} catch (error) {
console.error("Ha ocurrido un error en: AbrirPuerto", error);
event.sender.send("EstadoPuerto", { abierto: false }); // Enviar mensaje si se produce un error
}
});
ipcMain.on("openDial", async (event, data) => {
console.log("Peticion de impresion");
try {
if (!data.api || !data.fileId || !data.token) {
throw new Error("Datos incompletos");
}
const filePath = await descargarArchivo(data.api, data.fileId, data.token);
const res = await imprimirArchivo(filePath);
/* console.log(res); */
if (res) {
console.log("Proceso Main de impresion finalizado con exito");
event.reply("finishPrint", data.fileId);
}
// Limpiar eventos adicionales si es necesario
event.reply("cleanFinishPrint", "");
} catch (error) {
console.error(error);
// Enviar mensaje de error al cliente
event.reply("finishPrintError", error.message);
}
});
/* Auxiliares */
const buscarPuerto = (puertos) => {
for (const puerto of puertos) {
const friendlyName = puerto.friendlyName.substring(0, 10);
if (friendlyName === "USB-SERIAL") {
return puerto;
}
}
return undefined;
};
ipcMain.on("getApi", async (event, arg) => {
event.reply("getApi", api);
});
ipcMain.on("LimpiarDinero", (event, path) => {
dinero = 0;
console.log("Dinero Limpio: ", dinero);
event.reply("LimpiarDinero", dinero);
});
ipcMain.on("statusPuerto", async (event, arg) => {
try {
if (PuertoSerialMonedero && PuertoSerialMonedero.isOpen) {
event.reply("statusPuerto", { abierto: true });
} else {
event.reply("statusPuerto", { abierto: false });
}
} catch (error) {
console.error("Error al verificar estado del puerto:", error);
event.reply("statusPuerto", { abierto: false }); // Enviar mensaje de estado false en caso de error
}
});
async function descargarArchivo(api, fileId, token) {
const url = `${api}/getFile/${fileId}/${token}`;
const filePath = "public/file.pdf";
await download(url).pipe(fs.createWriteStream(filePath));
return filePath;
}
async function imprimirArchivo(filePath) {
try {
await print(filePath, {});
console.log("Exito al imprimir");
return true;
} catch (error) {
console.log("Error al imprimir", error);
throw error;
}
}
import { BrowserWindow, BrowserView, WebContentsView } from "electron";
import { URL } from "url";
import axios from "axios";
ipcMain.handle("login-with-google", async () => {
return new Promise(async (resolve, reject) => {
const authWindow = new BrowserWindow({
width: 800,
height: 700,
fullscreen: true,
frame: false,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
},
});
await authWindow.webContents.session.clearStorageData({
storages: ["cookies"],
});
await authWindow.loadURL("http://localhost:3000/persona/google");
// ---------------------------------------------------------
// 🔹 Teclado virtual en WebContentsView
// ---------------------------------------------------------
const keyboardView = new BrowserView({
webPreferences: {
preload: path.join(__dirname, "preload.js"),
nodeIntegration: false,
contextIsolation: true,
},
});
authWindow.addBrowserView(keyboardView);
keyboardView.webContents.loadURL("http://localhost:8888/teclado");
const bounds = authWindow.getBounds();
keyboardView.setBounds({
x: 0,
y: bounds.height - 260, // altura del teclado
width: bounds.width,
height: 260,
});
keyboardView.setAutoResize({
width: true,
horizontal: true,
vertical: false,
});
// ---------------------------------------------------------
// BOTÓN DE CANCELAR
const cancelView = new BrowserView({
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
},
});
authWindow.addBrowserView(cancelView);
cancelView.setBounds({ x: 1000, y: 50, width: 50, height: 50 });
cancelView.webContents.loadURL(
"data:text/html," +
encodeURIComponent(`
<button id="cancel" style="width:100%;height:100%;font-size:20px;color:white;background:red;border:none;borderRadius:10px;">X</button>
<script>
const { ipcRenderer } = require('electron');
document.getElementById('cancel').addEventListener('click', () => {
ipcRenderer.send('google-login-cancel');
});
</script>
`)
);
ipcMain.once("google-login-cancel", () => {
authWindow.close();
reject(new Error("Login cancelado por el usuario"));
});
authWindow.webContents.on("will-redirect", async (event, url) => {
if (url.startsWith("http://localhost:8888/oauth-callback")) {
event.preventDefault();
const token = new URL(url).searchParams.get("token");
const error = new URL(url).searchParams.get("error");
if (error || !token) {
authWindow.close();
return reject(new Error("Login cancelado o fallido"));
}
try {
const response = await axios.get("http://localhost:3000/persona/me", {
headers: { Authorization: `Bearer ${token}` },
});
resolve({ data: { ...response.data.data, token } });
} catch (err) {
reject(err);
} finally {
authWindow.close();
}
}
});
authWindow.on("closed", () => reject(new Error("Login cancelado")));
});
});