312 lines
18 KiB
HTML
312 lines
18 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>SMS Campaign Manager</title>
|
||
<script src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js" defer></script>
|
||
<script src="https://cdn.tailwindcss.com"></script>
|
||
<script src="https://cdn.socket.io/4.7.2/socket.io.min.js"></script>
|
||
<link rel="stylesheet" href="/static/css/dashboard.css">
|
||
</head>
|
||
<body class="bg-gray-50">
|
||
<div x-data="campaignApp()" x-init="init()" x-cloak class="container mx-auto px-4 py-8 max-w-7xl">
|
||
<!-- Header with Connection Status -->
|
||
<div class="bg-white rounded-lg shadow-sm p-6 mb-6">
|
||
<div class="flex justify-between items-center">
|
||
<div>
|
||
<h1 class="text-3xl font-bold text-gray-800">📱 SMS Campaign Manager</h1>
|
||
<p class="text-gray-600 mt-1">Homelab Campaign Management Interface</p>
|
||
</div>
|
||
<div class="flex flex-col space-y-2">
|
||
<!-- Termux API Status -->
|
||
<div class="flex items-center">
|
||
<span class="text-sm font-medium text-gray-600 mr-2 w-20">Termux:</span>
|
||
<span x-show="phoneStatus.termux_connected" class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
|
||
🟢 Online
|
||
</span>
|
||
<span x-show="!phoneStatus.termux_connected" class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800">
|
||
🔴 Offline
|
||
</span>
|
||
</div>
|
||
|
||
<!-- ADB Status -->
|
||
<div class="flex items-center">
|
||
<span class="text-sm font-medium text-gray-600 mr-2 w-20">ADB:</span>
|
||
<span x-show="phoneStatus.adb_connected" class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
|
||
🟢 Online
|
||
</span>
|
||
<span x-show="!phoneStatus.adb_connected" class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800">
|
||
🔴 Offline
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Tab Navigation -->
|
||
<div class="bg-white rounded-t-lg shadow-sm border-b">
|
||
<nav class="flex space-x-1 p-1">
|
||
<button @click="activeTab = 'campaigns'"
|
||
:class="activeTab === 'campaigns' ? 'bg-blue-500 text-white' : 'bg-gray-100 text-gray-700 hover:bg-gray-200'"
|
||
class="px-4 py-2 rounded-lg font-medium transition-colors">
|
||
📋 Campaigns
|
||
</button>
|
||
<button @click="activeTab = 'conversations'; loadConversations()"
|
||
:class="activeTab === 'conversations' ? 'bg-blue-500 text-white' : 'bg-gray-100 text-gray-700 hover:bg-gray-200'"
|
||
class="px-4 py-2 rounded-lg font-medium transition-colors">
|
||
💬 Conversations
|
||
</button>
|
||
<button @click="activeTab = 'testing'"
|
||
:class="activeTab === 'testing' ? 'bg-blue-500 text-white' : 'bg-gray-100 text-gray-700 hover:bg-gray-200'"
|
||
class="px-4 py-2 rounded-lg font-medium transition-colors">
|
||
🧪 System Testing
|
||
</button>
|
||
</nav>
|
||
</div>
|
||
|
||
<!-- Tab Content -->
|
||
<div class="bg-white rounded-b-lg shadow-sm min-h-[600px]">
|
||
<!-- Campaigns Tab (Preserving existing functionality) -->
|
||
<div x-show="activeTab === 'campaigns'" class="p-6">
|
||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||
<!-- Create Campaign Section -->
|
||
<div class="border rounded-lg p-4">
|
||
<h2 class="text-xl font-semibold mb-4">Create Campaign</h2>
|
||
|
||
<div class="space-y-4">
|
||
<div>
|
||
<label class="block text-sm font-medium text-gray-700 mb-1">Campaign Name</label>
|
||
<input type="text" x-model="campaignName"
|
||
placeholder="e.g., Weekend Volunteer Outreach"
|
||
class="w-full px-3 py-2 border rounded-lg">
|
||
</div>
|
||
|
||
<div>
|
||
<label class="block text-sm font-medium text-gray-700 mb-1">
|
||
Message Template <span class="text-gray-500">(Use {name}, {phone}, {date}, {time} for variables)</span>
|
||
</label>
|
||
<textarea x-model="messageTemplate"
|
||
placeholder="Hi {name}! Hope all is well. I am wondering if you got my last email..."
|
||
class="w-full px-3 py-2 border rounded-lg h-24"></textarea>
|
||
</div>
|
||
|
||
<div>
|
||
<label class="block text-sm font-medium text-gray-700 mb-1">Recipients CSV</label>
|
||
<input type="file" @change="handleFileUpload($event)"
|
||
accept=".csv"
|
||
class="w-full px-3 py-2 border rounded-lg">
|
||
<div x-show="uploadedFile" class="mt-2 text-sm text-green-600">
|
||
✓ <span x-text="uploadedFile"></span>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<label class="block text-sm font-medium text-gray-700 mb-1">Use Saved List</label>
|
||
<select x-model="selectedList" class="w-full px-3 py-2 border rounded-lg">
|
||
<option value="">-- Select a saved list --</option>
|
||
<template x-for="list in savedLists" :key="list.id">
|
||
<option :value="list.id" x-text="`${list.name} (${list.count} contacts)`"></option>
|
||
</template>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="flex gap-2">
|
||
<button @click="saveTemplate()"
|
||
class="bg-gray-500 text-white px-4 py-2 rounded hover:bg-gray-600">
|
||
Save Template
|
||
</button>
|
||
<button @click="testSMS()"
|
||
class="bg-yellow-500 text-white px-4 py-2 rounded hover:bg-yellow-600">
|
||
Test SMS
|
||
</button>
|
||
<button @click="startCampaign()"
|
||
:disabled="!campaignReady"
|
||
class="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600 disabled:opacity-50">
|
||
Start Campaign
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Campaign Status Section -->
|
||
<div class="space-y-4">
|
||
<!-- Analytics -->
|
||
<div class="border rounded-lg p-4">
|
||
<h3 class="font-semibold mb-3">Campaign Analytics</h3>
|
||
<div class="grid grid-cols-2 gap-4">
|
||
<div class="text-center">
|
||
<div class="text-2xl font-bold text-blue-600" x-text="analytics.total_sent || 0"></div>
|
||
<div class="text-sm text-gray-600">Total Sent</div>
|
||
</div>
|
||
<div class="text-center">
|
||
<div class="text-2xl font-bold text-green-600" x-text="analytics.responses || 0"></div>
|
||
<div class="text-sm text-gray-600">Responses</div>
|
||
</div>
|
||
<div class="text-center">
|
||
<div class="text-2xl font-bold text-yellow-600" x-text="analytics.follow_ups || 0"></div>
|
||
<div class="text-sm text-gray-600">Follow-ups Needed</div>
|
||
</div>
|
||
<div class="text-center">
|
||
<div class="text-2xl font-bold text-purple-600" x-text="analytics.opt_outs || 0"></div>
|
||
<div class="text-sm text-gray-600">Opt-outs</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Response Types -->
|
||
<div class="border rounded-lg p-4">
|
||
<h3 class="font-semibold mb-3">Response Types</h3>
|
||
<div x-show="!responseTypes.length" class="text-gray-500 text-sm">
|
||
No responses yet
|
||
</div>
|
||
<div class="space-y-2">
|
||
<template x-for="type in responseTypes" :key="type.type">
|
||
<div class="flex justify-between items-center">
|
||
<span x-text="type.type" class="text-sm"></span>
|
||
<span x-text="type.count" class="font-medium"></span>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Recent Campaigns -->
|
||
<div class="border rounded-lg p-4">
|
||
<h3 class="font-semibold mb-3">Recent Campaigns</h3>
|
||
<div x-show="!recentCampaigns.length" class="text-gray-500 text-sm">
|
||
No recent campaigns
|
||
</div>
|
||
<div class="space-y-2">
|
||
<template x-for="campaign in recentCampaigns" :key="campaign.id">
|
||
<div class="border-b pb-2">
|
||
<div class="font-medium" x-text="campaign.name"></div>
|
||
<div class="text-sm text-gray-600">
|
||
<span x-text="campaign.sent_count"></span> sent •
|
||
<span x-text="formatDate(campaign.created_at)"></span>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Conversations Tab -->
|
||
<div x-show="activeTab === 'conversations'" class="p-6">
|
||
<div id="conversations-container">
|
||
<!-- Enhanced conversations component will be loaded here -->
|
||
<include src="conversations_enhanced_component.html"></include>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- System Testing Tab -->
|
||
<div x-show="activeTab === 'testing'" class="p-6">
|
||
<h2 class="text-xl font-semibold mb-4">🧪 System Testing & Diagnostics</h2>
|
||
|
||
<!-- Connection Tests -->
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
|
||
<!-- Termux API Test -->
|
||
<div class="border rounded-lg p-4">
|
||
<h3 class="font-medium mb-3">📡 Termux API Test</h3>
|
||
<div class="text-sm text-gray-600 mb-3">
|
||
Endpoint: <code class="bg-gray-100 px-1">http://{{ phoneIP }}:5001</code>
|
||
</div>
|
||
<button @click="testTermuxConnection()"
|
||
:disabled="testingTermux"
|
||
class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600 disabled:opacity-50 transition-colors">
|
||
<span x-show="!testingTermux">Test Termux API</span>
|
||
<span x-show="testingTermux">Testing...</span>
|
||
</button>
|
||
<div x-show="termuxTestResult" class="mt-3 p-3 rounded text-sm"
|
||
:class="termuxTestResult?.success ? 'bg-green-50 text-green-700' : 'bg-red-50 text-red-700'">
|
||
<pre x-text="JSON.stringify(termuxTestResult, null, 2)"></pre>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ADB Connection Test -->
|
||
<div class="border rounded-lg p-4">
|
||
<h3 class="font-medium mb-3">🔌 ADB Connection Test</h3>
|
||
<div class="text-sm text-gray-600 mb-3">
|
||
Device: <code class="bg-gray-100 px-1">{{ phoneIP }}:5555</code>
|
||
</div>
|
||
<button @click="testAdbConnection()"
|
||
:disabled="testingAdb"
|
||
class="bg-purple-500 text-white px-4 py-2 rounded hover:bg-purple-600 disabled:opacity-50 transition-colors">
|
||
<span x-show="!testingAdb">Test ADB</span>
|
||
<span x-show="testingAdb">Testing...</span>
|
||
</button>
|
||
<div x-show="adbTestResult" class="mt-3 p-3 rounded text-sm"
|
||
:class="adbTestResult?.success ? 'bg-green-50 text-green-700' : 'bg-red-50 text-red-700'">
|
||
<pre x-text="JSON.stringify(adbTestResult, null, 2)"></pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Test SMS Send -->
|
||
<div class="border rounded-lg p-4 mb-6">
|
||
<h3 class="font-medium mb-3">📨 Test SMS Send</h3>
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<input type="tel" x-model="testPhone"
|
||
placeholder="Phone number (e.g., 7801234567)"
|
||
class="border rounded px-3 py-2">
|
||
<input type="text" x-model="testMessage"
|
||
placeholder="Test message"
|
||
class="border rounded px-3 py-2">
|
||
</div>
|
||
<div class="mt-4 flex gap-2">
|
||
<button @click="sendTestSms('termux')"
|
||
:disabled="!testPhone || sendingTest"
|
||
class="bg-green-500 text-white px-4 py-2 rounded hover:bg-green-600 disabled:opacity-50 transition-colors">
|
||
Send via Termux
|
||
</button>
|
||
<button @click="sendTestSms('adb')"
|
||
:disabled="!testPhone || sendingTest"
|
||
class="bg-purple-500 text-white px-4 py-2 rounded hover:bg-purple-600 disabled:opacity-50 transition-colors">
|
||
Send via ADB
|
||
</button>
|
||
<button @click="sendTestSms('auto')"
|
||
:disabled="!testPhone || sendingTest"
|
||
class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600 disabled:opacity-50 transition-colors">
|
||
Auto (Best Available)
|
||
</button>
|
||
</div>
|
||
<div x-show="testSmsResult" class="mt-3 p-3 rounded text-sm"
|
||
:class="testSmsResult?.success ? 'bg-green-50 text-green-700' : 'bg-red-50 text-red-700'">
|
||
<pre x-text="JSON.stringify(testSmsResult, null, 2)"></pre>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- System Information -->
|
||
<div class="border rounded-lg p-4">
|
||
<h3 class="font-medium mb-3">ℹ️ System Information</h3>
|
||
<div class="grid grid-cols-2 gap-4 text-sm">
|
||
<div>
|
||
<span class="font-medium">Phone IP:</span>
|
||
<span x-text="phoneIP"></span>
|
||
</div>
|
||
<div>
|
||
<span class="font-medium">Preferred Method:</span>
|
||
<span x-text="phoneStatus.prefer_termux ? 'Termux API' : 'ADB'"></span>
|
||
</div>
|
||
<div>
|
||
<span class="font-medium">Last Check:</span>
|
||
<span x-text="formatTime(phoneStatus.last_check)"></span>
|
||
</div>
|
||
<div>
|
||
<span class="font-medium">Active Connection:</span>
|
||
<span x-text="phoneStatus.termux_connected ? 'Termux' : (phoneStatus.adb_connected ? 'ADB' : 'None')"></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Load JavaScript files -->
|
||
<script src="/static/js/dashboard.js"></script>
|
||
<script src="/static/js/lists.js"></script>
|
||
<script src="/static/js/conversations_enhanced.js"></script>
|
||
</body>
|
||
</html>
|