326 lines
16 KiB
PHP
326 lines
16 KiB
PHP
<?php
|
||
require_once __DIR__ . '/../includes/bootstrap_global.php';
|
||
require_once APP_HTDOCS . '/includes/avatar_initiales.php';
|
||
$SPEC_CANON = require __DIR__ . '/includes/spec_map.php';
|
||
|
||
$canon = $SPEC_CANON[$lang] ?? [];
|
||
|
||
// ------- (ton code existant) -------
|
||
$praticien_id = (int) ($_GET['id'] ?? 0);
|
||
if ($praticien_id <= 0) {echo "<div class='container py-5'>ID invalide.</div>";exit;}
|
||
|
||
function h($s)
|
||
{return htmlspecialchars((string) $s, ENT_QUOTES, 'UTF-8');}
|
||
function percent_from_5($note)
|
||
{$n = max(0, min(5, (float) $note));return (int) round($n / 5 * 100);}
|
||
function pseudo_from($prenom, $nom)
|
||
{
|
||
$p = trim((string) $prenom);
|
||
$n = trim((string) $nom);
|
||
$p = $p !== '' ? mb_convert_case($p, MB_CASE_TITLE, 'UTF-8') : 'Client';
|
||
$i = $n !== '' ? mb_strtoupper(mb_substr($nom, 0, 1, 'UTF-8'), 'UTF-8') : '';
|
||
return $i ? ($p . '.' . $i) : $p;
|
||
}
|
||
function video_thumb_info(?string $url): ?array
|
||
{
|
||
if (! $url || ! trim($url)) {
|
||
return null;
|
||
}
|
||
|
||
$u = trim($url);
|
||
if (preg_match('~(?:youtube\.com/(?:watch\?v=|embed/|shorts/)|youtu\.be/)([A-Za-z0-9_-]{6,})~i', $u, $m)) {
|
||
$id = $m[1];return ['provider' => 'youtube', 'id' => $id, 'thumb' => "https://i.ytimg.com/vi/$id/hqdefault.jpg"];
|
||
}
|
||
if (preg_match('~dailymotion\.com/video/([A-Za-z0-9]+)|dai\.ly/([A-Za-z0-9]+)~i', $u, $m)) {
|
||
$id = $m[1] ?: $m[2];return ['provider' => 'dailymotion', 'id' => $id, 'thumb' => "https://www.dailymotion.com/thumbnail/video/$id"];
|
||
}
|
||
$path = parse_url($u, PHP_URL_PATH) ?? '';if (preg_match('~\.(mp4|webm|ogg)$~i', $path)) {return ['provider' => 'file', 'id' => null, 'thumb' => null];}
|
||
if (stripos($u, 'vimeo.com') !== false) {return ['provider' => 'vimeo', 'id' => null, 'thumb' => null];}
|
||
return ['provider' => 'other', 'id' => null, 'thumb' => null];
|
||
}
|
||
|
||
// 1) Praticien
|
||
$st = $pdo->prepare("SELECT id, titre, nom, prenom, telephone, adresse, ville, code_postal, specialite, presentation, photo, video, disponibilite
|
||
FROM praticien WHERE id = ?");
|
||
$st->execute([$praticien_id]);
|
||
$p = $st->fetch(PDO::FETCH_ASSOC);
|
||
if (! $p) {echo "<div class='container py-5'>" . $translations['praticien_introuvable'] . "</div>";exit;}
|
||
|
||
$name = $name = trim($p['prenom'] . ' ' . $p['nom']);
|
||
$photo = ! empty($p['photo']) ? "/public/uploads/" . ltrim($p['photo'], '/') : "/public/uploads/img/user_placeholder.png";
|
||
|
||
// 2) Vidéos additionnelles
|
||
$vs = $pdo->prepare("SELECT id, url, title, ordre FROM praticien_video WHERE praticien_id=? ORDER BY ordre ASC, id DESC");
|
||
$vs->execute([$praticien_id]);
|
||
$videos = $vs->fetchAll(PDO::FETCH_ASSOC);
|
||
|
||
// 3) Avis: moyenne + total + dernier
|
||
$avg = $pdo->prepare("SELECT ROUND(AVG(note),1) AS m, COUNT(*) AS c FROM avis_praticien WHERE praticien_id=? AND statut='publie'");
|
||
$avg->execute([$praticien_id]);
|
||
$stats = $avg->fetch(PDO::FETCH_ASSOC) ?: ['m' => null, 'c' => 0];
|
||
|
||
$last = $pdo->prepare("SELECT a.note,a.titre,a.commentaire,a.visit_date,a.created_at,c.prenom,c.nom
|
||
FROM avis_praticien a
|
||
LEFT JOIN client c ON c.id=a.client_id
|
||
WHERE a.praticien_id=? AND a.statut='publie'
|
||
ORDER BY a.created_at DESC LIMIT 1");
|
||
$last->execute([$praticien_id]);
|
||
$lrow = $last->fetch(PDO::FETCH_ASSOC);
|
||
?>
|
||
<!doctype html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<title><?php echo $name . " - " . $p['specialite'] . " - " . htmlspecialchars($translations['seo_detail_public_title'], ENT_QUOTES, 'UTF-8') ?></title>
|
||
<meta name="description" content="<?php echo $name . " - " . $p['specialite'] . " - " . $p['presentation'] ?>">
|
||
<meta name="keywords" content="<?php echo htmlspecialchars($translations['seo_detail_public_keywords'], ENT_QUOTES, 'UTF-8') ?>">
|
||
<meta name="author" content="Uslugi.fr">
|
||
|
||
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
|
||
<link href="/css/bootstrap.min.css" rel="stylesheet">
|
||
<link rel="stylesheet" href="<?php echo asset('/includes/site_style.css') ?>">
|
||
<link rel="stylesheet" href="<?php echo asset('/includes/custom_style.css') ?>">
|
||
<link rel="stylesheet" href="<?php echo asset('/includes/mobil_style.css') ?>">
|
||
<?php include_once __DIR__ . '/includes/tracking.php'; ?>
|
||
</head>
|
||
<body class="layout">
|
||
|
||
<?php if ($logged):
|
||
include_header_clean(APP_HTDOCS . '/public/includes/header.php');
|
||
else: ?>
|
||
<!-- Header public (Connexion + “?”) -->
|
||
<header class="site-header">
|
||
<div class="container">
|
||
<div class="header-left">
|
||
<div class="brand">
|
||
<a href="/index.php"><img src="/public/uploads/img/logo_u.png"
|
||
alt="uslugi.fr"
|
||
class="logo-mobile"></a>
|
||
|
||
<a href="/index.php"><img src="/public/uploads/img/logo.png"
|
||
alt="uslugi.fr"
|
||
class="logo-desktop"></a>
|
||
</div>
|
||
<div class="lang-switch">
|
||
<?php require __DIR__ . '/includes/menu_langue.php'; ?>
|
||
</div>
|
||
</div>
|
||
<nav class="header-actions">
|
||
<a class="btn-login" href="/connexion.php">
|
||
<span class="d-sm-none"><?php echo $translations['btn_se_connecter'] ?></span>
|
||
<span class="d-none d-sm-inline"><?php echo $translations['ja_spec'] ?></span>
|
||
</a>
|
||
<!--<a class="btn-login" href="/connexion.php"><?php echo $translations['ja_spec'] ?></a>-->
|
||
|
||
<div class="dropdown">
|
||
<button class="btn btn-logo rounded-circle d-inline-flex align-items-center justify-content-center question-btn"
|
||
type="button" data-bs-toggle="dropdown" data-bs-auto-close="true"
|
||
aria-expanded="false" aria-label="Помощь">?</button>
|
||
<ul class="dropdown-menu dropdown-menu-end shadow help-menu menu-panel">
|
||
<li><a href="/how-it-work.php"><?php echo $translations['kak_rabotaet'] ?></a></a></li>
|
||
<li><a href="/about.php"><?php echo $translations['pro_nas'] ?></a></li>
|
||
<li><a href="/faq.php"><?php echo $translations['faq'] ?></a></li>
|
||
<li><a href="/contact.php"><?php echo $translations['nam_pisat'] ?></a></li>
|
||
</ul>
|
||
</div>
|
||
</nav>
|
||
</div>
|
||
</header>
|
||
<?php endif; ?>
|
||
|
||
<div class="main">
|
||
<div class="container py-4">
|
||
<div class="profile-card">
|
||
<div class="profile-grid profile-top">
|
||
<!-- Cadre 1 : Infos -->
|
||
<section class="panel">
|
||
<div class="info-scroll">
|
||
<h2 class="pro-name"><?php echo h($name) ?></h2>
|
||
<?php if ($p['specialite']): ?><div><strong><?php echo h($translations['dp_specialite']) ?>:</strong> <?php echo h($p['specialite']) ?></div><?php endif; ?>
|
||
<!--<?php if ($p['telephone']): ?><div><strong><?php echo h($translations['dp_telephone']) ?>:</strong> <?php echo h($p['telephone']) ?></div><?php endif; ?>-->
|
||
<?php if ($p['titre']): ?><div><strong><?php echo h($translations['tarif_consultation']) ?>:</strong> <?php echo h($p['titre']) ?></div><?php endif; ?>
|
||
<?php if ($p['disponibilite']): ?><div><strong><?php echo h($translations['moyens_payement']) ?>:</strong> <?php echo h($p['disponibilite']) ?></div><?php endif; ?>
|
||
<?php if ($p['adresse']): ?><div><strong><?php echo h($translations['dp_adresse']) ?>:</strong> <?php echo nl2br(h($p['adresse'])) ?></div><?php endif; ?>
|
||
<?php if ($p['ville'] || $p['code_postal']): ?><div><strong><?php echo h($translations['dp_ville_cp']) ?>:</strong> <?php echo h(trim(($p['ville'] ?? '') . ' ' . ($p['code_postal'] ?? ''))) ?></div><?php endif; ?>
|
||
<?php if ($p['presentation']): ?><div class="mt-3"><strong><?php echo h($translations['dp_description']) ?>:</strong><br><?php echo nl2br(h($p['presentation'])) ?></div><?php endif; ?>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Centre : grande photo -->
|
||
<section class="big-photo">
|
||
<img class="img-fluid w-100" src="<?php echo h($photo) ?>" alt="Photo">
|
||
</section>
|
||
|
||
<!-- Cadre 2 : Vidéos -->
|
||
<?php if ($p['video'] != '') {?>
|
||
<aside class="panel">
|
||
<h2 class="pro-name"><?php echo h($translations['dp_videos']) ?></h2>
|
||
<div class="vlist">
|
||
<?php
|
||
$alt = h($translations['video_alt'] ?? 'Vidéo');
|
||
$printed = false;
|
||
|
||
// Petite fonction d'affichage d’une vignette
|
||
$printThumb = function ($provider, $id, $thumb, $rawUrl) use ($alt) {
|
||
if (in_array($provider, ['youtube', 'dailymotion']) && $id) {
|
||
echo '<a href="#" class="vitem d-block pro-video"
|
||
data-bs-toggle="modal" data-bs-target="#videoModal"
|
||
data-provider="' . h($provider) . '" data-id="' . h($id) . '">';
|
||
echo $thumb
|
||
? '<img src="' . h($thumb) . '" alt="' . $alt . '" loading="lazy">'
|
||
: '<img src="/public/uploads/img/video_placeholder.jpg" alt="' . $alt . '" loading="lazy">';
|
||
echo '</a>';
|
||
} else {
|
||
$safe = h($rawUrl);
|
||
echo '<a class="vitem d-block" href="' . $safe . '" target="_blank" rel="noopener">';
|
||
echo $thumb
|
||
? '<img src="' . h($thumb) . '" alt="' . $alt . '" loading="lazy">'
|
||
: '<img src="/public/uploads/img/video_placeholder.jpg" alt="' . $alt . '" loading="lazy">';
|
||
echo '</a>';
|
||
}
|
||
};
|
||
|
||
if (! empty($p['video'])) {
|
||
$vi = video_thumb_info($p['video']);
|
||
$thumb = $vi['thumb'] ?? null;
|
||
$prov = $vi['provider'] ?? null;
|
||
$vid = $vi['id'] ?? null;
|
||
$printThumb($prov, $vid, $thumb, $p['video']);
|
||
$printed = true;
|
||
}
|
||
foreach ($videos as $v) {
|
||
$vi = video_thumb_info($v['url']);
|
||
$thumb = $vi['thumb'] ?? null;
|
||
$prov = $vi['provider'] ?? null;
|
||
$vid = $vi['id'] ?? null;
|
||
$printThumb($prov, $vid, $thumb, $v['url']);
|
||
$printed = true;
|
||
}
|
||
if (! $printed) {
|
||
echo '<div class="vitem"><img src="/public/uploads/img/video_placeholder.jpg" alt="' . $alt . '"></div>';
|
||
//echo '<div class="text-muted small mt-1">'.h($translations['dp_aucune_video']).'</div>';
|
||
}
|
||
?>
|
||
</div>
|
||
</aside>
|
||
<?php }?>
|
||
|
||
</div>
|
||
|
||
<!-- Ligne du bas : Note / Dernier avis / Bouton RDV -->
|
||
<div class="bottom-grid mt-4">
|
||
<!-- Cadre 3 : Note -->
|
||
<div class="card shadow-sm p-3">
|
||
<div class="d-flex align-items-center gap-3">
|
||
<?php $m = (float) ($stats['m'] ?? 0);
|
||
$c = (int) ($stats['c'] ?? 0);
|
||
$w = percent_from_5($m); ?>
|
||
<div class="rating" aria-label="Note moyenne">
|
||
<div class="stars-base">★★★★★</div>
|
||
<div class="stars-fill" style="width:<?php echo $w ?>%">★★★★★</div>
|
||
</div>
|
||
<div>
|
||
<div><strong><?php echo h($translations['avis_note_moy']) ?>:</strong> <?php echo $m ? number_format($m, 1, ',', ' ') : '—' ?>/5</div>
|
||
<div class="text-muted">(<?php echo $c . ' ' . h($translations['avis_total']) ?>)</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Cadre 4 : Dernier avis -->
|
||
<div class="card shadow-sm p-3 avis-card">
|
||
<div class="d-flex justify-content-between align-items-start mb-2">
|
||
<strong><?php echo h($translations['avis_dernier']) ?></strong>
|
||
<a class="btn btn-link p-0" href="/avis_public.php?praticien_id=<?php echo (int) $praticien_id ?>">
|
||
<?php echo h($translations['avis_lire_tous']) ?>
|
||
</a>
|
||
</div>
|
||
<?php if ($lrow): ?>
|
||
<?php $lw = percent_from_5((float) $lrow['note']); ?>
|
||
<div class="rating mb-1">
|
||
<div class="stars-base">★★★★★</div>
|
||
<div class="stars-fill" style="width:<?php echo $lw ?>%">★★★★★</div>
|
||
</div>
|
||
<div class="meta">
|
||
<?php echo h(pseudo_from($lrow['prenom'] ?? '', $lrow['nom'] ?? '')) ?>
|
||
<?php if (! empty($lrow['visit_date'])): ?> • <?php echo date('d/m/Y', strtotime($lrow['visit_date'])) ?><?php endif; ?>
|
||
</div>
|
||
<div><?php echo nl2br(h(mb_strimwidth((string) $lrow['commentaire'], 0, 320, '…', 'UTF-8'))) ?></div>
|
||
<?php else: ?>
|
||
<div class="text-muted"><?php echo h($translations['avis_aucun']) ?></div>
|
||
<?php endif; ?>
|
||
</div>
|
||
|
||
<!-- Bouton RDV -->
|
||
<div class="text-end">
|
||
<a class="btn btn-danger btn-lg" href="/public/client/reserver_rdv.php?praticien_id=<?php echo (int) $praticien_id ?>">
|
||
<?php echo h($translations['dp_btn_rdv']) ?>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Modal vidéo -->
|
||
<div class="modal fade" id="videoModal" tabindex="-1" aria-labelledby="videoModalLabel" aria-hidden="true">
|
||
<div class="modal-dialog modal-dialog-centered modal-xl">
|
||
<div class="modal-content border-0 shadow-lg rounded-4">
|
||
<div class="modal-header border-0">
|
||
<h5 class="modal-title" id="videoModalLabel"><?php echo h($translations['video_titre'] ?? 'Vidéo') ?></h5>
|
||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="<?php echo h($translations['fermer'] ?? 'Fermer') ?>"></button>
|
||
</div>
|
||
<div class="modal-body pt-0">
|
||
<div class="ratio ratio-16x9 rounded-3 overflow-hidden bg-black">
|
||
<iframe id="vPlayer" src="" title="Video player"
|
||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||
allowfullscreen
|
||
referrerpolicy="strict-origin-when-cross-origin"></iframe>
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer border-0">
|
||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
||
<?php echo h($translations['fermer'] ?? 'Fermer') ?>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<script>
|
||
(function(){
|
||
const modal = document.getElementById('videoModal');
|
||
const iframe = document.getElementById('vPlayer');
|
||
|
||
function buildEmbed(provider, id){
|
||
if (!provider || !id) return '';
|
||
if (provider === 'youtube')
|
||
return 'https://www.youtube-nocookie.com/embed/' + id + '?autoplay=1&rel=0&modestbranding=1';
|
||
if (provider === 'dailymotion')
|
||
return 'https://www.dailymotion.com/embed/video/' + id + '?autoplay=1&ui-start-screen-info=false';
|
||
return '';
|
||
}
|
||
|
||
document.addEventListener('click', function(e){
|
||
const a = e.target.closest('a.pro-video[data-provider][data-id]');
|
||
if (!a) return;
|
||
e.preventDefault();
|
||
const src = buildEmbed(a.dataset.provider, a.dataset.id);
|
||
if (src) iframe.src = src;
|
||
}, false);
|
||
|
||
modal.addEventListener('hidden.bs.modal', function(){
|
||
iframe.src = '';
|
||
});
|
||
})();
|
||
</script>
|
||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" defer></script>
|
||
|
||
<footer class="site-footer">
|
||
<div class="container">
|
||
<p><?php echo $translations['copyr'] ?></p>
|
||
</div>
|
||
</footer>
|
||
</body>
|
||
</html>
|