186 lines
5.2 KiB
PHP
186 lines
5.2 KiB
PHP
<?php
|
|
// providers.php
|
|
// Simple page that pulls provider data via the Flask API.
|
|
// It expects the Flask API to be reachable at http://127.0.0.1:5000
|
|
// The API endpoint for providers is /providers.
|
|
|
|
// file settings
|
|
require_once __DIR__ . '/../fitness-config.php';
|
|
// --- Helper to call the API -------------------------------------------
|
|
function callApi(string $method, string $path, $body = null)
|
|
{
|
|
$url = BASE_API_URL . $path;
|
|
$ch = curl_init($url);
|
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
|
|
|
|
if ($body !== null) {
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
|
|
}
|
|
|
|
$response = curl_exec($ch);
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
|
|
if ($httpCode >= 400) {
|
|
return null; // or throw an exception
|
|
}
|
|
|
|
return json_decode($response, true);
|
|
}
|
|
|
|
// --- Fetch all providers -----------------------------------------------
|
|
$providers = callApi('GET', '/providers');
|
|
$providers = $providers ?? [];
|
|
|
|
// Normalize rates for display
|
|
foreach ($providers as &$p) {
|
|
$rates = $p['rates'] ?? '';
|
|
if (is_string($rates)) {
|
|
$decoded = json_decode($rates, true);
|
|
if (json_last_error() !== JSON_ERROR_NONE) {
|
|
// try stripping slashes
|
|
$unescaped = stripslashes($rates);
|
|
$decoded = json_decode($unescaped, true);
|
|
}
|
|
if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
|
|
$p['rates'] = $decoded;
|
|
} else {
|
|
// leave as is
|
|
$p['rates'] = $rates;
|
|
}
|
|
} elseif (is_array($rates)) {
|
|
$p['rates'] = $rates;
|
|
}
|
|
}
|
|
unset($p);
|
|
// -----------------------------------------------------------------------
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>Providers</title>
|
|
<link rel="stylesheet" href="https://cosmostat.matt-cloud.com/src/styles.css">
|
|
<style>
|
|
body { font-family: Arial, sans-serif; margin: 2rem; }
|
|
#search { margin-bottom: 1rem; padding: 0.5rem; width: 300px; }
|
|
table { width: 100%; border-collapse: collapse; }
|
|
img { max-width: 60px; height: auto; }
|
|
.header-container { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="card">
|
|
<div class="header-container">
|
|
<h1>Providers</h1>
|
|
<a href="add_provider.php" class="btn">Add Provider</a>
|
|
</div>
|
|
<?php
|
|
if (isset($_SESSION['authenticated'])){
|
|
echo "<p>";
|
|
echo "Welcome " . htmlspecialchars($_SESSION['name']);
|
|
}
|
|
?>
|
|
<input type="text" id="search" placeholder="Search providers...">
|
|
<table id="providers-table">
|
|
<thead>
|
|
<tr>
|
|
<th data-field="id">ID</th>
|
|
<th data-field="name">Name</th>
|
|
<th data-field="phone">Phone</th>
|
|
<th data-field="age">Age</th>
|
|
<th data-field="photo">Photo</th>
|
|
<th data-field="rates">Rates</th>
|
|
<th data-field="private">Private</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody></tbody>
|
|
</table>
|
|
</div>
|
|
<script>
|
|
const providers = <?php echo json_encode($providers); ?>;
|
|
let currentSort = { field: null, asc: true };
|
|
|
|
// Helper to format rates into readable lines
|
|
function formatRates(rates) {
|
|
if (!rates) return '';
|
|
if (Array.isArray(rates)) {
|
|
return rates.map(r => {
|
|
const key = Object.keys(r)[0];
|
|
const val = r[key];
|
|
return `${key}: ${val}`;
|
|
}).join('<br>');
|
|
}
|
|
return rates;
|
|
}
|
|
|
|
function renderTable(data) {
|
|
const tbody = document.querySelector('#providers-table tbody');
|
|
tbody.innerHTML = '';
|
|
data.forEach(p => {
|
|
const tr = document.createElement('tr');
|
|
tr.innerHTML = `
|
|
<td>${p.id}</td>
|
|
<td>${p.name}</td>
|
|
<td>${p.phone || ''}</td>
|
|
<td>${p.age || ''}</td>
|
|
<td>${p.photo ? `<img src="${p.photo}" alt="Photo">` : ''}</td>
|
|
<td>${formatRates(p.rates)}</td>
|
|
<td>${p.private ? 'Yes' : 'No'}</td>
|
|
<td><a href="edit_provider.php?id=${p.id}">Edit</a></td>
|
|
`;
|
|
tbody.appendChild(tr);
|
|
});
|
|
}
|
|
|
|
function sortData(field) {
|
|
if (currentSort.field === field) {
|
|
currentSort.asc = !currentSort.asc;
|
|
} else {
|
|
currentSort.field = field;
|
|
currentSort.asc = true;
|
|
}
|
|
const sorted = providers.slice().sort((a, b) => {
|
|
let aVal = a[field];
|
|
let bVal = b[field];
|
|
if (['id', 'age', 'private'].includes(field)) {
|
|
aVal = Number(aVal);
|
|
bVal = Number(bVal);
|
|
} else {
|
|
aVal = (aVal || '').toString().toLowerCase();
|
|
bVal = (bVal || '').toString().toLowerCase();
|
|
}
|
|
if (aVal < bVal) return currentSort.asc ? -1 : 1;
|
|
if (aVal > bVal) return currentSort.asc ? 1 : -1;
|
|
return 0;
|
|
});
|
|
renderTable(sorted);
|
|
}
|
|
|
|
renderTable(providers);
|
|
|
|
document.querySelectorAll('#providers-table th').forEach(th => {
|
|
th.addEventListener('click', () => {
|
|
const field = th.getAttribute('data-field');
|
|
if (!field) return;
|
|
sortData(field);
|
|
});
|
|
});
|
|
|
|
document.getElementById('search').addEventListener('input', e => {
|
|
const query = e.target.value.toLowerCase();
|
|
const filtered = providers.filter(p => {
|
|
return Object.values(p).some(v => {
|
|
if (!v) return false;
|
|
return String(v).toLowerCase().includes(query);
|
|
});
|
|
});
|
|
renderTable(filtered);
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|