Version stable, aprelic, connexion CFRS et autres corrections

This commit is contained in:
Oleg Barykin committed 2026-04-17 20:18:11 +02:00
1 parent 865de8a976
commit e9d0010451
62 files changed
+17483 -7256

No files matched your search

+192 -122
View File
@@ -1,17 +1,23 @@
<?php
declare (strict_types = 1);
// /public/praticien/disponibilites_date.php
require_once __DIR__ . '/../includes/init_praticien.php';
$praticien_id = (int) ($_SESSION['reference_id'] ?? 0);
if ($praticien_id <= 0) {http_response_code(403);exit('Forbidden');}
// Durée RDV praticien (garde-fou strict)
$praticien_id = (int) ($_SESSION['reference_id'] ?? 0);
if ($praticien_id <= 0) {
http_response_code(403);
exit('Forbidden');
}
// Durée RDV praticien
$stmt = $pdo->prepare("SELECT duree_rdv FROM praticien WHERE id = ?");
$stmt->execute([$praticien_id]);
$duree_minutes = (int) ($stmt->fetchColumn() ?: 0);
if ($duree_minutes <= 0) {
$duree_minutes = 30;
}
// ---- Ajouter une dispo ponctuelle (POST) ----
$erreur = null;
$toMin = function (string $hhmm): ?int {
@@ -27,13 +33,20 @@
return $h * 60 + $m;
};
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['date_dispo'], $_POST['heure_debut'], $_POST['heure_fin'])) {
// ---- Ajouter une dispo ponctuelle (POST + CSRF)
if (
$_SERVER['REQUEST_METHOD'] === 'POST'
&& ($_POST['action'] ?? '') === 'add'
&& isset($_POST['date_dispo'], $_POST['heure_debut'], $_POST['heure_fin'])
) {
require_post_csrf();
$date_dispo = trim((string) $_POST['date_dispo']); // YYYY-MM-DD
$debut = trim((string) $_POST['heure_debut']); // HH:MM
$fin = trim((string) $_POST['heure_fin']); // HH:MM
// Validation date simple
$dt = DateTimeImmutable::createFromFormat('Y-m-d', $date_dispo);
if (! $dt || $dt->format('Y-m-d') !== $date_dispo) {
$erreur = $translations['erreur_format_date'] ?? "Format de date invalide.";
} else {
@@ -59,10 +72,10 @@
$duree_minutes
);
} else {
$stmt = $pdo->prepare(
"INSERT INTO disponibilite_date (praticien_id, date_dispo, heure_debut, heure_fin)
VALUES (?, ?, ?, ?)"
);
$stmt = $pdo->prepare("
INSERT INTO disponibilite_date (praticien_id, date_dispo, heure_debut, heure_fin)
VALUES (?, ?, ?, ?)
");
$stmt->execute([$praticien_id, $date_dispo, $debut, $fin]);
header('Location: /public/praticien/disponibilites_date.php?ok=added', true, 303);
@@ -72,158 +85,209 @@
}
}
// ---- Supprimer une plage datée (GET) ----
if (isset($_GET['supprimer'])) {
$id = (int) $_GET['supprimer'];
$stmt = $pdo->prepare("DELETE FROM disponibilite_date WHERE id = ? AND praticien_id = ?");
$stmt->execute([$id, $praticien_id]);
header('Location: /public/praticien/disponibilites_date.php?ok=deleted', true, 303);
exit;
}
// ---- Récupérer les plages datées ----
$stmt = $pdo->prepare(
"SELECT id, date_dispo, heure_debut, heure_fin
FROM disponibilite_date
WHERE praticien_id = ?
ORDER BY date_dispo ASC, heure_debut ASC"
);
// ---- Récupérer les plages datées
$stmt = $pdo->prepare("
SELECT id, date_dispo, heure_debut, heure_fin
FROM disponibilite_date
WHERE praticien_id = ?
ORDER BY date_dispo ASC, heure_debut ASC
");
$stmt->execute([$praticien_id]);
$dates = $stmt->fetchAll(PDO::FETCH_ASSOC);
// 1️⃣ Titre de la page
$PAGE_TITLE = $translations['titre_disponibilites_date'] ?? 'Disponibilités (dates)';
// 2️⃣ Ce qui doit aller dans <head> EN PLUS du header global
$PAGE_TITLE = $translations['titre_disponibilites_date'] ?? 'Disponibilités (dates)';
$HEAD_EXTRA = <<<HTML
<script src="/js/sweetalert2@11.js"></script>
HTML;
require_once __DIR__ . '/../includes/header.php';
?>
<div class="main1">
<div class="container py-5">
<div class="shadow p-4 rounded bg-light">
<h2 class="mb-4 text-center"><?php echo htmlspecialchars($translations['h2_disponibilites_date'] ?? 'Mes disponibilités ponctuelles') ?></h2>
<div class="container py-5">
<div class="shadow p-4 rounded bg-light">
<h2 class="mb-4 text-center">
<?php echo htmlspecialchars($translations['h2_disponibilites_date'] ?? 'Mes disponibilités ponctuelles'); ?>
</h2>
<div class="d-flex justify-content-between align-items-center mb-3">
<a class="btn btn-outline-secondary"
href="/public/praticien/disponibilites.php">
<?php echo htmlspecialchars($translations['retour_au_planning'] ?? 'Retour') ?>
</a>
</div>
<div class="d-flex justify-content-between align-items-center mb-3">
<a class="btn btn-outline-secondary" href="/public/praticien/disponibilites.php">
<?php echo htmlspecialchars($translations['retour_au_planning'] ?? 'Retour'); ?>
</a>
</div>
<div class="table-responsive mb-4">
<table class="table table-bordered table-striped align-middle text-center mobile-cards" id="table_rdv">
<thead class="table-light">
<tr>
<th><?php echo htmlspecialchars($translations['cl_date_rdv'] ?? 'Date') ?></th>
<th><?php echo htmlspecialchars($translations['table_debut'] ?? 'Début') ?></th>
<th><?php echo htmlspecialchars($translations['table_fin'] ?? 'Fin') ?></th>
<th><?php echo htmlspecialchars($translations['table_action'] ?? 'Action') ?></th>
</tr>
</thead>
<tbody>
<?php if ($dates): foreach ($dates as $d): ?>
<tr>
<td>
<?php echo htmlspecialchars(
date('d/m/Y', strtotime($d['date_dispo']))
) ?>
</td>
<td><?php echo htmlspecialchars(substr((string) $d['heure_debut'], 0, 5)) ?></td>
<td><?php echo htmlspecialchars(substr((string) $d['heure_fin'], 0, 5)) ?></td>
<td>
<button type="button"
<div class="table-responsive mb-4">
<table class="table table-bordered table-striped align-middle text-center mobile-cards" id="table_rdv">
<thead class="table-light">
<tr>
<th><?php echo htmlspecialchars($translations['cl_date_rdv'] ?? 'Date'); ?></th>
<th><?php echo htmlspecialchars($translations['table_debut'] ?? 'Début'); ?></th>
<th><?php echo htmlspecialchars($translations['table_fin'] ?? 'Fin'); ?></th>
<th><?php echo htmlspecialchars($translations['table_action'] ?? 'Action'); ?></th>
</tr>
</thead>
<tbody>
<?php if ($dates): ?>
<?php foreach ($dates as $d): ?>
<tr>
<td><?php echo htmlspecialchars(date('d/m/Y', strtotime((string) $d['date_dispo']))); ?></td>
<td><?php echo htmlspecialchars(substr((string) $d['heure_debut'], 0, 5)); ?></td>
<td><?php echo htmlspecialchars(substr((string) $d['heure_fin'], 0, 5)); ?></td>
<td>
<button
type="button"
class="btn btn-sm btn-danger js-del"
data-id="<?php echo (int) $d['id'] ?>">
<?php echo htmlspecialchars($translations['btn_supprimer'] ?? 'Supprimer') ?>
</button>
</td>
</tr>
<?php endforeach;else: ?>
<tr><td colspan="4"><?php echo htmlspecialchars($translations['aucun_creneau'] ?? 'Aucun créneau.') ?></td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
data-id="<?php echo (int) $d['id']; ?>">
<?php echo htmlspecialchars($translations['btn_supprimer'] ?? 'Supprimer'); ?>
</button>
</td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr>
<td colspan="4"><?php echo htmlspecialchars($translations['aucun_creneau'] ?? 'Aucun créneau.'); ?></td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
<div class="card shadow-sm p-4">
<h4 class="mb-3 text-center"><?php echo htmlspecialchars($translations['card_ajouter_creneau_date'] ?? 'Ajouter une disponibilité ponctuelle') ?></h4>
<div class="card shadow-sm p-4">
<h4 class="mb-3 text-center">
<?php echo htmlspecialchars($translations['card_ajouter_creneau_date'] ?? 'Ajouter une disponibilité ponctuelle'); ?>
</h4>
<form method="POST">
<div class="mb-3">
<label class="form-label" for="date_dispo"><?php echo htmlspecialchars($translations['cl_date_rdv'] ?? 'Date') ?></label>
<input type="date" name="date_dispo" id="date_dispo" class="form-control" required>
</div>
<form method="POST">
<input type="hidden" name="action" value="add">
<input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars(ensure_csrf_token(), ENT_QUOTES, 'UTF-8'); ?>">
<div class="mb-3">
<label class="form-label" for="heure_debut"><?php echo htmlspecialchars($translations['label_heure_debut'] ?? 'Heure de début') ?></label>
<input type="time" name="heure_debut" id="heure_debut" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label" for="date_dispo"><?php echo htmlspecialchars($translations['cl_date_rdv'] ?? 'Date'); ?></label>
<input type="date" name="date_dispo" id="date_dispo" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label" for="heure_fin"><?php echo htmlspecialchars($translations['label_heure_fin'] ?? 'Heure de fin') ?></label>
<input type="time" name="heure_fin" id="heure_fin" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label" for="heure_debut"><?php echo htmlspecialchars($translations['label_heure_debut'] ?? 'Heure de début'); ?></label>
<input type="time" name="heure_debut" id="heure_debut" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary w-100">
<?php echo htmlspecialchars($translations['btn_ajouter'] ?? 'Ajouter') ?>
</button>
</form>
<div class="mb-3">
<label class="form-label" for="heure_fin"><?php echo htmlspecialchars($translations['label_heure_fin'] ?? 'Heure de fin'); ?></label>
<input type="time" name="heure_fin" id="heure_fin" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary w-100">
<?php echo htmlspecialchars($translations['btn_ajouter'] ?? 'Ajouter'); ?>
</button>
</form>
</div>
</div>
</div>
</div>
</div>
<script>
const csrfToken = <?php echo json_encode(ensure_csrf_token(), JSON_UNESCAPED_UNICODE); ?>;
document.addEventListener('DOMContentLoaded', function(){
const okParam = '<?php echo isset($_GET['ok']) ? addslashes((string) $_GET['ok']) : '' ?>';
const erreurMsg = '<?php echo $erreur ? addslashes((string) $erreur) : '' ?>';
const okParam = <?php echo json_encode(isset($_GET['ok']) ? (string) $_GET['ok'] : '', JSON_UNESCAPED_UNICODE); ?>;
const erreurMsg = <?php echo json_encode($erreur ?: '', JSON_UNESCAPED_UNICODE); ?>;
if (okParam === 'added') {
Swal.fire({ icon:'success', title:'<?php echo addslashes($translations["msg_creneau_ajoute"] ?? "Créneau ajouté.") ?>', timer:1800, showConfirmButton:false });
} else if (okParam === 'deleted') {
Swal.fire({ icon:'success', title:'<?php echo addslashes($translations["msg_creneau_supprime"] ?? "Créneau supprimé.") ?>', timer:1800, showConfirmButton:false });
Swal.fire({
icon: 'success',
title: <?php echo json_encode($translations["msg_creneau_ajoute"] ?? "Créneau ajouté.", JSON_UNESCAPED_UNICODE); ?>,
timer: 1800,
showConfirmButton: false
});
if (window.history.replaceState) {
window.history.replaceState({}, document.title, window.location.pathname);
}
}
if (erreurMsg) {
Swal.fire({
icon: 'error',
title: '<?php echo addslashes($translations["erreur_titre"] ?? "Erreur") ?>',
html: erreurMsg,
showCancelButton: true,
confirmButtonText: '<?php echo addslashes($translations["btn_modifier_profil"] ?? "Modifier mon profil") ?>',
cancelButtonText: 'OK'
}).then((result) => {
if (result.isConfirmed) {
window.location.href = '/public/praticien/modifier.php';
}
});
}
Swal.fire({
icon: 'error',
title: <?php echo json_encode($translations["erreur_titre"] ?? "Erreur", JSON_UNESCAPED_UNICODE); ?>,
html: erreurMsg,
showCancelButton: true,
confirmButtonText: <?php echo json_encode($translations["btn_modifier_profil"] ?? "Modifier mon profil", JSON_UNESCAPED_UNICODE); ?>,
cancelButtonText: 'OK'
}).then((result) => {
if (result.isConfirmed) {
window.location.href = '/public/praticien/modifier.php';
}
});
}
});
document.addEventListener('click', async function(e){
const btn = e.target.closest('.js-del');
if (!btn) return;
const id = btn.dataset.id;
if (!id) return;
const result = await Swal.fire({
icon: 'warning',
title: '<?php echo addslashes($translations["confirm_title"] ?? "Confirmation") ?>',
text: '<?php echo addslashes($translations["confirm_supprimer_creneau"] ?? "Supprimer ce créneau ?") ?>',
title: <?php echo json_encode($translations["confirm_title"] ?? "Confirmation", JSON_UNESCAPED_UNICODE); ?>,
text: <?php echo json_encode($translations["confirm_supprimer_creneau"] ?? "Supprimer ce créneau ?", JSON_UNESCAPED_UNICODE); ?>,
showCancelButton: true,
confirmButtonText: '<?php echo addslashes($translations["btn_da_udalit"] ?? "Oui") ?>',
cancelButtonText: '<?php echo addslashes($translations["btn_annuler"] ?? "Annuler") ?>',
confirmButtonText: <?php echo json_encode($translations["btn_da_udalit"] ?? "Oui", JSON_UNESCAPED_UNICODE); ?>,
cancelButtonText: <?php echo json_encode($translations["btn_annuler"] ?? "Annuler", JSON_UNESCAPED_UNICODE); ?>,
reverseButtons: true
});
if (result.isConfirmed) {
window.location.href = '?supprimer=' + encodeURIComponent(id);
}
if (!result.isConfirmed) return;
const formData = new FormData();
formData.append('id', String(id));
formData.append('csrf_token', csrfToken);
fetch('/public/praticien/supprimer_disponibilite_date.php', {
method: 'POST',
headers: {
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
},
body: formData
})
.then(async r => {
const text = await r.text();
try {
return JSON.parse(text);
} catch (e) {
return { ok: false, message: text };
}
})
.then(data => {
if (data.ok) {
Swal.fire({
icon: 'success',
title: <?php echo json_encode($translations["msg_creneau_supprime"] ?? "Créneau supprimé.", JSON_UNESCAPED_UNICODE); ?>,
timer: 1400,
showConfirmButton: false
}).then(() => {
window.location.reload();
});
} else {
Swal.fire({
icon: 'error',
title: <?php echo json_encode($translations["erreur_titre"] ?? "Erreur", JSON_UNESCAPED_UNICODE); ?>,
text: data.message || 'Suppression impossible.'
});
}
})
.catch(() => {
Swal.fire({
icon: 'error',
title: 'Erreur réseau',
text: 'Veuillez réessayer.'
});
});
});
</script>
<!--*********Adaptation des tables pour un affichage mobile***************-->
<script defer>
(function(){
function initMobileCards(tbl){
@@ -236,14 +300,20 @@ document.addEventListener('click', async function(e){
});
document.documentElement.classList.add('mc-ready');
}
function ready(fn){ if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', fn); else fn(); }
ready(function(){ initMobileCards(document.getElementById('table_rdv')); });
function ready(fn){
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', fn);
else fn();
}
ready(function(){
initMobileCards(document.getElementById('table_rdv'));
});
})();
</script>
<footer class="site-footer">
<div class="container">
<p><?php echo $translations['copyr'] ?? '&copy; ' . date('Y') ?></p>
<p><?php echo $translations['copyr'] ?? '&copy; ' . date('Y'); ?></p>
</div>
</footer>
</body>
</html>
</html>