354 lines
14 KiB
Plaintext
354 lines
14 KiB
Plaintext
<% if @gateway.nil? %>
|
|
<div class="rounded-lg bg-red-50 px-4 py-4 ring-1 ring-red-600/10">
|
|
<p class="text-red-800">Error: Gateway not found</p>
|
|
<%= link_to "Back to Gateways", admin_gateways_path, class: "text-red-600 underline" %>
|
|
</div>
|
|
<% else %>
|
|
<div class="space-y-6">
|
|
<!-- Back link -->
|
|
<div class="flex items-center gap-4">
|
|
<%= link_to admin_gateway_path(@gateway), class: "inline-flex items-center gap-2 text-sm font-medium text-gray-600 hover:text-gray-900 transition-colors" do %>
|
|
<i class="fas fa-arrow-left"></i>
|
|
Back to Gateway Details
|
|
<% end %>
|
|
</div>
|
|
|
|
<!-- Page header -->
|
|
<div class="border-b border-gray-200 pb-5">
|
|
<h1 class="text-3xl font-bold leading-tight tracking-tight text-gray-900">Test Gateway: <%= @gateway.name %></h1>
|
|
<p class="mt-2 text-sm text-gray-600">Test connection and send test SMS messages to verify gateway functionality.</p>
|
|
</div>
|
|
|
|
<!-- Gateway Status Card -->
|
|
<div class="rounded-xl bg-white shadow-sm ring-1 ring-gray-900/5 px-6 py-6">
|
|
<div class="flex items-center justify-between mb-4">
|
|
<h3 class="text-lg font-semibold text-gray-900">Gateway Status</h3>
|
|
<button
|
|
onclick="checkConnection()"
|
|
class="inline-flex items-center gap-2 rounded-lg bg-blue-600 px-4 py-2 text-sm font-semibold text-white shadow-sm hover:bg-blue-500 transition-all duration-200">
|
|
<i class="fas fa-sync-alt"></i>
|
|
Refresh Status
|
|
</button>
|
|
</div>
|
|
|
|
<div id="status-container" class="space-y-4">
|
|
<!-- Status will be loaded here -->
|
|
<div class="flex items-center justify-center py-8">
|
|
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Connection Information Card -->
|
|
<div class="rounded-xl bg-white shadow-sm ring-1 ring-gray-900/5 px-6 py-6">
|
|
<h3 class="text-lg font-semibold text-gray-900 mb-4">Connection Information</h3>
|
|
|
|
<dl class="divide-y divide-gray-100">
|
|
<div class="px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
|
|
<dt class="text-sm font-medium text-gray-900">Device ID</dt>
|
|
<dd class="mt-1 text-sm sm:col-span-2 sm:mt-0">
|
|
<code class="rounded bg-gray-100 px-2 py-1 text-xs font-mono text-gray-800"><%= @gateway.device_id %></code>
|
|
</dd>
|
|
</div>
|
|
|
|
<div class="px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
|
|
<dt class="text-sm font-medium text-gray-900">Gateway Name</dt>
|
|
<dd class="mt-1 text-sm text-gray-700 sm:col-span-2 sm:mt-0"><%= @gateway.name %></dd>
|
|
</div>
|
|
|
|
<div class="px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
|
|
<dt class="text-sm font-medium text-gray-900">Priority</dt>
|
|
<dd class="mt-1 text-sm sm:col-span-2 sm:mt-0">
|
|
<span class="inline-flex items-center rounded-full bg-purple-50 px-3 py-1 text-sm font-medium text-purple-700 ring-1 ring-inset ring-purple-700/10">
|
|
<%= @gateway.priority %>
|
|
</span>
|
|
</dd>
|
|
</div>
|
|
|
|
<div class="px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
|
|
<dt class="text-sm font-medium text-gray-900">Active</dt>
|
|
<dd class="mt-1 text-sm sm:col-span-2 sm:mt-0">
|
|
<% if @gateway.active %>
|
|
<span class="inline-flex items-center gap-1 rounded-full bg-green-50 px-2 py-1 text-xs font-medium text-green-700 ring-1 ring-inset ring-green-700/10">
|
|
<i class="fas fa-check"></i> Active
|
|
</span>
|
|
<% else %>
|
|
<span class="inline-flex items-center gap-1 rounded-full bg-red-50 px-2 py-1 text-xs font-medium text-red-700 ring-1 ring-inset ring-red-700/10">
|
|
<i class="fas fa-times"></i> Inactive
|
|
</span>
|
|
<% end %>
|
|
</dd>
|
|
</div>
|
|
</dl>
|
|
</div>
|
|
|
|
<!-- Send Test SMS Card -->
|
|
<div class="rounded-xl bg-white shadow-sm ring-1 ring-gray-900/5 px-6 py-6">
|
|
<h3 class="text-lg font-semibold text-gray-900 mb-4">Send Test SMS</h3>
|
|
<p class="text-sm text-gray-600 mb-6">Send a test SMS message through this gateway to verify it's working correctly.</p>
|
|
|
|
<form id="test-sms-form" class="space-y-6">
|
|
<!-- Phone Number -->
|
|
<div>
|
|
<label for="phone_number" class="block text-sm font-medium text-gray-700">Phone Number</label>
|
|
<div class="mt-1 relative">
|
|
<div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
|
|
<i class="fas fa-phone text-gray-400"></i>
|
|
</div>
|
|
<input
|
|
type="tel"
|
|
id="phone_number"
|
|
name="phone_number"
|
|
class="block w-full pl-10 rounded-lg border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm py-3"
|
|
placeholder="+959123456789"
|
|
required>
|
|
</div>
|
|
<p class="mt-1 text-sm text-gray-500">Enter phone number with country code (e.g., +959123456789)</p>
|
|
</div>
|
|
|
|
<!-- Message Body -->
|
|
<div>
|
|
<label for="message_body" class="block text-sm font-medium text-gray-700">Message</label>
|
|
<div class="mt-1">
|
|
<textarea
|
|
id="message_body"
|
|
name="message_body"
|
|
rows="4"
|
|
class="block w-full rounded-lg border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm py-3"
|
|
placeholder="This is a test message from the admin interface."
|
|
required>This is a test message from MySMSAPio admin interface. Gateway: <%= @gateway.name %></textarea>
|
|
</div>
|
|
<p class="mt-1 text-sm text-gray-500" id="char-count">160 characters remaining</p>
|
|
</div>
|
|
|
|
<!-- Result Display -->
|
|
<div id="sms-result" class="hidden">
|
|
<!-- Success/Error message will be displayed here -->
|
|
</div>
|
|
|
|
<!-- Submit Button -->
|
|
<div class="flex items-center gap-3">
|
|
<button
|
|
type="submit"
|
|
class="inline-flex justify-center items-center gap-2 rounded-lg bg-blue-600 px-6 py-3 text-sm font-semibold text-white shadow-sm hover:bg-blue-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 transition-all duration-200">
|
|
<i class="fas fa-paper-plane"></i>
|
|
<span id="submit-text">Send Test SMS</span>
|
|
</button>
|
|
<button
|
|
type="button"
|
|
onclick="resetForm()"
|
|
class="inline-flex justify-center items-center gap-2 rounded-lg bg-gray-100 px-6 py-3 text-sm font-semibold text-gray-700 hover:bg-gray-200 transition-all duration-200">
|
|
<i class="fas fa-redo"></i>
|
|
Reset Form
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Warning Card -->
|
|
<div class="rounded-lg bg-yellow-50 px-4 py-4 ring-1 ring-yellow-600/10">
|
|
<div class="flex items-start gap-3">
|
|
<div class="flex-shrink-0">
|
|
<i class="fas fa-exclamation-triangle text-yellow-600 text-xl"></i>
|
|
</div>
|
|
<div>
|
|
<h3 class="text-sm font-semibold text-yellow-800">Important Notes</h3>
|
|
<ul class="mt-2 text-sm text-yellow-700 list-disc list-inside space-y-1">
|
|
<li>Test SMS messages will be sent to real phone numbers</li>
|
|
<li>Ensure the gateway is online and connected before testing</li>
|
|
<li>Standard SMS charges may apply to the recipient</li>
|
|
<li>Test messages are marked with metadata for identification</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Check connection on page load
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
checkConnection();
|
|
updateCharCount();
|
|
});
|
|
|
|
// Update character count
|
|
const messageBody = document.getElementById('message_body');
|
|
messageBody.addEventListener('input', updateCharCount);
|
|
|
|
function updateCharCount() {
|
|
const length = messageBody.value.length;
|
|
const remaining = 160 - length;
|
|
const charCount = document.getElementById('char-count');
|
|
|
|
if (remaining < 0) {
|
|
charCount.textContent = `${Math.abs(remaining)} characters over limit (message will be split into ${Math.ceil(length / 160)} parts)`;
|
|
charCount.classList.add('text-red-600');
|
|
charCount.classList.remove('text-gray-500');
|
|
} else {
|
|
charCount.textContent = `${remaining} characters remaining`;
|
|
charCount.classList.remove('text-red-600');
|
|
charCount.classList.add('text-gray-500');
|
|
}
|
|
}
|
|
|
|
// Check gateway connection
|
|
async function checkConnection() {
|
|
const container = document.getElementById('status-container');
|
|
container.innerHTML = '<div class="flex items-center justify-center py-8"><div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div></div>';
|
|
|
|
try {
|
|
const response = await fetch('<%= check_connection_admin_gateway_path(@gateway) %>', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRF-Token': document.querySelector('[name="csrf-token"]').content
|
|
}
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.status === 'success') {
|
|
container.innerHTML = `
|
|
<div class="rounded-lg bg-green-50 px-4 py-4 ring-1 ring-green-600/10">
|
|
<div class="flex items-start gap-3">
|
|
<div class="flex-shrink-0">
|
|
<i class="fas fa-check-circle text-green-600 text-2xl"></i>
|
|
</div>
|
|
<div class="flex-1">
|
|
<h3 class="text-sm font-semibold text-green-800">Gateway is Online</h3>
|
|
<p class="mt-1 text-sm text-green-700">
|
|
Last heartbeat: ${data.time_ago} ago
|
|
</p>
|
|
<p class="mt-1 text-xs text-green-600">
|
|
${data.last_heartbeat}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
} else {
|
|
container.innerHTML = `
|
|
<div class="rounded-lg bg-red-50 px-4 py-4 ring-1 ring-red-600/10">
|
|
<div class="flex items-start gap-3">
|
|
<div class="flex-shrink-0">
|
|
<i class="fas fa-times-circle text-red-600 text-2xl"></i>
|
|
</div>
|
|
<div class="flex-1">
|
|
<h3 class="text-sm font-semibold text-red-800">Gateway is Offline</h3>
|
|
<p class="mt-1 text-sm text-red-700">
|
|
${data.message}
|
|
</p>
|
|
${data.last_heartbeat ? `<p class="mt-1 text-xs text-red-600">Last seen: ${data.time_ago} ago</p>` : '<p class="mt-1 text-xs text-red-600">Never connected</p>'}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
} catch (error) {
|
|
container.innerHTML = `
|
|
<div class="rounded-lg bg-red-50 px-4 py-4 ring-1 ring-red-600/10">
|
|
<div class="flex items-start gap-3">
|
|
<div class="flex-shrink-0">
|
|
<i class="fas fa-exclamation-circle text-red-600 text-2xl"></i>
|
|
</div>
|
|
<div class="flex-1">
|
|
<h3 class="text-sm font-semibold text-red-800">Error Checking Status</h3>
|
|
<p class="mt-1 text-sm text-red-700">${error.message}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
}
|
|
|
|
// Handle form submission
|
|
document.getElementById('test-sms-form').addEventListener('submit', async function(e) {
|
|
e.preventDefault();
|
|
|
|
const submitButton = e.target.querySelector('button[type="submit"]');
|
|
const submitText = document.getElementById('submit-text');
|
|
const resultDiv = document.getElementById('sms-result');
|
|
|
|
// Disable button and show loading
|
|
submitButton.disabled = true;
|
|
submitText.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Sending...';
|
|
|
|
const formData = {
|
|
phone_number: document.getElementById('phone_number').value,
|
|
message_body: document.getElementById('message_body').value
|
|
};
|
|
|
|
try {
|
|
const response = await fetch('<%= send_test_sms_admin_gateway_path(@gateway) %>', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRF-Token': document.querySelector('[name="csrf-token"]').content
|
|
},
|
|
body: JSON.stringify(formData)
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.status === 'success') {
|
|
resultDiv.className = 'rounded-lg bg-green-50 px-4 py-4 ring-1 ring-green-600/10';
|
|
resultDiv.innerHTML = `
|
|
<div class="flex items-start gap-3">
|
|
<div class="flex-shrink-0">
|
|
<i class="fas fa-check-circle text-green-600 text-xl"></i>
|
|
</div>
|
|
<div class="flex-1">
|
|
<h3 class="text-sm font-semibold text-green-800">Test SMS Sent Successfully!</h3>
|
|
<p class="mt-1 text-sm text-green-700">${data.message}</p>
|
|
<div class="mt-2 text-xs text-green-600">
|
|
<p>Message ID: <code class="bg-green-100 px-2 py-1 rounded">${data.message_id}</code></p>
|
|
<p class="mt-1">Status: <span class="font-semibold">${data.sms_status}</span></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
} else {
|
|
resultDiv.className = 'rounded-lg bg-red-50 px-4 py-4 ring-1 ring-red-600/10';
|
|
resultDiv.innerHTML = `
|
|
<div class="flex items-start gap-3">
|
|
<div class="flex-shrink-0">
|
|
<i class="fas fa-times-circle text-red-600 text-xl"></i>
|
|
</div>
|
|
<div class="flex-1">
|
|
<h3 class="text-sm font-semibold text-red-800">Failed to Send Test SMS</h3>
|
|
<p class="mt-1 text-sm text-red-700">${data.message}</p>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
resultDiv.classList.remove('hidden');
|
|
} catch (error) {
|
|
resultDiv.className = 'rounded-lg bg-red-50 px-4 py-4 ring-1 ring-red-600/10';
|
|
resultDiv.innerHTML = `
|
|
<div class="flex items-start gap-3">
|
|
<div class="flex-shrink-0">
|
|
<i class="fas fa-exclamation-circle text-red-600 text-xl"></i>
|
|
</div>
|
|
<div class="flex-1">
|
|
<h3 class="text-sm font-semibold text-red-800">Error</h3>
|
|
<p class="mt-1 text-sm text-red-700">${error.message}</p>
|
|
</div>
|
|
</div>
|
|
`;
|
|
resultDiv.classList.remove('hidden');
|
|
} finally {
|
|
// Re-enable button
|
|
submitButton.disabled = false;
|
|
submitText.innerHTML = '<i class="fas fa-paper-plane"></i> Send Test SMS';
|
|
}
|
|
});
|
|
|
|
function resetForm() {
|
|
document.getElementById('test-sms-form').reset();
|
|
document.getElementById('sms-result').classList.add('hidden');
|
|
updateCharCount();
|
|
}
|
|
</script>
|
|
<% end %>
|