Pasos para crear «MySalon» como software con instalador

Te voy a guiar paso a paso para convertir tu HTML en un software instalable, con la carpeta exactamente en C:\Users\migue\mysalon

Paso 1: Preparar la carpeta y archivos

  1. Crear la carpeta:
  • Ve a C:\Users\migue\
  • Crea una nueva carpeta llamada mysalon (exactamente así)
  1. Dentro de C:\Users\migue\mysalon\, crea estos archivos:

Archivo 1: index.html (pega TODO tu código HTML aquí)

Archivo 2: package.json

{
  "name": "mysalon",
  "version": "1.0.0",
  "description": "Sistema de gestión para peluquería MySalon",
  "main": "main.js",
  "scripts": {
    "start": "electron .",
    "build": "electron-builder"
  },
  "author": "migue",
  "license": "MIT",
  "devDependencies": {
    "electron": "^22.0.0",
    "electron-builder": "^23.0.0"
  },
  "build": {
    "appId": "com.migue.mysalon",
    "productName": "MySalon",
    "directories": {
      "output": "dist"
    },
    "files": [
      "**/*",
      "!dist",
      "!node_modules"
    ],
    "win": {
      "target": "nsis",
      "icon": "icon.ico"
    },
    "nsis": {
      "oneClick": false,
      "allowToChangeInstallationDirectory": true,
      "createDesktopShortcut": true,
      "createStartMenuShortcut": true
    }
  }
}

Archivo 3: main.js

const { app, BrowserWindow } = require('electron');
const path = require('path');

function createWindow() {
  const mainWindow = new BrowserWindow({
    width: 1400,
    height: 900,
    webPreferences: {
      nodeIntegration: true,
      contextIsolation: false,
      enableRemoteModule: true
    },
    icon: path.join(__dirname, 'icon.ico'),
    title: 'MySalon - Sistema de Gestión'
  });

  mainWindow.loadFile('index.html');

  // Opcional: quita el comentario de la siguiente línea para ver las herramientas de desarrollo
  // mainWindow.webContents.openDevTools();
}

app.whenReady().then(createWindow);

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate', () => {
  if (BrowserWindow.getAllWindows().length === 0) {
    createWindow();
  }
});

Paso 2: Instalar Node.js (si no lo tienes)

  1. Ve a nodejs.org
  2. Descarga la versión LTS (la recomendada)
  3. Instálalo con todos los valores por defecto

Paso 3: Abrir la terminal y ejecutar comandos

  1. Abrir Symbolo del sistema:
  • Presiona Windows + R
  • Escribe cmd y presiona Enter
  1. Navegar a la carpeta:
   cd C:\Users\migue\mysalon
  1. Instalar Electron:
   npm install

Paso 4: Probar la aplicación

npm start

Si todo funciona correctamente, debería abrirse una ventana con tu aplicación MySalon.

Paso 5: Crear el instalador

npm run build

Paso 6: Encontrar el instalador

  1. Después del paso anterior, se creará una carpeta dist dentro de C:\Users\migue\mysalon\
  2. En C:\Users\migue\mysalon\dist\ encontrarás:
  • MySalon Setup 1.0.0.exe – El instalador
  • win-unpacked – La versión portable (no necesita instalación)

Estructura final de tu carpeta:

C:\Users\migue\mysalon\
├── index.html          (tu código)
├── package.json        (configuración)
├── main.js            (archivo principal)
├── node_modules\      (se crea automáticamente)
├── dist\              (se crea después de build)
│   ├── MySalon Setup 1.0.0.exe
│   └── win-unpacked\
└── package-lock.json  (se crea automáticamente)

Para distribuir tu software:

  1. Opción Instalador: Entrega MySalon Setup 1.0.0.exe
  2. Opción Portable: Comprime la carpeta win-unpacked y entrégala como ZIP

Comandos rápidos de referencia:

cd C:\Users\migue\mysalon
npm install          # Solo la primera vez
npm start            # Para probar
npm run build        # Para crear instalador

Solución de problemas comunes:

  • Error de permisos: Ejecuta el Symbolo del sistema como Administrador
  • Error de npm: Asegúrate de que Node.js esté instalado correctamente
  • La aplicación no se abre: Verifica que todos los archivos estén en la carpeta correcta

¡Excelente pregunta! Esta es una diferencia CRUCIAL.

📊 RESPUESTA CORTA:

NO, el portable NO guarda la información automáticamente entre sesiones (con la configuración actual).

🔍 EXPLICACIÓN DETALLADA:

PROBLEMA ACTUAL:

Tu código HTML usa variables en memoria (let employees = [...], let services = [...]), que:

  • Se guardan SOLO mientras la aplicación esté abierta
  • Se PIERDEN cuando cierras el programa
  • No se guardan en archivos

DIFERENCIAS EN LA PRÁCTICA:

EscenarioInstaladorPortable
Agregas empleados❌ Se pierden al cerrar❌ Se pierden al cerrar
Agregas servicios❌ Se pierden al cerrar❌ Se pierden al cerrar
Programas citas❌ Se pierden al cerrar❌ Se pierden al cerrar
Cierras y reabresTodo vacíoTodo vacío

🛠 SOLUCIÓN NECESARIA:

Necesitas modificar el código para que guarde los datos en archivos. Te muestro cómo:

Paso 1: Modificar el código para guardar datos

En tu archivo index.html, busca esta línea:

// Sample data
let roles = ["Peluquero/a", "Manicurista", "Estilista", "Colorista"];

