Skip to main content
This guide covers the cashout rules system for managing company-specific procedures.

Rules Overview

The rules section displays cashout procedures for each company registered in the system.

Accessing Rules

Click the ”📜 Cashout Rules” button in the sidebar:
rulesBtn.addEventListener('click', () => {
  desactivarBotones();
  rulesBtn.classList.add('active');
  rulesSection.style.display = 'block';
  cargarReglasDesdeBD();
});

Loading Rules from Database

1

Fetch Rules

Rules are loaded from the API on page load and when viewing the rules section:
async function cargarReglasDesdeBD(silencioso = false) {
  const res = await apiFetch(`/rules`);
  const json = await res.json();
  const rules = json.data;
  
  actualizarSelectsConReglas(rules);
  // ... render rules grid
}
API Endpoint: GET /api/rules
2

Update Company Selects

Rules automatically populate company dropdowns across the app:
function actualizarSelectsConReglas(rules) {
  const selects = [
    document.getElementById('company'),
    document.getElementById('statsCompanyFilter')
  ];
  
  selects.forEach(select => {
    if(!select) return;
    const val = select.value; 
    select.innerHTML = select.id === 'company' 
      ? '<option value="">Seleccione una compañía</option>' 
      : '<option value="">Todas las compañías</option>';
    rules.forEach(r => select.appendChild(new Option(r.name, r.name)));
    if(Array.from(select.options).some(o => o.value === val)) select.value = val;
  });
}

Rule Card Display

Each company rule is displayed in a card with:
  • Company Name: Header (e.g., “Betsson”, “Inkabet”)
  • Rule Text: Pre-formatted text with company-specific procedures
  • Edit Button: ✏️ Only visible to supervisors
rulesGrid.innerHTML = rules.map(rule => `
  <div class="rule-card">
    <div style="display: flex; justify-content: space-between; align-items: center;">
      <h3>${rule.name}</h3>
      ${isSupervisor ? `<button onclick="toggleEditRegla('${rule._id}')" ...>✏️ Editar</button>` : ''}
    </div>
    <div id="view-mode-${rule._id}">${rule.ruleText || '<i>Sin reglas.</i>'}</div>
    <div id="edit-mode-${rule._id}" style="display: none;">
      <textarea class="rule-text" id="rule-text-${rule._id}">${rule.ruleText || ''}</textarea>
      <button onclick="guardarEdicionRegla('${rule._id}')">💾 Guardar</button>
      <button onclick="toggleEditRegla('${rule._id}')">❌ Cancelar</button>
    </div>
  </div>
`).join('');

Search Functionality

The search box filters companies in real-time:
searchRulesInput.addEventListener('input', (e) => {
  const term = e.target.value.toLowerCase();
  document.querySelectorAll('#rulesGrid .rule-card').forEach(card => {
    const companyName = card.querySelector('h3').textContent.toLowerCase();
    card.style.display = companyName.includes(term) ? '' : 'none';
  });
});
HTML Input:
<input 
  type="text" 
  id="searchRules" 
  placeholder="🔍 Buscar compañía por nombre..."
  style="width: 100%; padding: 14px; border-radius: 10px;"
>

Editing Rules (Supervisor Only)

Supervisors can click the ✏️ Editar button to toggle between view and edit mode:
window.toggleEditRegla = (id) => {
  const v = document.getElementById(`view-mode-${id}`);
  const e = document.getElementById(`edit-mode-${id}`);
  v.style.display = v.style.display === 'none' ? 'block' : 'none';
  e.style.display = e.style.display === 'none' ? 'block' : 'none';
};
After editing the textarea, click 💾 Guardar to save:
window.guardarEdicionRegla = async (id) => {
  const text = document.getElementById(`rule-text-${id}`).value.trim();
  const btn = document.getElementById(`btn-save-${id}`);
  btn.disabled = true; 
  btn.textContent = "⏳";
  
  try {
    await apiFetch(`/rules/${id}`, { 
      method: 'PUT', 
      body: JSON.stringify({ ruleText: text }) 
    });
    
    document.getElementById(`view-mode-${id}`).innerHTML = text || '<i>Sin reglas.</i>';
    toggleEditRegla(id);
    showNotification("Regla actualizada");
  } catch(e) { 
    showNotification("Error", "error"); 
  } finally { 
    btn.disabled = false; 
    btn.textContent = "💾 Guardar"; 
  }
};
API Endpoint: PUT /api/rules/{id}

Adding New Companies (Supervisor Only)

Supervisors see a hidden form to add new companies:
<div id="newCompanyContainer" style="display: none;">
  <h3>+ Agregar Nueva Compañía</h3>
  <input type="text" id="newCompanyName" placeholder="Nombre de la nueva compañía">
  <button id="btnCreateCompany">Guardar</button>
</div>
Display Logic:
const isSupervisor = currentUser.role === 'supervisor';
if (newCompanyContainer) {
  newCompanyContainer.style.display = isSupervisor ? 'block' : 'none';
}

Role-Based Access Control

FeatureAnalistaSupervisor
View Rules
Search Rules
Edit Rules
Add Companies

Rule Text Format

Rule text is stored as plain text with white-space: pre-wrap for formatting:
white-space: pre-wrap; 
color: var(--tertiary); 
padding: 15px; 
border-radius: 10px; 
min-height: 60px;
This preserves line breaks and spacing in the text area.

API Reference

GET /api/rules

Response:
{
  "data": [
    {
      "_id": "...",
      "name": "Betsson",
      "ruleText": "1. Verificar saldo...\n2. Confirmar con cliente...\n3. Procesar retiro..."
    },
    {
      "_id": "...",
      "name": "Inkabet",
      "ruleText": "Procedimiento especial para Inkabet..."
    }
  ]
}

PUT /api/rules/:id

Body:
{
  "ruleText": "Updated procedures for this company..."
}
Response: Updated rule object

POST /api/rules

Body:
{
  "name": "New Company Name",
  "ruleText": ""
}
Response: Created rule object

Loading States

1

Initial Load

Shows loading message while fetching:
rulesGrid.innerHTML = '<p style="text-align: center;">Cargando reglas...</p>';
2

Empty State

If no rules exist:
if (rules.length === 0) {
  rulesGrid.innerHTML = '<p style="text-align:center;">No hay compañías.</p>';
}
3

Silent Load

On app initialization, rules load silently to populate selects:
cargarReglasDesdeBD(true); // silencioso = true

CSS Classes

  • .rule-card: Card container with border and padding
  • .rule-text: Textarea for editing (defined in style.css)
  • .rules-grid: Grid layout for multiple cards

Build docs developers (and LLMs) love