Version stable, aprelic, connexion CFRS et autres corrections
This commit is contained in:
1 parent
865de8a976
commit
e9d0010451
62 files changed
+17483
-7256
No files matched your search
+55
-40
@@ -1,37 +1,41 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../includes/init_praticien.php';
|
||||
require_once __DIR__ . '/../includes/init_praticien.php';
|
||||
|
||||
$success = $erreur = '';
|
||||
$id = $_SESSION['compte_id'];
|
||||
$success = $erreur = '';
|
||||
$id = $_SESSION['compte_id'];
|
||||
|
||||
// Récupérer e-mail actuel
|
||||
$stmt = $pdo->prepare("SELECT email FROM compte WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$compte = $stmt->fetch();
|
||||
// Récupérer e-mail actuel
|
||||
$stmt = $pdo->prepare("SELECT email, mot_de_passe FROM compte WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$compte = $stmt->fetch();
|
||||
|
||||
if (!$compte) {
|
||||
if (! $compte) {
|
||||
die($translations['compte_introuvable']);
|
||||
}
|
||||
}
|
||||
|
||||
$email_actuel = $compte['email'];
|
||||
$email_actuel = $compte['email'];
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
require_post_csrf();
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$nouvel_email = trim($_POST['email'] ?? '');
|
||||
$mdp1 = $_POST['mot_de_passe'] ?? '';
|
||||
$mdp2 = $_POST['confirm_mot_de_passe'] ?? '';
|
||||
$mdpActuel = $_POST['mot_de_passe_actuel'] ?? '';
|
||||
$mdp1 = $_POST['mot_de_passe'] ?? '';
|
||||
$mdp2 = $_POST['confirm_mot_de_passe'] ?? '';
|
||||
|
||||
if (!filter_var($nouvel_email, FILTER_VALIDATE_EMAIL)) {
|
||||
if (! password_verify($mdpActuel, (string) ($compte['mot_de_passe'] ?? ''))) {
|
||||
$erreur = $translations['erreur_mdp_actuel_incorrect'] ?? 'Mot de passe actuel incorrect.';
|
||||
} elseif (! filter_var($nouvel_email, FILTER_VALIDATE_EMAIL)) {
|
||||
$erreur = $translations['erreur_email_non_valide'];
|
||||
} elseif ($mdp1 && ($mdp1 !== $mdp2 || strlen($mdp1) < 8)) {
|
||||
$erreur = $translations['erreur_mdp_invalides'];
|
||||
} else {
|
||||
// Vérifier si l'email est déjà pris (sauf si c’est le sien)
|
||||
$stmt = $pdo->prepare("SELECT id FROM compte WHERE email = ? AND id != ?");
|
||||
$stmt->execute([$nouvel_email, $id]);
|
||||
|
||||
if ($stmt->fetch()) {
|
||||
$erreur = $translations['err_email_deja_utilise'];
|
||||
} else {
|
||||
// Mise à jour
|
||||
if ($mdp1) {
|
||||
$hash = password_hash($mdp1, PASSWORD_DEFAULT);
|
||||
$stmt = $pdo->prepare("UPDATE compte SET email = ?, mot_de_passe = ? WHERE id = ?");
|
||||
@@ -40,37 +44,48 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$stmt = $pdo->prepare("UPDATE compte SET email = ? WHERE id = ?");
|
||||
$stmt->execute([$nouvel_email, $id]);
|
||||
}
|
||||
$success = $translations['success_compte_mis_a_jour'];
|
||||
// Optionnel : mettre à jour $email_actuel pour refléter l'écran
|
||||
|
||||
$success = $translations['success_compte_mis_a_jour'];
|
||||
$email_actuel = $nouvel_email;
|
||||
|
||||
// garder la valeur en mémoire pour la suite de la page
|
||||
$compte['mot_de_passe'] = $mdp1 ? $hash : $compte['mot_de_passe'];
|
||||
}
|
||||
}
|
||||
}
|
||||
require_once '../includes/header.php';
|
||||
}
|
||||
require_once '../includes/header.php';
|
||||
?>
|
||||
|
||||
<div class="main1">
|
||||
<div class="container py-5">
|
||||
<form method="POST" class="shadow p-4 rounded bg-light">
|
||||
<h2 class="text-center mb-4"><?= htmlspecialchars($translations['h2_infos_connexion']) ?></h2>
|
||||
<input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars(ensure_csrf_token(), ENT_QUOTES, 'UTF-8') ?>">
|
||||
<h2 class="text-center mb-4"><?php echo htmlspecialchars($translations['h2_infos_connexion']) ?></h2>
|
||||
|
||||
<?php if (!empty($erreur)): ?>
|
||||
<div class="alert alert-danger"><?= htmlspecialchars($erreur) ?></div>
|
||||
<?php if (! empty($erreur)): ?>
|
||||
<div class="alert alert-danger"><?php echo htmlspecialchars($erreur) ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($success)): ?>
|
||||
<div class="alert alert-success"><?= htmlspecialchars($success) ?></div>
|
||||
<?php if (! empty($success)): ?>
|
||||
<div class="alert alert-success"><?php echo htmlspecialchars($success) ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?= htmlspecialchars($translations['label_email']) ?></label>
|
||||
<input type="email" name="email" class="form-control" value="<?= htmlspecialchars($email_actuel ?? '') ?>" required>
|
||||
<label class="form-label"><?php echo htmlspecialchars($translations['label_email']) ?></label>
|
||||
<input type="email" name="email" class="form-control" value="<?php echo htmlspecialchars($email_actuel ?? '') ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?php echo htmlspecialchars($translations['label_mdp_actuel'] ?? 'Mot de passe actuel') ?></label>
|
||||
<div class="field-wrapper">
|
||||
<input type="password" name="mot_de_passe_actuel" id="mot_de_passe_actuel" class="form-control"
|
||||
placeholder="<?php echo htmlspecialchars($translations['placeholder_mdp_actuel'] ?? 'Entrez votre mot de passe actuel') ?>" required>
|
||||
<span class="toggle-password" onclick="toggle('mot_de_passe_actuel')">👁️</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?= htmlspecialchars($translations['label_nouveau_mdp_opt']) ?></label>
|
||||
<label class="form-label"><?php echo htmlspecialchars($translations['label_nouveau_mdp_opt']) ?></label>
|
||||
<div class="field-wrapper">
|
||||
<input type="password" name="mot_de_passe" id="mot_de_passe" class="form-control"
|
||||
placeholder="<?= htmlspecialchars($translations['placeholder_nouveau_mdp']) ?>">
|
||||
placeholder="<?php echo htmlspecialchars($translations['placeholder_nouveau_mdp']) ?>">
|
||||
<span class="toggle-password" onclick="toggle('mot_de_passe')">👁️</span>
|
||||
</div>
|
||||
<div class="strength-bar mt-2">
|
||||
@@ -79,21 +94,21 @@ require_once '../includes/header.php';
|
||||
<div class="strength-fill"></div>
|
||||
</div>
|
||||
<div id="niveau-securite" class="mb-2 text-muted">
|
||||
<?= htmlspecialchars($translations['securite_label']) ?> : <?= htmlspecialchars($translations['securite_vide']) ?>
|
||||
<?php echo htmlspecialchars($translations['securite_label']) ?> : <?php echo htmlspecialchars($translations['securite_vide']) ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?= htmlspecialchars($translations['label_confirmer_mdp']) ?></label>
|
||||
<label class="form-label"><?php echo htmlspecialchars($translations['label_confirmer_mdp']) ?></label>
|
||||
<div class="field-wrapper">
|
||||
<input type="password" name="confirm_mot_de_passe" id="confirm_mot_de_passe" class="form-control"
|
||||
placeholder="<?= htmlspecialchars($translations['placeholder_confirmer_mdp']) ?>">
|
||||
placeholder="<?php echo htmlspecialchars($translations['placeholder_confirmer_mdp']) ?>">
|
||||
<span class="toggle-password" onclick="toggle('confirm_mot_de_passe')">👁️</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 text-center">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<?= htmlspecialchars($translations['btn_mettre_a_jour']) ?>
|
||||
<?php echo htmlspecialchars($translations['btn_mettre_a_jour']) ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -112,11 +127,11 @@ document.getElementById('mot_de_passe').addEventListener('input', function () {
|
||||
segments.forEach(s => s.style.backgroundColor = '#ccc');
|
||||
|
||||
// base label
|
||||
const label = <?= json_encode($translations['securite_label'], JSON_UNESCAPED_UNICODE) ?>;
|
||||
const faible = <?= json_encode($translations['securite_faible'], JSON_UNESCAPED_UNICODE) ?>;
|
||||
const moyen = <?= json_encode($translations['securite_moyen'], JSON_UNESCAPED_UNICODE) ?>;
|
||||
const fort = <?= json_encode($translations['securite_fort'], JSON_UNESCAPED_UNICODE) ?>;
|
||||
const vide = <?= json_encode($translations['securite_vide'], JSON_UNESCAPED_UNICODE) ?>;
|
||||
const label = <?php echo json_encode($translations['securite_label'], JSON_UNESCAPED_UNICODE) ?>;
|
||||
const faible = <?php echo json_encode($translations['securite_faible'], JSON_UNESCAPED_UNICODE) ?>;
|
||||
const moyen = <?php echo json_encode($translations['securite_moyen'], JSON_UNESCAPED_UNICODE) ?>;
|
||||
const fort = <?php echo json_encode($translations['securite_fort'], JSON_UNESCAPED_UNICODE) ?>;
|
||||
const vide = <?php echo json_encode($translations['securite_vide'], JSON_UNESCAPED_UNICODE) ?>;
|
||||
|
||||
niveauText.textContent = `${label} : ${vide}`;
|
||||
niveauText.classList.remove("text-danger", "text-warning", "text-success");
|
||||
@@ -152,7 +167,7 @@ document.getElementById('mot_de_passe').addEventListener('input', function () {
|
||||
</div>
|
||||
<footer class="site-footer">
|
||||
<div class="container">
|
||||
<p><?= $translations['copyr'] ?></p>
|
||||
<p><?php echo $translations['copyr'] ?></p>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
|
||||
+208
-150
@@ -1,23 +1,25 @@
|
||||
<?php
|
||||
// /public/praticien/disponibilites.php
|
||||
declare (strict_types = 1);
|
||||
|
||||
require_once __DIR__ . '/../includes/init_praticien.php';
|
||||
|
||||
$praticien_id = (int) ($_SESSION['reference_id'] ?? 0);
|
||||
if ($praticien_id <= 0) {http_response_code(403);exit('Forbidden');}
|
||||
if ($praticien_id <= 0) {
|
||||
http_response_code(403);
|
||||
exit('Forbidden');
|
||||
}
|
||||
|
||||
// Durée RDV praticien (garde-fou strict)
|
||||
// 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;
|
||||
}
|
||||
// fallback sécurité
|
||||
// ---- Ajouter un créneau (POST) ----
|
||||
|
||||
$erreur = null;
|
||||
|
||||
$toMin = function (string $hhmm): ?int {
|
||||
// input type="time" renvoie souvent HH:MM
|
||||
if (! preg_match('/^\d{2}:\d{2}$/', $hhmm)) {
|
||||
return null;
|
||||
}
|
||||
@@ -30,7 +32,14 @@
|
||||
return $h * 60 + $m;
|
||||
};
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['jour'], $_POST['heure_debut'], $_POST['heure_fin'])) {
|
||||
// ---- Ajouter un créneau (POST) ----
|
||||
if (
|
||||
$_SERVER['REQUEST_METHOD'] === 'POST'
|
||||
&& ($_POST['action'] ?? '') === 'add'
|
||||
&& isset($_POST['jour'], $_POST['heure_debut'], $_POST['heure_fin'])
|
||||
) {
|
||||
require_post_csrf();
|
||||
|
||||
$jour = trim((string) $_POST['jour']);
|
||||
$debut = trim((string) $_POST['heure_debut']);
|
||||
$fin = trim((string) $_POST['heure_fin']);
|
||||
@@ -43,7 +52,7 @@
|
||||
} elseif ($md >= $mf) {
|
||||
$erreur = $translations['erreur_debut_avant_fin'] ?? "Heure de début après l’heure de fin.";
|
||||
} else {
|
||||
$window = $mf - $md; // minutes
|
||||
$window = $mf - $md;
|
||||
|
||||
if ($window < $duree_minutes) {
|
||||
$erreur = sprintf(
|
||||
@@ -69,194 +78,238 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Supprimer un créneau (GET) ----
|
||||
// (idéalement: POST + CSRF, on garde GET pour aller vite)
|
||||
if (isset($_GET['supprimer'])) {
|
||||
$id = (int) $_GET['supprimer'];
|
||||
$stmt = $pdo->prepare("DELETE FROM disponibilite WHERE id = ? AND praticien_id = ?");
|
||||
$stmt->execute([$id, $praticien_id]);
|
||||
header('Location: /public/praticien/disponibilites.php?ok=deleted', true, 303);
|
||||
exit;
|
||||
}
|
||||
|
||||
// ---- Récupérer les créneaux ----
|
||||
$stmt = $pdo->prepare(
|
||||
"SELECT * FROM disponibilite
|
||||
"SELECT *
|
||||
FROM disponibilite
|
||||
WHERE praticien_id = ?
|
||||
ORDER BY FIELD(jour_semaine,'lundi','mardi','mercredi','jeudi','vendredi','samedi','dimanche'), heure_debut"
|
||||
);
|
||||
$stmt->execute([$praticien_id]);
|
||||
$dispos = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Prépare les traductions de jours
|
||||
// Traductions jours
|
||||
$jourKeyMap = [
|
||||
'lundi' => 'jour_lundi', 'mardi' => 'jour_mardi', 'mercredi' => 'jour_mercredi',
|
||||
'jeudi' => 'jour_jeudi', 'vendredi' => 'jour_vendredi', 'samedi' => 'jour_samedi', 'dimanche' => 'jour_dimanche',
|
||||
'lundi' => 'jour_lundi',
|
||||
'mardi' => 'jour_mardi',
|
||||
'mercredi' => 'jour_mercredi',
|
||||
'jeudi' => 'jour_jeudi',
|
||||
'vendredi' => 'jour_vendredi',
|
||||
'samedi' => 'jour_samedi',
|
||||
'dimanche' => 'jour_dimanche',
|
||||
];
|
||||
// 1️⃣ Titre de la page
|
||||
$PAGE_TITLE = $translations['titre_disponibilites'] ?? 'Disponibilités';
|
||||
|
||||
// 2️⃣ Ce qui doit aller dans <head> EN PLUS du header global
|
||||
$PAGE_TITLE = $translations['titre_disponibilites'] ?? 'Disponibilités';
|
||||
$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'] ?? 'Mes disponibilités') ?></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'] ?? 'Mes disponibilités'); ?></h2>
|
||||
|
||||
<!-- Plus d'alertes Bootstrap ici : on affiche via Swal selon ?ok=... et $erreur -->
|
||||
<div class="text-end">
|
||||
<a href="/public/praticien/disponibilites_date.php" class="btn btn-outline-secondary mb-4">
|
||||
<?php echo htmlspecialchars($translations['btn_ajouter_par_date'] ?? 'Ajouter par date') ?>
|
||||
</a>
|
||||
</div>
|
||||
<div class="table-responsive mb-4">
|
||||
<div class="text-end">
|
||||
<a href="/public/praticien/disponibilites_date.php" class="btn btn-outline-secondary mb-4">
|
||||
<?php echo htmlspecialchars($translations['btn_ajouter_par_date'] ?? 'Ajouter par date'); ?>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<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['table_jour'] ?? 'Jour') ?></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 ($dispos): foreach ($dispos as $d): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<?php
|
||||
$key = $jourKeyMap[$d['jour_semaine']] ?? null;
|
||||
echo htmlspecialchars($key ? ($translations[$key] ?? ucfirst($d['jour_semaine'])) : ucfirst($d['jour_semaine']));
|
||||
?>
|
||||
</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['table_jour'] ?? 'Jour'); ?></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 ($dispos): ?>
|
||||
<?php foreach ($dispos as $d): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<?php
|
||||
$key = $jourKeyMap[$d['jour_semaine']] ?? null;
|
||||
echo htmlspecialchars($key ? ($translations[$key] ?? ucfirst($d['jour_semaine'])) : ucfirst($d['jour_semaine']));
|
||||
?>
|
||||
</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'] ?? 'Ajouter un créneau') ?></h4>
|
||||
<form method="POST">
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="jour"><?php echo htmlspecialchars($translations['label_jour'] ?? 'Jour') ?></label>
|
||||
<select name="jour" id="jour" class="form-select" required>
|
||||
<option value=""><?php echo htmlspecialchars($translations['option_choisir'] ?? '— Choisir —') ?></option>
|
||||
<?php
|
||||
$jours = [
|
||||
'lundi' => $translations['jour_lundi'] ?? 'Lundi',
|
||||
'mardi' => $translations['jour_mardi'] ?? 'Mardi',
|
||||
'mercredi' => $translations['jour_mercredi'] ?? 'Mercredi',
|
||||
'jeudi' => $translations['jour_jeudi'] ?? 'Jeudi',
|
||||
'vendredi' => $translations['jour_vendredi'] ?? 'Vendredi',
|
||||
'samedi' => $translations['jour_samedi'] ?? 'Samedi',
|
||||
'dimanche' => $translations['jour_dimanche'] ?? 'Dimanche',
|
||||
];
|
||||
foreach ($jours as $val => $label):
|
||||
?>
|
||||
<option value="<?php echo htmlspecialchars($val) ?>"><?php echo htmlspecialchars($label) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="card shadow-sm p-4">
|
||||
<h4 class="mb-3 text-center"><?php echo htmlspecialchars($translations['card_ajouter_creneau'] ?? 'Ajouter un créneau'); ?></h4>
|
||||
|
||||
<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>
|
||||
<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_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="jour"><?php echo htmlspecialchars($translations['label_jour'] ?? 'Jour'); ?></label>
|
||||
<select name="jour" id="jour" class="form-select" required>
|
||||
<option value=""><?php echo htmlspecialchars($translations['option_choisir'] ?? '— Choisir —'); ?></option>
|
||||
<?php
|
||||
$jours = [
|
||||
'lundi' => $translations['jour_lundi'] ?? 'Lundi',
|
||||
'mardi' => $translations['jour_mardi'] ?? 'Mardi',
|
||||
'mercredi' => $translations['jour_mercredi'] ?? 'Mercredi',
|
||||
'jeudi' => $translations['jour_jeudi'] ?? 'Jeudi',
|
||||
'vendredi' => $translations['jour_vendredi'] ?? 'Vendredi',
|
||||
'samedi' => $translations['jour_samedi'] ?? 'Samedi',
|
||||
'dimanche' => $translations['jour_dimanche'] ?? 'Dimanche',
|
||||
];
|
||||
foreach ($jours as $val => $label):
|
||||
?>
|
||||
<option value="<?php echo htmlspecialchars($val); ?>"><?php echo htmlspecialchars($label); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</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_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>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// --- SweetAlert2: messages succès / erreur depuis PHP ---
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
const okParam = '<?php echo isset($_GET['ok']) ? addslashes((string) $_GET['ok']) : '' ?>';
|
||||
const erreurMsg = '<?php echo $erreur ? addslashes((string) $erreur) : '' ?>';
|
||||
const csrfToken = <?php echo json_encode(ensure_csrf_token(), JSON_UNESCAPED_UNICODE); ?>;
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
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) {
|
||||
const cleanUrl = window.location.pathname;
|
||||
window.history.replaceState({}, document.title, cleanUrl);
|
||||
}
|
||||
}
|
||||
|
||||
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';
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// --- Confirmation de suppression avec SweetAlert2 ---
|
||||
document.addEventListener('click', async function(e){
|
||||
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) {
|
||||
// Suppression côté serveur (GET) — garde la mécanique existante
|
||||
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.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){
|
||||
@@ -269,15 +322,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'] ?? '© ' . date('Y') ?></p>
|
||||
<p><?php echo $translations['copyr'] ?? '© ' . date('Y'); ?></p>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@@ -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'] ?? '© ' . date('Y') ?></p>
|
||||
<p><?php echo $translations['copyr'] ?? '© ' . date('Y'); ?></p>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@@ -1,86 +1,113 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../includes/init_praticien.php';
|
||||
|
||||
require_once __DIR__ . '/../includes/init_praticien.php';
|
||||
$id = $_SESSION['reference_id'] ?? null;
|
||||
if (! $id) {
|
||||
http_response_code(403);
|
||||
exit('Forbidden');
|
||||
}
|
||||
|
||||
$currentLang = $lang ?? 'ru';
|
||||
if (! in_array($currentLang, ['ru', 'fr', 'en'], true)) {
|
||||
$currentLang = 'ru';
|
||||
}
|
||||
|
||||
// Base praticien
|
||||
$stmt = $pdo->prepare("SELECT * FROM praticien WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$praticien = $stmt->fetch();
|
||||
|
||||
// Récupérer les infos du praticien
|
||||
$stmt = $pdo->prepare("SELECT * FROM praticien WHERE id = ?");
|
||||
$stmt->execute([$_SESSION['reference_id'] ?? 0]);
|
||||
$praticien = $stmt->fetch();
|
||||
if (! $praticien) {
|
||||
http_response_code(404);
|
||||
exit(htmlspecialchars($translations['praticien_introuvable'] ?? 'Introuvable.'));
|
||||
}
|
||||
|
||||
$id = $_SESSION['reference_id'] ?? null;
|
||||
if (!$id) { http_response_code(403); exit('Forbidden'); }
|
||||
require_once __DIR__ . '/../includes/header.php';
|
||||
// Traduction courante
|
||||
$stmtTr = $pdo->prepare("
|
||||
SELECT *
|
||||
FROM praticien_traduction
|
||||
WHERE praticien_id = ? AND langue = ?
|
||||
LIMIT 1
|
||||
");
|
||||
$stmtTr->execute([$id, $currentLang]);
|
||||
$traduction = $stmtTr->fetch() ?: null;
|
||||
|
||||
// Valeurs affichées avec fallback
|
||||
$nomAffiche = $traduction['nom_affiche'] ?? $praticien['nom'] ?? '';
|
||||
$prenomAffiche = $traduction['prenom_affiche'] ?? $praticien['prenom'] ?? '';
|
||||
$villeAffichee = $traduction['ville_affichee'] ?? $praticien['ville'] ?? '';
|
||||
$titreAffiche = $traduction['titre'] ?? $praticien['titre'] ?? '';
|
||||
$specialiteAffiche = $traduction['specialite'] ?? $praticien['specialite'] ?? '';
|
||||
$presentationAffiche = $traduction['presentation'] ?? $praticien['presentation'] ?? '';
|
||||
$dispoAffiche = $traduction['disponibilite'] ?? $praticien['disponibilite'] ?? '';
|
||||
|
||||
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"><?= htmlspecialchars($translations['mes_infos_heading']) ?></h2>
|
||||
<h2 class="mb-4 text-center"><?php echo htmlspecialchars($translations['mes_infos_heading']) ?></h2>
|
||||
|
||||
<div class="card-body">
|
||||
<div class="row g-4 mb-3">
|
||||
<!-- Colonne gauche -->
|
||||
<div class="col-12 col-sm-6">
|
||||
<p><strong><?= htmlspecialchars($translations['label_nom']) ?> :</strong>
|
||||
<?= htmlspecialchars($praticien['nom'] ?? '') ?></p>
|
||||
<p><strong><?php echo htmlspecialchars($translations['label_nom']) ?> :</strong>
|
||||
<?php echo htmlspecialchars($nomAffiche) ?></p>
|
||||
|
||||
<p><strong><?= htmlspecialchars($translations['label_prenom']) ?> :</strong>
|
||||
<?= htmlspecialchars($praticien['prenom'] ?? '') ?></p>
|
||||
<p><strong><?php echo htmlspecialchars($translations['label_prenom']) ?> :</strong>
|
||||
<?php echo htmlspecialchars($prenomAffiche) ?></p>
|
||||
|
||||
<p><strong><?= htmlspecialchars($translations['label_email']) ?> :</strong>
|
||||
<?= htmlspecialchars($praticien['email'] ?? '') ?></p>
|
||||
<p><strong><?php echo htmlspecialchars($translations['label_email']) ?> :</strong>
|
||||
<?php echo htmlspecialchars($praticien['email'] ?? '') ?></p>
|
||||
|
||||
<p><strong><?= htmlspecialchars($translations['label_telephone']) ?> :</strong>
|
||||
<?= htmlspecialchars($praticien['telephone'] ?? '') ?></p>
|
||||
<p><strong><?php echo htmlspecialchars($translations['label_telephone']) ?> :</strong>
|
||||
<?php echo htmlspecialchars($praticien['telephone'] ?? '') ?></p>
|
||||
|
||||
<div>
|
||||
<strong><?= htmlspecialchars($translations['alt_photo']) ?> :</strong><br><br>
|
||||
<?php if (!empty($praticien['photo'])): ?>
|
||||
<strong><?php echo htmlspecialchars($translations['alt_photo']) ?> :</strong><br><br>
|
||||
<?php if (! empty($praticien['photo'])): ?>
|
||||
<img
|
||||
src="/public/uploads/<?= htmlspecialchars($praticien['photo']) ?>"
|
||||
alt="<?= htmlspecialchars($translations['alt_photo']) ?>"
|
||||
src="/public/uploads/<?php echo htmlspecialchars($praticien['photo']) ?>"
|
||||
alt="<?php echo htmlspecialchars($translations['alt_photo']) ?>"
|
||||
class="img-fluid rounded-4 shadow"
|
||||
style="max-width:230px;height:auto;">
|
||||
<?php else: ?>
|
||||
<span class="text-muted"><?= htmlspecialchars($translations['aucune_photo'] ?? 'Aucune photo') ?></span>
|
||||
<span class="text-muted"><?php echo htmlspecialchars($translations['aucune_photo'] ?? 'Aucune photo') ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Colonne droite -->
|
||||
<div class="col-12 col-sm-6">
|
||||
<p><strong><?= htmlspecialchars($translations['placeholder_siret']) ?> :</strong>
|
||||
<?= htmlspecialchars($praticien['siret'] ?? '') ?></p>
|
||||
<p><strong><?php echo htmlspecialchars($translations['placeholder_siret']) ?> :</strong>
|
||||
<?php echo htmlspecialchars($praticien['siret'] ?? '') ?></p>
|
||||
|
||||
<p><strong><?= htmlspecialchars($translations['label_specialite']) ?> :</strong>
|
||||
<?= htmlspecialchars($praticien['specialite'] ?? '') ?></p>
|
||||
<p><strong><?php echo htmlspecialchars($translations['label_specialite']) ?> :</strong>
|
||||
<?php echo htmlspecialchars($specialiteAffiche) ?></p>
|
||||
|
||||
<!-- Ajout tarif et moyen de paiement -->
|
||||
<p><strong><?= htmlspecialchars($translations['tarif_consultation']) ?> :</strong>
|
||||
<?= htmlspecialchars($praticien['titre'] ?? '') ?></p>
|
||||
<p><strong><?php echo htmlspecialchars($translations['tarif_consultation']) ?> :</strong>
|
||||
<?php echo htmlspecialchars($titreAffiche) ?></p>
|
||||
|
||||
<p><strong><?= htmlspecialchars($translations['moyens_payement']) ?> :</strong>
|
||||
<?= htmlspecialchars($praticien['disponibilite'] ?? '') ?></p>
|
||||
<p><strong><?php echo htmlspecialchars($translations['moyens_payement']) ?> :</strong>
|
||||
<?php echo htmlspecialchars($dispoAffiche) ?></p>
|
||||
|
||||
<p><strong><?= htmlspecialchars($translations['label_ville']) ?> :</strong>
|
||||
<?= htmlspecialchars($praticien['ville'] ?? '') ?></p>
|
||||
<p><strong><?php echo htmlspecialchars($translations['label_ville']) ?> :</strong>
|
||||
<?php echo htmlspecialchars($villeAffichee) ?></p>
|
||||
|
||||
<p><strong><?= htmlspecialchars($translations['label_code_postal']) ?> :</strong>
|
||||
<?= htmlspecialchars($praticien['code_postal'] ?? '') ?></p>
|
||||
<p><strong><?php echo htmlspecialchars($translations['label_code_postal']) ?> :</strong>
|
||||
<?php echo htmlspecialchars($praticien['code_postal'] ?? '') ?></p>
|
||||
|
||||
<p><strong><?= htmlspecialchars($translations['label_adresse']) ?> :</strong><br>
|
||||
<?= nl2br(htmlspecialchars($praticien['adresse'] ?? '')) ?></p>
|
||||
<p><strong><?php echo htmlspecialchars($translations['label_adresse']) ?> :</strong><br>
|
||||
<?php echo nl2br(htmlspecialchars($praticien['adresse'] ?? '')) ?></p>
|
||||
|
||||
<p><strong><?= htmlspecialchars($translations['label_presentation']) ?> :</strong><br>
|
||||
<?= nl2br(htmlspecialchars($praticien['presentation'] ?? '')) ?></p>
|
||||
<p><strong><?php echo htmlspecialchars($translations['label_presentation']) ?> :</strong><br>
|
||||
<?php echo nl2br(htmlspecialchars($presentationAffiche)) ?></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 text-center">
|
||||
<a href="/public/praticien/modifier.php" class="btn btn-primary">
|
||||
<?= htmlspecialchars($translations['btn_modifier_mes_infos']) ?>
|
||||
<?php echo htmlspecialchars($translations['btn_modifier_mes_infos']) ?>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -90,11 +117,6 @@ require_once __DIR__ . '/../includes/header.php';
|
||||
|
||||
<footer class="site-footer">
|
||||
<div class="container">
|
||||
<p><?= $translations['copyr'] ?></p>
|
||||
<p><?php echo $translations['copyr'] ?></p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<?php
|
||||
// Si ton header.php ouvre <body>, pense à fermer proprement dans footer.php.
|
||||
// Si tu n'as pas de footer commun, laisse comme ça.
|
||||
?>
|
||||
+548
-229
@@ -1,289 +1,617 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../includes/init_praticien.php';
|
||||
require_once __DIR__ . '/../includes/init_praticien.php';
|
||||
|
||||
$id = $_SESSION['reference_id'] ?? null;
|
||||
if (! $id) {
|
||||
http_response_code(403);
|
||||
exit('Forbidden');
|
||||
}
|
||||
|
||||
$id = $_SESSION['reference_id'] ?? null;
|
||||
if (!$id) { http_response_code(403); exit('Forbidden'); }
|
||||
$currentLang = $lang ?? 'ru';
|
||||
if (! in_array($currentLang, ['ru', 'fr', 'en'], true)) {
|
||||
$currentLang = 'ru';
|
||||
}
|
||||
$isRu = ($currentLang === 'ru');
|
||||
|
||||
// Récupérer les données (pour affichage initial & valeurs par défaut)
|
||||
$stmt = $pdo->prepare("SELECT * FROM praticien WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$praticien = $stmt->fetch();
|
||||
if (!$praticien) {
|
||||
$ro = $isRu ? '' : 'readonly';
|
||||
$dis = $isRu ? '' : 'disabled';
|
||||
|
||||
/**
|
||||
* Upsert traduction
|
||||
*/
|
||||
function upsertPraticienTraduction(PDO $pdo, int $praticienId, string $langue, array $data): void
|
||||
{
|
||||
$sql = "
|
||||
INSERT INTO praticien_traduction (
|
||||
praticien_id,
|
||||
langue,
|
||||
nom_affiche,
|
||||
prenom_affiche,
|
||||
ville_affichee,
|
||||
titre,
|
||||
specialite,
|
||||
presentation,
|
||||
disponibilite,
|
||||
statut,
|
||||
created_at,
|
||||
updated_at
|
||||
) VALUES (
|
||||
:praticien_id,
|
||||
:langue,
|
||||
:nom_affiche,
|
||||
:prenom_affiche,
|
||||
:ville_affichee,
|
||||
:titre,
|
||||
:specialite,
|
||||
:presentation,
|
||||
:disponibilite,
|
||||
:statut,
|
||||
NOW(),
|
||||
NOW()
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
nom_affiche = VALUES(nom_affiche),
|
||||
prenom_affiche = VALUES(prenom_affiche),
|
||||
ville_affichee = VALUES(ville_affichee),
|
||||
titre = VALUES(titre),
|
||||
specialite = VALUES(specialite),
|
||||
presentation = VALUES(presentation),
|
||||
disponibilite = VALUES(disponibilite),
|
||||
statut = VALUES(statut),
|
||||
updated_at = NOW()
|
||||
";
|
||||
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([
|
||||
'praticien_id' => $praticienId,
|
||||
'langue' => $langue,
|
||||
'nom_affiche' => $data['nom_affiche'],
|
||||
'prenom_affiche' => $data['prenom_affiche'],
|
||||
'ville_affichee' => $data['ville_affichee'],
|
||||
'titre' => $data['titre'],
|
||||
'specialite' => $data['specialite'],
|
||||
'presentation' => $data['presentation'],
|
||||
'disponibilite' => $data['disponibilite'],
|
||||
'statut' => $data['statut'],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lecture traduction par langue
|
||||
*/
|
||||
function getPraticienTraduction(PDO $pdo, int $praticienId, string $langue): ?array
|
||||
{
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT *
|
||||
FROM praticien_traduction
|
||||
WHERE praticien_id = ? AND langue = ?
|
||||
LIMIT 1
|
||||
");
|
||||
$stmt->execute([$praticienId, $langue]);
|
||||
$row = $stmt->fetch();
|
||||
return $row ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translittération simple cyrillique -> latin
|
||||
* Suffisant pour test / affichage.
|
||||
*/
|
||||
function transliterateToLatin(string $text): string
|
||||
{
|
||||
$map = [
|
||||
'А' => 'A', 'а' => 'a', 'Б' => 'B', 'б' => 'b', 'В' => 'V', 'в' => 'v', 'Г' => 'G', 'г' => 'g',
|
||||
'Д' => 'D', 'д' => 'd', 'Е' => 'E', 'е' => 'e', 'Ё' => 'Yo', 'ё' => 'yo', 'Ж' => 'Zh', 'ж' => 'zh',
|
||||
'З' => 'Z', 'з' => 'z', 'И' => 'I', 'и' => 'i', 'Й' => 'Y', 'й' => 'y', 'К' => 'K', 'к' => 'k',
|
||||
'Л' => 'L', 'л' => 'l', 'М' => 'M', 'м' => 'm', 'Н' => 'N', 'н' => 'n', 'О' => 'O', 'о' => 'o',
|
||||
'П' => 'P', 'п' => 'p', 'Р' => 'R', 'р' => 'r', 'С' => 'S', 'с' => 's', 'Т' => 'T', 'т' => 't',
|
||||
'У' => 'U', 'у' => 'u', 'Ф' => 'F', 'ф' => 'f', 'Х' => 'Kh', 'х' => 'kh', 'Ц' => 'Ts', 'ц' => 'ts',
|
||||
'Ч' => 'Ch', 'ч' => 'ch', 'Ш' => 'Sh', 'ш' => 'sh', 'Щ' => 'Shch', 'щ' => 'shch',
|
||||
'Ы' => 'Y', 'ы' => 'y', 'Э' => 'E', 'э' => 'e', 'Ю' => 'Yu', 'ю' => 'yu', 'Я' => 'Ya', 'я' => 'ya',
|
||||
'Ь' => '', 'ь' => '', 'Ъ' => '', 'ъ' => '',
|
||||
];
|
||||
return strtr($text, $map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stub traduction.
|
||||
* Pour l’instant :
|
||||
* - renvoie le texte tel quel si pas de vrai moteur branché
|
||||
* - tu pourras remplacer ici par DeepL/API plus tard
|
||||
*/
|
||||
function translateText(string $text, string $sourceLang, string $targetLang): string
|
||||
{
|
||||
$text = trim($text);
|
||||
if ($text === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$sourceLang = strtoupper($sourceLang);
|
||||
$targetLang = strtoupper($targetLang);
|
||||
|
||||
if ($sourceLang === $targetLang) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
if (! defined('DEEPL_API_KEY') || DEEPL_API_KEY === '') {
|
||||
throw new RuntimeException('Clé API DeepL manquante.');
|
||||
}
|
||||
|
||||
$endpoint = 'https://api-free.deepl.com/v2/translate';
|
||||
|
||||
$postFields = http_build_query([
|
||||
'text' => $text,
|
||||
'source_lang' => $sourceLang,
|
||||
'target_lang' => $targetLang,
|
||||
]);
|
||||
|
||||
$ch = curl_init($endpoint);
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_POSTFIELDS => $postFields,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_TIMEOUT => 20,
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'Authorization: DeepL-Auth-Key ' . DEEPL_API_KEY,
|
||||
'Content-Type: application/x-www-form-urlencoded',
|
||||
],
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$curlErr = curl_error($ch);
|
||||
curl_close($ch);
|
||||
|
||||
if ($response === false || $curlErr) {
|
||||
throw new RuntimeException('Erreur réseau DeepL : ' . $curlErr);
|
||||
}
|
||||
|
||||
if ($httpCode < 200 || $httpCode >= 300) {
|
||||
throw new RuntimeException('Erreur DeepL HTTP ' . $httpCode . ' : ' . $response);
|
||||
}
|
||||
|
||||
$data = json_decode($response, true);
|
||||
|
||||
if (
|
||||
! is_array($data)
|
||||
|| empty($data['translations'])
|
||||
|| ! isset($data['translations'][0]['text'])
|
||||
) {
|
||||
throw new RuntimeException('Réponse DeepL invalide.');
|
||||
}
|
||||
|
||||
return trim($data['translations'][0]['text']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Détecte si une traduction est manuelle
|
||||
*/
|
||||
function isManualTranslation(?array $row): bool
|
||||
{
|
||||
return isset($row['statut']) && $row['statut'] === 'manuel';
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronise les traductions à partir de la source RU dans praticien
|
||||
* - ru toujours sync
|
||||
* - fr/en mis à jour seulement si absents ou non manuels
|
||||
*/
|
||||
function syncTranslationsFromSource(PDO $pdo, array $praticien): void
|
||||
{
|
||||
$praticienId = (int) $praticien['id'];
|
||||
|
||||
$ruData = [
|
||||
'nom_affiche' => $praticien['nom'] ?? '',
|
||||
'prenom_affiche' => $praticien['prenom'] ?? '',
|
||||
'ville_affichee' => $praticien['ville'] ?? '',
|
||||
'titre' => $praticien['titre'] ?? '',
|
||||
'specialite' => $praticien['specialite'] ?? '',
|
||||
'presentation' => $praticien['presentation'] ?? '',
|
||||
'disponibilite' => $praticien['disponibilite'] ?? '',
|
||||
'statut' => 'auto',
|
||||
];
|
||||
upsertPraticienTraduction($pdo, $praticienId, 'ru', $ruData);
|
||||
|
||||
foreach (['fr', 'en'] as $langue) {
|
||||
$existing = getPraticienTraduction($pdo, $praticienId, $langue);
|
||||
|
||||
if ($existing && isManualTranslation($existing)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$nomLatin = transliterateToLatin((string) ($praticien['nom'] ?? ''));
|
||||
$prenomLatin = transliterateToLatin((string) ($praticien['prenom'] ?? ''));
|
||||
|
||||
try {
|
||||
$data = [
|
||||
'nom_affiche' => $nomLatin,
|
||||
'prenom_affiche' => $prenomLatin,
|
||||
'ville_affichee' => translateText((string) ($praticien['ville'] ?? ''), 'RU', $langue),
|
||||
'titre' => translateText((string) ($praticien['titre'] ?? ''), 'RU', $langue),
|
||||
'specialite' => translateText((string) ($praticien['specialite'] ?? ''), 'RU', $langue),
|
||||
'presentation' => translateText((string) ($praticien['presentation'] ?? ''), 'RU', $langue),
|
||||
'disponibilite' => translateText((string) ($praticien['disponibilite'] ?? ''), 'RU', $langue),
|
||||
'statut' => 'auto',
|
||||
];
|
||||
} catch (Throwable $e) {
|
||||
error_log('DeepL translation error [' . $langue . '] praticien_id=' . $praticienId . ' : ' . $e->getMessage());
|
||||
//die($e->getMessage());
|
||||
|
||||
$data = [
|
||||
'nom_affiche' => $nomLatin,
|
||||
'prenom_affiche' => $prenomLatin,
|
||||
'ville_affichee' => (string) ($praticien['ville'] ?? ''),
|
||||
'titre' => (string) ($praticien['titre'] ?? ''),
|
||||
'specialite' => (string) ($praticien['specialite'] ?? ''),
|
||||
'presentation' => (string) ($praticien['presentation'] ?? ''),
|
||||
'disponibilite' => (string) ($praticien['disponibilite'] ?? ''),
|
||||
'statut' => 'erreur',
|
||||
];
|
||||
}
|
||||
|
||||
upsertPraticienTraduction($pdo, $praticienId, $langue, $data);
|
||||
}
|
||||
}
|
||||
|
||||
// Base praticien
|
||||
$stmt = $pdo->prepare("SELECT * FROM praticien WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$praticien = $stmt->fetch();
|
||||
|
||||
if (! $praticien) {
|
||||
die(htmlspecialchars($translations['praticien_introuvable'] ?? 'Introuvable.'));
|
||||
}
|
||||
}
|
||||
|
||||
// ==== Traitement POST avant tout output ====
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// Traduction langue courante
|
||||
$traduction = getPraticienTraduction($pdo, (int) $id, $currentLang);
|
||||
|
||||
// Valeurs formulaire avec fallback
|
||||
$formNom = $traduction['nom_affiche'] ?? $praticien['nom'] ?? '';
|
||||
$formPrenom = $traduction['prenom_affiche'] ?? $praticien['prenom'] ?? '';
|
||||
$formVilleAffichee = $traduction['ville_affichee'] ?? $praticien['ville'] ?? '';
|
||||
$formTitre = $traduction['titre'] ?? $praticien['titre'] ?? '';
|
||||
$formSpecialite = $traduction['specialite'] ?? $praticien['specialite'] ?? '';
|
||||
$formPresentation = $traduction['presentation'] ?? $praticien['presentation'] ?? '';
|
||||
$formDispo = $traduction['disponibilite'] ?? $praticien['disponibilite'] ?? '';
|
||||
|
||||
// ==== POST ====
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
require_post_csrf();
|
||||
$titre = trim($_POST['titre'] ?? '');
|
||||
$nom = trim($_POST['nom'] ?? '');
|
||||
$prenom = trim($_POST['prenom'] ?? '');
|
||||
$nomAffiche = trim($_POST['nom'] ?? '');
|
||||
$prenomAffiche = trim($_POST['prenom'] ?? '');
|
||||
$telephone = trim($_POST['telephone'] ?? '');
|
||||
$specialite = trim($_POST['specialite'] ?? '');
|
||||
$adresse = trim($_POST['adresse'] ?? '');
|
||||
$ville = trim($_POST['ville'] ?? '');
|
||||
$code_postal = trim($_POST['code_postal'] ?? '');
|
||||
$presentation = trim($_POST['presentation'] ?? '');
|
||||
$duree_rdv = (int)($_POST['duree_rdv'] ?? 60);
|
||||
$duree_rdv = (int) ($_POST['duree_rdv'] ?? 60);
|
||||
$disponibilite = trim($_POST['disponibilite'] ?? '');
|
||||
$photo = $praticien['photo'] ?? null;
|
||||
|
||||
if ($specialite === '' || $presentation === '') {
|
||||
die(htmlspecialchars($translations['err_champs_obligatoires'] ?? 'Merci de remplir les champs obligatoires.'));
|
||||
}
|
||||
|
||||
// En FR/EN on ignore tout update des champs globaux même si quelqu’un bidouille le HTML
|
||||
if (! $isRu) {
|
||||
$telephone = $praticien['telephone'] ?? '';
|
||||
$adresse = $praticien['adresse'] ?? '';
|
||||
$ville = $praticien['ville'] ?? '';
|
||||
$code_postal = $praticien['code_postal'] ?? '';
|
||||
$duree_rdv = (int) ($praticien['duree_rdv'] ?? 60);
|
||||
}
|
||||
|
||||
// Upload photo : uniquement RU
|
||||
if ($isRu && ! empty($_FILES['photo']['tmp_name'])) {
|
||||
$file = $_FILES['photo'];
|
||||
$maxSize = 5 * 1024 * 1024;
|
||||
|
||||
// --- BLOC UPLOAD SÉCURISÉ ---
|
||||
if (!empty($_FILES['photo']['tmp_name'])) {
|
||||
$file = $_FILES['photo'];
|
||||
$maxSize = 5 * 1024 * 1024; // 5 Mo
|
||||
|
||||
// 1. Vérification de la taille
|
||||
if ($file['size'] > $maxSize) {
|
||||
die("Erreur : Le fichier est trop volumineux (max 5 Mo).");
|
||||
}
|
||||
|
||||
// 2. Vérification du type réel (MIME) pour bloquer les faux fichiers
|
||||
$finfo = new finfo(FILEINFO_MIME_TYPE);
|
||||
$mimeType = $finfo->file($file['tmp_name']);
|
||||
$finfo = new finfo(FILEINFO_MIME_TYPE);
|
||||
$mimeType = $finfo->file($file['tmp_name']);
|
||||
$allowedMimeTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
|
||||
|
||||
if (!in_array($mimeType, $allowedMimeTypes)) {
|
||||
if (! in_array($mimeType, $allowedMimeTypes, true)) {
|
||||
die("Erreur : Type de fichier non autorisé (Seuls JPG, PNG, GIF et WEBP sont acceptés).");
|
||||
}
|
||||
|
||||
// 3. Préparation du nom et du chemin
|
||||
$nom_nettoye = strtolower(preg_replace('/[^A-Za-z0-9]/', '', $nom));
|
||||
$prenom_nettoye = strtolower(preg_replace('/[^A-Za-z0-9]/', '', $prenom));
|
||||
$nom_nettoye = strtolower(preg_replace('/[^A-Za-z0-9]/', '', transliterateToLatin($nomAffiche)));
|
||||
$prenom_nettoye = strtolower(preg_replace('/[^A-Za-z0-9]/', '', transliterateToLatin($prenomAffiche)));
|
||||
$nouveau_nom_fichier = $nom_nettoye . '_' . $prenom_nettoye . '_' . time() . '.png';
|
||||
$chemin_destination = __DIR__ . '/../uploads/' . $nouveau_nom_fichier;
|
||||
$chemin_destination = __DIR__ . '/../uploads/' . $nouveau_nom_fichier;
|
||||
|
||||
// 4. Traitement de l'image (Conversion & Redimensionnement)
|
||||
$image_source = @imagecreatefromstring(file_get_contents($file['tmp_name']));
|
||||
|
||||
if ($image_source) {
|
||||
list($largeur_orig, $hauteur_orig) = getimagesize($file['tmp_name']);
|
||||
$largeur_max = 800;
|
||||
|
||||
if ($largeur_orig > $largeur_max) {
|
||||
$ratio = $largeur_max / $largeur_orig;
|
||||
$nouvelle_largeur = $largeur_max;
|
||||
$nouvelle_hauteur = (int)($hauteur_orig * $ratio);
|
||||
} else {
|
||||
$nouvelle_largeur = $largeur_orig;
|
||||
$nouvelle_hauteur = $hauteur_orig;
|
||||
}
|
||||
|
||||
$image_dest = imagecreatetruecolor($nouvelle_largeur, $nouvelle_hauteur);
|
||||
imagealphablending($image_dest, false);
|
||||
imagesavealpha($image_dest, true);
|
||||
|
||||
imagecopyresampled($image_dest, $image_source, 0, 0, 0, 0, $nouvelle_largeur, $nouvelle_hauteur, $largeur_orig, $hauteur_orig);
|
||||
|
||||
// Sauvegarde effective
|
||||
if (imagepng($image_dest, $chemin_destination, 7)) {
|
||||
// Suppression de l'ancienne photo si elle existe
|
||||
if (!empty($praticien['photo'])) {
|
||||
$ancien_chemin = __DIR__ . '/../uploads/' . $praticien['photo'];
|
||||
if (file_exists($ancien_chemin)) {
|
||||
unlink($ancien_chemin);
|
||||
}
|
||||
}
|
||||
$photo = $nouveau_nom_fichier;
|
||||
}
|
||||
|
||||
imagedestroy($image_source);
|
||||
imagedestroy($image_dest);
|
||||
} else {
|
||||
if (! $image_source) {
|
||||
die("Erreur : Le fichier image semble corrompu.");
|
||||
}
|
||||
}
|
||||
|
||||
// SIRET - normalisation + vérifs
|
||||
$siret = preg_replace('/\D/', '', $_POST['siret'] ?? '');
|
||||
if (strlen($siret) !== 14) {
|
||||
die(htmlspecialchars($translations['siret_format_invalide'] ?? 'SIRET invalide (14 chiffres).'));
|
||||
}
|
||||
// Luhn
|
||||
$luhnOk = (function($num){
|
||||
$sum=0; $alt=false;
|
||||
for ($i=strlen($num)-1; $i>=0; $i--){
|
||||
$n=(int)$num[$i];
|
||||
if($alt){ $n*=2; if($n>9)$n-=9; }
|
||||
$sum+=$n; $alt=!$alt;
|
||||
[$largeur_orig, $hauteur_orig] = getimagesize($file['tmp_name']);
|
||||
$largeur_max = 800;
|
||||
|
||||
if ($largeur_orig > $largeur_max) {
|
||||
$ratio = $largeur_max / $largeur_orig;
|
||||
$nouvelle_largeur = $largeur_max;
|
||||
$nouvelle_hauteur = (int) ($hauteur_orig * $ratio);
|
||||
} else {
|
||||
$nouvelle_largeur = $largeur_orig;
|
||||
$nouvelle_hauteur = $hauteur_orig;
|
||||
}
|
||||
return $sum%10===0;
|
||||
})($siret);
|
||||
if (!$luhnOk) {
|
||||
die(htmlspecialchars($translations['siret_format_invalide'] ?? 'SIRET invalide (Luhn).'));
|
||||
|
||||
$image_dest = imagecreatetruecolor($nouvelle_largeur, $nouvelle_hauteur);
|
||||
imagealphablending($image_dest, false);
|
||||
imagesavealpha($image_dest, true);
|
||||
|
||||
imagecopyresampled(
|
||||
$image_dest,
|
||||
$image_source,
|
||||
0, 0, 0, 0,
|
||||
$nouvelle_largeur,
|
||||
$nouvelle_hauteur,
|
||||
$largeur_orig,
|
||||
$hauteur_orig
|
||||
);
|
||||
|
||||
if (imagepng($image_dest, $chemin_destination, 7)) {
|
||||
if (! empty($praticien['photo'])) {
|
||||
$ancien_chemin = __DIR__ . '/../uploads/' . $praticien['photo'];
|
||||
if (file_exists($ancien_chemin)) {
|
||||
unlink($ancien_chemin);
|
||||
}
|
||||
}
|
||||
$photo = $nouveau_nom_fichier;
|
||||
}
|
||||
|
||||
imagedestroy($image_source);
|
||||
imagedestroy($image_dest);
|
||||
}
|
||||
|
||||
// Unicité SIRET (exclure l'utilisateur courant)
|
||||
$chk = $pdo->prepare("SELECT id FROM praticien WHERE siret = :s AND id <> :id LIMIT 1");
|
||||
$chk->execute(['s' => $siret, 'id' => $id]);
|
||||
if ($chk->fetch()) {
|
||||
die(htmlspecialchars($translations['err_siret_deja_utilise'] ?? 'Ce SIRET est déjà utilisé.'));
|
||||
$pdo->beginTransaction();
|
||||
|
||||
try {
|
||||
if ($isRu) {
|
||||
$siret = preg_replace('/\D/', '', $_POST['siret'] ?? '');
|
||||
|
||||
if (strlen($siret) !== 14) {
|
||||
throw new RuntimeException($translations['siret_format_invalide'] ?? 'SIRET invalide (14 chiffres).');
|
||||
}
|
||||
|
||||
$luhnOk = (function ($num) {
|
||||
$sum = 0;
|
||||
$alt = false;
|
||||
for ($i = strlen($num) - 1; $i >= 0; $i--) {
|
||||
$n = (int) $num[$i];
|
||||
if ($alt) {
|
||||
$n *= 2;
|
||||
if ($n > 9) {
|
||||
$n -= 9;
|
||||
}
|
||||
|
||||
}
|
||||
$sum += $n;
|
||||
$alt = ! $alt;
|
||||
}
|
||||
return $sum % 10 === 0;
|
||||
})($siret);
|
||||
|
||||
if (! $luhnOk) {
|
||||
throw new RuntimeException($translations['siret_format_invalide'] ?? 'SIRET invalide (Luhn).');
|
||||
}
|
||||
|
||||
$chk = $pdo->prepare("SELECT id FROM praticien WHERE siret = :s AND id <> :id LIMIT 1");
|
||||
$chk->execute(['s' => $siret, 'id' => $id]);
|
||||
if ($chk->fetch()) {
|
||||
throw new RuntimeException($translations['err_siret_deja_utilise'] ?? 'Ce SIRET est déjà utilisé.');
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
UPDATE praticien SET
|
||||
titre = :titre,
|
||||
nom = :nom,
|
||||
prenom = :prenom,
|
||||
telephone = :telephone,
|
||||
specialite = :specialite,
|
||||
adresse = :adresse,
|
||||
ville = :ville,
|
||||
code_postal = :code_postal,
|
||||
presentation = :presentation,
|
||||
photo = :photo,
|
||||
disponibilite = :disponibilite,
|
||||
duree_rdv = :duree_rdv,
|
||||
siret = :siret,
|
||||
langue_source = 'ru'
|
||||
WHERE id = :id
|
||||
");
|
||||
$stmt->execute([
|
||||
'titre' => $titre,
|
||||
'nom' => $nomAffiche,
|
||||
'prenom' => $prenomAffiche,
|
||||
'telephone' => $telephone,
|
||||
'specialite' => $specialite,
|
||||
'adresse' => $adresse,
|
||||
'ville' => $ville,
|
||||
'code_postal' => $code_postal,
|
||||
'presentation' => $presentation,
|
||||
'photo' => $photo,
|
||||
'disponibilite' => $disponibilite,
|
||||
'duree_rdv' => $duree_rdv,
|
||||
'siret' => $siret,
|
||||
'id' => $id,
|
||||
]);
|
||||
|
||||
// Recharge la source après update
|
||||
$stmt = $pdo->prepare("SELECT * FROM praticien WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$praticien = $stmt->fetch();
|
||||
|
||||
if (! $praticien) {
|
||||
throw new RuntimeException('Praticien introuvable après mise à jour.');
|
||||
}
|
||||
|
||||
syncTranslationsFromSource($pdo, $praticien);
|
||||
} else {
|
||||
upsertPraticienTraduction($pdo, (int) $id, $currentLang, [
|
||||
'nom_affiche' => $nomAffiche,
|
||||
'prenom_affiche' => $prenomAffiche,
|
||||
'ville_affichee' => $traduction['ville_affichee'] ?? $praticien['ville'] ?? '',
|
||||
'titre' => $titre,
|
||||
'specialite' => $specialite,
|
||||
'presentation' => $presentation,
|
||||
'disponibilite' => $disponibilite,
|
||||
'statut' => 'manuel',
|
||||
]);
|
||||
}
|
||||
|
||||
$pdo->commit();
|
||||
} catch (Throwable $e) {
|
||||
if ($pdo->inTransaction()) {
|
||||
$pdo->rollBack();
|
||||
}
|
||||
die(htmlspecialchars($e->getMessage()));
|
||||
}
|
||||
|
||||
// Mise à jour
|
||||
$stmt = $pdo->prepare("
|
||||
UPDATE praticien SET
|
||||
titre = :titre,
|
||||
nom = :nom,
|
||||
prenom = :prenom,
|
||||
telephone = :telephone,
|
||||
specialite = :specialite,
|
||||
adresse = :adresse,
|
||||
ville = :ville,
|
||||
code_postal = :code_postal,
|
||||
presentation = :presentation,
|
||||
photo = :photo,
|
||||
disponibilite = :disponibilite,
|
||||
duree_rdv = :duree_rdv,
|
||||
siret = :siret
|
||||
WHERE id = :id
|
||||
");
|
||||
$stmt->execute([
|
||||
'titre' => $titre,
|
||||
'nom' => $nom,
|
||||
'prenom' => $prenom,
|
||||
'telephone' => $telephone,
|
||||
'specialite' => $specialite,
|
||||
'adresse' => $adresse,
|
||||
'ville' => $ville,
|
||||
'code_postal' => $code_postal,
|
||||
'presentation' => $presentation,
|
||||
'photo' => $photo,
|
||||
'disponibilite' => $disponibilite,
|
||||
'duree_rdv' => $duree_rdv,
|
||||
'siret' => $siret,
|
||||
'id' => $id,
|
||||
]);
|
||||
|
||||
// Redirection ABSOLUE (ou "informations.php" si même dossier)
|
||||
header('Location: /public/praticien/informations.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$PAGE_TITLE = $translations['modifier_infos_title'];
|
||||
$HEAD_EXTRA = <<<HTML
|
||||
<style>
|
||||
.message-erreur {
|
||||
color: red;
|
||||
font-size: 0.9em;
|
||||
display: none;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
$PAGE_TITLE = $translations['modifier_infos_title'];
|
||||
$HEAD_EXTRA = <<<HTML
|
||||
<style>
|
||||
.message-erreur {
|
||||
color: red;
|
||||
font-size: 0.9em;
|
||||
display: none;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
HTML;
|
||||
// ==== À partir d’ici, on peut afficher ====
|
||||
require_once __DIR__ . '/../includes/header.php';
|
||||
|
||||
require_once __DIR__ . '/../includes/header.php';
|
||||
?>
|
||||
|
||||
<div class="main1">
|
||||
<div class="container py-5">
|
||||
<form id="form-praticien-edit" method="POST" enctype="multipart/form-data" class="shadow p-4 rounded bg-light">
|
||||
<h2 class="text-center mb-4"><?= htmlspecialchars($translations['modifier_infos_title']) ?></h2>
|
||||
<input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars(ensure_csrf_token(), ENT_QUOTES, 'UTF-8'); ?>">
|
||||
<h2 class="text-center mb-4"><?php echo htmlspecialchars($translations['modifier_infos_title']) ?></h2>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?= htmlspecialchars($translations['label_nom']) ?> *</label>
|
||||
<input type="text" name="nom" class="form-control" value="<?= htmlspecialchars($praticien['nom']?? '') ?>" required>
|
||||
<label class="form-label"><?php echo htmlspecialchars($translations['label_nom']) ?> *</label>
|
||||
<input type="text" name="nom" class="form-control" value="<?php echo htmlspecialchars($formNom) ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?= htmlspecialchars($translations['label_prenom']) ?> *</label>
|
||||
<input type="text" name="prenom" class="form-control" value="<?= htmlspecialchars($praticien['prenom']?? '') ?>" required>
|
||||
<label class="form-label"><?php echo htmlspecialchars($translations['label_prenom']) ?> *</label>
|
||||
<input type="text" name="prenom" class="form-control" value="<?php echo htmlspecialchars($formPrenom) ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?= htmlspecialchars($translations['label_telephone']) ?> *</label>
|
||||
<input type="tel" name="telephone" id="telephone" class="form-control" value="<?= htmlspecialchars($praticien['telephone']?? '') ?>" required placeholder="+33600000000"
|
||||
|
||||
pattern="^\+?[1-9]\d{6,14}$"
|
||||
title="<?=htmlspecialchars($translations['telephone_format_message']?? '') ?>">
|
||||
<label class="form-label"><?php echo htmlspecialchars($translations['label_telephone']) ?> *</label>
|
||||
<input type="tel" name="telephone" id="telephone" class="form-control"
|
||||
value="<?php echo htmlspecialchars($praticien['telephone'] ?? '') ?>"
|
||||
required
|
||||
placeholder="+33600000000"
|
||||
pattern="^\+?[1-9]\d{6,14}$"
|
||||
title="<?php echo htmlspecialchars($translations['telephone_format_message'] ?? '') ?>"
|
||||
<?php echo $ro; ?>>
|
||||
</div>
|
||||
<!-- Champ SIREN/SIRET -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?= htmlspecialchars($translations['placeholder_siret']) ?> *</label>
|
||||
<input type="text"
|
||||
name="siret"
|
||||
id="siret"
|
||||
class="form-control"
|
||||
value="<?= htmlspecialchars($praticien['siret']?? '') ?>"
|
||||
required
|
||||
maxlength="17"
|
||||
inputmode="numeric"
|
||||
pattern="[0-9 ]+">
|
||||
<div id="siret-feedback" class="message-erreur" style="display:none;"></div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?= htmlspecialchars($translations['label_specialite']) ?> *</label>
|
||||
<input type="text" name="specialite" class="form-control" value="<?= htmlspecialchars($praticien['specialite']?? '') ?>" required>
|
||||
<label class="form-label"><?php echo htmlspecialchars($translations['placeholder_siret']) ?> *</label>
|
||||
<input type="text"
|
||||
name="siret"
|
||||
id="siret"
|
||||
class="form-control"
|
||||
value="<?php echo htmlspecialchars($praticien['siret'] ?? '') ?>"
|
||||
required
|
||||
maxlength="17"
|
||||
inputmode="numeric"
|
||||
pattern="[0-9 ]+"
|
||||
>
|
||||
<div id="siret-feedback" class="message-erreur" style="display:none;"></div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?= htmlspecialchars($translations['tarif_consultation']) ?></label>
|
||||
<input type="text" name="titre" class="form-control" value="<?= htmlspecialchars($praticien['titre']?? '') ?>">
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?php echo htmlspecialchars($translations['label_specialite']) ?> *</label>
|
||||
<input type="text" name="specialite" class="form-control" value="<?php echo htmlspecialchars($formSpecialite) ?>" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?= htmlspecialchars($translations['moyens_payement']) ?></label>
|
||||
<input type="text" name="disponibilite" class="form-control" value="<?= htmlspecialchars($praticien['disponibilite']?? '') ?>">
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?php echo htmlspecialchars($translations['tarif_consultation']) ?></label>
|
||||
<input type="text" name="titre" class="form-control" value="<?php echo htmlspecialchars($formTitre) ?>">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?php echo htmlspecialchars($translations['moyens_payement']) ?></label>
|
||||
<input type="text" name="disponibilite" class="form-control" value="<?php echo htmlspecialchars($formDispo) ?>">
|
||||
</div>
|
||||
|
||||
<div class="mb-3 position-relative">
|
||||
<label class="form-label"><?= htmlspecialchars($translations['label_adresse']) ?></label>
|
||||
<textarea name="adresse" id="adresse" class="form-control"><?= htmlspecialchars($praticien['adresse']?? '') ?></textarea>
|
||||
<label class="form-label"><?php echo htmlspecialchars($translations['label_adresse']) ?></label>
|
||||
<textarea name="adresse" id="adresse" class="form-control" <?php echo $ro; ?>><?php echo htmlspecialchars($praticien['adresse'] ?? '') ?></textarea>
|
||||
<ul id="suggestions"></ul>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?= htmlspecialchars($translations['label_ville']) ?></label>
|
||||
<input type="text" name="ville" id="ville" class="form-control" value="<?= htmlspecialchars($praticien['ville']?? '') ?>">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?= htmlspecialchars($translations['label_code_postal']) ?></label>
|
||||
<input type="text" name="code_postal" id="code_postal" class="form-control" value="<?= htmlspecialchars($praticien['code_postal']?? '') ?>">
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?= htmlspecialchars($translations['label_presentation']) ?></label>
|
||||
<textarea name="presentation" class="form-control"><?= htmlspecialchars($praticien['presentation']?? '') ?></textarea>
|
||||
<label class="form-label"><?php echo htmlspecialchars($translations['label_ville']) ?></label>
|
||||
<input type="text" name="ville" id="ville" class="form-control"
|
||||
value="<?php echo htmlspecialchars($praticien['ville'] ?? '') ?>" readonly>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?= htmlspecialchars($translations['label_duree_rdv']) ?></label>
|
||||
<input type="number" name="duree_rdv" class="form-control" value="<?= $praticien['duree_rdv'] ?>" min="15" max="180" required>
|
||||
<label class="form-label"><?php echo htmlspecialchars($translations['label_code_postal']) ?></label>
|
||||
<input type="text" name="code_postal" id="code_postal" class="form-control"
|
||||
value="<?php echo htmlspecialchars($praticien['code_postal'] ?? '') ?>"
|
||||
<?php echo $ro; ?>>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?= htmlspecialchars($translations['label_photo']) ?></label>
|
||||
<input type="file" name="photo" class="form-control" accept="image/*">
|
||||
<label class="form-label"><?php echo htmlspecialchars($translations['label_presentation']) ?> *</label>
|
||||
<textarea name="presentation" class="form-control" required><?php echo htmlspecialchars($formPresentation) ?></textarea>
|
||||
</div>
|
||||
|
||||
<?php if ($praticien['photo']): ?>
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?php echo htmlspecialchars($translations['label_duree_rdv']) ?></label>
|
||||
<input type="number" name="duree_rdv" class="form-control"
|
||||
value="<?php echo (int) ($praticien['duree_rdv'] ?? 60); ?>"
|
||||
min="15" max="180" required
|
||||
<?php echo $ro; ?>>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><?php echo htmlspecialchars($translations['label_photo']) ?></label>
|
||||
<input type="file" name="photo" class="form-control" accept="image/*" <?php echo $dis; ?>>
|
||||
</div>
|
||||
|
||||
<?php if (! empty($praticien['photo'])): ?>
|
||||
<div class="mb-3">
|
||||
<p><?= htmlspecialchars($translations['photo_actuelle']) ?></p>
|
||||
<img src="/public/uploads/<?= htmlspecialchars($praticien['photo']) ?>" class="img-fluid rounded-4 shadow" style="width:230px;height:auto;">
|
||||
<p><?php echo htmlspecialchars($translations['photo_actuelle']) ?></p>
|
||||
<img src="/public/uploads/<?php echo htmlspecialchars($praticien['photo']) ?>"
|
||||
class="img-fluid rounded-4 shadow"
|
||||
style="width:230px;height:auto;">
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="mt-4 text-center">
|
||||
<button type="submit" class="btn btn-primary"><?= htmlspecialchars($translations['btn_enregistrer']) ?></button>
|
||||
|
||||
|
||||
<div class="mt-4 text-center">
|
||||
<button type="submit" class="btn btn-primary"><?php echo htmlspecialchars($translations['btn_enregistrer']) ?></button>
|
||||
</div>
|
||||
<?= $translations['champs_obligatoire'] ?>
|
||||
|
||||
|
||||
<?php echo $translations['champs_obligatoire'] ?>
|
||||
</form>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
// === Téléphone: simple & efficace ===
|
||||
const tel = document.getElementById('telephone');
|
||||
|
||||
// 1) Nettoyage en direct (espaces, tirets, points, parenthèses)
|
||||
tel?.addEventListener('input', function () {
|
||||
const pos = this.selectionStart;
|
||||
this.value = this.value.replace(/[\s\-._()/]/g, '');
|
||||
try { this.setSelectionRange(pos, pos); } catch(_) {}
|
||||
});
|
||||
|
||||
// 2) Normalisation au blur
|
||||
tel?.addEventListener('blur', function() {
|
||||
let val = this.value.trim().replace(/[\s\-._()/]/g, '');
|
||||
if (val.startsWith('00')) val = '+' + val.slice(2);
|
||||
@@ -292,7 +620,6 @@ tel?.addEventListener('blur', function() {
|
||||
this.value = val;
|
||||
});
|
||||
|
||||
// 3) Au submit : applique la normalisation même si l’utilisateur n’a pas quitté le champ
|
||||
tel?.form?.addEventListener('submit', function (e) {
|
||||
tel.dispatchEvent(new Event('blur'));
|
||||
if (!tel.checkValidity()) {
|
||||
@@ -304,23 +631,24 @@ tel?.form?.addEventListener('submit', function (e) {
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const adresseInput = document.getElementById("adresse");
|
||||
const villeInput = document.getElementById("ville");
|
||||
const cpInput = document.getElementById("code_postal");
|
||||
const suggestions = document.getElementById("suggestions");
|
||||
const villeInput = document.getElementById("ville");
|
||||
const cpInput = document.getElementById("code_postal");
|
||||
const suggestions = document.getElementById("suggestions");
|
||||
|
||||
if (adresseInput.hasAttribute('readonly')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// petite fonction utilitaire : construit "numero + rue"
|
||||
function buildStreet(props) {
|
||||
const num = (props.housenumber || '').trim();
|
||||
const street = (props.street || props.name || '').trim();
|
||||
return [num, street].filter(Boolean).join(' ');
|
||||
}
|
||||
// fallback ville si city manquant (rare)
|
||||
|
||||
function getCity(props) {
|
||||
if (props.city) return props.city;
|
||||
// ex: "84160, Cucuron, Vaucluse, Provence-Alpes-Côte d'Azur"
|
||||
if (props.context) {
|
||||
const parts = props.context.split(',').map(s => s.trim());
|
||||
// généralement la 2e valeur correspond à la commune
|
||||
return parts[1] || parts[0] || '';
|
||||
}
|
||||
return '';
|
||||
@@ -335,7 +663,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
return;
|
||||
}
|
||||
|
||||
// annule la requête précédente si on retape vite
|
||||
try { abortCtrl?.abort(); } catch(_) {}
|
||||
abortCtrl = new AbortController();
|
||||
|
||||
@@ -352,9 +679,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
li.textContent = props.label || buildStreet(props);
|
||||
|
||||
li.addEventListener("click", function () {
|
||||
// ✅ Adresse = seulement numéro + rue
|
||||
adresseInput.value = buildStreet(props);
|
||||
// ✅ Ville + CP séparés
|
||||
villeInput.value = getCity(props);
|
||||
cpInput.value = props.postcode || '';
|
||||
suggestions.innerHTML = '';
|
||||
@@ -366,7 +691,6 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
.catch(() => {});
|
||||
});
|
||||
|
||||
// clic hors zone -> ferme la liste
|
||||
document.addEventListener("click", function (e) {
|
||||
if (!suggestions.contains(e.target) && e.target !== adresseInput) {
|
||||
suggestions.innerHTML = '';
|
||||
@@ -375,11 +699,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
});
|
||||
</script>
|
||||
|
||||
<!--***********************************************************
|
||||
Verification ajax pour SIRET
|
||||
**************************************************************-->
|
||||
<script>
|
||||
// Luhn SIRET
|
||||
function luhnCheck(num) {
|
||||
const arr = (num + '').split('').reverse().map(x => parseInt(x, 10));
|
||||
const sum = arr.reduce((acc, val, i) => {
|
||||
@@ -390,21 +710,24 @@ function luhnCheck(num) {
|
||||
}
|
||||
|
||||
(function(){
|
||||
const form = document.getElementById('form-praticien-edit'); // <-- bon id
|
||||
const form = document.getElementById('form-praticien-edit');
|
||||
const siretInput = document.getElementById('siret');
|
||||
const feedback = document.getElementById('siret-feedback');
|
||||
|
||||
// init
|
||||
if (!siretInput || siretInput.hasAttribute('readonly')) {
|
||||
return;
|
||||
}
|
||||
|
||||
form.dataset.siretExists = '0';
|
||||
let debounceId = null;
|
||||
let lastQueried = '';
|
||||
|
||||
const MSG = {
|
||||
invalide: '<?= addslashes($translations["siret_format_invalide"] ?? "Numéro SIRET invalide.") ?>',
|
||||
valide: '<?= addslashes($translations["siret_valide_format"] ?? "Format SIRET valide.") ?>',
|
||||
existe: '<?= addslashes($translations["siret_trouve"] ?? "Numéro reconnu dans la base INSEE.") ?>',
|
||||
nexiste: '<?= addslashes($translations["siret_non_trouve"] ?? "Numéro introuvable dans la base INSEE.") ?>',
|
||||
attente: '<?= addslashes($translations["siret_verification_en_cours"] ?? "Vérification en cours…") ?>'
|
||||
invalide: '<?php echo addslashes($translations["siret_format_invalide"] ?? "Numéro SIRET invalide.") ?>',
|
||||
valide: '<?php echo addslashes($translations["siret_valide_format"] ?? "Format SIRET valide.") ?>',
|
||||
existe: '<?php echo addslashes($translations["siret_trouve"] ?? "Numéro reconnu dans la base INSEE.") ?>',
|
||||
nexiste: '<?php echo addslashes($translations["siret_non_trouve"] ?? "Numéro introuvable dans la base INSEE.") ?>',
|
||||
attente: '<?php echo addslashes($translations["siret_verification_en_cours"] ?? "Vérification en cours…") ?>'
|
||||
};
|
||||
|
||||
function formatSiret(value) {
|
||||
@@ -414,13 +737,13 @@ function luhnCheck(num) {
|
||||
if (value.length > 11) value = value.slice(0,11) + ' ' + value.slice(11);
|
||||
return value;
|
||||
}
|
||||
|
||||
function setFeedback(text, color) {
|
||||
feedback.textContent = text;
|
||||
feedback.style.color = color;
|
||||
feedback.style.display = 'block';
|
||||
}
|
||||
|
||||
// Pré-formate la valeur initiale si elle est brute (14 chiffres)
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
if (/^\d{14}$/.test(siretInput.value)) {
|
||||
siretInput.value = formatSiret(siretInput.value);
|
||||
@@ -428,7 +751,6 @@ function luhnCheck(num) {
|
||||
});
|
||||
|
||||
function checkSiretImmediate() {
|
||||
// formatage visuel
|
||||
const formatted = formatSiret(siretInput.value);
|
||||
if (siretInput.value !== formatted) siretInput.value = formatted;
|
||||
|
||||
@@ -446,7 +768,7 @@ function luhnCheck(num) {
|
||||
|
||||
clearTimeout(debounceId);
|
||||
debounceId = setTimeout(() => {
|
||||
fetch('/../../js/ajax_verif_siret.php?siret=' + encodeURIComponent(raw)) // <-- chemin ABSOLU
|
||||
fetch('/../../js/ajax_verif_siret.php?siret=' + encodeURIComponent(raw))
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data && data.exists) {
|
||||
@@ -466,7 +788,6 @@ function luhnCheck(num) {
|
||||
|
||||
siretInput.addEventListener('input', checkSiretImmediate);
|
||||
|
||||
// Normalise AVANT envoi (supprime les espaces)
|
||||
form.addEventListener('submit', function(e){
|
||||
const raw = siretInput.value.replace(/\s+/g, '');
|
||||
if (raw.length !== 14 || !luhnCheck(raw)) {
|
||||
@@ -475,9 +796,7 @@ function luhnCheck(num) {
|
||||
siretInput.focus();
|
||||
return;
|
||||
}
|
||||
siretInput.value = raw; // <- on poste 14 chiffres à PHP
|
||||
// Si tu veux forcer l’existence INSEE côté front, décommente :
|
||||
// if (form.dataset.siretExists !== '1') { e.preventDefault(); setFeedback(MSG.nexiste, 'red'); siretInput.focus(); }
|
||||
siretInput.value = raw;
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
@@ -485,7 +804,7 @@ function luhnCheck(num) {
|
||||
</div>
|
||||
<footer class="site-footer">
|
||||
<div class="container">
|
||||
<p><?= $translations['copyr'] ?></p>
|
||||
<p><?php echo $translations['copyr'] ?></p>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
require_once __DIR__ . '/../includes/init_praticien.php';
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
|
||||
echo json_encode([
|
||||
'ok' => false,
|
||||
'message' => 'Méthode non autorisée.',
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
require_post_csrf();
|
||||
|
||||
$praticien_id = (int) ($_SESSION['reference_id'] ?? 0);
|
||||
if ($praticien_id <= 0) {
|
||||
echo json_encode([
|
||||
'ok' => false,
|
||||
'message' => 'Praticien non autorisé.',
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
$id = (int) ($_POST['id'] ?? 0);
|
||||
if ($id <= 0) {
|
||||
echo json_encode([
|
||||
'ok' => false,
|
||||
'message' => 'ID invalide.',
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$check = $pdo->prepare("
|
||||
SELECT id, praticien_id
|
||||
FROM disponibilite
|
||||
WHERE id = ?
|
||||
LIMIT 1
|
||||
");
|
||||
$check->execute([$id]);
|
||||
$slot = $check->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (! $slot) {
|
||||
echo json_encode([
|
||||
'ok' => false,
|
||||
'message' => 'Créneau introuvable.',
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ((int) $slot['praticien_id'] !== $praticien_id) {
|
||||
echo json_encode([
|
||||
'ok' => false,
|
||||
'message' => 'Ce créneau ne vous appartient pas.',
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("DELETE FROM disponibilite WHERE id = ? AND praticien_id = ?");
|
||||
$stmt->execute([$id, $praticien_id]);
|
||||
|
||||
echo json_encode([
|
||||
'ok' => ($stmt->rowCount() > 0),
|
||||
'message' => $stmt->rowCount() > 0
|
||||
? 'Créneau supprimé.'
|
||||
: 'Aucune ligne supprimée.',
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
|
||||
} catch (Throwable $e) {
|
||||
error_log('supprimer_disponibilite.php: ' . $e->getMessage());
|
||||
echo json_encode([
|
||||
'ok' => false,
|
||||
'message' => 'Erreur serveur.',
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
declare (strict_types = 1);
|
||||
|
||||
require_once __DIR__ . '/../includes/init_praticien.php';
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
|
||||
echo json_encode([
|
||||
'ok' => false,
|
||||
'message' => 'Méthode non autorisée.',
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
require_post_csrf();
|
||||
|
||||
$praticien_id = (int) ($_SESSION['reference_id'] ?? 0);
|
||||
if ($praticien_id <= 0) {
|
||||
echo json_encode([
|
||||
'ok' => false,
|
||||
'message' => 'Accès refusé.',
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
$id = (int) ($_POST['id'] ?? 0);
|
||||
if ($id <= 0) {
|
||||
echo json_encode([
|
||||
'ok' => false,
|
||||
'message' => 'ID invalide.',
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$check = $pdo->prepare("
|
||||
SELECT id, praticien_id
|
||||
FROM disponibilite_date
|
||||
WHERE id = ?
|
||||
LIMIT 1
|
||||
");
|
||||
$check->execute([$id]);
|
||||
$slot = $check->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (! $slot) {
|
||||
echo json_encode([
|
||||
'ok' => false,
|
||||
'message' => 'Créneau introuvable.',
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ((int) $slot['praticien_id'] !== $praticien_id) {
|
||||
echo json_encode([
|
||||
'ok' => false,
|
||||
'message' => 'Ce créneau ne vous appartient pas.',
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("DELETE FROM disponibilite_date WHERE id = ? AND praticien_id = ?");
|
||||
$stmt->execute([$id, $praticien_id]);
|
||||
|
||||
echo json_encode([
|
||||
'ok' => ($stmt->rowCount() > 0),
|
||||
'message' => $stmt->rowCount() > 0
|
||||
? 'Créneau supprimé.'
|
||||
: 'Aucune ligne supprimée.',
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
|
||||
} catch (Throwable $e) {
|
||||
error_log('praticien/supprimer_disponibilite_date.php: ' . $e->getMessage());
|
||||
echo json_encode([
|
||||
'ok' => false,
|
||||
'message' => 'Erreur serveur.',
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
Reference in new issue
Block a user