Init Git Prod Mars 2026
This commit is contained in:
commit
d81efe93b1
362 files changed
+86627
No files matched your search
@@ -0,0 +1,249 @@
|
||||
<?php
|
||||
// /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)
|
||||
$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 {
|
||||
if (! preg_match('/^\d{2}:\d{2}$/', $hhmm)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
[$h, $m] = array_map('intval', explode(':', $hhmm));
|
||||
if ($h < 0 || $h > 23 || $m < 0 || $m > 59) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $h * 60 + $m;
|
||||
};
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['date_dispo'], $_POST['heure_debut'], $_POST['heure_fin'])) {
|
||||
$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 {
|
||||
$md = $toMin($debut);
|
||||
$mf = $toMin($fin);
|
||||
|
||||
if ($md === null || $mf === null) {
|
||||
$erreur = $translations['erreur_format_heure'] ?? "Format d'heure invalide.";
|
||||
} elseif ($md >= $mf) {
|
||||
$erreur = $translations['erreur_debut_avant_fin'] ?? "Heure de début après l’heure de fin.";
|
||||
} else {
|
||||
$window = $mf - $md;
|
||||
|
||||
if ($window < $duree_minutes) {
|
||||
$erreur = sprintf(
|
||||
$translations['erreur_plage_trop_courte'] ?? "Créneau trop court (%d min). Minimum : %d min.",
|
||||
$window,
|
||||
$duree_minutes
|
||||
);
|
||||
} elseif (($window % $duree_minutes) !== 0) {
|
||||
$erreur = sprintf(
|
||||
$translations['erreur_plage_incompatible_duree'] ?? "Créneau incompatible. La durée doit être un multiple de %d min.",
|
||||
$duree_minutes
|
||||
);
|
||||
} else {
|
||||
$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);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 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"
|
||||
);
|
||||
$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
|
||||
$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="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"
|
||||
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>
|
||||
|
||||
<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>
|
||||
|
||||
<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="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>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
const okParam = '<?php echo isset($_GET['ok']) ? addslashes((string) $_GET['ok']) : '' ?>';
|
||||
const erreurMsg = '<?php echo $erreur ? addslashes((string) $erreur) : '' ?>';
|
||||
|
||||
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 });
|
||||
}
|
||||
|
||||
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';
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
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: '<?php echo addslashes($translations["confirm_title"] ?? "Confirmation") ?>',
|
||||
text: '<?php echo addslashes($translations["confirm_supprimer_creneau"] ?? "Supprimer ce créneau ?") ?>',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: '<?php echo addslashes($translations["btn_da_udalit"] ?? "Oui") ?>',
|
||||
cancelButtonText: '<?php echo addslashes($translations["btn_annuler"] ?? "Annuler") ?>',
|
||||
reverseButtons: true
|
||||
});
|
||||
|
||||
if (result.isConfirmed) {
|
||||
window.location.href = '?supprimer=' + encodeURIComponent(id);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<!--*********Adaptation des tables pour un affichage mobile***************-->
|
||||
<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_rdv')); });
|
||||
})();
|
||||
</script>
|
||||
<footer class="site-footer">
|
||||
<div class="container">
|
||||
<p><?php echo $translations['copyr'] ?? '© ' . date('Y') ?></p>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user