musaliac/nsp-tracker-pro
0
1<!DOCTYPE html>2<html lang="en">3<head>4 <meta charset="UTF-8">5 <meta name="viewport" content="width=device-width, initial-scale=1.0">6 <title>API Explorer | NSP Tracker Pro</title>7 <script src="https://cdn.tailwindcss.com"></script>8 <script src="https://unpkg.com/feather-icons"></script>9 <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>10</head>11<body class="bg-gray-50 min-h-screen">12 <!-- Top Navigation -->13 <nav class="bg-white shadow-sm">14 <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">15 <div class="flex justify-between h-16">16 <div class="flex items-center">17 <div class="flex-shrink-0 flex items-center">18 <i data-feather="code" class="text-indigo-600 h-8 w-8"></i>19 <span class="ml-2 text-xl font-bold text-indigo-600">NSP Tracker Pro - API Explorer</span>20 </div>21 <div class="hidden sm:ml-6 sm:flex sm:space-x-8">22 <a href="index.html" class="border-transparent text-gray-500 hover:text-gray-700 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium">Back to Dashboard</a>23 </div>24 </div>25 </div>26 </div>27 </nav>28 <!-- Main Content -->29 <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">30 <div id="loading" class="fixed inset-0 flex items-center justify-center bg-white bg-opacity-90 z-50">31 <div class="animate-spin rounded-full h-32 w-32 border-t-2 border-b-2 border-indigo-500"></div>32 </div>33<div class="bg-white rounded-lg shadow-sm p-6">34 <h2 class="text-2xl font-bold text-gray-800 mb-6">API Explorer</h2>35 36 <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">37 <!-- API Endpoint Selection -->38 <div class="border border-gray-200 rounded-lg p-4">39 <h3 class="text-lg font-medium text-gray-900 mb-4">Available Endpoints</h3>40 <div class="space-y-2">41 <select id="api-endpoint" class="w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">42 <option value="">Select an endpoint</option>43 <option value="/api/projects">/api/projects</option>44 <option value="/api/sectors">/api/sectors</option>45 <option value="/api/officers">/api/officers</option>46 <option value="/api/recommendations">/api/recommendations</option>47 </select>48 </div>49 <div class="mt-4">50 <h4 class="text-sm font-medium text-gray-700 mb-2">HTTP Method</h4>51 <div class="flex space-x-2">52 <button class="api-method-btn bg-green-100 text-green-800 px-3 py-1 rounded" data-method="GET">GET</button>53 <button class="api-method-btn bg-blue-100 text-blue-800 px-3 py-1 rounded" data-method="POST">POST</button>54 <button class="api-method-btn bg-yellow-100 text-yellow-800 px-3 py-1 rounded" data-method="PUT">PUT</button>55 <button class="api-method-btn bg-red-100 text-red-800 px-3 py-1 rounded" data-method="DELETE">DELETE</button>56 </div>57 </div>58 </div>59 60 <!-- Request Parameters -->61 <div class="border border-gray-200 rounded-lg p-4">62 <h3 class="text-lg font-medium text-gray-900 mb-4">Request Parameters</h3>63 <div id="params-container">64 <div class="flex items-center mb-2">65 <input type="text" placeholder="Key" class="param-key w-1/2 rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">66 <span class="mx-2">=</span>67 <input type="text" placeholder="Value" class="param-value w-1/2 rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">68 <button class="remove-param ml-2 text-red-500 hover:text-red-700">69 <i data-feather="x"></i>70 </button>71 </div>72 </div>73 <button id="add-param" class="mt-2 text-sm text-indigo-600 hover:text-indigo-800">+ Add Parameter</button>74 </div>75 76 <!-- Request Body -->77 <div class="border border-gray-200 rounded-lg p-4">78 <h3 class="text-lg font-medium text-gray-900 mb-4">Request Body</h3>79 <textarea id="request-body" class="w-full h-32 p-2 border border-gray-300 rounded-md focus:ring-indigo-500 focus:border-indigo-500" placeholder='{"key": "value"}'></textarea>80 </div>81 </div>82 83 <div class="flex justify-center mb-6">84 <button id="send-request" class="bg-indigo-600 text-white py-2 px-6 rounded-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">85 Send Request86 </button>87 </div>88 89 <!-- Response Section -->90 <div class="border border-gray-200 rounded-lg p-4">91 <div class="flex justify-between items-center mb-4">92 <h3 class="text-lg font-medium text-gray-900">Response</h3>93 <div class="flex items-center">94 <span id="response-status" class="px-2 py-1 rounded text-sm font-medium mr-2">Status: -</span>95 <span id="response-time" class="px-2 py-1 rounded text-sm font-medium">Time: -</span>96 </div>97 </div>98 <pre id="response-data" class="bg-gray-50 p-4 rounded-md overflow-x-auto text-sm">Response will appear here...</pre>99 </div>100 </div>101 </div>102 <script>103 document.addEventListener('DOMContentLoaded', function() {104 // Hide loading spinner when page is fully loaded105 setTimeout(() => {106 document.getElementById('loading').style.display = 'none';107 }, 1500);108if (typeof feather !== 'undefined') {109 feather.replace();110 }111// Initialize variables112 let selectedMethod = 'GET';113 114 // Method selection115 document.querySelectorAll('.api-method-btn').forEach(btn => {116 btn.addEventListener('click', function() {117 document.querySelectorAll('.api-method-btn').forEach(b => b.classList.remove('bg-indigo-600', 'text-white'));118 this.classList.add('bg-indigo-600', 'text-white');119 selectedMethod = this.dataset.method;120 });121 });122 123 // Add parameter row124 document.getElementById('add-param').addEventListener('click', function() {125 const paramRow = document.createElement('div');126 paramRow.className = 'flex items-center mb-2';127 paramRow.innerHTML = `128 <input type="text" placeholder="Key" class="param-key w-1/2 rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">129 <span class="mx-2">=</span>130 <input type="text" placeholder="Value" class="param-value w-1/2 rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">131 <button class="remove-param ml-2 text-red-500 hover:text-red-700">132 <i data-feather="x"></i>133 </button>134 `;135 document.getElementById('params-container').appendChild(paramRow);136 feather.replace();137 138 // Add remove functionality139 paramRow.querySelector('.remove-param').addEventListener('click', function() {140 paramRow.remove();141 });142 });143 144 // Send request145 document.getElementById('send-request').addEventListener('click', async function() {146 const endpoint = document.getElementById('api-endpoint').value;147 if (!endpoint) {148 alert('Please select an endpoint');149 return;150 }151 152 // Prepare URL with query parameters153 let url = endpoint;154 const params = [];155 document.querySelectorAll('#params-container > div').forEach(row => {156 const key = row.querySelector('.param-key').value;157 const value = row.querySelector('.param-value').value;158 if (key && value) {159 params.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);160 }161 });162 163 if (params.length > 0) {164 url += `?${params.join('&')}`;165 }166 167 // Prepare request body168 let requestBody = {};169 try {170 const bodyText = document.getElementById('request-body').value;171 if (bodyText) {172 requestBody = JSON.parse(bodyText);173 }174 } catch (e) {175 alert('Invalid JSON in request body');176 return;177 }178 179 // Show loading180 const sendBtn = this;181 sendBtn.disabled = true;182 sendBtn.textContent = 'Sending...';183 184 const startTime = Date.now();185 186 try {187 let response;188 switch (selectedMethod) {189 case 'GET':190 response = await axios.get(url);191 break;192 case 'POST':193 response = await axios.post(url, requestBody);194 break;195 case 'PUT':196 response = await axios.put(url, requestBody);197 break;198 case 'DELETE':199 response = await axios.delete(url);200 break;201 }202 203 const endTime = Date.now();204 const duration = endTime - startTime;205 206 // Display response207 document.getElementById('response-status').textContent = `Status: ${response.status}`;208 document.getElementById('response-time').textContent = `Time: ${duration}ms`;209 document.getElementById('response-data').textContent = JSON.stringify(response.data, null, 2);210 211 } catch (error) {212 document.getElementById('response-status').textContent = `Error: ${error.message}`;213 document.getElementById('response-data').textContent = error.response ? JSON.stringify(error.response.data, null, 2) : error.message;214 } finally {215 sendBtn.disabled = false;216 sendBtn.textContent = 'Send Request';217 }218 });219 });220 </script>221</body>222</html>