Files
maria_uslugi/public/cabinet/disponibilites_date.php
T
2026-03-05 10:25:39 +01:00

253 lines
9.7 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
// /public/cabinet/disponibilites_date.php (VERSION SECRÉTAIRE)
require_once __DIR__ . '/../includes/init_secretaire.php';
if (!function_exists('h')) {
function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }
}
// --- Contexte praticien obligatoire
$compteId = (int)($_SESSION['compte_id'] ?? 0);
$userRole = strtolower((string)($_SESSION['role'] ?? ''));
$praticien_id = isset($_GET['praticien_id']) ? (int)$_GET['praticien_id'] : 0;
if ($praticien_id <= 0 || $userRole !== 'secretaire') { http_response_code(403); exit('Forbidden'); }
// --- Vérifier pivot + droit can_edit_slots
$st = $pdo->prepare("
SELECT can_edit_slots
FROM secretaire_praticien
WHERE secretaire_user_id = :u
AND praticien_id = :p
AND is_active = 1
LIMIT 1
");
$st->execute(['u'=>$compteId,'p'=>$praticien_id]);
$pivot = $st->fetch(PDO::FETCH_ASSOC);
if (!$pivot || (int)$pivot['can_edit_slots'] !== 1) { http_response_code(403); exit('Forbidden'); }
// --- Optionnel: récupérer nom praticien pour titre
$st = $pdo->prepare("SELECT nom, prenom FROM praticien WHERE id = ? LIMIT 1");
$st->execute([$praticien_id]);
$prat = $st->fetch(PDO::FETCH_ASSOC);
$currentPraticienName = trim(($prat['prenom'] ?? '').' '.($prat['nom'] ?? ''));
$erreur = null;
// ---- Ajouter une plage datée (POST)
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['date_dispo'], $_POST['heure_debut'], $_POST['heure_fin'])) {
$date = trim((string)$_POST['date_dispo']); // YYYY-MM-DD
$debut = trim((string)$_POST['heure_debut']); // HH:MM
$fin = trim((string)$_POST['heure_fin']); // HH:MM
$tz = new DateTimeZone('Europe/Paris');
$today = (new DateTimeImmutable('now', $tz))->format('Y-m-d');
if (!preg_match('#^\d{4}-\d{2}-\d{2}$#', $date)) {
$erreur = $translations['erreur_format_date'] ?? "Format de date invalide.";
} elseif (!preg_match('#^\d{2}:\d{2}$#', $debut) || !preg_match('#^\d{2}:\d{2}$#', $fin)) {
$erreur = $translations['erreur_format_heure'] ?? "Format d’heure invalide.";
} elseif ($date < $today) {
$erreur = $translations['erreur_date_passee'] ?? "Date dans le passé.";
} elseif ($debut >= $fin) {
$erreur = $translations['erreur_debut_avant_fin'] ?? "Heure de début après l’heure de fin.";
}
if (!$erreur) {
try {
$stmt = $pdo->prepare("
INSERT INTO disponibilite_date (praticien_id, date_dispo, heure_debut, heure_fin)
VALUES (:p, :d, :hd, :hf)
");
$stmt->execute([
'p' => $praticien_id,
'd' => $date,
'hd' => $debut . ':00',
'hf' => $fin . ':00',
]);
header('Location: /public/cabinet/disponibilites_date.php?praticien_id='.$praticien_id.'&ok=added', true, 303);
exit;
} catch (PDOException $e) {
$erreur = $translations['erreur_enregistrement'] ?? "Impossible d’enregistrer (doublon ou erreur).";
}
}
}
// ---- Supprimer une plage datée (GET)
if (isset($_GET['supprimer'])) {
$id = (int)$_GET['supprimer'];
// Vérifier appartenance
$own = $pdo->prepare("SELECT 1 FROM disponibilite_date WHERE id = :id AND praticien_id = :p LIMIT 1");
$own->execute(['id'=>$id,'p'=>$praticien_id]);
if ($own->fetchColumn()) {
$stmt = $pdo->prepare("DELETE FROM disponibilite_date WHERE id = :id AND praticien_id = :p");
$stmt->execute(['id'=>$id,'p'=>$praticien_id]);
header('Location: /public/cabinet/disponibilites_date.php?praticien_id='.$praticien_id.'&ok=deleted', true, 303);
exit;
} else {
http_response_code(403); exit('Forbidden');
}
}
// ---- Liste
$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);
// Header cabinet
$PAGE_TITRE = $translations['titre_disponibilites_date'] ?? 'Disponibilités (dates)';
$HEAD_EXTRA = <<<HTML
<script src="/js/sweetalert2@11.js"></script>
HTML;
require_once __DIR__ . '/../includes/header_cabinet.php';
?>
<div class="main1">
<div class="container py-5">
<div class="shadow p-4 rounded bg-light">
<h2 class="mb-4 text-center">
<?= h($currentPraticienName ?: ($translations['h2_disponibilites_date'] ?? 'Disponibilités ponctuelles')) ?>
<?php if ($currentPraticienName): ?>
- <?= h($translations['h2_disponibilites_date'] ?? 'Disponibilités ponctuelles') ?>
<?php endif; ?>
</h2>
<div class="d-flex justify-content-between align-items-center mb-3">
<a class="btn btn-outline-secondary"
href="/public/cabinet/disponibilites.php?praticien_id=<?= (int)$praticien_id ?>">
<?= h($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_dispo_date">
<thead class="table-light">
<tr>
<th><?= h($translations['cl_date_rdv'] ?? 'Date') ?></th>
<th><?= h($translations['table_debut'] ?? 'Début') ?></th>
<th><?= h($translations['table_fin'] ?? 'Fin') ?></th>
<th><?= h($translations['table_action'] ?? 'Action') ?></th>
</tr>
</thead>
<tbody>
<?php if ($dates): foreach ($dates as $d): ?>
<tr>
<td><?= h(date('d/m/Y', strtotime((string)$d['date_dispo']))) ?></td>
<td><?= h(substr((string)$d['heure_debut'], 0, 5)) ?></td>
<td><?= h(substr((string)$d['heure_fin'], 0, 5)) ?></td>
<td>
<button type="button" class="btn btn-sm btn-danger js-del" data-id="<?= (int)$d['id'] ?>">
<?= h($translations['btn_supprimer'] ?? 'Supprimer') ?>
</button>
</td>
</tr>
<?php endforeach; else: ?>
<tr><td colspan="4"><?= h($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"><?= h($translations['card_ajouter_creneau_date'] ?? 'Ajouter une disponibilité ponctuelle') ?></h4>
<form method="POST">
<input type="hidden" name="praticien_id" value="<?= (int)$praticien_id ?>">
<div class="mb-3">
<label class="form-label" for="date_dispo"><?= h($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_debut"><?= h($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="heure_fin"><?= h($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">
<?= h($translations['btn_ajouter'] ?? 'Ajouter') ?>
</button>
</form>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function(){
const okParam = '<?= isset($_GET['ok']) ? addslashes((string)$_GET['ok']) : '' ?>';
const erreurMsg = '<?= $erreur ? addslashes((string)$erreur) : '' ?>';
if (okParam === 'added') {
Swal.fire({ icon:'success', title:'<?= addslashes($translations["msg_creneau_ajoute"] ?? "Créneau ajouté.") ?>', timer:1800, showConfirmButton:false });
} else if (okParam === 'deleted') {
Swal.fire({ icon:'success', title:'<?= addslashes($translations["msg_creneau_supprime"] ?? "Créneau supprimé.") ?>', timer:1800, showConfirmButton:false });
}
if (erreurMsg) {
Swal.fire({ icon:'error', title:'<?= addslashes($translations["erreur_titre"] ?? "Erreur") ?>', text:erreurMsg, confirmButtonText:'OK' });
}
});
document.addEventListener('click', async function(e){
const btn = e.target.closest('.js-del');
if (!btn) return;
const id = btn.dataset.id;
const result = await Swal.fire({
icon: 'warning',
title: '<?= addslashes($translations["confirm_title"] ?? "Confirmation") ?>',
text: '<?= addslashes($translations["confirm_supprimer_creneau"] ?? "Supprimer ce créneau ?") ?>',
showCancelButton: true,
confirmButtonText: '<?= addslashes($translations["btn_da_udalit"] ?? "Oui") ?>',
cancelButtonText: '<?= addslashes($translations["btn_annuler"] ?? "Annuler") ?>',
reverseButtons: true
});
if (result.isConfirmed) {
const pid = '<?= (int)$praticien_id ?>';
window.location.href = '?praticien_id=' + encodeURIComponent(pid) + '&supprimer=' + encodeURIComponent(id);
}
});
</script>
<script defer>
(function(){
function initMobileCards(tbl){
if (!tbl) return;
const heads = Array.from(tbl.querySelectorAll('thead th')).map(th => th.textContent.trim());
tbl.querySelectorAll('tbody tr').forEach(tr => {
Array.from(tr.children).forEach((td, i) => {
if (!td.hasAttribute('data-label')) td.setAttribute('data-label', heads[i] || '');
});
});
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_dispo_date')); });
})();
</script>
<footer class="site-footer">
<div class="container">
<p><?= $translations['copyr'] ?? '&copy; '.date('Y') ?></p>
</div>
</footer>
</body>
</html>