| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Baileys Command Generator</title> |
| <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&family=Roboto+Mono:wght@400;500&display=swap" rel="stylesheet"> |
| <style> |
| :root { |
| --primary: #6c5ce7; |
| --primary-dark: #5649c0; |
| --secondary: #00cec9; |
| --dark: #2d3436; |
| --light: #f5f6fa; |
| --danger: #d63031; |
| --warning: #fdcb6e; |
| --success: #00b894; |
| --gray: #636e72; |
| --gray-light: #dfe6e9; |
| } |
| |
| * { |
| margin: 0; |
| padding: 0; |
| box-sizing: border-box; |
| } |
| |
| body { |
| font-family: 'Poppins', sans-serif; |
| background-color: var(--light); |
| color: var(--dark); |
| line-height: 1.6; |
| } |
| |
| .container { |
| max-width: 1200px; |
| margin: 0 auto; |
| padding: 20px; |
| } |
| |
| header { |
| display: flex; |
| justify-content: space-between; |
| align-items: center; |
| padding: 20px 0; |
| border-bottom: 1px solid var(--gray-light); |
| margin-bottom: 30px; |
| } |
| |
| .logo { |
| font-size: 24px; |
| font-weight: 700; |
| color: var(--primary); |
| display: flex; |
| align-items: center; |
| } |
| |
| .logo-icon { |
| margin-right: 10px; |
| font-size: 28px; |
| } |
| |
| .btn { |
| padding: 10px 20px; |
| border-radius: 6px; |
| font-weight: 500; |
| cursor: pointer; |
| transition: all 0.3s ease; |
| border: none; |
| font-family: 'Poppins', sans-serif; |
| display: inline-flex; |
| align-items: center; |
| justify-content: center; |
| } |
| |
| .btn-primary { |
| background-color: var(--primary); |
| color: white; |
| } |
| |
| .btn-primary:hover { |
| background-color: var(--primary-dark); |
| } |
| |
| .btn-outline { |
| background-color: transparent; |
| border: 1px solid var(--primary); |
| color: var(--primary); |
| } |
| |
| .btn-outline:hover { |
| background-color: var(--primary); |
| color: white; |
| } |
| |
| .btn-danger { |
| background-color: var(--danger); |
| color: white; |
| } |
| |
| .btn-danger:hover { |
| background-color: #c0392b; |
| } |
| |
| .btn-sm { |
| padding: 6px 12px; |
| font-size: 14px; |
| } |
| |
| .main { |
| display: grid; |
| grid-template-columns: 300px 1fr; |
| gap: 30px; |
| } |
| |
| .sidebar { |
| background-color: white; |
| border-radius: 10px; |
| padding: 20px; |
| box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); |
| } |
| |
| .sidebar-title { |
| font-size: 18px; |
| font-weight: 600; |
| margin-bottom: 20px; |
| display: flex; |
| align-items: center; |
| justify-content: space-between; |
| } |
| |
| .command-list { |
| list-style: none; |
| } |
| |
| .command-item { |
| padding: 10px; |
| border-radius: 6px; |
| margin-bottom: 8px; |
| cursor: pointer; |
| transition: all 0.2s; |
| display: flex; |
| align-items: center; |
| justify-content: space-between; |
| } |
| |
| .command-item:hover { |
| background-color: var(--gray-light); |
| } |
| |
| .command-item.active { |
| background-color: var(--primary); |
| color: white; |
| } |
| |
| .command-item .badge { |
| background-color: var(--secondary); |
| color: var(--dark); |
| padding: 2px 6px; |
| border-radius: 4px; |
| font-size: 12px; |
| font-weight: 500; |
| } |
| |
| .command-builder { |
| background-color: white; |
| border-radius: 10px; |
| padding: 20px; |
| box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); |
| } |
| |
| .builder-header { |
| display: flex; |
| justify-content: space-between; |
| align-items: center; |
| margin-bottom: 20px; |
| padding-bottom: 15px; |
| border-bottom: 1px solid var(--gray-light); |
| } |
| |
| .builder-title { |
| font-size: 20px; |
| font-weight: 600; |
| } |
| |
| .flow-container { |
| min-height: 500px; |
| border: 2px dashed var(--gray-light); |
| border-radius: 8px; |
| padding: 20px; |
| position: relative; |
| } |
| |
| .flow-start { |
| background-color: var(--success); |
| color: white; |
| padding: 15px; |
| border-radius: 8px; |
| width: 200px; |
| text-align: center; |
| margin: 0 auto 30px; |
| position: relative; |
| } |
| |
| .flow-start:after { |
| content: ''; |
| position: absolute; |
| bottom: -15px; |
| left: 50%; |
| transform: translateX(-50%); |
| width: 2px; |
| height: 15px; |
| background-color: var(--gray-light); |
| } |
| |
| .flow-node { |
| background-color: white; |
| border: 2px solid var(--primary); |
| border-radius: 8px; |
| padding: 15px; |
| width: 250px; |
| margin: 30px auto; |
| box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); |
| position: relative; |
| } |
| |
| .flow-node:before { |
| content: ''; |
| position: absolute; |
| top: -15px; |
| left: 50%; |
| transform: translateX(-50%); |
| width: 2px; |
| height: 15px; |
| background-color: var(--gray-light); |
| } |
| |
| .flow-node-header { |
| display: flex; |
| justify-content: space-between; |
| align-items: center; |
| margin-bottom: 10px; |
| padding-bottom: 8px; |
| border-bottom: 1px solid var(--gray-light); |
| } |
| |
| .flow-node-title { |
| font-weight: 600; |
| color: var(--primary); |
| } |
| |
| .flow-node-actions { |
| display: flex; |
| gap: 5px; |
| } |
| |
| .flow-node-content { |
| margin-top: 10px; |
| } |
| |
| .form-group { |
| margin-bottom: 15px; |
| } |
| |
| .form-label { |
| display: block; |
| margin-bottom: 5px; |
| font-size: 14px; |
| font-weight: 500; |
| } |
| |
| .form-control { |
| width: 100%; |
| padding: 8px 12px; |
| border: 1px solid var(--gray-light); |
| border-radius: 4px; |
| font-family: 'Poppins', sans-serif; |
| } |
| |
| .form-control:focus { |
| outline: none; |
| border-color: var(--primary); |
| } |
| |
| .select-control { |
| width: 100%; |
| padding: 8px 12px; |
| border: 1px solid var(--gray-light); |
| border-radius: 4px; |
| font-family: 'Poppins', sans-serif; |
| background-color: white; |
| } |
| |
| .btn-group { |
| display: flex; |
| gap: 10px; |
| margin-top: 20px; |
| } |
| |
| .options-grid { |
| display: grid; |
| grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); |
| gap: 10px; |
| margin-top: 15px; |
| } |
| |
| .option-card { |
| border: 1px solid var(--gray-light); |
| border-radius: 6px; |
| padding: 12px; |
| text-align: center; |
| cursor: pointer; |
| transition: all 0.2s; |
| } |
| |
| .option-card:hover { |
| border-color: var(--primary); |
| background-color: rgba(108, 92, 231, 0.05); |
| } |
| |
| .option-card.selected { |
| border-color: var(--primary); |
| background-color: rgba(108, 92, 231, 0.1); |
| } |
| |
| .option-icon { |
| font-size: 24px; |
| margin-bottom: 5px; |
| color: var(--primary); |
| } |
| |
| .option-title { |
| font-size: 14px; |
| font-weight: 500; |
| } |
| |
| .preview-modal { |
| position: fixed; |
| top: 0; |
| left: 0; |
| right: 0; |
| bottom: 0; |
| background-color: rgba(0, 0, 0, 0.5); |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| z-index: 1000; |
| opacity: 0; |
| pointer-events: none; |
| transition: all 0.3s; |
| } |
| |
| .preview-modal.active { |
| opacity: 1; |
| pointer-events: all; |
| } |
| |
| .preview-content { |
| background-color: white; |
| border-radius: 10px; |
| width: 80%; |
| max-width: 900px; |
| max-height: 80vh; |
| overflow: auto; |
| padding: 30px; |
| position: relative; |
| } |
| |
| .preview-header { |
| display: flex; |
| justify-content: space-between; |
| align-items: center; |
| margin-bottom: 20px; |
| } |
| |
| .preview-title { |
| font-size: 22px; |
| font-weight: 600; |
| } |
| |
| .close-btn { |
| background: none; |
| border: none; |
| font-size: 24px; |
| cursor: pointer; |
| color: var(--gray); |
| } |
| |
| .code-block { |
| background-color: #f8f9fa; |
| border-radius: 6px; |
| padding: 15px; |
| font-family: 'Roboto Mono', monospace; |
| font-size: 14px; |
| overflow-x: auto; |
| margin-bottom: 20px; |
| } |
| |
| .download-btn { |
| display: block; |
| width: 100%; |
| text-align: center; |
| padding: 12px; |
| background-color: var(--success); |
| color: white; |
| border-radius: 6px; |
| text-decoration: none; |
| font-weight: 500; |
| margin-top: 20px; |
| } |
| |
| .download-btn:hover { |
| background-color: #00a884; |
| } |
| |
| .badge { |
| padding: 3px 8px; |
| border-radius: 4px; |
| font-size: 12px; |
| font-weight: 500; |
| display: inline-block; |
| } |
| |
| .badge-primary { |
| background-color: var(--primary); |
| color: white; |
| } |
| |
| .badge-secondary { |
| background-color: var(--secondary); |
| color: var(--dark); |
| } |
| |
| .badge-danger { |
| background-color: var(--danger); |
| color: white; |
| } |
| |
| .badge-warning { |
| background-color: var(--warning); |
| color: var(--dark); |
| } |
| |
| .tabs { |
| display: flex; |
| border-bottom: 1px solid var(--gray-light); |
| margin-bottom: 20px; |
| } |
| |
| .tab { |
| padding: 10px 20px; |
| cursor: pointer; |
| border-bottom: 2px solid transparent; |
| font-weight: 500; |
| } |
| |
| .tab.active { |
| border-bottom-color: var(--primary); |
| color: var(--primary); |
| } |
| |
| .tab-content { |
| display: none; |
| } |
| |
| .tab-content.active { |
| display: block; |
| } |
| |
| .node-options { |
| position: absolute; |
| background: white; |
| border: 1px solid var(--gray-light); |
| border-radius: 6px; |
| box-shadow: 0 4px 12px rgba(0,0,0,0.1); |
| z-index: 100; |
| width: 200px; |
| display: none; |
| } |
| |
| .node-option { |
| padding: 10px; |
| cursor: pointer; |
| transition: background 0.2s; |
| } |
| |
| .node-option:hover { |
| background: var(--gray-light); |
| } |
| |
| .node-option i { |
| margin-right: 8px; |
| color: var(--primary); |
| } |
| |
| .condition-branch { |
| display: flex; |
| flex-direction: column; |
| align-items: center; |
| margin-top: 20px; |
| } |
| |
| .condition-node { |
| background-color: var(--warning); |
| color: var(--dark); |
| padding: 15px; |
| border-radius: 8px; |
| width: 250px; |
| margin: 0 auto; |
| position: relative; |
| } |
| |
| .condition-branches { |
| display: flex; |
| justify-content: space-around; |
| width: 100%; |
| margin-top: 20px; |
| position: relative; |
| } |
| |
| .condition-branch-label { |
| position: absolute; |
| top: -20px; |
| background: white; |
| padding: 2px 8px; |
| border-radius: 4px; |
| font-size: 12px; |
| font-weight: 500; |
| border: 1px solid var(--gray-light); |
| } |
| |
| .branch { |
| position: relative; |
| width: 45%; |
| } |
| |
| .branch:before { |
| content: ''; |
| position: absolute; |
| top: -20px; |
| left: 50%; |
| width: 2px; |
| height: 20px; |
| background-color: var(--gray-light); |
| } |
| |
| @media (max-width: 768px) { |
| .main { |
| grid-template-columns: 1fr; |
| } |
| } |
| </style> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"> |
| </head> |
| <body> |
| <div class="container"> |
| <header> |
| <div class="logo"> |
| <i class="fas fa-robot logo-icon"></i> |
| <span>Baileys Command Generator</span> |
| </div> |
| <button class="btn btn-primary" id="newCommandBtn"> |
| <i class="fas fa-plus"></i> New Command |
| </button> |
| </header> |
|
|
| <div class="main"> |
| <div class="sidebar"> |
| <div class="sidebar-title"> |
| <span>Your Commands</span> |
| <i class="fas fa-sync-alt" id="refreshCommands" style="cursor: pointer;"></i> |
| </div> |
| <ul class="command-list" id="commandList"> |
| |
| </ul> |
| </div> |
|
|
| <div class="command-builder"> |
| <div class="builder-header"> |
| <div class="builder-title" id="commandTitle">New Command</div> |
| <div> |
| <button class="btn btn-outline btn-sm" id="saveCommandBtn"> |
| <i class="fas fa-save"></i> Save |
| </button> |
| <button class="btn btn-primary btn-sm" id="previewBtn"> |
| <i class="fas fa-eye"></i> Preview |
| </button> |
| </div> |
| </div> |
|
|
| <div class="tabs"> |
| <div class="tab active" data-tab="flow">Flow</div> |
| <div class="tab" data-tab="settings">Settings</div> |
| <div class="tab" data-tab="packages">Packages</div> |
| </div> |
|
|
| <div class="tab-content active" id="flowTab"> |
| <div class="flow-container" id="flowContainer"> |
| <div class="flow-start"> |
| <i class="fas fa-play"></i> Command Start |
| </div> |
| |
| </div> |
|
|
| <div class="btn-group"> |
| <button class="btn btn-primary" id="addStepBtn"> |
| <i class="fas fa-plus"></i> Add Step |
| </button> |
| <button class="btn btn-outline" id="addConditionBtn"> |
| <i class="fas fa-share-alt"></i> Add Condition |
| </button> |
| </div> |
|
|
| <div class="node-options" id="nodeOptions"> |
| <div class="node-option" data-type="trigger"> |
| <i class="fas fa-bolt"></i> Trigger |
| </div> |
| <div class="node-option" data-type="response"> |
| <i class="fas fa-reply"></i> Response |
| </div> |
| <div class="node-option" data-type="api"> |
| <i class="fas fa-plug"></i> API Call |
| </div> |
| <div class="node-option" data-type="media"> |
| <i class="fas fa-image"></i> Media Upload |
| </div> |
| <div class="node-option" data-type="database"> |
| <i class="fas fa-database"></i> Database Operation |
| </div> |
| <div class="node-option" data-type="delay"> |
| <i class="fas fa-clock"></i> Delay |
| </div> |
| </div> |
| </div> |
|
|
| <div class="tab-content" id="settingsTab"> |
| <div class="form-group"> |
| <label class="form-label">Command Name:</label> |
| <input type="text" class="form-control" id="commandName" placeholder="myCommand"> |
| </div> |
| <div class="form-group"> |
| <label class="form-label">Command Description:</label> |
| <textarea class="form-control" id="commandDescription" rows="3" placeholder="What this command does"></textarea> |
| </div> |
| <div class="form-group"> |
| <label class="form-label">Required Permissions:</label> |
| <div class="options-grid" id="permissionOptions"> |
| <div class="option-card selected" data-value="everyone"> |
| <div class="option-icon"> |
| <i class="fas fa-user"></i> |
| </div> |
| <div class="option-title">Everyone</div> |
| </div> |
| <div class="option-card" data-value="admin"> |
| <div class="option-icon"> |
| <i class="fas fa-user-shield"></i> |
| </div> |
| <div class="option-title">Group Admin</div> |
| </div> |
| <div class="option-card" data-value="owner"> |
| <div class="option-icon"> |
| <i class="fas fa-crown"></i> |
| </div> |
| <div class="option-title">Bot Owner</div> |
| </div> |
| </div> |
| </div> |
| <div class="form-group"> |
| <label class="form-label">Works in:</label> |
| <div class="options-grid" id="contextOptions"> |
| <div class="option-card selected" data-value="groups"> |
| <div class="option-icon"> |
| <i class="fas fa-comments"></i> |
| </div> |
| <div class="option-title">Groups</div> |
| </div> |
| <div class="option-card selected" data-value="private"> |
| <div class="option-icon"> |
| <i class="fas fa-user"></i> |
| </div> |
| <div class="option-title">Private</div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| <div class="tab-content" id="packagesTab"> |
| <div class="form-group"> |
| <label class="form-label">Required Packages:</label> |
| <div style="margin-top: 10px;" id="packageOptions"> |
| <div style="display: flex; align-items: center; margin-bottom: 10px;"> |
| <input type="checkbox" id="axios" checked style="margin-right: 10px;"> |
| <label for="axios">axios - For HTTP requests</label> |
| </div> |
| <div style="display: flex; align-items: center; margin-bottom: 10px;"> |
| <input type="checkbox" id="formData" style="margin-right: 10px;"> |
| <label for="formData">form-data - For multipart form data</label> |
| </div> |
| <div style="display: flex; align-items: center; margin-bottom: 10px;"> |
| <input type="checkbox" id="fs" checked style="margin-right: 10px;"> |
| <label for="fs">fs - File system operations</label> |
| </div> |
| <div style="display: flex; align-items: center; margin-bottom: 10px;"> |
| <input type="checkbox" id="path" checked style="margin-right: 10px;"> |
| <label for="path">path - Path utilities</label> |
| </div> |
| </div> |
| </div> |
| <div class="form-group"> |
| <label class="form-label">Custom Package (npm):</label> |
| <div style="display: flex; gap: 10px; margin-top: 10px;"> |
| <input type="text" class="form-control" id="customPackage" placeholder="package-name"> |
| <button class="btn btn-primary btn-sm" id="addPackageBtn">Add</button> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| <div class="preview-modal" id="previewModal"> |
| <div class="preview-content"> |
| <div class="preview-header"> |
| <div class="preview-title">Command Preview</div> |
| <button class="close-btn" id="closePreview">×</button> |
| </div> |
| |
| <div class="tabs"> |
| <div class="tab active" data-preview-tab="code">Code</div> |
| <div class="tab" data-preview-tab="info">Information</div> |
| <div class="tab" data-preview-tab="test">Test Command</div> |
| </div> |
| |
| <div class="tab-content active" id="previewCodeTab"> |
| <div class="code-block" id="generatedCode"> |
| |
| </div> |
| <a href="#" class="download-btn" id="downloadBtn"> |
| <i class="fas fa-download"></i> Download Command |
| </a> |
| </div> |
| |
| <div class="tab-content" id="previewInfoTab"> |
| <div style="margin-bottom: 20px;"> |
| <h3 style="margin-bottom: 10px;">Command Information</h3> |
| <p><strong>Name:</strong> <span id="infoName"></span></p> |
| <p><strong>Description:</strong> <span id="infoDescription"></span></p> |
| <p><strong>Trigger:</strong> <span id="infoTrigger"></span></p> |
| <p><strong>Response:</strong> <span id="infoResponse"></span></p> |
| </div> |
| |
| <div> |
| <h3 style="margin-bottom: 10px;">Required Packages</h3> |
| <ul style="list-style-type: none;" id="infoPackages"> |
| |
| </ul> |
| </div> |
| </div> |
|
|
| <div class="tab-content" id="previewTestTab"> |
| <div class="form-group"> |
| <label class="form-label">Test Command:</label> |
| <input type="text" class="form-control" id="testCommandInput" placeholder="Type your command here"> |
| </div> |
| <button class="btn btn-primary" id="runTestBtn">Run Test</button> |
| <div class="form-group" style="margin-top: 20px;"> |
| <label class="form-label">Bot Response:</label> |
| <div class="code-block" id="testOutput" style="min-height: 100px;"> |
| |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| <script> |
| // Command storage |
| let commands = JSON.parse(localStorage.getItem('baileysCommands')) || []; |
| let currentCommand = null; |
| let selectedNode = null; |
| |
| // DOM elements |
| const commandList = document.getElementById('commandList'); |
| const commandTitle = document.getElementById('commandTitle'); |
| const flowContainer = document.getElementById('flowContainer'); |
| const nodeOptions = document.getElementById('nodeOptions'); |
| const addStepBtn = document.getElementById('addStepBtn'); |
| const addConditionBtn = document.getElementById('addConditionBtn'); |
| const newCommandBtn = document.getElementById('newCommandBtn'); |
| const saveCommandBtn = document.getElementById('saveCommandBtn'); |
| const previewBtn = document.getElementById('previewBtn'); |
| const closePreview = document.getElementById('closePreview'); |
| const previewModal = document.getElementById('previewModal'); |
| const generatedCode = document.getElementById('generatedCode'); |
| const downloadBtn = document.getElementById('downloadBtn'); |
| const refreshCommands = document.getElementById('refreshCommands'); |
| const commandName = document.getElementById('commandName'); |
| const commandDescription = document.getElementById('commandDescription'); |
| const permissionOptions = document.getElementById('permissionOptions'); |
| const contextOptions = document.getElementById('contextOptions'); |
| const packageOptions = document.getElementById('packageOptions'); |
| const customPackage = document.getElementById('customPackage'); |
| const addPackageBtn = document.getElementById('addPackageBtn'); |
| const infoName = document.getElementById('infoName'); |
| const infoDescription = document.getElementById('infoDescription'); |
| const infoTrigger = document.getElementById('infoTrigger'); |
| const infoResponse = document.getElementById('infoResponse'); |
| const infoPackages = document.getElementById('infoPackages'); |
| const testCommandInput = document.getElementById('testCommandInput'); |
| const runTestBtn = document.getElementById('runTestBtn'); |
| const testOutput = document.getElementById('testOutput'); |
| |
| // Initialize the app |
| function init() { |
| loadCommands(); |
| setupEventListeners(); |
| |
| // Create a default command if none exist |
| if (commands.length === 0) { |
| createNewCommand(); |
| } else { |
| loadCommand(commands[0].id); |
| } |
| } |
| |
| // Load all commands into the sidebar |
| function loadCommands() { |
| commandList.innerHTML = ''; |
| |
| commands.forEach(cmd => { |
| const li = document.createElement('li'); |
| li.className = 'command-item'; |
| li.dataset.id = cmd.id; |
| li.innerHTML = ` |
| <span>${cmd.name || 'Unnamed Command'}</span> |
| <span class="badge">${cmd.type || 'Basic'}</span> |
| `; |
| |
| li.addEventListener('click', () => loadCommand(cmd.id)); |
| commandList.appendChild(li); |
| }); |
| |
| // Highlight the current command if it exists |
| if (currentCommand) { |
| document.querySelectorAll('.command-item').forEach(item => { |
| item.classList.toggle('active', item.dataset.id === currentCommand.id); |
| }); |
| } |
| } |
| |
| // Load a specific command |
| function loadCommand(commandId) { |
| const command = commands.find(c => c.id === commandId); |
| if (!command) return; |
| |
| currentCommand = command; |
| commandTitle.textContent = command.name || 'New Command'; |
| commandName.value = command.name || ''; |
| commandDescription.value = command.description || ''; |
| |
| // Update UI to reflect the loaded command |
| updateCommandUI(); |
| |
| // Highlight the selected command in the sidebar |
| document.querySelectorAll('.command-item').forEach(item => { |
| item.classList.toggle('active', item.dataset.id === commandId); |
| }); |
| } |
| |
| // Update the UI based on the current command |
| function updateCommandUI() { |
| if (!currentCommand) return; |
| |
| // Clear the flow container except for the start node |
| flowContainer.innerHTML = ` |
| <div class="flow-start"> |
| <i class="fas fa-play"></i> Command Start |
| </div> |
| `; |
| |
| // Rebuild the flow from the command data |
| if (currentCommand.flow && currentCommand.flow.length > 0) { |
| currentCommand.flow.forEach((node, index) => { |
| addNodeToFlow(node, index); |
| }); |
| } |
| } |
| |
| // Create a new command |
| function createNewCommand() { |
| const newCommand = { |
| id: generateId(), |
| name: 'New Command', |
| description: '', |
| type: 'Basic', |
| permissions: ['everyone'], |
| contexts: ['groups', 'private'], |
| packages: ['axios', 'fs', 'path'], |
| flow: [] |
| }; |
| |
| commands.push(newCommand); |
| currentCommand = newCommand; |
| saveCommands(); |
| loadCommands(); |
| loadCommand(newCommand.id); |
| } |
| |
| // Save all commands to localStorage |
| function saveCommands() { |
| localStorage.setItem('baileysCommands', JSON.stringify(commands)); |
| } |
| |
| // Add a node to the flow |
| function addNodeToFlow(nodeData, index) { |
| const nodeTypes = { |
| trigger: { |
| title: 'Trigger', |
| icon: 'bolt', |
| template: ` |
| <div class="form-group"> |
| <label class="form-label">When user sends:</label> |
| <select class="select-control trigger-type"> |
| <option value="prefix" ${nodeData.triggerType === 'prefix' ? 'selected' : ''}>Prefix command (!ping)</option> |
| <option value="exact" ${nodeData.triggerType === 'exact' ? 'selected' : ''}>Exact match (ping)</option> |
| <option value="regex" ${nodeData.triggerType === 'regex' ? 'selected' : ''}>Regex pattern</option> |
| </select> |
| </div> |
| <div class="form-group"> |
| <label class="form-label">Command:</label> |
| <input type="text" class="form-control trigger-command" value="${nodeData.command || ''}"> |
| </div> |
| ${nodeData.triggerType === 'regex' ? ` |
| <div class="form-group"> |
| <label class="form-label">Regex Pattern:</label> |
| <input type="text" class="form-control trigger-regex" value="${nodeData.regex || ''}"> |
| </div> |
| ` : ''} |
| ` |
| }, |
| response: { |
| title: 'Response', |
| icon: 'reply', |
| template: ` |
| <div class="form-group"> |
| <label class="form-label">Response Type:</label> |
| <select class="select-control response-type"> |
| <option value="text" ${nodeData.responseType === 'text' ? 'selected' : ''}>Text</option> |
| <option value="image" ${nodeData.responseType === 'image' ? 'selected' : ''}>Image</option> |
| <option value="video" ${nodeData.responseType === 'video' ? 'selected' : ''}>Video</option> |
| <option value="buttons" ${nodeData.responseType === 'buttons' ? 'selected' : ''}>Buttons</option> |
| <option value="list" ${nodeData.responseType === 'list' ? 'selected' : ''}>List</option> |
| </select> |
| </div> |
| <div class="form-group"> |
| <label class="form-label">Response Content:</label> |
| <textarea class="form-control response-content" rows="3">${nodeData.content || ''}</textarea> |
| </div> |
| ${nodeData.responseType === 'image' || nodeData.responseType === 'video' ? ` |
| <div class="form-group"> |
| <label class="form-label">Media URL:</label> |
| <input type="text" class="form-control media-url" value="${nodeData.mediaUrl || ''}"> |
| </div> |
| ` : ''} |
| ` |
| }, |
| api: { |
| title: 'API Call', |
| icon: 'plug', |
| template: ` |
| <div class="form-group"> |
| <label class="form-label">API URL:</label> |
| <input type="text" class="form-control api-url" value="${nodeData.apiUrl || ''}"> |
| </div> |
| <div class="form-group"> |
| <label class="form-label">Method:</label> |
| <select class="select-control api-method"> |
| <option value="GET" ${nodeData.method === 'GET' ? 'selected' : ''}>GET</option> |
| <option value="POST" ${nodeData.method === 'POST' ? 'selected' : ''}>POST</option> |
| <option value="PUT" ${nodeData.method === 'PUT' ? 'selected' : ''}>PUT</option> |
| <option value="DELETE" ${nodeData.method === 'DELETE' ? 'selected' : ''}>DELETE</option> |
| </select> |
| </div> |
| <div class="form-group"> |
| <label class="form-label">Request Data (JSON):</label> |
| <textarea class="form-control api-data" rows="3">${nodeData.data ? JSON.stringify(nodeData.data, null, 2) : ''}</textarea> |
| </div> |
| <div class="form-group"> |
| <label class="form-label">Response Variable:</label> |
| <input type="text" class="form-control api-var" value="${nodeData.varName || 'apiResponse'}"> |
| </div> |
| ` |
| }, |
| condition: { |
| title: 'Condition', |
| icon: 'code-branch', |
| template: ` |
| <div class="form-group"> |
| <label class="form-label">Condition Type:</label> |
| <select class="select-control condition-type"> |
| <option value="text" ${nodeData.conditionType === 'text' ? 'selected' : ''}>Text Comparison</option> |
| <option value="var" ${nodeData.conditionType === 'var' ? 'selected' : ''}>Variable Comparison</option> |
| <option value="group" ${nodeData.conditionType === 'group' ? 'selected' : ''}>Group Check</option> |
| <option value="admin" ${nodeData.conditionType === 'admin' ? 'selected' : ''}>Admin Check</option> |
| </select> |
| </div> |
| ${nodeData.conditionType === 'text' ? ` |
| <div class="form-group"> |
| <label class="form-label">Comparison:</label> |
| <select class="select-control condition-compare"> |
| <option value="equals" ${nodeData.compare === 'equals' ? 'selected' : ''}>Equals</option> |
| <option value="contains" ${nodeData.compare === 'contains' ? 'selected' : ''}>Contains</option> |
| <option value="startsWith" ${nodeData.compare === 'startsWith' ? 'selected' : ''}>Starts With</option> |
| <option value="endsWith" ${nodeData.compare === 'endsWith' ? 'selected' : ''}>Ends With</option> |
| </select> |
| </div> |
| <div class="form-group"> |
| <label class="form-label">Value to Compare:</label> |
| <input type="text" class="form-control condition-value" value="${nodeData.value || ''}"> |
| </div> |
| ` : ''} |
| ${nodeData.conditionType === 'var' ? ` |
| <div class="form-group"> |
| <label class="form-label">Variable Name:</label> |
| <input type="text" class="form-control condition-var" value="${nodeData.varName || ''}"> |
| </div> |
| <div class="form-group"> |
| <label class="form-label">Comparison:</label> |
| <select class="select-control condition-compare"> |
| <option value="equals" ${nodeData.compare === 'equals' ? 'selected' : ''}>Equals</option> |
| <option value="contains" ${nodeData.compare === 'contains' ? 'selected' : ''}>Contains</option> |
| <option value="greater" ${nodeData.compare === 'greater' ? 'selected' : ''}>Greater Than</option> |
| <option value="less" ${nodeData.compare === 'less' ? 'selected' : ''}>Less Than</option> |
| </select> |
| </div> |
| <div class="form-group"> |
| <label class="form-label">Value to Compare:</label> |
| <input type="text" class="form-control condition-value" value="${nodeData.value || ''}"> |
| </div> |
| ` : ''} |
| ` |
| } |
| }; |
| |
| if (nodeData.type === 'condition') { |
| // Create condition node with branches |
| const conditionDiv = document.createElement('div'); |
| conditionDiv.className = 'condition-branch'; |
| conditionDiv.innerHTML = ` |
| <div class="condition-node"> |
| <div class="flow-node-header"> |
| <div class="flow-node-title"> |
| <i class="fas fa-code-branch"></i> Condition |
| </div> |
| <div class="flow-node-actions"> |
| <button class="btn btn-sm config-btn" style="padding: 0 5px;"> |
| <i class="fas fa-cog"></i> |
| </button> |
| <button class="btn btn-sm delete-btn" style="padding: 0 5px;"> |
| <i class="fas fa-trash"></i> |
| </button> |
| </div> |
| </div> |
| <div class="flow-node-content"> |
| ${nodeTypes.condition.template} |
| </div> |
| </div> |
| <div class="condition-branches"> |
| <div class="branch"> |
| <div class="condition-branch-label">If True</div> |
| ${nodeData.trueBranch && nodeData.trueBranch.length > 0 ? |
| nodeData.trueBranch.map(n => addNodeToFlow(n)).join('') : |
| '<div style="height: 50px;"></div>'} |
| </div> |
| <div class="branch"> |
| <div class="condition-branch-label">If False</div> |
| ${nodeData.falseBranch && nodeData.falseBranch.length > 0 ? |
| nodeData.falseBranch.map(n => addNodeToFlow(n)).join('') : |
| '<div style="height: 50px;"></div>'} |
| </div> |
| </div> |
| `; |
| flowContainer.appendChild(conditionDiv); |
| } else { |
| // Create regular node |
| const nodeDiv = document.createElement('div'); |
| nodeDiv.className = 'flow-node'; |
| nodeDiv.dataset.index = index; |
| nodeDiv.dataset.type = nodeData.type; |
| nodeDiv.innerHTML = ` |
| <div class="flow-node-header"> |
| <div class="flow-node-title"> |
| <i class="fas fa-${nodeTypes[nodeData.type]?.icon || 'code'}"></i> ${nodeTypes[nodeData.type]?.title || nodeData.type} |
| </div> |
| <div class="flow-node-actions"> |
| <button class="btn btn-sm config-btn" style="padding: 0 5px;"> |
| <i class="fas fa-cog"></i> |
| </button> |
| <button class="btn btn-sm delete-btn" style="padding: 0 5px;"> |
| <i class="fas fa-trash"></i> |
| </button> |
| </div> |
| </div> |
| <div class="flow-node-content"> |
| ${nodeTypes[nodeData.type]?.template || ''} |
| </div> |
| `; |
| flowContainer.appendChild(nodeDiv); |
| } |
| |
| // Add event listeners to the new node |
| addNodeEventListeners(); |
| } |
| |
| // Add event listeners to nodes |
| function addNodeEventListeners() { |
| document.querySelectorAll('.config-btn').forEach(btn => { |
| btn.addEventListener('click', (e) => { |
| e.stopPropagation(); |
| // Handle node configuration |
| }); |
| }); |
| |
| document.querySelectorAll('.delete-btn').forEach(btn => { |
| btn.addEventListener('click', (e) => { |
| e.stopPropagation(); |
| const node = btn.closest('.flow-node'); |
| if (node) { |
| const index = node.dataset.index; |
| if (currentCommand.flow[index]) { |
| currentCommand.flow.splice(index, 1); |
| saveCurrentCommand(); |
| updateCommandUI(); |
| } |
| } |
| }); |
| }); |
| |
| // Add change listeners for form elements |
| document.querySelectorAll('.flow-node-content select, .flow-node-content input, .flow-node-content textarea').forEach(el => { |
| el.addEventListener('change', updateNodeData); |
| el.addEventListener('input', updateNodeData); |
| }); |
| } |
| |
| // Update node data when form elements change |
| function updateNodeData(e) { |
| const node = e.target.closest('.flow-node'); |
| if (!node) return; |
| |
| const index = node.dataset.index; |
| const type = node.dataset.type; |
| |
| if (!currentCommand.flow[index]) { |
| currentCommand.flow[index] = { type }; |
| } |
| |
| // Update node data based on type |
| switch (type) { |
| case 'trigger': |
| currentCommand.flow[index].triggerType = node.querySelector('.trigger-type').value; |
| currentCommand.flow[index].command = node.querySelector('.trigger-command').value; |
| if (currentCommand.flow[index].triggerType === 'regex') { |
| currentCommand.flow[index].regex = node.querySelector('.trigger-regex')?.value || ''; |
| } |
| break; |
| case 'response': |
| currentCommand.flow[index].responseType = node.querySelector('.response-type').value; |
| currentCommand.flow[index].content = node.querySelector('.response-content').value; |
| if (['image', 'video'].includes(currentCommand.flow[index].responseType)) { |
| currentCommand.flow[index].mediaUrl = node.querySelector('.media-url')?.value || ''; |
| } |
| break; |
| case 'api': |
| currentCommand.flow[index].apiUrl = node.querySelector('.api-url').value; |
| currentCommand.flow[index].method = node.querySelector('.api-method').value; |
| try { |
| currentCommand.flow[index].data = JSON.parse(node.querySelector('.api-data').value); |
| } catch (e) { |
| currentCommand.flow[index].data = {}; |
| } |
| currentCommand.flow[index].varName = node.querySelector('.api-var').value; |
| break; |
| case 'condition': |
| currentCommand.flow[index].conditionType = node.querySelector('.condition-type').value; |
| currentCommand.flow[index].compare = node.querySelector('.condition-compare')?.value || ''; |
| currentCommand.flow[index].value = node.querySelector('.condition-value')?.value || ''; |
| currentCommand.flow[index].varName = node.querySelector('.condition-var')?.value || ''; |
| break; |
| } |
| |
| saveCurrentCommand(); |
| } |
| |
| // Save the current command |
| function saveCurrentCommand() { |
| if (!currentCommand) return; |
| |
| // Update command metadata |
| currentCommand.name = commandName.value; |
| currentCommand.description = commandDescription.value; |
| currentCommand.permissions = Array.from(permissionOptions.querySelectorAll('.option-card.selected')).map(card => card.dataset.value); |
| currentCommand.contexts = Array.from(contextOptions.querySelectorAll('.option-card.selected')).map(card => card.dataset.value); |
| |
| // Update packages |
| currentCommand.packages = ['fs', 'path']; // Always include these |
| if (packageOptions.querySelector('#axios').checked) currentCommand.packages.push('axios'); |
| if (packageOptions.querySelector('#formData').checked) currentCommand.packages.push('form-data'); |
| |
| // Update command title |
| commandTitle.textContent = currentCommand.name || 'New Command'; |
| |
| // Save to storage |
| const index = commands.findIndex(c => c.id === currentCommand.id); |
| if (index !== -1) { |
| commands[index] = currentCommand; |
| saveCommands(); |
| loadCommands(); |
| } |
| } |
| |
| // Generate a unique ID |
| function generateId() { |
| return Date.now().toString(36) + Math.random().toString(36).substr(2); |
| } |
| |
| // Setup event listeners |
| function setupEventListeners() { |
| // Tab switching |
| document.querySelectorAll('.tab').forEach(tab => { |
| tab.addEventListener('click', () => { |
| const tabId = tab.getAttribute('data-tab'); |
| |
| // Hide all tab contents |
| document.querySelectorAll('.tab-content').forEach(content => { |
| content.classList.remove('active'); |
| }); |
| |
| // Deactivate all tabs |
| document.querySelectorAll('.tab').forEach(t => { |
| t.classList.remove('active'); |
| }); |
| |
| // Activate selected tab |
| tab.classList.add('active'); |
| document.getElementById(tabId + 'Tab').classList.add('active'); |
| }); |
| }); |
| |
| // Preview tab switching |
| document.querySelectorAll('[data-preview-tab]').forEach(tab => { |
| tab.addEventListener('click', () => { |
| const tabId = tab.getAttribute('data-preview-tab'); |
| |
| // Hide all preview tab contents |
| document.querySelectorAll('.preview-content .tab-content').forEach(content => { |
| content.classList.remove('active'); |
| }); |
| |
| // Deactivate all preview tabs |
| document.querySelectorAll('[data-preview-tab]').forEach(t => { |
| t.classList.remove('active'); |
| }); |
| |
| // Activate selected preview tab |
| tab.classList.add('active'); |
| document.getElementById('preview' + tabId.charAt(0).toUpperCase() + tabId.slice(1) + 'Tab').classList.add('active'); |
| }); |
| }); |
| |
| // Option card selection |
| document.querySelectorAll('.option-card').forEach(card => { |
| card.addEventListener('click', () => { |
| const parent = card.parentElement; |
| if (parent.classList.contains('options-grid')) { |
| // For single selection groups |
| if (!card.classList.contains('selected')) { |
| parent.querySelectorAll('.option-card').forEach(c => { |
| c.classList.remove('selected'); |
| }); |
| card.classList.add('selected'); |
| saveCurrentCommand(); |
| } |
| } else { |
| // For multiple selection |
| card.classList.toggle('selected'); |
| saveCurrentCommand(); |
| } |
| }); |
| }); |
| |
| // Add step button |
| addStepBtn.addEventListener('click', (e) => { |
| const rect = addStepBtn.getBoundingClientRect(); |
| nodeOptions.style.display = 'block'; |
| nodeOptions.style.top = `${rect.bottom + 5}px`; |
| nodeOptions.style.left = `${rect.left}px`; |
| selectedNode = null; |
| }); |
| |
| // Add condition button |
| addConditionBtn.addEventListener('click', () => { |
| if (!currentCommand) return; |
| |
| const newCondition = { |
| type: 'condition', |
| conditionType: 'text', |
| compare: 'equals', |
| value: '', |
| trueBranch: [], |
| falseBranch: [] |
| }; |
| |
| currentCommand.flow.push(newCondition); |
| saveCurrentCommand(); |
| updateCommandUI(); |
| }); |
| |
| // Node options |
| document.querySelectorAll('.node-option').forEach(option => { |
| option.addEventListener('click', () => { |
| const type = option.dataset.type; |
| nodeOptions.style.display = 'none'; |
| |
| if (!currentCommand) return; |
| |
| const newNode = { type }; |
| |
| // Set defaults based on type |
| switch (type) { |
| case 'trigger': |
| newNode.triggerType = 'prefix'; |
| newNode.command = ''; |
| break; |
| case 'response': |
| newNode.responseType = 'text'; |
| newNode.content = ''; |
| break; |
| case 'api': |
| newNode.apiUrl = ''; |
| newNode.method = 'GET'; |
| newNode.data = {}; |
| newNode.varName = 'apiResponse'; |
| break; |
| } |
| |
| if (selectedNode !== null && currentCommand.flow[selectedNode]) { |
| // Add after selected node |
| currentCommand.flow.splice(selectedNode + 1, 0, newNode); |
| } else { |
| // Add to end |
| currentCommand.flow.push(newNode); |
| } |
| |
| saveCurrentCommand(); |
| updateCommandUI(); |
| }); |
| }); |
| |
| // Click outside node options to close |
| document.addEventListener('click', (e) => { |
| if (!nodeOptions.contains(e.target) && e.target !== addStepBtn) { |
| nodeOptions.style.display = 'none'; |
| } |
| }); |
| |
| // Select node on click |
| flowContainer.addEventListener('click', (e) => { |
| const node = e.target.closest('.flow-node'); |
| if (node) { |
| document.querySelectorAll('.flow-node').forEach(n => { |
| n.style.borderColor = 'var(--primary)'; |
| }); |
| node.style.borderColor = 'var(--secondary)'; |
| selectedNode = parseInt(node.dataset.index); |
| } |
| }); |
| |
| // New command button |
| newCommandBtn.addEventListener('click', createNewCommand); |
| |
| // Save command button |
| saveCommandBtn.addEventListener('click', saveCurrentCommand); |
| |
| // Preview button |
| previewBtn.addEventListener('click', showPreview); |
| |
| // Close preview |
| closePreview.addEventListener('click', () => { |
| previewModal.classList.remove('active'); |
| }); |
| |
| // Refresh commands |
| refreshCommands.addEventListener('click', loadCommands); |
| |
| // Add package button |
| addPackageBtn.addEventListener('click', () => { |
| const pkg = customPackage.value.trim(); |
| if (pkg) { |
| const div = document.createElement('div'); |
| div.style.display = 'flex'; |
| div.style.alignItems = 'center'; |
| div.style.marginBottom = '10px'; |
| div.innerHTML = ` |
| <input type="checkbox" id="${pkg}" checked style="margin-right: 10px;"> |
| <label for="${pkg}">${pkg} - Custom package</label> |
| `; |
| packageOptions.appendChild(div); |
| customPackage.value = ''; |
| saveCurrentCommand(); |
| } |
| }); |
| |
| // Download button |
| downloadBtn.addEventListener('click', (e) => { |
| e.preventDefault(); |
| downloadCommand(); |
| }); |
| |
| // Run test button |
| runTestBtn.addEventListener('click', runTest); |
| } |
| |
| // Show command preview |
| function showPreview() { |
| if (!currentCommand) return; |
| |
| // Generate code |
| generateCode(); |
| |
| // Update info tab |
| infoName.textContent = currentCommand.name || 'Unnamed Command'; |
| infoDescription.textContent = currentCommand.description || 'No description'; |
| |
| // Find trigger command |
| const triggerNode = currentCommand.flow.find(node => node.type === 'trigger'); |
| if (triggerNode) { |
| let triggerText = ''; |
| if (triggerNode.triggerType === 'prefix') { |
| triggerText = `!${triggerNode.command}`; |
| } else if (triggerNode.triggerType === 'exact') { |
| triggerText = triggerNode.command; |
| } else if (triggerNode.triggerType === 'regex') { |
| triggerText = `Regex: ${triggerNode.regex}`; |
| } |
| infoTrigger.textContent = triggerText; |
| } else { |
| infoTrigger.textContent = 'No trigger defined'; |
| } |
| |
| // Find response |
| const responseNode = currentCommand.flow.find(node => node.type === 'response'); |
| if (responseNode) { |
| infoResponse.textContent = responseNode.content || 'No content'; |
| } else { |
| infoResponse.textContent = 'No response defined'; |
| } |
| |
| // Update packages list |
| infoPackages.innerHTML = ''; |
| currentCommand.packages.forEach(pkg => { |
| const li = document.createElement('li'); |
| li.innerHTML = `<span class="badge badge-primary">${pkg}</span> - ${getPackageDescription(pkg)}`; |
| infoPackages.appendChild(li); |
| }); |
| |
| // Show modal |
| previewModal.classList.add('active'); |
| } |
| |
| // Get package description |
| function getPackageDescription(pkg) { |
| const descriptions = { |
| 'axios': 'For HTTP requests', |
| 'form-data': 'For multipart form data', |
| 'fs': 'File system operations', |
| 'path': 'Path utilities' |
| }; |
| return descriptions[pkg] || 'Custom package'; |
| } |
| |
| // Generate JavaScript code from the command |
| function generateCode() { |
| if (!currentCommand) return ''; |
| |
| let code = `const config = require('../config');\n`; |
| |
| // Add required packages |
| currentCommand.packages.forEach(pkg => { |
| if (pkg === 'fs' || pkg === 'path') { |
| code += `const ${pkg} = require('${pkg}');\n`; |
| } else { |
| code += `const ${pkg} = require('${pkg}');\n`; |
| } |
| }); |
| |
| code += `\nconst ${currentCommand.name || 'myCommand'} = async (m, sock) => {\n`; |
| code += ` try {\n`; |
| |
| // Add permission checks |
| if (currentCommand.permissions.includes('admin')) { |
| code += ` // Check if user is admin\n`; |
| code += ` if (!m.isGroup) return;\n`; |
| code += ` const participants = await sock.groupMetadata(m.key.remoteJid);\n`; |
| code += ` const isAdmin = participants.participants.find(p => p.id === m.key.participant)?.admin === 'admin';\n`; |
| code += ` if (!isAdmin) {\n`; |
| code += ` await sock.sendMessage(m.key.remoteJid, { text: 'You need to be an admin to use this command' }, { quoted: m });\n`; |
| code += ` return;\n`; |
| code += ` }\n\n`; |
| } else if (currentCommand.permissions.includes('owner')) { |
| code += ` // Check if user is owner\n`; |
| code += ` const isOwner = m.key.participant === config.ownerNumber;\n`; |
| code += ` if (!isOwner) {\n`; |
| code += ` await sock.sendMessage(m.key.remoteJid, { text: 'Only the bot owner can use this command' }, { quoted: m });\n`; |
| code += ` return;\n`; |
| code += ` }\n\n`; |
| } |
| |
| // Add context checks |
| if (currentCommand.contexts.length === 1) { |
| if (currentCommand.contexts[0] === 'groups') { |
| code += ` // Command only works in groups\n`; |
| code += ` if (!m.isGroup) {\n`; |
| code += ` await sock.sendMessage(m.key.remoteJid, { text: 'This command only works in groups' }, { quoted: m });\n`; |
| code += ` return;\n`; |
| code += ` }\n\n`; |
| } else if (currentCommand.contexts[0] === 'private') { |
| code += ` // Command only works in private chats\n`; |
| code += ` if (m.isGroup) {\n`; |
| code += ` await sock.sendMessage(m.key.remoteJid, { text: 'This command only works in private chats' }, { quoted: m });\n`; |
| code += ` return;\n`; |
| code += ` }\n\n`; |
| } |
| } |
| |
| // Process flow nodes |
| currentCommand.flow.forEach(node => { |
| switch (node.type) { |
| case 'trigger': |
| if (node.triggerType === 'prefix') { |
| code += ` const prefix = config.prefix || '!';\n`; |
| code += ` const text = m.message?.conversation || m.message?.extendedTextMessage?.text || '';\n`; |
| code += ` \n`; |
| code += ` if (!text.toLowerCase().startsWith(\`\${prefix}${node.command.toLowerCase()}\`)) return;\n`; |
| code += ` const args = text.slice(prefix.length + '${node.command}'.length).trim().split(/\\s+/);\n\n`; |
| } else if (node.triggerType === 'exact') { |
| code += ` const text = m.message?.conversation || m.message?.extendedTextMessage?.text || '';\n`; |
| code += ` \n`; |
| code += ` if (text.toLowerCase() !== '${node.command.toLowerCase()}') return;\n\n`; |
| } else if (node.triggerType === 'regex') { |
| code += ` const text = m.message?.conversation || m.message?.extendedTextMessage?.text || '';\n`; |
| code += ` \n`; |
| code += ` if (!new RegExp(\`${node.regex}\`, 'i').test(text)) return;\n\n`; |
| } |
| break; |
| |
| case 'response': |
| if (node.responseType === 'text') { |
| code += ` await sock.sendMessage(m.key.remoteJid, {\n`; |
| code += ` text: \`${node.content.replace(/`/g, '\\`')}\`\n`; |
| code += ` }, { quoted: m });\n\n`; |
| } else if (node.responseType === 'image' || node.responseType === 'video') { |
| code += ` // Send ${node.responseType}\n`; |
| code += ` const media = await sock.downloadMediaMessage(m);\n`; |
| code += ` await sock.sendMessage(m.key.remoteJid, {\n`; |
| code += ` ${node.responseType}: media,\n`; |
| code += ` caption: \`${node.content.replace(/`/g, '\\`')}\`\n`; |
| code += ` }, { quoted: m });\n\n`; |
| } else if (node.responseType === 'buttons') { |
| code += ` // Send buttons\n`; |
| code += ` const buttons = [\n`; |
| code += ` { buttonId: 'id1', buttonText: { displayText: 'Button 1' }, type: 1 },\n`; |
| code += ` { buttonId: 'id2', buttonText: { displayText: 'Button 2' }, type: 1 }\n`; |
| code += ` ];\n\n`; |
| code += ` await sock.sendMessage(m.key.remoteJid, {\n`; |
| code += ` text: \`${node.content.replace(/`/g, '\\`')}\`,\n`; |
| code += ` footer: 'Select an option',\n`; |
| code += ` buttons: buttons,\n`; |
| code += ` headerType: 1\n`; |
| code += ` }, { quoted: m });\n\n`; |
| } else if (node.responseType === 'list') { |
| code += ` // Send list\n`; |
| code += ` const sections = [\n`; |
| code += ` {\n`; |
| code += ` title: "Section 1",\n`; |
| code += ` rows: [\n`; |
| code += ` { title: "Option 1", rowId: "option1" },\n`; |
| code += ` { title: "Option 2", rowId: "option2" }\n`; |
| code += ` ]\n`; |
| code += ` }\n`; |
| code += ` ];\n\n`; |
| code += ` await sock.sendMessage(m.key.remoteJid, {\n`; |
| code += ` text: \`${node.content.replace(/`/g, '\\`')}\`,\n`; |
| code += ` footer: 'Select an option',\n`; |
| code += ` title: 'Menu',\n`; |
| code += ` buttonText: 'View Options',\n`; |
| code += ` sections: sections\n`; |
| code += ` }, { quoted: m });\n\n`; |
| } |
| break; |
| |
| case 'api': |
| code += ` // API call\n`; |
| code += ` const ${node.varName} = await axios({\n`; |
| code += ` method: '${node.method}',\n`; |
| code += ` url: '${node.apiUrl}',\n`; |
| if (node.method !== 'GET' && node.data) { |
| code += ` data: ${JSON.stringify(node.data, null, 4).split('\n').join('\n ')},\n`; |
| } |
| code += ` });\n\n`; |
| break; |
| |
| case 'condition': |
| code += ` // Condition check\n`; |
| if (node.conditionType === 'text') { |
| code += ` const text = m.message?.conversation || m.message?.extendedTextMessage?.text || '';\n`; |
| if (node.compare === 'equals') { |
| code += ` if (text === '${node.value}') {\n`; |
| } else if (node.compare === 'contains') { |
| code += ` if (text.includes('${node.value}')) {\n`; |
| } else if (node.compare === 'startsWith') { |
| code += ` if (text.startsWith('${node.value}')) {\n`; |
| } else if (node.compare === 'endsWith') { |
| code += ` if (text.endsWith('${node.value}')) {\n`; |
| } |
| } else if (node.conditionType === 'var') { |
| code += ` if (${node.varName} ${getComparisonOperator(node.compare)} '${node.value}') {\n`; |
| } else if (node.conditionType === 'group') { |
| code += ` if (m.isGroup) {\n`; |
| } else if (node.conditionType === 'admin') { |
| code += ` const participants = await sock.groupMetadata(m.key.remoteJid);\n`; |
| code += ` const isAdmin = participants.participants.find(p => p.id === m.key.participant)?.admin === 'admin';\n`; |
| code += ` if (isAdmin) {\n`; |
| } |
| |
| // True branch |
| if (node.trueBranch && node.trueBranch.length > 0) { |
| // Would generate code for true branch here |
| code += ` // True branch actions\n`; |
| } else { |
| code += ` // No actions for true branch\n`; |
| } |
| |
| code += ` } else {\n`; |
| |
| // False branch |
| if (node.falseBranch && node.falseBranch.length > 0) { |
| // Would generate code for false branch here |
| code += ` // False branch actions\n`; |
| } else { |
| code += ` // No actions for false branch\n`; |
| } |
| |
| code += ` }\n\n`; |
| break; |
| } |
| }); |
| |
| code += ` } catch (error) {\n`; |
| code += ` console.error('Error in ${currentCommand.name || 'command'}:', error);\n`; |
| code += ` await sock.sendMessage(m.key.remoteJid, { text: 'An error occurred while processing your command' }, { quoted: m });\n`; |
| code += ` }\n`; |
| code += `};\n\n`; |
| code += `module.exports = ${currentCommand.name || 'myCommand'};\n`; |
| |
| generatedCode.innerHTML = `<pre>${escapeHtml(code)}</pre>`; |
| return code; |
| } |
| |
| // Get comparison operator for condition |
| function getComparisonOperator(compare) { |
| switch (compare) { |
| case 'equals': return '==='; |
| case 'contains': return '.includes'; |
| case 'greater': return '>'; |
| case 'less': return '<'; |
| default: return '==='; |
| } |
| } |
| |
| // Escape HTML for code display |
| function escapeHtml(unsafe) { |
| return unsafe |
| .replace(/&/g, "&") |
| .replace(/</g, "<") |
| .replace(/>/g, ">") |
| .replace(/"/g, """) |
| .replace(/'/g, "'"); |
| } |
| |
| // Download command as file |
| function downloadCommand() { |
| if (!currentCommand) return; |
| |
| const code = generateCode(); |
| const blob = new Blob([code], { type: 'text/javascript' }); |
| const url = URL.createObjectURL(blob); |
| |
| const a = document.createElement('a'); |
| a.href = url; |
| a.download = `${currentCommand.name || 'command'}.js`; |
| document.body.appendChild(a); |
| a.click(); |
| document.body.removeChild(a); |
| URL.revokeObjectURL(url); |
| } |
| |
| // Run test command |
| function runTest() { |
| const command = testCommandInput.value.trim(); |
| if (!command) return; |
| |
| // Simple test simulation |
| testOutput.innerHTML = 'Testing command...\n\n'; |
| |
| // Find trigger node |
| const triggerNode = currentCommand.flow.find(node => node.type === 'trigger'); |
| if (!triggerNode) { |
| testOutput.innerHTML += 'Error: No trigger defined in command'; |
| return; |
| } |
| |
| // Check if command matches trigger |
| let matches = false; |
| if (triggerNode.triggerType === 'prefix') { |
| matches = command.toLowerCase().startsWith(`!${triggerNode.command.toLowerCase()}`); |
| } else if (triggerNode.triggerType === 'exact') { |
| matches = command.toLowerCase() === triggerNode.command.toLowerCase(); |
| } else if (triggerNode.triggerType === 'regex') { |
| try { |
| matches = new RegExp(triggerNode.regex, 'i').test(command); |
| } catch (e) { |
| testOutput.innerHTML += `Regex error: ${e.message}`; |
| return; |
| } |
| } |
| |
| if (!matches) { |
| testOutput.innerHTML += 'Command did not match trigger pattern'; |
| return; |
| } |
| |
| // Find response node |
| const responseNode = currentCommand.flow.find(node => node.type === 'response'); |
| if (responseNode) { |
| if (responseNode.responseType === 'text') { |
| testOutput.innerHTML += `Bot would reply with:\n\n${responseNode.content}`; |
| } else { |
| testOutput.innerHTML += `Bot would send ${responseNode.responseType} response`; |
| } |
| } else { |
| testOutput.innerHTML += 'Command matched but no response defined'; |
| } |
| } |
| |
| // Initialize the application |
| init(); |
| </script> |
| </body> |
| </html> |