Y REEMPLÁZALA con este código:

// Sistema de guardado de datos
const fs = require('fs');
const path = require('path');

// Rutas de archivos de datos
const dataDir = path.join(__dirname, 'data');
const employeesFile = path.join(dataDir, 'employees.json');
const servicesFile = path.join(dataDir, 'services.json');
const rolesFile = path.join(dataDir, 'roles.json');
const appointmentsFile = path.join(dataDir, 'appointments.json');
const settingsFile = path.join(dataDir, 'settings.json');

// Crear carpeta de datos si no existe
if (!fs.existsSync(dataDir)) {
    fs.mkdirSync(dataDir);
}

// Función para cargar datos
function loadData(file, defaultValue = []) {
    try {
        if (fs.existsSync(file)) {
            const data = fs.readFileSync(file, 'utf8');
            return JSON.parse(data);
        }
    } catch (error) {
        console.error('Error loading data:', error);
    }
    return defaultValue;
}

// Función para guardar datos
function saveData(file, data) {
    try {
        fs.writeFileSync(file, JSON.stringify(data, null, 2));
        return true;
    } catch (error) {
        console.error('Error saving data:', error);
        return false;
    }
}

// Cargar datos existentes o usar valores por defecto
let roles = loadData(rolesFile, ["Peluquero/a", "Manicurista", "Estilista", "Colorista"]);
let employees = loadData(employeesFile, [
    {
        id: 1,
        name: "María González",
        role: "Peluquero/a",
        phone: "+1 234 567 890",
        email: "maria@beautystyle.com",
        photo: null,
        services: ["Corte de cabello", "Tinte", "Peinado"],
        earnings: [
            { date: "2023-05-15", time: "10:30", service: "Corte de cabello", amount: 25 },
            { date: "2023-05-15", time: "14:00", service: "Tinte", amount: 50 }
        ],
        attendance: [
            { date: "2023-05-15", checkIn: "09:00", checkOut: "18:00" }
        ],
        isClockedIn: false,
        workingHours: {
            start: "09:00",
            end: "18:00",
            breaks: [
                { start: "13:00", end: "14:00" }
            ]
        },
        daysOff: []
    }
]);

let services = loadData(servicesFile, [
    { id: 1, name: "Corte de cabello", duration: 30, color: "#8a6d3b" },
    { id: 2, name: "Tinte", duration: 60, color: "#d4b483" },
    { id: 3, name: "Peinado", duration: 45, color: "#f9f2e8" },
    { id: 4, name: "Manicure", duration: 30, color: "#e74c3c" },
    { id: 5, name: "Pedicure", duration: 45, color: "#3498db" }
]);

let appointments = loadData(appointmentsFile, []);
let salonSettings = loadData(settingsFile, {
    name: "MySalon",
    address: "Calle Principal 123, Ciudad",
    phone: "+1 234 567 890"
});

// Función para guardar todos los datos
function saveAllData() {
    saveData(employeesFile, employees);
    saveData(servicesFile, services);
    saveData(rolesFile, roles);
    saveData(appointmentsFile, appointments);
    saveData(settingsFile, salonSettings);
}

// Guardar datos automáticamente cada 30 segundos
setInterval(saveAllData, 30000);

// También guardar cuando se cierre la aplicación
window.addEventListener('beforeunload', saveAllData);

Paso 2: Modificar las funciones que cambian datos

Cada vez que modifiques datos, añade saveAllData():

Ejemplo en la función de agregar empleado:

// Busca esta función y añádele la última línea:
employeeForm.addEventListener('submit', function(e) {
    e.preventDefault();

    // ... todo tu código actual ...

    employees.push(newEmployee);
    updateEmployeesGrid();
    updateEmployeesTable();
    updateReportEmployeeSelect();
    updateCalendarEmployeeFilter();
    employeeForm.reset();

    // AÑADE ESTA LÍNEA:
    saveAllData();

    alert('Empleado agregado exitosamente');
});

Haz lo mismo en estas funciones:

  • addServiceBtn.addEventListener('click', ...) – añade saveAllData()
  • deleteService() – añade saveAllData()
  • deleteEmployee() – añade saveAllData()
  • settingsForm.addEventListener('submit', ...) – añade saveAllData()
  • saveAppointment() – añade saveAllData()
  • deleteAppointment() – añade saveAllData()
  • addRoleBtn.addEventListener('click', ...) – añade saveAllData()
  • deleteRole() – añade saveAllData()

📁 ESTRUCTURA FINAL CON DATOS:

C:\Users\migue\mysalon\
├── index.html
├── package.json
├── main.js
├── data\                   (← NUEVA CARPETA)
│   ├── employees.json
│   ├── services.json
│   ├── roles.json
│   ├── appointments.json
│   └── settings.json
├── dist\
│   ├── MySalon Setup.exe
│   └── win-unpacked\
│       ├── MySalon.exe
│       └── data\          (← LOS DATOS VAN AQUÍ TAMBIÉN)

RESULTADO FINAL:

Con esta modificación:

  • PORTABLE: Guarda datos en la carpeta data junto al ejecutable
  • INSTALADOR: Guarda datos en la carpeta de instalación
  • Los datos PERSISTEN entre sesiones
  • Funciona igual en ambas versiones


Descubre más desde Clasenet

Suscríbete y recibe las últimas entradas en tu correo electrónico.

Miguel Ángel Urbaez
Miguel Ángel Urbaez
Artículos: 108

Deja un comentario