253 lines
9.7 KiB
PHP
253 lines
9.7 KiB
PHP
<?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'] ?? '© '.date('Y') ?></p>
|
||
</div>
|
||
</footer>
|
||
</body>
|
||
</html>
|