add username to list_providers
This commit is contained in:
1 parent
9e4c6571cf
commit
9dc05a72b5
5 files changed
+9
-1
No files matched your search
@@ -1,146 +0,0 @@
|
||||
<?php
|
||||
// add_providers.php
|
||||
// Simple page that displays a form to create a new fitness provider.
|
||||
// It uses the same Flask API as list_providers.php (http://172.25.1.105:5000).
|
||||
// When the form is submitted, it POSTs JSON to /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 rate options setting
|
||||
$rateOptionsSetting = callApi('GET', '/settings/rate_options');
|
||||
$rateOptions = [];
|
||||
if ($rateOptionsSetting && isset($rateOptionsSetting['value'])) {
|
||||
$rateOptions = explode(',', $rateOptionsSetting['value']);
|
||||
/*
|
||||
$parsed = json_decode($rateOptionsSetting['value'], true);
|
||||
if (is_array($parsed)) {
|
||||
$rateOptions = $parsed;
|
||||
}
|
||||
echo "Rate options:".$rateOptionsSetting['value'];
|
||||
*/
|
||||
}
|
||||
|
||||
// Update form handling to process selected rates
|
||||
$selectedRateKeys = $_POST['rate_selected'] ?? [];
|
||||
$ratesArray = [];
|
||||
foreach ($selectedRateKeys as $key) {
|
||||
$value = $_POST['rate_value'][$key] ?? '0';
|
||||
$ratesArray[] = [$key => $value];
|
||||
}
|
||||
$created = null;
|
||||
$errors = [];
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// Collect form data
|
||||
$name = trim($_POST['name'] ?? '');
|
||||
$phone = trim($_POST['phone'] ?? '');
|
||||
$age = trim($_POST['age'] ?? '');
|
||||
$photo = trim($_POST['photo'] ?? '');
|
||||
$private = isset($_POST['private']) ? true : false;
|
||||
|
||||
// Basic validation
|
||||
if ($name === '') { $errors[] = 'Name is required.'; }
|
||||
if ($age !== '' && !is_numeric($age)) { $errors[] = 'Age must be a number.'; }
|
||||
// Rates now processed from checkboxes
|
||||
if (empty($errors)) {
|
||||
$body = [
|
||||
'name' => $name,
|
||||
'phone' => $phone,
|
||||
'age' => $age === '' ? null : (int)$age,
|
||||
'photo' => $photo === '' ? null : $photo,
|
||||
'rates' => empty($ratesArray) ? null : $ratesArray,
|
||||
'private'=> $private
|
||||
];
|
||||
$result = callApi('POST', '/providers', $body);
|
||||
if ($result) {
|
||||
// On successful creation, redirect to the list providers page
|
||||
header('Location: list_providers.php');
|
||||
exit;
|
||||
} else {
|
||||
$errors[] = 'Failed to create provider. API error.';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Add Provider</title>
|
||||
<link rel="stylesheet" href="https://cosmostat.matt-cloud.com/src/styles.css">
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; margin: 2rem; }
|
||||
form { max-width: 600px; }
|
||||
label { display: block; margin-top: 1rem; }
|
||||
input[type=text], input[type=number] { width: 100%; padding: 0.5rem; }
|
||||
.error { color: red; }
|
||||
.success { color: green; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="card">
|
||||
<h1>Add New Provider</h1>
|
||||
<?php if ($errors): ?>
|
||||
<div class="error">
|
||||
<?php foreach ($errors as $e): ?>
|
||||
<p><?=htmlspecialchars($e)?></p>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<form method="post" action="">
|
||||
<?php
|
||||
// echo $rateOptions[0];
|
||||
|
||||
?>
|
||||
<label>Name:<br><input type="text" name="name" value="<?=htmlspecialchars($_POST['name'] ?? '')?>" required></label>
|
||||
<label>Phone:<br><input type="text" name="phone" value="<?=htmlspecialchars($_POST['phone'] ?? '')?>"></label>
|
||||
<label>Age:<br><input type="number" name="age" value="<?=htmlspecialchars($_POST['age'] ?? '')?>"></label>
|
||||
<label>Photo URL:<br><input type="text" name="photo" value="<?=htmlspecialchars($_POST['photo'] ?? '')?>"></label>
|
||||
<?php if (!empty($rateOptions)) : ?>
|
||||
<label>Rate Options:<br>
|
||||
<?php
|
||||
foreach ($rateOptions as $option) :
|
||||
// echo $option;
|
||||
$key = $option;
|
||||
$value = 0;
|
||||
?>
|
||||
<input type="checkbox" name="rate_selected[]" value="<?=htmlspecialchars($key)?>"
|
||||
<?php if (in_array($key, $selectedRateKeys)) echo 'checked'; ?>>
|
||||
<?=htmlspecialchars($key)?>:
|
||||
<input type="number" name="rate_value[<?=htmlspecialchars($key)?>]" value="<?=htmlspecialchars($ratesArray[$key] ?? $value)?>" style="width:60px;">
|
||||
<br>
|
||||
<?php endforeach; ?>
|
||||
</label>
|
||||
<?php endif; ?>
|
||||
<label><input type="checkbox" name="private" <?=isset($_POST['private'])?'checked':''?>> Private</label><br>
|
||||
<button type="submit" class="btn">Create Provider</button>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,321 +0,0 @@
|
||||
<?php
|
||||
// edit_provider.php
|
||||
// Edit an existing fitness provider.
|
||||
// Handles rate options similar to add_provider.php.
|
||||
|
||||
require_once __DIR__ . '/../fitness-config.php';
|
||||
|
||||
$provider_id = (int)($_GET['id'] ?? 0);
|
||||
if ($provider_id <= 0) {
|
||||
echo '<h1>Error</h1><p>Provider ID is missing or invalid.</p>';
|
||||
exit;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Helper: Call the API (GET/PUT) – returns decoded JSON or null
|
||||
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;
|
||||
}
|
||||
return json_decode($response, true);
|
||||
}
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Helper: upload photos (multipart)
|
||||
// Returns the JSON response from the API (or null on error)
|
||||
function uploadPhotosApi(int $provider_id, array $files): ?array
|
||||
{
|
||||
$url = BASE_API_URL . "/api/providers/{$provider_id}/photos";
|
||||
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
|
||||
// Build multipart array
|
||||
$multipart = [];
|
||||
foreach ($files['tmp_name'] as $i => $tmp) {
|
||||
if ($files['name'][$i] === '') continue;
|
||||
$multipart[] = [
|
||||
'name' => 'photos',
|
||||
'contents' => fopen($tmp, 'r'),
|
||||
'filename' => $files['name'][$i]
|
||||
];
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $multipart);
|
||||
// Let PHP set the correct Content‑Type boundary
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: multipart/form-data']);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
return ($httpCode < 400) ? json_decode($response, true) : null;
|
||||
}
|
||||
|
||||
// Get provider details
|
||||
$provider = callApi('GET', '/providers?id=' . $provider_id);
|
||||
if (!$provider) {
|
||||
echo '<h1>Error</h1><p>Could not load provider details.</p>';
|
||||
exit;
|
||||
}
|
||||
if (is_array($provider) && count($provider) > 0 && isset($provider[0])) {
|
||||
$provider = $provider[0];
|
||||
}
|
||||
|
||||
// Get rate‑option list (comma‑separated string → array)
|
||||
$rateSetting = callApi('GET', '/settings/rate_options');
|
||||
$rateOptions = [];
|
||||
if ($rateSetting && isset($rateSetting['value'])) {
|
||||
$rateOptions = array_map('trim', explode(',', $rateSetting['value']));
|
||||
}
|
||||
|
||||
// Decode the API’s rate string (JSON → array of arrays)
|
||||
$ratesData = $provider['rates'] ?? '[]';
|
||||
$decoded = [];
|
||||
if (is_string($ratesData)) {
|
||||
$decoded = json_decode($ratesData, true);
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
$decoded = []; // bad JSON – treat as empty
|
||||
}
|
||||
} elseif (is_array($ratesData)) {
|
||||
$decoded = $ratesData; // already an array – legacy path
|
||||
}
|
||||
|
||||
// Build two helper arrays
|
||||
$selectedRateKeys = []; // lowercase keys of selected rates
|
||||
$ratesAssoc = []; // key → value
|
||||
|
||||
foreach ($decoded as $entry) {
|
||||
if (!is_array($entry)) continue;
|
||||
foreach ($entry as $k => $v) {
|
||||
$kTrim = strtolower(trim($k));
|
||||
$selectedRateKeys[] = $kTrim;
|
||||
$ratesAssoc[$kTrim] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
// Find orphan rates (present in $decoded but not in $rateOptions)
|
||||
$orphanRates = [];
|
||||
$orphanKeys = [];
|
||||
foreach ($decoded as $entry) {
|
||||
if (!is_array($entry)) continue;
|
||||
foreach ($entry as $k => $v) {
|
||||
$kTrim = strtolower(trim($k));
|
||||
if (!in_array($kTrim, array_map('strtolower', $rateOptions))) {
|
||||
$orphanRates[$kTrim] = $v;
|
||||
$orphanKeys[] = $kTrim;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Handle form POST
|
||||
/*
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// Base payload
|
||||
$payload = [
|
||||
'name' => $_POST['name'] ?? '',
|
||||
'age' => (int)($_POST['age'] ?? 0),
|
||||
'photo' => $_POST['photo'] ?? '',
|
||||
'phone' => $_POST['phone'] ?? '',
|
||||
// Convert checkbox to boolean
|
||||
'private' => isset($_POST['private']),
|
||||
];
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Rebuild the rates array from the form.
|
||||
$finalRates = [];
|
||||
|
||||
// Add the selected valid rate options (value may be changed by the user)
|
||||
$selectedRateKeysRaw = $_POST['rate_selected'] ?? [];
|
||||
foreach ($selectedRateKeysRaw as $opt) { // $opt is the original rate name
|
||||
$newVal = $_POST['rate_value'][$opt] ?? '0'; // the updated value
|
||||
$finalRates[] = [$opt => $newVal];
|
||||
}
|
||||
|
||||
// Add orphan rates that the user chose **not** to delete
|
||||
$orphanDeleteSet = array_flip(array_map('strtolower', $_POST['orphan_delete'] ?? []));
|
||||
foreach ($orphanRates as $key => $value) { // $key is already lower‑cased
|
||||
if (!isset($orphanDeleteSet[strtolower($key)])) {
|
||||
$finalRates[] = [$key => $value];
|
||||
}
|
||||
}
|
||||
|
||||
// Encode the new array as JSON
|
||||
//$payload['rates'] = !empty($finalRates) ? json_encode($finalRates) : null;
|
||||
$payload['rates'] = !empty($finalRates) ? $finalRates : null;
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Submit the updated provider
|
||||
$result = callApi('PUT', '/providers/' . $provider_id, $payload);
|
||||
if ($result) {
|
||||
header('Location: list_providers.php');
|
||||
exit;
|
||||
}
|
||||
echo '<h1>Error</h1><p>Failed to update provider.</p>';
|
||||
}*/
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
|
||||
/* -------- 1. Build the base payload -------- */
|
||||
$payload = [
|
||||
'name' => $_POST['name'] ?? '',
|
||||
'age' => (int)($_POST['age'] ?? 0),
|
||||
'photo' => $_POST['photo'] ?? '',
|
||||
'phone' => $_POST['phone'] ?? '',
|
||||
'private' => isset($_POST['private']),
|
||||
];
|
||||
|
||||
/* -------- 2. Re‑build the rates array -------- */
|
||||
$finalRates = [];
|
||||
$selectedRateKeysRaw = $_POST['rate_selected'] ?? [];
|
||||
foreach ($selectedRateKeysRaw as $opt) {
|
||||
$newVal = $_POST['rate_value'][$opt] ?? '0';
|
||||
$finalRates[] = [$opt => $newVal];
|
||||
}
|
||||
// orphan rates that the user chose *not* to delete
|
||||
$orphanDeleteSet = array_flip(array_map('strtolower', $_POST['orphan_delete'] ?? []));
|
||||
foreach ($orphanRates as $key => $value) {
|
||||
if (!isset($orphanDeleteSet[$key])) {
|
||||
$finalRates[] = [$key => $value];
|
||||
}
|
||||
}
|
||||
$payload['rates'] = !empty($finalRates) ? $finalRates : null;
|
||||
|
||||
/* -------- 3. Call the API to update provider -------- */
|
||||
$result = callApi('PUT', "/providers/{$provider_id}", $payload);
|
||||
if (!$result) {
|
||||
echo '<h1>Error</h1><p>Failed to update provider.</p>';
|
||||
exit;
|
||||
}
|
||||
|
||||
/* -------- 4. Upload photos if any were chosen -------- */
|
||||
if (!empty($_FILES['photos']['name'][0])) {
|
||||
$uploadRes = uploadPhotosApi($provider_id, $_FILES['photos']);
|
||||
if ($uploadRes && isset($uploadRes['photos'])) {
|
||||
// Update main photo if the user selected one
|
||||
$selectedMain = $_POST['main_photo'] ?? null;
|
||||
if ($selectedMain) {
|
||||
callApi('PUT', "/api/providers/{$provider_id}/main_photo",
|
||||
['url' => $selectedMain]);
|
||||
}
|
||||
} else {
|
||||
// Photo upload failed – you may want to show a message
|
||||
echo '<p style="color:red;">Photo upload failed.</p>';
|
||||
}
|
||||
}
|
||||
|
||||
/* -------- 5. Set the chosen main photo from the new uploads -------- */
|
||||
// If a main photo was chosen from the new uploads, send it
|
||||
if (!empty($_POST['main_photo'])) {
|
||||
callApi('PUT', "/api/providers/{$provider_id}/main_photo",
|
||||
['url' => $_POST['main_photo']]);
|
||||
}
|
||||
|
||||
/* -------- 6. Redirect back to the list -------- */
|
||||
header('Location: list_providers.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Edit Provider</title>
|
||||
<link rel="stylesheet" href="https://cosmostat.matt-cloud.com/src/styles.css">
|
||||
<style>
|
||||
body {font-family: Arial, sans-serif; margin: 20px;}
|
||||
form {max-width: 600px;}
|
||||
label {display: block; margin-top: 10px;}
|
||||
input[type=text], input[type=number], textarea {width: 100%; padding: 8px; box-sizing: border-box;}
|
||||
input[type=checkbox] {margin-top: 5px;}
|
||||
button {margin-top: 15px; padding: 10px 15px;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="card">
|
||||
<h1>Edit Provider</h1>
|
||||
<form method="post" id="editForm">
|
||||
<!-- Basic fields -->
|
||||
|
||||
<?php if (!empty($provider['photos'])): ?>
|
||||
<fieldset>
|
||||
<legend>Existing Photos</legend>
|
||||
<div style="display:flex; flex-wrap:wrap;">
|
||||
<?php foreach ($provider['photos'] as $idx => $url): ?>
|
||||
<div style="margin:4px; text-align:center;">
|
||||
<img src="<?= htmlspecialchars($url) ?>" style="max-width:100px; height:auto;">
|
||||
<br>
|
||||
<input type="radio" name="main_photo" value="<?= htmlspecialchars($url) ?>"
|
||||
<?= ($provider['main_photo'] ?? '') === $url ? 'checked' : '' ?>>
|
||||
<label>Thumbnail</label>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</fieldset>
|
||||
<?php endif; ?>
|
||||
<fieldset>
|
||||
<legend>Upload New Photos</legend>
|
||||
<label>
|
||||
<input type="file" name="photos[]" multiple accept="image/*">
|
||||
</label>
|
||||
<p>You can select several images at once.</p>
|
||||
</fieldset>
|
||||
<label>Name: <input type="text" name="name" required value="<?php echo htmlspecialchars($provider['name'] ?? ''); ?>"></label>
|
||||
<label>Age: <input type="number" name="age" required value="<?php echo htmlspecialchars($provider['age'] ?? ''); ?>"></label>
|
||||
<label>Photo URL: <input type="text" name="photo" value="<?php echo htmlspecialchars($provider['photo'] ?? ''); ?>"></label>
|
||||
<label>Phone: <input type="text" name="phone" required value="<?php echo htmlspecialchars($provider['phone'] ?? ''); ?>"></label>
|
||||
|
||||
<!-- Rate options -->
|
||||
<?php if (!empty($rateOptions)) : ?>
|
||||
<label>Rate Options:<br>
|
||||
<?php foreach ($rateOptions as $opt) :
|
||||
$key = strtolower(trim($opt));
|
||||
$value = $ratesAssoc[$key] ?? 0;
|
||||
?>
|
||||
<input type="checkbox" name="rate_selected[]" value="<?php echo htmlspecialchars($opt); ?>"
|
||||
<?php if (in_array($key, $selectedRateKeys)) echo 'checked'; ?> >
|
||||
<?php echo htmlspecialchars($opt); ?>:
|
||||
<input type="number" name="rate_value[<?php echo htmlspecialchars($opt); ?>]" value="<?php echo htmlspecialchars($value); ?>" style="width:60px;">
|
||||
<br>
|
||||
<?php endforeach; ?>
|
||||
</label>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Orphan rates – show value and a Delete checkbox -->
|
||||
<?php if (!empty($orphanRates)) : ?>
|
||||
<label>Orphan Rates:<br>
|
||||
<?php foreach ($orphanRates as $key => $value) : ?>
|
||||
<?php echo htmlspecialchars($key); ?>:
|
||||
<input type="number" value="<?php echo htmlspecialchars($value); ?>" style="width:60px;" disabled>
|
||||
<input type="checkbox" name="orphan_delete[]" value="<?php echo htmlspecialchars($key); ?>" style="margin-left:10px;"> Delete
|
||||
<br>
|
||||
<?php endforeach; ?>
|
||||
</label>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Private flag -->
|
||||
<label><input type="checkbox" name="private" <?php echo (!empty($provider['private'])) ? 'checked' : ''; ?>> Private</label><br>
|
||||
|
||||
<!-- Buttons -->
|
||||
<button type="submit">Save</button>
|
||||
<button type="button" onclick="window.location.href='list_providers.php'">Cancel</button>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,179 +0,0 @@
|
||||
<?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>
|
||||
<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>
|
||||
@@ -1,130 +0,0 @@
|
||||
<?php
|
||||
// settings.php
|
||||
// This page displays all settings stored in the Flask API and allows editing them.
|
||||
// It supports updating existing settings via PUT and creating a single new setting via POST.
|
||||
// The design follows the pattern used in list_providers.php.
|
||||
|
||||
// file settings
|
||||
require_once __DIR__ . '/../fitness-config.php';
|
||||
|
||||
// --- Helper to call the Flask API -------------------------------------------
|
||||
function callApi(string $method, string $path, $body = null)
|
||||
{
|
||||
// API base URL – update if your API is hosted elsewhere
|
||||
$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; // Could also throw an exception if preferred
|
||||
}
|
||||
|
||||
return json_decode($response, true);
|
||||
}
|
||||
|
||||
$messages = [];
|
||||
|
||||
// Handle form submission – update existing settings and/or create a new one
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// Update existing settings
|
||||
if (isset($_POST['orig_name'], $_POST['value'])) {
|
||||
foreach ($_POST['orig_name'] as $idx => $orig) {
|
||||
$newVal = $_POST['value'][$idx] ?? '';
|
||||
if ($newVal === '') continue; // skip empty values
|
||||
$res = callApi('PUT', '/settings/' . urlencode($orig), ['value' => $newVal]);
|
||||
if ($res === null) {
|
||||
$messages[] = "Failed to update setting '" . htmlspecialchars($orig) . "'.";
|
||||
} else {
|
||||
$messages[] = "Updated setting '" . htmlspecialchars($orig) . "'.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a single new setting
|
||||
$newName = $_POST['new_name'] ?? '';
|
||||
$newValue = $_POST['new_value'] ?? '';
|
||||
if ($newName !== '' && $newValue !== '') {
|
||||
$res = callApi('POST', '/settings', ['name' => $newName, 'value' => $newValue]);
|
||||
if ($res === null) {
|
||||
$messages[] = "Failed to create new setting '" . htmlspecialchars($newName) . "'.";
|
||||
} else {
|
||||
$messages[] = "Created new setting '" . htmlspecialchars($newName) . "'.";
|
||||
}
|
||||
} elseif ($newName !== '' || $newValue !== '') {
|
||||
$messages[] = "Both name and value are required to create a new setting.";
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve current settings to display
|
||||
$settings = callApi('GET', '/settings');
|
||||
$settings = $settings ?? [];
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Settings</title>
|
||||
<link rel="stylesheet" href="https://cosmostat.matt-cloud.com/src/styles.css">
|
||||
<style>
|
||||
body {font-family: Arial, sans-serif; margin: 2rem;}
|
||||
.messages {margin-bottom: 1rem;}
|
||||
.messages .error {color: red;}
|
||||
.messages .success {color: green;}
|
||||
table {width: 100%; border-collapse: collapse;}
|
||||
input[type=text] {width: 95%;}
|
||||
.btn {padding: 6px 12px; margin-top: 10px;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="card">
|
||||
<h1>Settings</h1>
|
||||
<?php if (!empty($messages)) : ?>
|
||||
<div class="messages">
|
||||
<?php foreach ($messages as $msg) : ?>
|
||||
<div class="success"><?= htmlspecialchars($msg) ?></div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<form method="post">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (!empty($settings)) : ?>
|
||||
<?php foreach ($settings as $s) : ?>
|
||||
<tr>
|
||||
<td><?= htmlspecialchars($s['name']) ?></td>
|
||||
<td>
|
||||
<input type="text" name="value[]" value="<?= htmlspecialchars($s['value']) ?>" />
|
||||
<input type="hidden" name="orig_name[]" value="<?= htmlspecialchars($s['name']) ?>" />
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
<tr>
|
||||
<td><input type="text" name="new_name" placeholder="New setting name" /></td>
|
||||
<td><input type="text" name="new_value" placeholder="New setting value" /></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<input type="submit" value="Save Settings" class="btn" />
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
Reference in new issue
Block a user