Files
2026-03-05 10:25:39 +01:00

320 lines
13 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
// /public/cabinet/invitations.php
require_once __DIR__ . '/../includes/init_praticien.php';
if (!function_exists('h')) { function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); } }
$praticien_id = (int)($_SESSION['reference_id'] ?? 0);
if ($praticien_id<=0) { header('Location:/index.php'); exit; }
// CSRF
if (empty($_SESSION['csrf'])) $_SESSION['csrf']=bin2hex(random_bytes(16));
$csrf = $_SESSION['csrf'];
// Handle POST (invite or toggle)
$msg = '';
if (($_SERVER['REQUEST_METHOD']??'')==='POST' && hash_equals($csrf, $_POST['csrf'] ?? '')) {
if (isset($_POST['action']) && $_POST['action']==='invite') {
$email = trim((string)($_POST['email'] ?? ''));
$can_manage_rdv = !empty($_POST['can_manage_rdv']) ? 1 : 0;
$can_edit_slots = !empty($_POST['can_edit_slots']) ? 1 : 0;
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$msg = $translations['inv_email_invalide'] ?? 'Email invalide.';
} else {
// token & expiration
$token = bin2hex(random_bytes(24));
$expires = (new DateTime('+10 days'))->format('Y-m-d H:i:s');
// Insert invitation (role 'secretaire')
$ins = $pdo->prepare("INSERT INTO invitations (email, role, praticien_id, token, status, expires_at, invited_by)
VALUES (:email,'secretaire',:pid,:tk,'envoyee',:exp,:by)");
$ins->execute([
'email'=>$email,
'pid'=>$praticien_id,
'tk'=>$token,
'exp'=>$expires,
'by'=> (int)($_SESSION['compte_id'] ?? 0),
]);
// Stocker droits sélectionnés côté "mémo" (façon simple : dans token via table dédiée ?)
// Ici on ajoute un petit "mémo" côté invitations.meta_json si tu souhaites :
// Si tu veux, ajoute une colonne meta_json JSON dans invitations. Sinon, on appliquera des droits par défaut à l'acceptation, et on pourra basculer ensuite.
// Pour rester 100% compatible avec ta structure actuelle, on applique par défaut can_manage_rdv=1, can_edit_slots=0, puis on laisse l'UI permettre de modifier après acceptation.
// Envoi email (si tu as un mailer)
if (function_exists('uslugi_mail')) {
$acceptUrl = sprintf(
'%s/public/cabinet/accepter_invitation.php?token=%s',
rtrim((isset($_SERVER['REQUEST_SCHEME']) ? $_SERVER['REQUEST_SCHEME'].'://' : '').($_SERVER['HTTP_HOST']??''), '/'),
$token
);
$subject = $translations['inv_mail_sujet']
?? 'Invitation à rejoindre un cabinet sur uslugi.fr';
$body = '
<div style="font-family:Arial,Helvetica,sans-serif;font-size:15px;color:#333;background:#f9f9fb;padding:20px;">
<div style="max-width:600px;margin:0 auto;background:#fff;border-radius:12px;overflow:hidden;box-shadow:0 2px 10px rgba(0,0,0,.05);">
<!-- Titre -->
<div style="background:#38378B;color:#fff;padding:18px 24px;font-size:18px;font-weight:bold;">
<img src="https://uslugi.fr/public/uploads/img/logo_mail.png"
alt="uslugi.fr" style="max-height:30px;display:block;">
</div>
<!-- Contenu -->
<div style="padding:24px;">
<p>'.h($translations['inv_mail_bonjour'] ?? 'Bonjour,').'</p>
<p>'.
h($translations['inv_mail_intro'] ??
'Vous avez été invité(e) à rejoindre le secrétariat d’un praticien sur uslugi.fr.
Grâce à cet accès, vous pourrez gérer les rendez-vous et organiser l’agenda du cabinet.').
'</p>
<p style="margin:24px 0;text-align:center;">
<a href="'.h($acceptUrl).'"
style="background:#E03C3F;color:#fff;text-decoration:none;
padding:12px 22px;border-radius:999px;font-weight:bold;display:inline-block;">
'.h($translations['inv_mail_btn'] ?? 'Accepter l’invitation').'
</a>
</p>
<p>'.
h($translations['inv_mail_validite'] ??
'Ce lien est valide pendant 10 jours. Passé ce délai, il expirera automatiquement.').
'</p>
<p style="font-size:13px;color:#777;margin-top:24px;">
'.h($translations['inv_mail_ignore'] ??
'Si vous n’êtes pas concerné(e) par cette invitation, vous pouvez ignorer cet email.').'
</p>
</div>
<!-- Footer -->
<div style="background:#f1f1f1;color:#555;padding:12px 24px;font-size:13px;text-align:center;">
'.h($translations['inv_mail_footer'] ?? ('© '.date('Y').' uslugi.fr – Tous droits réservés')).'
</div>
</div>
</div>';
uslugi_mail($email, $subject, $body);
}
$msg = $translations['invitation_envoyee'] ?? 'Invitation envoyée.';
}
}
if (isset($_POST['action']) && $_POST['action']==='toggle_rights') {
$spid = (int)($_POST['spid'] ?? 0);
$field = ($_POST['field'] ?? '');
if ($spid>0 && in_array($field,['can_manage_rdv','can_edit_slots','is_active'],true)) {
// secure update scoped to this praticien
$upd = $pdo->prepare("UPDATE secretaire_praticien SET $field = 1 - $field WHERE id=:id AND praticien_id=:pid");
$upd->execute(['id'=>$spid,'pid'=>$praticien_id]);
$msg = $translations['droits_mis_a_jour'] ?? 'Droits mis à jour.';
}
}
}
// DATA: invitations + secretaire_praticien liés à CE praticien
$invitations = $pdo->prepare("SELECT id,email,status,expires_at,created_at FROM invitations WHERE praticien_id=:pid ORDER BY created_at DESC");
$invitations->execute(['pid'=>$praticien_id]);
$invRows = $invitations->fetchAll(PDO::FETCH_ASSOC);
// secrétaires liées
$secs = $pdo->prepare("
SELECT sp.id, sp.secretaire_user_id, sp.can_manage_rdv, sp.can_edit_slots, sp.is_active, sp.created_at,
c.email
FROM secretaire_praticien sp
JOIN compte c ON c.id = sp.secretaire_user_id
WHERE sp.praticien_id = :pid
ORDER BY sp.created_at DESC
");
$secs->execute(['pid'=>$praticien_id]);
$secRows = $secs->fetchAll(PDO::FETCH_ASSOC);
require_once __DIR__ . '/../includes/header.php';
?>
<div class="main1">
<div class="container py-5">
<div class="shadow p-4 rounded bg-light">
<h1 class="h3 mb-3"><?= h($translations['secretariat_titre'] ?? 'Secrétariat') ?></h1>
<?php if(!empty($msg)): ?>
<div class="alert alert-info"><?= h($msg) ?></div>
<?php endif; ?>
<div class="card mb-4">
<div class="card-body">
<h2 class="h5 mb-3"><?= h($translations['secretariat_inviter_secretaire'] ?? 'Inviter une secrétaire') ?></h2>
<form method="post" class="row g-3">
<input type="hidden" name="csrf" value="<?= h($csrf) ?>">
<input type="hidden" name="action" value="invite">
<div class="col-md-6">
<label class="form-label"><?= h($translations['inv_email_label'] ?? 'Email de la secrétaire') ?></label>
<input type="email" name="email" class="form-control" required placeholder="email@example.com">
</div>
<div class="col-md-6">
<label class="form-label"><?= h($translations['inv_droits_label'] ?? 'Droits initiaux') ?></label>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="can_manage_rdv" id="c1" checked>
<label class="form-check-label" for="c1"><?= h($translations['droits_peut_gestion_rdv'] ?? 'Gérer les rendez-vous') ?></label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="can_edit_slots" id="c2" checked>
<label class="form-check-label" for="c2"><?= h($translations['droits_peut_modifier_slots'] ?? 'Modifier les disponibilités') ?></label>
</div>
</div>
<div class="col-12">
<button class="btn btn-primary"><?= h($translations['btn_envoyer_invitation'] ?? 'Envoyer l’invitation') ?></button>
</div>
</form>
</div>
</div>
<div class="card mb-4">
<div class="card-body">
<h2 class="h6 mb-3"><?= h($translations['inv_invitations_envoyees'] ?? 'Invitations envoyées') ?></h2>
<div class="table-responsive">
<table class="table align-middle mobile-cards1" id="table_rdv1">
<thead><tr>
<th>Email</th><th><?= h($translations['inv_statut'] ?? 'Statut') ?></th>
<th><?= h($translations['inv_expires'] ?? 'Expire le') ?></th>
<th><?= h($translations['inv_envoyee_le'] ?? 'Envoyée le') ?></th>
</tr></thead>
<tbody>
<?php foreach($invRows as $r): ?>
<tr>
<td><?= h($r['email']) ?></td>
<td><?= h($r['status']) ?></td>
<td><?= h($r['expires_at'] ?? '') ?></td>
<td><?= h($r['created_at'] ?? '') ?></td>
</tr>
<?php endforeach; if(!$invRows): ?>
<tr><td colspan="4" class="text-muted"><?= h($translations['inv_aucune'] ?? 'Aucune invitation pour le moment.') ?></td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
<div class="card mb-5">
<div class="card-body">
<h2 class="h6 mb-3"><?= h($translations['inv_secretaires_liees'] ?? 'Secrétaires liées') ?></h2>
<div class="table-responsive">
<table class="table align-middle mobile-cards" id="table_rdv">
<thead><tr>
<th>Email</th><th><?= h($translations['droits_gestion_rdv'] ?? 'RDV') ?></th><th><?= h($translations['droits_dispos'] ?? 'Dispos') ?></th><th><?= h($translations['etat'] ?? 'État') ?></th>
</tr></thead>
<tbody>
<?php foreach($secRows as $r): ?>
<tr>
<td><?= h($r['email']) ?></td>
<td>
<form method="post" class="d-inline">
<input type="hidden" name="csrf" value="<?= h($csrf) ?>">
<input type="hidden" name="action" value="toggle_rights">
<input type="hidden" name="spid" value="<?= (int)$r['id'] ?>">
<input type="hidden" name="field" value="can_manage_rdv">
<button class="btn btn-sm <?= $r['can_manage_rdv']?'btn-success':'btn-outline-secondary' ?>">
<?= $r['can_manage_rdv'] ? h($translations['actif'] ?? 'Actif') : h($translations['inactif'] ?? 'Inactif') ?>
</button>
</form>
</td>
<td>
<form method="post" class="d-inline">
<input type="hidden" name="csrf" value="<?= h($csrf) ?>">
<input type="hidden" name="action" value="toggle_rights">
<input type="hidden" name="spid" value="<?= (int)$r['id'] ?>">
<input type="hidden" name="field" value="can_edit_slots">
<button class="btn btn-sm <?= $r['can_edit_slots']?'btn-success':'btn-outline-secondary' ?>">
<?= $r['can_edit_slots'] ? h($translations['actif'] ?? 'Actif') : h($translations['inactif'] ?? 'Inactif') ?>
</button>
</form>
</td>
<td>
<form method="post" class="d-inline">
<input type="hidden" name="csrf" value="<?= h($csrf) ?>">
<input type="hidden" name="action" value="toggle_rights">
<input type="hidden" name="spid" value="<?= (int)$r['id'] ?>">
<input type="hidden" name="field" value="is_active">
<button class="btn btn-sm <?= $r['is_active']?'btn-success':'btn-outline-secondary' ?>">
<?= $r['is_active'] ? h($translations['actif'] ?? 'Actif') : h($translations['inactif'] ?? 'Inactif') ?>
</button>
</form>
</td>
</tr>
<?php endforeach; if(!$secRows): ?>
<tr><td colspan="4" class="text-muted"><?= h($translations['inv_aucune_secretaire'] ?? 'Aucune secrétaire liée pour le moment.') ?></td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<script defer>
(function(){
function initMobileCards(tbl){
if (!tbl) return;
const heads = Array.from(tbl.querySelectorAll('thead th'))
.map(th => th.textContent.trim());
tbl.querySelectorAll('tbody tr').forEach(tr => {
Array.from(tr.children).forEach((td, i) => {
if (!td.hasAttribute('data-label')) {
td.setAttribute('data-label', heads[i] || '');
}
});
});
}
function ready(fn){
if (document.readyState === 'loading')
document.addEventListener('DOMContentLoaded', fn);
else
fn();
}
ready(function(){
// 👉 liste de toutes les variantes
const selectors = [
'#table_rdv',
'table.mobile-cards',
'#table_rdv1',
'table.mobile-cards1'
];
// 👉 récupérer toutes les tables existantes dans la page
const tables = selectors
.map(sel => document.querySelector(sel))
.filter(Boolean); // retire les null
tables.forEach(initMobileCards);
if (tables.length > 0) {
document.documentElement.classList.add('mc-ready');
}
});
})();
</script>
<footer class="site-footer">
<div class="container">
<p><?= $translations['copyr'] ?? '&copy; '.date('Y') ?></p>
</div>
</footer>