Derniere version de site au 4/10/2026

This commit is contained in:
Oleg Barykin committed 2026-10-04 14:50:04 +02:00
1 parent 21f34c64c9
commit dbb8e299a0
35 files changed
+8697 -1242

No files matched your search

+6
View File
@@ -0,0 +1,6 @@
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="USLUGI_BD" uuid="ee47d4b7-b40e-4b04-8b18-3457e823b1de">
<driver-ref>mariadb</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.mariadb.jdbc.Driver</jdbc-driver>
<jdbc-url>jdbc:mariadb://mariadb:3306/uslugi_db</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="DBE_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/maria_uslugi.iml" filepath="$PROJECT_DIR$/.idea/maria_uslugi.iml" />
</modules>
</component>
</project>
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
+111 -87
View File
@@ -1,74 +1,98 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/../includes/bootstrap_global.php';
declare (strict_types = 1);
require_once __DIR__ . '/../includes/bootstrap_global.php';
// ===== Helpers header (identiques à index.php) =====
function is_client_logged_in(): bool {
$role = $_SESSION['role'] ?? ($_SESSION['user_type'] ?? '');
if (!empty($_SESSION['user_id']) && $role === 'client') return true;
if (!empty($_SESSION['client_id'])) return true;
if (!empty($_SESSION['reference_id']) && $role === 'client') return true;
if (!empty($_SESSION['user_id']) && $role === 'praticien') return true;
if (!empty($_SESSION['praticien_id'])) return true;
if (!empty($_SESSION['reference_id']) && $role === 'praticien') return true;
return false;
}
// ===== Helpers header (identiques à index.php) =====
function is_client_logged_in(): bool
{
$role = $_SESSION['role'] ?? ($_SESSION['user_type'] ?? '');
if (! empty($_SESSION['user_id']) && $role === 'client') {
return true;
}
function include_header_clean(string $absPath): void {
global $translations, $lang;
ob_start();
include $absPath; // /public/includes/header.php
$buf = ob_get_clean() ?: '';
if (! empty($_SESSION['client_id'])) {
return true;
}
// 0) DOCTYPE + <html>…</html>
$buf = preg_replace('~<!doctype\s+html[^>]*>~i', '', $buf);
$buf = preg_replace('~</?html\b[^>]*>~i', '', $buf);
if (! empty($_SESSION['reference_id']) && $role === 'client') {
return true;
}
// 1) retirer <head>…</head> et <body> ouverts/fermés
$buf = preg_replace('~<head\b[^>]*>.*?</head>~is', '', $buf);
$buf = preg_replace('~</?body\b[^>]*>~i', '', $buf);
if (! empty($_SESSION['user_id']) && $role === 'praticien') {
return true;
}
// 2) retirer les <link> CSS “globaux” pour éviter d’écraser la home
$buf = preg_replace('~<link[^>]+href="[^"]*(bootstrap[^"]*\.css|mobil_style\.css|site_style\.css|fonts\.googleapis)[^"]*"[^>]*>~i', '', $buf);
if (! empty($_SESSION['praticien_id'])) {
return true;
}
// 3) retirer le <script> Bootstrap CDN (on le charge déjà en bas de la page)
$buf = preg_replace('~<script[^>]+src="[^"]*bootstrap[^"]*bundle[^"]*\.js[^"]*"[^>]*>\s*</script>~i', '', $buf);
if (! empty($_SESSION['reference_id']) && $role === 'praticien') {
return true;
}
echo $buf; // garde <header> + tes scripts inline utiles
}
return false;
}
function t(array $translations, string $key, string $fallback = ''): string {
$val = $translations[$key] ?? '';
if ($val === '') return $fallback;
return (string)$val;
}
function include_header_clean(string $absPath): void
{
global $translations, $lang;
ob_start();
include $absPath; // /public/includes/header.php
$buf = ob_get_clean() ?: '';
// Lang HTML
$langHtml = preg_match('~^[a-z]{2}(-[A-Z]{2})?$~', (string)($lang ?? '')) ? (string)$lang : 'ru';
// 0) DOCTYPE + <html>…</html>
$buf = preg_replace('~<!doctype\s+html[^>]*>~i', '', $buf);
$buf = preg_replace('~</?html\b[^>]*>~i', '', $buf);
// 1) retirer <head>…</head> et <body> ouverts/fermés
$buf = preg_replace('~<head\b[^>]*>.*?</head>~is', '', $buf);
$buf = preg_replace('~</?body\b[^>]*>~i', '', $buf);
// 2) retirer les <link> CSS “globaux” pour éviter d’écraser la home
$buf = preg_replace('~<link[^>]+href="[^"]*(bootstrap[^"]*\.css|mobil_style\.css|site_style\.css|fonts\.googleapis)[^"]*"[^>]*>~i', '', $buf);
// 3) retirer le <script> Bootstrap CDN (on le charge déjà en bas de la page)
$buf = preg_replace('~<script[^>]+src="[^"]*bootstrap[^"]*bundle[^"]*\.js[^"]*"[^>]*>\s*</script>~i', '', $buf);
echo $buf; // garde <header> + tes scripts inline utiles
}
function t(array $translations, string $key, string $fallback = ''): string
{
$val = $translations[$key] ?? '';
if ($val === '') {
return $fallback;
}
return (string) $val;
}
// Lang HTML
$langHtml = preg_match('~^[a-z]{2}(-[A-Z]{2})?$~', (string) ($lang ?? '')) ? (string) $lang : 'ru';
?>
<!doctype html>
<html lang="<?= htmlspecialchars($langHtml, ENT_QUOTES, 'UTF-8') ?>">
<html lang="<?php echo htmlspecialchars($langHtml, ENT_QUOTES, 'UTF-8') ?>">
<head>
<meta charset="UTF-8">
<title><?= htmlspecialchars($translations['seo_about_title'], ENT_QUOTES, 'UTF-8') ?></title>
<meta name="description" content="<?= htmlspecialchars($translations['seo_about_desc'], ENT_QUOTES, 'UTF-8') ?>">
<meta name="keywords" content="<?= htmlspecialchars($translations['seo_about_keywords'], ENT_QUOTES, 'UTF-8') ?>">
<title><?php echo htmlspecialchars($translations['seo_about_title'], ENT_QUOTES, 'UTF-8') ?></title>
<meta name="description" content="<?php echo htmlspecialchars($translations['seo_about_desc'], ENT_QUOTES, 'UTF-8') ?>">
<meta name="keywords" content="<?php echo htmlspecialchars($translations['seo_about_keywords'], ENT_QUOTES, 'UTF-8') ?>">
<meta name="author" content="Uslugi.fr">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="<?= asset('/includes/site_style.css') ?>">
<link rel="stylesheet" href="<?= asset('/includes/custom_style.css') ?>">
<link rel="stylesheet" href="<?= asset('/includes/mobil_style.css') ?>">
<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>
<?php if (is_client_logged_in()): ?>
<?php
require_once __DIR__ . '/public/includes/init_pr_cl.php';
include_header_clean(__DIR__ . '/public/includes/header.php'); ?>
<?php
require_once __DIR__ . '/public/includes/init_pr_cl.php';
include_header_clean(__DIR__ . '/public/includes/header.php'); ?>
<?php else: ?>
<header class="site-header">
<div class="container">
@@ -88,8 +112,8 @@ $langHtml = preg_match('~^[a-z]{2}(-[A-Z]{2})?$~', (string)($lang ?? '')) ? (str
</div>
<nav class="header-actions">
<a class="btn-login" href="/connexion.php">
<span class="d-sm-none"><?= htmlspecialchars($translations['btn_se_connecter'] ?? 'Connexion', ENT_QUOTES, 'UTF-8') ?></span>
<span class="d-none d-sm-inline"><?= htmlspecialchars($translations['ja_spec'] ?? 'Je suis spécialiste', ENT_QUOTES, 'UTF-8') ?></span>
<span class="d-sm-none"><?php echo htmlspecialchars($translations['btn_se_connecter'] ?? 'Connexion', ENT_QUOTES, 'UTF-8') ?></span>
<span class="d-none d-sm-inline"><?php echo htmlspecialchars($translations['ja_spec'] ?? 'Je suis spécialiste', ENT_QUOTES, 'UTF-8') ?></span>
</a>
<div class="dropdown">
@@ -99,15 +123,15 @@ $langHtml = preg_match('~^[a-z]{2}(-[A-Z]{2})?$~', (string)($lang ?? '')) ? (str
data-bs-toggle="dropdown"
data-bs-auto-close="true"
aria-expanded="false"
aria-label="<?= htmlspecialchars(t($translations, 'about_help_aria', 'Help'), ENT_QUOTES, 'UTF-8') ?>">
aria-label="<?php echo htmlspecialchars(t($translations, 'about_help_aria', 'Help'), ENT_QUOTES, 'UTF-8') ?>">
?
</button>
<ul class="dropdown-menu dropdown-menu-end shadow help-menu menu-panel">
<li><a href="/how-it-work.php"><?= htmlspecialchars($translations['kak_rabotaet'] ?? 'Как это работает', ENT_QUOTES, 'UTF-8') ?></a></li>
<li><a href="/about.php"><?= htmlspecialchars($translations['pro_nas'] ?? 'О нас', ENT_QUOTES, 'UTF-8') ?></a></li>
<li><a href="/faq.php"><?= htmlspecialchars($translations['faq'] ?? 'FAQ', ENT_QUOTES, 'UTF-8') ?></a></li>
<li><a href="/contact.php"><?= htmlspecialchars($translations['nam_pisat'] ?? 'Написать нам', ENT_QUOTES, 'UTF-8') ?></a></li>
<li><a href="/how-it-work.php"><?php echo htmlspecialchars($translations['kak_rabotaet'] ?? 'Как это работает', ENT_QUOTES, 'UTF-8') ?></a></li>
<li><a href="/about.php"><?php echo htmlspecialchars($translations['pro_nas'] ?? 'О нас', ENT_QUOTES, 'UTF-8') ?></a></li>
<li><a href="/faq.php"><?php echo htmlspecialchars($translations['faq'] ?? 'FAQ', ENT_QUOTES, 'UTF-8') ?></a></li>
<li><a href="/contact.php"><?php echo htmlspecialchars($translations['nam_pisat'] ?? 'Написать нам', ENT_QUOTES, 'UTF-8') ?></a></li>
</ul>
</div>
</nav>
@@ -151,67 +175,67 @@ $langHtml = preg_match('~^[a-z]{2}(-[A-Z]{2})?$~', (string)($lang ?? '')) ? (str
<div class="wrap">
<div class="card" style="margin-bottom:18px;">
<h2><?= htmlspecialchars(t($translations, 'about_intro_title', 'About'), ENT_QUOTES, 'UTF-8') ?></h2>
<p><?= htmlspecialchars(t($translations, 'about_intro_text', 'uslugi.fr is a platform...'), ENT_QUOTES, 'UTF-8') ?></p>
<h2><?php echo htmlspecialchars(t($translations, 'about_intro_title', 'About'), ENT_QUOTES, 'UTF-8') ?></h2>
<p><?php echo htmlspecialchars(t($translations, 'about_intro_text', 'uslugi.fr is a platform...'), ENT_QUOTES, 'UTF-8') ?></p>
</div>
<div class="about-grid">
<div class="card">
<h2><?= htmlspecialchars(t($translations, 'about_mission_title', 'Our mission'), ENT_QUOTES, 'UTF-8') ?></h2>
<h2><?php echo htmlspecialchars(t($translations, 'about_mission_title', 'Our mission'), ENT_QUOTES, 'UTF-8') ?></h2>
<ul class="about-list">
<li class="about-item">
<div class="about-ico">🤝</div>
<div>
<h4><?= htmlspecialchars(t($translations, 'about_mission_item1_title', 'Easy booking'), ENT_QUOTES, 'UTF-8') ?></h4>
<p><?= htmlspecialchars(t($translations, 'about_mission_item1_text', 'Book in a few clicks...'), ENT_QUOTES, 'UTF-8') ?></p>
<h4><?php echo htmlspecialchars(t($translations, 'about_mission_item1_title', 'Easy booking'), ENT_QUOTES, 'UTF-8') ?></h4>
<p><?php echo htmlspecialchars(t($translations, 'about_mission_item1_text', 'Book in a few clicks...'), ENT_QUOTES, 'UTF-8') ?></p>
</div>
</li>
<li class="about-item">
<div class="about-ico">🛡️</div>
<div>
<h4><?= htmlspecialchars(t($translations, 'about_mission_item2_title', 'Security'), ENT_QUOTES, 'UTF-8') ?></h4>
<p><?= htmlspecialchars(t($translations, 'about_mission_item2_text', 'Data privacy and Jitsi...'), ENT_QUOTES, 'UTF-8') ?></p>
<h4><?php echo htmlspecialchars(t($translations, 'about_mission_item2_title', 'Security'), ENT_QUOTES, 'UTF-8') ?></h4>
<p><?php echo htmlspecialchars(t($translations, 'about_mission_item2_text', 'Data privacy and Jitsi...'), ENT_QUOTES, 'UTF-8') ?></p>
</div>
</li>
<li class="about-item">
<div class="about-ico">⏱️</div>
<div>
<h4><?= htmlspecialchars(t($translations, 'about_mission_item3_title', 'Save time'), ENT_QUOTES, 'UTF-8') ?></h4>
<p><?= htmlspecialchars(t($translations, 'about_mission_item3_text', 'Calendar and online consults...'), ENT_QUOTES, 'UTF-8') ?></p>
<h4><?php echo htmlspecialchars(t($translations, 'about_mission_item3_title', 'Save time'), ENT_QUOTES, 'UTF-8') ?></h4>
<p><?php echo htmlspecialchars(t($translations, 'about_mission_item3_text', 'Calendar and online consults...'), ENT_QUOTES, 'UTF-8') ?></p>
</div>
</li>
</ul>
</div>
<div class="card">
<h2><?= htmlspecialchars(t($translations, 'about_platform_title', 'How the platform works'), ENT_QUOTES, 'UTF-8') ?></h2>
<h2><?php echo htmlspecialchars(t($translations, 'about_platform_title', 'How the platform works'), ENT_QUOTES, 'UTF-8') ?></h2>
<ul class="about-list">
<li class="about-item">
<div class="about-ico">📚</div>
<div>
<h4><?= htmlspecialchars(t($translations, 'about_platform_item1_title', 'Specialists catalog'), ENT_QUOTES, 'UTF-8') ?></h4>
<p><?= htmlspecialchars(t($translations, 'about_platform_item1_text', 'Lawyers, notaries...'), ENT_QUOTES, 'UTF-8') ?></p>
<h4><?php echo htmlspecialchars(t($translations, 'about_platform_item1_title', 'Specialists catalog'), ENT_QUOTES, 'UTF-8') ?></h4>
<p><?php echo htmlspecialchars(t($translations, 'about_platform_item1_text', 'Lawyers, notaries...'), ENT_QUOTES, 'UTF-8') ?></p>
</div>
</li>
<li class="about-item">
<div class="about-ico">🗓️</div>
<div>
<h4><?= htmlspecialchars(t($translations, 'about_platform_item2_title', 'Online booking'), ENT_QUOTES, 'UTF-8') ?></h4>
<p><?= htmlspecialchars(t($translations, 'about_platform_item2_text', 'Choose a time and get email confirmation...'), ENT_QUOTES, 'UTF-8') ?></p>
<h4><?php echo htmlspecialchars(t($translations, 'about_platform_item2_title', 'Online booking'), ENT_QUOTES, 'UTF-8') ?></h4>
<p><?php echo htmlspecialchars(t($translations, 'about_platform_item2_text', 'Choose a time and get email confirmation...'), ENT_QUOTES, 'UTF-8') ?></p>
</div>
</li>
<li class="about-item">
<div class="about-ico">💬</div>
<div>
<h4><?= htmlspecialchars(t($translations, 'about_platform_item3_title', 'Chat before the session'), ENT_QUOTES, 'UTF-8') ?></h4>
<p><?= htmlspecialchars(t($translations, 'about_platform_item3_text', 'Ask details directly...'), ENT_QUOTES, 'UTF-8') ?></p>
<h4><?php echo htmlspecialchars(t($translations, 'about_platform_item3_title', 'Chat before the session'), ENT_QUOTES, 'UTF-8') ?></h4>
<p><?php echo htmlspecialchars(t($translations, 'about_platform_item3_text', 'Ask details directly...'), ENT_QUOTES, 'UTF-8') ?></p>
</div>
</li>
<li class="about-item">
<div class="about-ico">🎥</div>
<div>
<h4><?= htmlspecialchars(t($translations, 'about_platform_item4_title', 'Video calls'), ENT_QUOTES, 'UTF-8') ?></h4>
<p><?= htmlspecialchars(t($translations, 'about_platform_item4_text', 'Meetings via Jitsi...'), ENT_QUOTES, 'UTF-8') ?></p>
<h4><?php echo htmlspecialchars(t($translations, 'about_platform_item4_title', 'Video calls'), ENT_QUOTES, 'UTF-8') ?></h4>
<p><?php echo htmlspecialchars(t($translations, 'about_platform_item4_text', 'Meetings via Jitsi...'), ENT_QUOTES, 'UTF-8') ?></p>
</div>
</li>
</ul>
@@ -220,30 +244,30 @@ $langHtml = preg_match('~^[a-z]{2}(-[A-Z]{2})?$~', (string)($lang ?? '')) ? (str
<div class="about-grid" style="margin-top:14px;">
<div class="card">
<h2><?= htmlspecialchars(t($translations, 'about_clients_title', 'For clients'), ENT_QUOTES, 'UTF-8') ?></h2>
<p><?= htmlspecialchars(t($translations, 'about_clients_text', 'Fast search and booking...'), ENT_QUOTES, 'UTF-8') ?></p>
<h2><?php echo htmlspecialchars(t($translations, 'about_clients_title', 'For clients'), ENT_QUOTES, 'UTF-8') ?></h2>
<p><?php echo htmlspecialchars(t($translations, 'about_clients_text', 'Fast search and booking...'), ENT_QUOTES, 'UTF-8') ?></p>
<div class="about-callout">
<strong><?= htmlspecialchars(t($translations, 'about_clients_note_label', 'Important:'), ENT_QUOTES, 'UTF-8') ?></strong>
<?= htmlspecialchars(t($translations, 'about_clients_note_text', 'uslugi.fr helps you find...'), ENT_QUOTES, 'UTF-8') ?>
<strong><?php echo htmlspecialchars(t($translations, 'about_clients_note_label', 'Important:'), ENT_QUOTES, 'UTF-8') ?></strong>
<?php echo htmlspecialchars(t($translations, 'about_clients_note_text', 'uslugi.fr helps you find...'), ENT_QUOTES, 'UTF-8') ?>
</div>
</div>
<div class="card">
<h2><?= htmlspecialchars(t($translations, 'about_specialists_title', 'For specialists'), ENT_QUOTES, 'UTF-8') ?></h2>
<p><?= htmlspecialchars(t($translations, 'about_specialists_text', 'Dashboard, calendar...'), ENT_QUOTES, 'UTF-8') ?></p>
<h2><?php echo htmlspecialchars(t($translations, 'about_specialists_title', 'For specialists'), ENT_QUOTES, 'UTF-8') ?></h2>
<p><?php echo htmlspecialchars(t($translations, 'about_specialists_text', 'Dashboard, calendar...'), ENT_QUOTES, 'UTF-8') ?></p>
<ul class="about-list">
<li class="about-item">
<div class="about-ico">🔒</div>
<div>
<h4><?= htmlspecialchars(t($translations, 'about_specialists_item1_title', 'Data is safe'), ENT_QUOTES, 'UTF-8') ?></h4>
<p><?= htmlspecialchars(t($translations, 'about_specialists_item1_text', 'Basic security practices...'), ENT_QUOTES, 'UTF-8') ?></p>
<h4><?php echo htmlspecialchars(t($translations, 'about_specialists_item1_title', 'Data is safe'), ENT_QUOTES, 'UTF-8') ?></h4>
<p><?php echo htmlspecialchars(t($translations, 'about_specialists_item1_text', 'Basic security practices...'), ENT_QUOTES, 'UTF-8') ?></p>
</div>
</li>
<li class="about-item">
<div class="about-ico">📈</div>
<div>
<h4><?= htmlspecialchars(t($translations, 'about_specialists_item2_title', 'Grow your audience'), ENT_QUOTES, 'UTF-8') ?></h4>
<p><?= htmlspecialchars(t($translations, 'about_specialists_item2_text', 'Visibility in the catalog...'), ENT_QUOTES, 'UTF-8') ?></p>
<h4><?php echo htmlspecialchars(t($translations, 'about_specialists_item2_title', 'Grow your audience'), ENT_QUOTES, 'UTF-8') ?></h4>
<p><?php echo htmlspecialchars(t($translations, 'about_specialists_item2_text', 'Visibility in the catalog...'), ENT_QUOTES, 'UTF-8') ?></p>
</div>
</li>
</ul>
@@ -253,11 +277,11 @@ $langHtml = preg_match('~^[a-z]{2}(-[A-Z]{2})?$~', (string)($lang ?? '')) ? (str
<br>
<div class="card">
<h2><?= htmlspecialchars(t($translations, 'about_contact_title', 'Contact us'), ENT_QUOTES, 'UTF-8') ?></h2>
<p><?= htmlspecialchars(t($translations, 'about_contact_text', 'Have suggestions or questions? Write to us.'), ENT_QUOTES, 'UTF-8') ?></p>
<h2><?php echo htmlspecialchars(t($translations, 'about_contact_title', 'Contact us'), ENT_QUOTES, 'UTF-8') ?></h2>
<p><?php echo htmlspecialchars(t($translations, 'about_contact_text', 'Have suggestions or questions? Write to us.'), ENT_QUOTES, 'UTF-8') ?></p>
<div class="text-start">
<a class="btn btn-danger" href="/contact.php" style="padding:12px 16px;border-radius:999px;">
<?= htmlspecialchars(t($translations, 'about_contact_btn', 'Write to us'), ENT_QUOTES, 'UTF-8') ?>
<?php echo htmlspecialchars(t($translations, 'about_contact_btn', 'Write to us'), ENT_QUOTES, 'UTF-8') ?>
</a>
</div>
</div>
@@ -270,7 +294,7 @@ $langHtml = preg_match('~^[a-z]{2}(-[A-Z]{2})?$~', (string)($lang ?? '')) ? (str
<footer class="site-footer">
<div class="container">
<p><?= $translations['copyr'] ?></p>
<p><?php echo $translations['copyr'] ?></p>
</div>
</footer>
+6 -3
View File
@@ -1,4 +1,5 @@
<?php
ob_start();
require_once __DIR__ . '/../public/includes/init_admin.php';
// FIX: cast pour comparaison stricte
@@ -115,9 +116,9 @@
<span class="submenu-arrow">▾</span>
</button>
<ul class="submenu" hidden>
<li onclick="window.open('https://staging.uslugi.fr/matomo/index.php','_blank')">
<!--<li onclick="window.open('https://staging.uslugi.fr/matomo/index.php','_blank')">
<?php echo h($translations['admin_analytic'] ?? 'Analytics') ?>
</li>
</li>-->
<li onclick="location.href='<?php echo h(admin_url('logs')) ?>'">
<?php echo h($translations['afficher_logs'] ?? 'Logs') ?>
</li>
@@ -292,7 +293,9 @@ document.addEventListener('DOMContentLoaded', function () {
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<?php ob_end_flush(); ?>
<?php if (ob_get_level() > 0) {
ob_end_flush();
}?>
</body>
</html>
<?php endif; ?>
+140 -133
View File
@@ -1,74 +1,79 @@
<?php
require_once __DIR__ . '/../includes/bootstrap_global.php';
require_once APP_HTDOCS . '/includes/avatar_initiales.php';
require_once __DIR__ . '/../includes/bootstrap_global.php';
require_once APP_HTDOCS . '/includes/avatar_initiales.php';
$praticien_id = (int) ($_GET['praticien_id'] ?? 0);
if ($praticien_id <= 0) {echo "<div class='container py-5'>ID invalide.</div>";exit;}
$praticien_id = (int)($_GET['praticien_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($n){ $n=max(0,min(5,(float)$n)); 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($n,0,1,'UTF-8'),'UTF-8') : '';
return $i ? ($p.'.'.$i) : $p;
}
// Titre + stats
$pp = $pdo->prepare("SELECT titre, prenom, nom FROM praticien WHERE id=?");
$pp->execute([$praticien_id]);
$pr = $pp->fetch(PDO::FETCH_ASSOC);
if (!$pr) { echo "<div class='container py-5'>".$translations['praticien_introuvable']."</div>"; exit; }
$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];
// Form POST
$flash = null;
if ($_SERVER['REQUEST_METHOD']==='POST' && ($_POST['do'] ?? '')==='add') {
if (!hash_equals($_SESSION['csrf_token'] ?? '', $_POST['csrf'] ?? '')) {
$flash = ['type'=>'danger','msg'=>$translations['avis_form_err']];
} elseif ($_SESSION['role'] !== 'client') {
$flash = ['type'=>'danger','msg'=>$translations['non_autorise'] ?? 'Non autorisé'];
} else {
$note = (int)($_POST['note'] ?? 0);
$titre = trim((string)($_POST['titre'] ?? ''));
$commentaire = trim((string)($_POST['commentaire'] ?? ''));
$visit_date = trim((string)($_POST['visit_date'] ?? ''));
$ok = $note>=1 && $note<=5 && mb_strlen($commentaire,'UTF-8')>=10;
$date_ok = true;
if ($visit_date !== '') {
$ts = strtotime($visit_date.' 00:00:00');
$date_ok = $ts && $ts <= time()+86400; // pas dans le futur
function h($s)
{return htmlspecialchars((string) $s, ENT_QUOTES, 'UTF-8');}
function percent_from_5($n)
{$n = max(0, min(5, (float) $n));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($n, 0, 1, 'UTF-8'), 'UTF-8') : '';
return $i ? ($p . '.' . $i) : $p;
}
if ($ok && $date_ok) {
$st = $pdo->prepare("INSERT INTO avis_praticien (praticien_id, client_id, note, titre, commentaire, visit_date, statut)
VALUES (?, ?, ?, ?, ?, ?, 'publie')");
$st->execute([$praticien_id, (int)$_SESSION['reference_id'], $note,
($titre!==''?$titre:null), ($commentaire!==''?$commentaire:null),
($visit_date!==''?$visit_date:null)]);
$flash = ['type'=>'success','msg'=>$translations['avis_form_ok']];
// refresh stats
$avg->execute([$praticien_id]); $stats = $avg->fetch(PDO::FETCH_ASSOC) ?: ['m'=>null,'c'=>0];
// Titre + stats
$pp = $pdo->prepare("SELECT titre, prenom, nom FROM praticien WHERE id=?");
$pp->execute([$praticien_id]);
$pr = $pp->fetch(PDO::FETCH_ASSOC);
if (! $pr) {echo "<div class='container py-5'>" . $translations['praticien_introuvable'] . "</div>";exit;}
$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];
// Form POST
$flash = null;
if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['do'] ?? '') === 'add') {
if (! hash_equals($_SESSION['csrf_token'] ?? '', $_POST['csrf'] ?? '')) {
$flash = ['type' => 'danger', 'msg' => $translations['avis_form_err']];
} elseif ($_SESSION['role'] !== 'client') {
$flash = ['type' => 'danger', 'msg' => $translations['non_autorise'] ?? 'Non autorisé'];
} else {
$flash = ['type'=>'danger','msg'=>$translations['avis_form_err']];
$note = (int) ($_POST['note'] ?? 0);
$titre = trim((string) ($_POST['titre'] ?? ''));
$commentaire = trim((string) ($_POST['commentaire'] ?? ''));
$visit_date = trim((string) ($_POST['visit_date'] ?? ''));
$ok = $note >= 1 && $note <= 5 && mb_strlen($commentaire, 'UTF-8') >= 10;
$date_ok = true;
if ($visit_date !== '') {
$ts = strtotime($visit_date . ' 00:00:00');
$date_ok = $ts && $ts <= time() + 86400; // pas dans le futur
}
if ($ok && $date_ok) {
$st = $pdo->prepare("INSERT INTO avis_praticien (praticien_id, client_id, note, titre, commentaire, visit_date, statut)
VALUES (?, ?, ?, ?, ?, ?, 'publie')");
$st->execute([$praticien_id, (int) $_SESSION['reference_id'], $note,
($titre !== '' ? $titre : null), ($commentaire !== '' ? $commentaire : null),
($visit_date !== '' ? $visit_date : null)]);
$flash = ['type' => 'success', 'msg' => $translations['avis_form_ok']];
// refresh stats
$avg->execute([$praticien_id]);
$stats = $avg->fetch(PDO::FETCH_ASSOC) ?: ['m' => null, 'c' => 0];
} else {
$flash = ['type' => 'danger', 'msg' => $translations['avis_form_err']];
}
}
}
}
}
// Pagination
$perPage = 10;
$page = max(1, (int)($_GET['page'] ?? 1));
$offset = ($page - 1) * $perPage;
// Pagination
$perPage = 10;
$page = max(1, (int) ($_GET['page'] ?? 1));
$offset = ($page - 1) * $perPage;
$cnt = $pdo->prepare("SELECT COUNT(*) FROM avis_praticien WHERE praticien_id = :pid AND statut = 'publie'");
$cnt->execute([':pid' => $praticien_id]);
$total = (int)$cnt->fetchColumn();
$pages = max(1, (int)ceil($total / $perPage));
$cnt = $pdo->prepare("SELECT COUNT(*) FROM avis_praticien WHERE praticien_id = :pid AND statut = 'publie'");
$cnt->execute([':pid' => $praticien_id]);
$total = (int) $cnt->fetchColumn();
$pages = max(1, (int) ceil($total / $perPage));
$sql = "SELECT a.note, a.titre, a.commentaire, a.visit_date, a.created_at,
$sql = "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
@@ -76,58 +81,58 @@ $sql = "SELECT a.note, a.titre, a.commentaire, a.visit_date, a.created_at,
ORDER BY a.created_at DESC
LIMIT :o, :l";
$ls = $pdo->prepare($sql);
$ls->bindValue(':pid', $praticien_id, PDO::PARAM_INT);
$ls->bindValue(':o', (int)$offset, PDO::PARAM_INT);
$ls->bindValue(':l', (int)$perPage, PDO::PARAM_INT);
$ls->execute();
$ls = $pdo->prepare($sql);
$ls->bindValue(':pid', $praticien_id, PDO::PARAM_INT);
$ls->bindValue(':o', (int) $offset, PDO::PARAM_INT);
$ls->bindValue(':l', (int) $perPage, PDO::PARAM_INT);
$ls->execute();
$avis = $ls->fetchAll(PDO::FETCH_ASSOC);
$avis = $ls->fetchAll(PDO::FETCH_ASSOC);
// ID depuis l'URL (on passe bien ?praticien_id=...)
$praticien_id = (int)($_GET['praticien_id'] ?? 0);
if ($praticien_id <= 0) { echo "<div class='container py-5'>ID invalide.</div>"; exit; }
// ID depuis l'URL (on passe bien ?praticien_id=...)
$praticien_id = (int) ($_GET['praticien_id'] ?? 0);
if ($praticien_id <= 0) {echo "<div class='container py-5'>ID invalide.</div>";exit;}
// Charger le praticien
$pp = $pdo->prepare("SELECT titre, prenom, nom FROM praticien WHERE id = :id");
$pp->execute([':id' => $praticien_id]);
$pr = $pp->fetch(PDO::FETCH_ASSOC);
// Charger le praticien
$pp = $pdo->prepare("SELECT titre, prenom, nom FROM praticien WHERE id = :id");
$pp->execute([':id' => $praticien_id]);
$pr = $pp->fetch(PDO::FETCH_ASSOC);
if (!$pr) {
echo "<div class='container py-5'>".$translations['praticien_introuvable']."</div>";
exit;
}
if (! $pr) {
echo "<div class='container py-5'>" . $translations['praticien_introuvable'] . "</div>";
exit;
}
// Définir $name AVANT de l'utiliser
$name = trim(
($pr['prenom'] ?? '')
. ' '
. ($pr['nom'] ?? '')
);
$CSRF = $_SESSION['csrf_token'] ?? '';
// Définir $name AVANT de l'utiliser
$name = trim(
($pr['prenom'] ?? '')
. ' '
. ($pr['nom'] ?? '')
);
$CSRF = $_SESSION['csrf_token'] ?? '';
?>
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title><?= htmlspecialchars($translations['seo_avis_title'], ENT_QUOTES, 'UTF-8') ?></title>
<meta name="description" content="<?= htmlspecialchars($translations['seo_avis_desc'], ENT_QUOTES, 'UTF-8') ?>">
<meta name="keywords" content="<?= htmlspecialchars($translations['seo_avis_keywords'], ENT_QUOTES, 'UTF-8') ?>">
<title><?php echo htmlspecialchars($translations['seo_avis_title'], ENT_QUOTES, 'UTF-8') ?></title>
<meta name="description" content="<?php echo htmlspecialchars($translations['seo_avis_desc'], ENT_QUOTES, 'UTF-8') ?>">
<meta name="keywords" content="<?php echo htmlspecialchars($translations['seo_avis_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="<?= asset('/includes/site_style.css') ?>">
<link rel="stylesheet" href="<?= asset('/includes/custom_style.css') ?>">
<link rel="stylesheet" href="<?= asset('/includes/mobil_style.css') ?>">
<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');
include_header_clean(APP_HTDOCS . '/public/includes/header.php');
else: ?>
<!-- Header public (Connexion + “?”) -->
<header class="site-header">
@@ -148,20 +153,20 @@ else: ?>
</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>
<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>-->
<!--<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"><?= $translations['kak_rabotaet'] ?></a></a></li>
<li><a href="/about.php"><?= $translations['pro_nas'] ?></a></li>
<li><a href="/faq.php"><?= $translations['faq'] ?></a></li>
<li><a href="/contact.php"><?= $translations['nam_pisat'] ?></a></li>
<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>
@@ -172,93 +177,95 @@ else: ?>
<div class="main">
<div class="container py-5">
<div class="shadow p-4 rounded bg-light">
<h2 class="mb-2"><?= h($translations['avis_titre_page']) ?> — <?= h($name) ?></h2>
<h2 class="mb-2"><?php echo h($translations['avis_titre_page']) ?> — <?php echo h($name) ?></h2>
<div class="d-flex align-items-center gap-3 mb-3">
<?php $m=(float)($stats['m'] ?? 0); $c=(int)($stats['c'] ?? 0); $w=percent_from_5($m); ?>
<?php $m = (float) ($stats['m'] ?? 0);
$c = (int) ($stats['c'] ?? 0);
$w = percent_from_5($m); ?>
<div class="rating" aria-label="Note">
<div class="stars-base">★★★★★</div>
<div class="stars-fill" style="width:<?= $w ?>%">★★★★★</div>
<div class="stars-fill" style="width:<?php echo $w ?>%">★★★★★</div>
</div>
<div class="text-muted"><?= $m ? number_format($m,1,',',' ') : '—' ?>/5 • <?= $c.' '.h($translations['avis_total']) ?></div>
<div class="text-muted"><?php echo $m ? number_format($m, 1, ',', ' ') : '—' ?>/5 • <?php echo $c . ' ' . h($translations['avis_total']) ?></div>
</div>
<?php if ($flash): ?>
<div class="alert alert-<?= h($flash['type']) ?>"><?= h($flash['msg']) ?></div>
<div class="alert alert-<?php echo h($flash['type']) ?>"><?php echo h($flash['msg']) ?></div>
<?php endif; ?>
<?php if ($_SESSION['role']==='client'): ?>
<?php if (($_SESSION['role'] ?? '') === 'client'): ?>
<div class="card shadow-sm mb-4">
<div class="card-body">
<h5 class="mb-3"><?= h($translations['avis_form_titre']) ?></h5>
<h5 class="mb-3"><?php echo h($translations['avis_form_titre']) ?></h5>
<form method="post" class="row g-3">
<div class="col-12 col-md-4">
<label class="form-label"><?= h($translations['avis_form_note']) ?></label>
<label class="form-label"><?php echo h($translations['avis_form_note']) ?></label>
<select name="note" class="form-select" required>
<?php for($i=5;$i>=1;$i--): ?>
<option value="<?= $i ?>"> <?= $i ?> ★</option>
<?php for ($i = 5; $i >= 1; $i--): ?>
<option value="<?php echo $i ?>"> <?php echo $i ?> ★</option>
<?php endfor; ?>
</select>
</div>
<div class="col-12 col-md-4">
<label class="form-label"><?= h($translations['avis_form_date_visite']) ?></label>
<label class="form-label"><?php echo h($translations['avis_form_date_visite']) ?></label>
<input type="date" name="visit_date" class="form-control">
</div>
<div class="col-12">
<label class="form-label"><?= h($translations['avis_form_titre_lbl']) ?></label>
<label class="form-label"><?php echo h($translations['avis_form_titre_lbl']) ?></label>
<input type="text" name="titre" class="form-control" maxlength="150">
</div>
<div class="col-12">
<label class="form-label"><?= h($translations['avis_form_commentaire']) ?></label>
<label class="form-label"><?php echo h($translations['avis_form_commentaire']) ?></label>
<textarea name="commentaire" class="form-control" rows="4" minlength="10" required></textarea>
</div>
<div class="col-12">
<input type="hidden" name="csrf" value="<?= h($CSRF) ?>">
<input type="hidden" name="csrf" value="<?php echo h($CSRF) ?>">
<input type="hidden" name="do" value="add">
<button class="btn btn-primary"><?= h($translations['avis_form_envoyer']) ?></button>
<button class="btn btn-primary"><?php echo h($translations['avis_form_envoyer']) ?></button>
</div>
</form>
</div>
</div>
<?php endif; ?>
<?php if (!$avis): ?>
<div class="text-muted"><?= h($translations['avis_aucun']) ?></div>
<?php else: foreach ($avis as $a): $pw=percent_from_5((float)$a['note']); ?>
<?php if (! $avis): ?>
<div class="text-muted"><?php echo h($translations['avis_aucun']) ?></div>
<?php else: foreach ($avis as $a): $pw = percent_from_5((float) $a['note']); ?>
<div class="card shadow-sm mb-3">
<div class="card-body">
<div class="d-flex justify-content-between align-items-start mb-1">
<div>
<div class="rating mb-1">
<div class="stars-base">★★★★★</div>
<div class="stars-fill" style="width:<?= $pw ?>%">★★★★★</div>
<div class="stars-fill" style="width:<?php echo $pw ?>%">★★★★★</div>
</div>
<div class="small text-muted">
<strong><?= h(pseudo_from($a['prenom'] ?? '', $a['nom'] ?? '')) ?></strong>
<?php if(!empty($a['visit_date'])): ?> • <?= date('d/m/Y', strtotime($a['visit_date'])) ?><?php endif; ?>
<strong><?php echo h(pseudo_from($a['prenom'] ?? '', $a['nom'] ?? '')) ?></strong>
<?php if (! empty($a['visit_date'])): ?> • <?php echo date('d/m/Y', strtotime($a['visit_date'])) ?><?php endif; ?>
</div>
</div>
<div class="small text-muted"><?= date('d/m/Y', strtotime($a['created_at'])) ?></div>
<div class="small text-muted"><?php echo date('d/m/Y', strtotime($a['created_at'])) ?></div>
</div>
<?php if(!empty($a['titre'])): ?><div class="fw-semibold mb-1"><?= h($a['titre']) ?></div><?php endif; ?>
<div><?= nl2br(h($a['commentaire'] ?? '')) ?></div>
<?php if (! empty($a['titre'])): ?><div class="fw-semibold mb-1"><?php echo h($a['titre']) ?></div><?php endif; ?>
<div><?php echo nl2br(h($a['commentaire'] ?? '')) ?></div>
</div>
</div>
<?php endforeach; endif; ?>
<?php endforeach;endif; ?>
<?php if ($pages>1): ?>
<?php if ($pages > 1): ?>
<nav class="mt-3">
<?php for ($i=1;$i<=$pages;$i++):
$href = '/public/client/avis.php?praticien_id='.$praticien_id.'&page='.$i;
$cls = $i===$page ? 'btn btn-sm btn-primary me-1' : 'btn btn-sm btn-outline-primary me-1';
<?php for ($i = 1; $i <= $pages; $i++):
$href = '/public/client/avis.php?praticien_id=' . $praticien_id . '&page=' . $i;
$cls = $i === $page ? 'btn btn-sm btn-primary me-1' : 'btn btn-sm btn-outline-primary me-1';
?>
<a class="<?= $cls ?>" href="<?= h($href) ?>"><?= $i ?></a>
<a class="<?php echo $cls ?>" href="<?php echo h($href) ?>"><?php echo $i ?></a>
<?php endfor; ?>
</nav>
<?php endif; ?>
<div class="mt-4">
<a class="btn btn-outline-secondary" href="/detail_public.php?id=<?= (int)$praticien_id ?>">⬅️ <?= $translations['retour_avis_profil'] ?></a>
<a class="btn btn-outline-secondary" href="/detail_public.php?id=<?php echo (int) $praticien_id ?>">⬅️ <?php echo $translations['retour_avis_profil'] ?></a>
</div>
</div>
</div>
@@ -266,7 +273,7 @@ else: ?>
<footer class="site-footer">
<div class="container">
<p><?= $translations['copyr'] ?></p>
<p><?php echo $translations['copyr'] ?></p>
</div>
</footer>
<script src="/js/bootstrap.bundle.min.js"></script>
+22 -22
View File
@@ -1,22 +1,22 @@
<?php
require_once __DIR__ . '/../includes/bootstrap_global.php';
<?php
require_once __DIR__ . '/../includes/bootstrap_global.php';
?>
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title><?= htmlspecialchars($translations['seo_choix_inscription_title'], ENT_QUOTES, 'UTF-8') ?></title>
<meta name="description" content="<?= htmlspecialchars($translations['seo_choix_inscription_desc'], ENT_QUOTES, 'UTF-8') ?>">
<meta name="keywords" content="<?= htmlspecialchars($translations['seo_choix_inscription_keywords'], ENT_QUOTES, 'UTF-8') ?>">
<title><?php echo htmlspecialchars($translations['seo_choix_inscription_title'], ENT_QUOTES, 'UTF-8') ?></title>
<meta name="description" content="<?php echo htmlspecialchars($translations['seo_choix_inscription_desc'], ENT_QUOTES, 'UTF-8') ?>">
<meta name="keywords" content="<?php echo htmlspecialchars($translations['seo_choix_inscription_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="<?= asset('/includes/site_style.css') ?>">
<link rel="stylesheet" href="<?= asset('/includes/custom_style.css') ?>">
<link rel="stylesheet" href="<?= asset('/includes/mobil_style.css') ?>">
<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>
@@ -42,13 +42,13 @@ require_once __DIR__ . '/../includes/bootstrap_global.php';
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"><?= $translations['kak_rabotaet'] ?></a></a></li>
<li><a href="/about.php"><?= $translations['pro_nas'] ?></a></li>
<li><a href="/faq.php"><?= $translations['faq'] ?></a></li>
<li><a href="/contact.php"><?= $translations['nam_pisat'] ?></a></li>
<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>
@@ -61,15 +61,15 @@ require_once __DIR__ . '/../includes/bootstrap_global.php';
</style>
<div class="main">
<div class="container p-4 shadow-sm bg-white rounded-3" style="min-width: 380px; width: 100%; margin:40px auto;">
<h2 class="text-center mb-4"><?= $translations['choix_type_inscription'] ?></h2>
<h2 class="text-center mb-4"><?php echo $translations['choix_type_inscription'] ?></h2>
<div class="row justify-content-center">
<div class="col-md-4">
<div class="card shadow-sm">
<div class="card-body text-center">
<h5 class="card-title"><?= $translations['choix_client_titre'] ?></h5>
<p class="card-text"><?= $translations['choix_client_texte'] ?></p>
<a href="/inscription_client.php" class="btn btn-primary"><?= $translations['btn_inscription_client'] ?></a>
<h5 class="card-title"><?php echo $translations['choix_client_titre'] ?></h5>
<p class="card-text"><?php echo $translations['choix_client_texte'] ?></p>
<a href="/inscription_client.php" class="btn btn-primary"><?php echo $translations['btn_inscription_client'] ?></a>
</div>
</div>
</div>
@@ -77,9 +77,9 @@ require_once __DIR__ . '/../includes/bootstrap_global.php';
<div class="col-md-4 mt-4 mt-md-0">
<div class="card shadow-sm">
<div class="card-body text-center">
<h5 class="card-title"><?= $translations['choix_pro_titre'] ?></h5>
<p class="card-text"><?= $translations['choix_pro_texte'] ?></p>
<a href="/inscription_praticien.php" class="btn btn-secondary"><?= $translations['btn_inscription_pro'] ?></a>
<h5 class="card-title"><?php echo $translations['choix_pro_titre'] ?></h5>
<p class="card-text"><?php echo $translations['choix_pro_texte'] ?></p>
<a href="/inscription_praticien.php" class="btn btn-secondary"><?php echo $translations['btn_inscription_pro'] ?></a>
</div>
</div>
</div>
@@ -89,7 +89,7 @@ require_once __DIR__ . '/../includes/bootstrap_global.php';
<footer class="site-footer">
<div class="container">
<p><?= $translations['copyr'] ?></p>
<p><?php echo $translations['copyr'] ?></p>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
+264 -220
View File
@@ -1,219 +1,263 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/../includes/bootstrap_global.php';
declare (strict_types = 1);
require_once __DIR__ . '/../includes/bootstrap_global.php';
// ===== Helpers header (identiques à index.php) =====
function is_client_logged_in(): bool {
$role = $_SESSION['role'] ?? ($_SESSION['user_type'] ?? '');
if (!empty($_SESSION['user_id']) && $role === 'client') return true;
if (!empty($_SESSION['client_id'])) return true;
if (!empty($_SESSION['reference_id']) && $role === 'client') return true;
if (!empty($_SESSION['user_id']) && $role === 'praticien') return true;
if (!empty($_SESSION['praticien_id'])) return true;
if (!empty($_SESSION['reference_id']) && $role === 'praticien') return true;
return false;
}
function include_header_clean(string $absPath): void {
global $translations, $lang;
ob_start();
include $absPath; // /public/includes/header.php
$buf = ob_get_clean() ?: '';
// 0) DOCTYPE + <html>…</html>
$buf = preg_replace('~<!doctype\s+html[^>]*>~i', '', $buf);
$buf = preg_replace('~</?html\b[^>]*>~i', '', $buf);
// 1) retirer <head>…</head> et <body> ouverts/fermés
$buf = preg_replace('~<head\b[^>]*>.*?</head>~is', '', $buf);
$buf = preg_replace('~</?body\b[^>]*>~i', '', $buf);
// 2) retirer les <link> CSS “globaux” pour éviter d’écraser la home
$buf = preg_replace('~<link[^>]+href="[^"]*(bootstrap[^"]*\.css|mobil_style\.css|site_style\.css|fonts\.googleapis)[^"]*"[^>]*>~i', '', $buf);
// 3) retirer le <script> Bootstrap CDN (on le charge déjà en bas de la page)
$buf = preg_replace('~<script[^>]+src="[^"]*bootstrap[^"]*bundle[^"]*\.js[^"]*"[^>]*>\s*</script>~i', '', $buf);
echo $buf; // garde <header> + tes scripts inline utiles
}
/* ---------- Utils ---------- */
function envget(string $k): string {
return trim((string)($_ENV[$k] ?? $_SERVER[$k] ?? getenv($k) ?? ''));
}
function t(array $translations, string $key, string $fallback = ''): string {
$val = $translations[$key] ?? '';
if ($val === '') return $fallback;
return (string)$val;
}
$LOG_DIR = __DIR__ . '/tmp';
$LOG_FILE = $LOG_DIR . '/contact.log';
if (!is_dir($LOG_DIR)) { @mkdir($LOG_DIR, 0770, true); } // dossier local, pas servi publiquement
/* ---------- CSRF ---------- */
if (empty($_SESSION['pub_csrf'])) {
$_SESSION['pub_csrf'] = bin2hex(random_bytes(32));
}
$CSRF = $_SESSION['pub_csrf'];
// --- reCAPTCHA v2 (lecture robuste) ---
$rcCfg = [];
$cfgPath = __DIR__ . '/includes/recaptcha.php';
if (is_file($cfgPath)) {
$rcCfg = require $cfgPath; // ['site' => '...', 'secret' => '...']
}
$RECAPTCHA_SITE_KEY = trim((string)($rcCfg['site'] ?? envget('RECAPTCHA_SITE_KEY') ?? ''));
$RECAPTCHA_SECRET_KEY = trim((string)($rcCfg['secret'] ?? envget('RECAPTCHA_SECRET_KEY') ?? ''));
// Considère la clé "valide" si longueur réaliste (>= 20) – évite les faux négatifs
$HAS_SITE = (strlen($RECAPTCHA_SITE_KEY) >= 20);
$HAS_SECRET = (strlen($RECAPTCHA_SECRET_KEY) >= 20);
// (optionnel) forcer l’affichage en test: /contact.php?testcaptcha=1
if (($_GET['testcaptcha'] ?? '') === '1') $HAS_SITE = true;
/* ---------- État page ---------- */
$errors = [];
$sent = false;
/* ---------- POST ---------- */
if (($_SERVER['REQUEST_METHOD'] ?? '') === 'POST') {
// CSRF
if (!hash_equals($_SESSION['pub_csrf'] ?? '', $_POST['csrf'] ?? '')) {
$errors[] = t($translations, 'contact_err_security', 'Security error. Refresh and try again.');
}
// Honeypot anti-bot
if (!empty($_POST['website'] ?? '')) {
$errors[] = t($translations, 'contact_err_spam', 'Spam suspected.');
}
// Données utilisateur
$prenom = trim($_POST['prenom'] ?? '');
$nom = trim($_POST['nom'] ?? '');
$email = trim($_POST['email'] ?? '');
$sujet = trim($_POST['sujet'] ?? '');
$message = trim($_POST['message'] ?? '');
// Validations
if (mb_strlen($prenom) < 2) $errors[] = t($translations, 'contact_err_prenom', 'Please enter your first name.');
if (mb_strlen($nom) < 2) $errors[] = t($translations, 'contact_err_nom', 'Please enter your last name.');
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) $errors[] = t($translations, 'contact_err_email', 'Please enter a valid email.');
if (mb_strlen($sujet) < 3) $errors[] = t($translations, 'contact_err_sujet', 'Subject is too short.');
if (mb_strlen($message) < 10) $errors[] = t($translations, 'contact_err_message', 'Message is too short.');
// reCAPTCHA serveur
if ($HAS_SECRET) {
$token = $_POST['g-recaptcha-response'] ?? '';
if ($token === '') {
$errors[] = t($translations, 'contact_err_captcha_required', 'Please confirm you are not a robot.');
} else {
$resp = @file_get_contents(
'https://www.google.com/recaptcha/api/siteverify?secret=' . urlencode($RECAPTCHA_SECRET_KEY) .
'&response=' . urlencode($token) .
'&remoteip=' . urlencode($_SERVER['REMOTE_ADDR'] ?? '')
);
$ver = $resp ? json_decode($resp, true) : ['success' => false];
if (empty($ver['success'])) $errors[] = t($translations, 'contact_err_captcha_failed', 'reCAPTCHA verification failed.');
// ===== Helpers header (identiques à index.php) =====
function is_client_logged_in(): bool
{
$role = $_SESSION['role'] ?? ($_SESSION['user_type'] ?? '');
if (! empty($_SESSION['user_id']) && $role === 'client') {
return true;
}
}
// Envoi
if (!$errors) {
$to = 'contact@uslugi.fr';
if (! empty($_SESSION['client_id'])) {
return true;
}
$subjectPrefix = t($translations, 'contact_send_subject_prefix', 'Contact form message — ');
$subject = $subjectPrefix . $sujet;
if (! empty($_SESSION['reference_id']) && $role === 'client') {
return true;
}
$mailH3 = t($translations, 'contact_mail_h3', 'New message from uslugi.fr');
$lblName = t($translations, 'contact_mail_label_name', 'Name');
$lblEmail = t($translations, 'contact_mail_label_email', 'Email');
$lblSubject = t($translations, 'contact_mail_label_subject', 'Subject');
$lblMessage = t($translations, 'contact_mail_label_message', 'Message');
if (! empty($_SESSION['user_id']) && $role === 'praticien') {
return true;
}
$html = '
<h3>'.htmlspecialchars($mailH3, ENT_QUOTES, 'UTF-8').'</h3>
<p><strong>'.htmlspecialchars($lblName, ENT_QUOTES, 'UTF-8').':</strong> '.htmlspecialchars($prenom).' '.htmlspecialchars($nom).'</p>
<p><strong>'.htmlspecialchars($lblEmail, ENT_QUOTES, 'UTF-8').':</strong> '.htmlspecialchars($email).'</p>
<p><strong>'.htmlspecialchars($lblSubject, ENT_QUOTES, 'UTF-8').':</strong> '.htmlspecialchars($sujet).'</p>
<p><strong>'.htmlspecialchars($lblMessage, ENT_QUOTES, 'UTF-8').':</strong><br>'.nl2br(htmlspecialchars($message)).'</p>
if (! empty($_SESSION['praticien_id'])) {
return true;
}
if (! empty($_SESSION['reference_id']) && $role === 'praticien') {
return true;
}
return false;
}
function include_header_clean(string $absPath): void
{
global $translations, $lang;
ob_start();
include $absPath; // /public/includes/header.php
$buf = ob_get_clean() ?: '';
// 0) DOCTYPE + <html>…</html>
$buf = preg_replace('~<!doctype\s+html[^>]*>~i', '', $buf);
$buf = preg_replace('~</?html\b[^>]*>~i', '', $buf);
// 1) retirer <head>…</head> et <body> ouverts/fermés
$buf = preg_replace('~<head\b[^>]*>.*?</head>~is', '', $buf);
$buf = preg_replace('~</?body\b[^>]*>~i', '', $buf);
// 2) retirer les <link> CSS “globaux” pour éviter d’écraser la home
$buf = preg_replace('~<link[^>]+href="[^"]*(bootstrap[^"]*\.css|mobil_style\.css|site_style\.css|fonts\.googleapis)[^"]*"[^>]*>~i', '', $buf);
// 3) retirer le <script> Bootstrap CDN (on le charge déjà en bas de la page)
$buf = preg_replace('~<script[^>]+src="[^"]*bootstrap[^"]*bundle[^"]*\.js[^"]*"[^>]*>\s*</script>~i', '', $buf);
echo $buf; // garde <header> + tes scripts inline utiles
}
/* ---------- Utils ---------- */
function envget(string $k): string
{
return trim((string) ($_ENV[$k] ?? $_SERVER[$k] ?? getenv($k) ?? ''));
}
function t(array $translations, string $key, string $fallback = ''): string
{
$val = $translations[$key] ?? '';
if ($val === '') {
return $fallback;
}
return (string) $val;
}
$LOG_DIR = __DIR__ . '/tmp';
$LOG_FILE = $LOG_DIR . '/contact.log';
if (! is_dir($LOG_DIR)) {@mkdir($LOG_DIR, 0770, true);} // dossier local, pas servi publiquement
/* ---------- CSRF ---------- */
if (empty($_SESSION['pub_csrf'])) {
$_SESSION['pub_csrf'] = bin2hex(random_bytes(32));
}
$CSRF = $_SESSION['pub_csrf'];
// --- reCAPTCHA v2 (lecture robuste) ---
$rcCfg = [];
$cfgPath = __DIR__ . '/includes/recaptcha.php';
if (is_file($cfgPath)) {
$rcCfg = require $cfgPath; // ['site' => '...', 'secret' => '...']
}
$RECAPTCHA_SITE_KEY = trim((string) ($rcCfg['site'] ?? envget('RECAPTCHA_SITE_KEY') ?? ''));
$RECAPTCHA_SECRET_KEY = trim((string) ($rcCfg['secret'] ?? envget('RECAPTCHA_SECRET_KEY') ?? ''));
// Considère la clé "valide" si longueur réaliste (>= 20) – évite les faux négatifs
$HAS_SITE = (strlen($RECAPTCHA_SITE_KEY) >= 20);
$HAS_SECRET = (strlen($RECAPTCHA_SECRET_KEY) >= 20);
// (optionnel) forcer l’affichage en test: /contact.php?testcaptcha=1
if (($_GET['testcaptcha'] ?? '') === '1') {
$HAS_SITE = true;
}
/* ---------- État page ---------- */
$errors = [];
$sent = false;
/* ---------- POST ---------- */
if (($_SERVER['REQUEST_METHOD'] ?? '') === 'POST') {
// CSRF
if (! hash_equals($_SESSION['pub_csrf'] ?? '', $_POST['csrf'] ?? '')) {
$errors[] = t($translations, 'contact_err_security', 'Security error. Refresh and try again.');
}
// Honeypot anti-bot
if (! empty($_POST['website'] ?? '')) {
$errors[] = t($translations, 'contact_err_spam', 'Spam suspected.');
}
// Données utilisateur
$prenom = trim($_POST['prenom'] ?? '');
$nom = trim($_POST['nom'] ?? '');
$email = trim($_POST['email'] ?? '');
$sujet = trim($_POST['sujet'] ?? '');
$message = trim($_POST['message'] ?? '');
// Validations
if (mb_strlen($prenom) < 2) {
$errors[] = t($translations, 'contact_err_prenom', 'Please enter your first name.');
}
if (mb_strlen($nom) < 2) {
$errors[] = t($translations, 'contact_err_nom', 'Please enter your last name.');
}
if (! filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors[] = t($translations, 'contact_err_email', 'Please enter a valid email.');
}
if (mb_strlen($sujet) < 3) {
$errors[] = t($translations, 'contact_err_sujet', 'Subject is too short.');
}
if (mb_strlen($message) < 10) {
$errors[] = t($translations, 'contact_err_message', 'Message is too short.');
}
// reCAPTCHA serveur
if ($HAS_SECRET) {
$token = $_POST['g-recaptcha-response'] ?? '';
if ($token === '') {
$errors[] = t($translations, 'contact_err_captcha_required', 'Please confirm you are not a robot.');
} else {
$resp = @file_get_contents(
'https://www.google.com/recaptcha/api/siteverify?secret=' . urlencode($RECAPTCHA_SECRET_KEY) .
'&response=' . urlencode($token) .
'&remoteip=' . urlencode($_SERVER['REMOTE_ADDR'] ?? '')
);
$ver = $resp ? json_decode($resp, true) : ['success' => false];
if (empty($ver['success'])) {
$errors[] = t($translations, 'contact_err_captcha_failed', 'reCAPTCHA verification failed.');
}
}
}
// Envoi
if (! $errors) {
$to = 'contact@uslugi.fr';
$subjectPrefix = t($translations, 'contact_send_subject_prefix', 'Contact form message — ');
$subject = $subjectPrefix . $sujet;
$mailH3 = t($translations, 'contact_mail_h3', 'New message from uslugi.fr');
$lblName = t($translations, 'contact_mail_label_name', 'Name');
$lblEmail = t($translations, 'contact_mail_label_email', 'Email');
$lblSubject = t($translations, 'contact_mail_label_subject', 'Subject');
$lblMessage = t($translations, 'contact_mail_label_message', 'Message');
$html = '
<h3>' . htmlspecialchars($mailH3, ENT_QUOTES, 'UTF-8') . '</h3>
<p><strong>' . htmlspecialchars($lblName, ENT_QUOTES, 'UTF-8') . ':</strong> ' . htmlspecialchars($prenom) . ' ' . htmlspecialchars($nom) . '</p>
<p><strong>' . htmlspecialchars($lblEmail, ENT_QUOTES, 'UTF-8') . ':</strong> ' . htmlspecialchars($email) . '</p>
<p><strong>' . htmlspecialchars($lblSubject, ENT_QUOTES, 'UTF-8') . ':</strong> ' . htmlspecialchars($sujet) . '</p>
<p><strong>' . htmlspecialchars($lblMessage, ENT_QUOTES, 'UTF-8') . ':</strong><br>' . nl2br(htmlspecialchars($message)) . '</p>
';
$text = $mailH3 . "\n"
. $lblName . ": $prenom $nom\n"
. $lblEmail . ": $email\n"
. $lblSubject . ": $sujet\n\n"
. $lblMessage . ":\n$message\n";
$text = $mailH3 . "\n"
. $lblName . ": $prenom $nom\n"
. $lblEmail . ": $email\n"
. $lblSubject . ": $sujet\n\n"
. $lblMessage . ":\n$message\n";
try {
// From et Reply-To (tableaux) comme attendus par ton wrapper
$fromEmail = 'no-reply@uslugi.fr';
$fromName = 'USLUGI.FR';
try {
// From et Reply-To (tableaux) comme attendus par ton wrapper
$fromEmail = 'no-reply@uslugi.fr';
$fromName = 'USLUGI.FR';
$replyEmail = filter_var($email, FILTER_VALIDATE_EMAIL) ? $email : 'contact@uslugi.fr';
$replyName = trim($prenom.' '.$nom) ?: 'USLUGI.FR';
$replyEmail = filter_var($email, FILTER_VALIDATE_EMAIL) ? $email : 'contact@uslugi.fr';
$replyName = trim($prenom . ' ' . $nom) ?: 'USLUGI.FR';
// Appel wrapper: retourne [bool $ok, ?string $err]
[$ok, $err] = uslugi_mail(
$to,
$subject,
$html,
$text,
[
'from' => [$fromEmail, $fromName],
'reply_to' => [$replyEmail, $replyName],
// 'bcc' => ['tonmail@gmail.com'],
]
);
// Appel wrapper: retourne [bool $ok, ?string $err]
[$ok, $err] = uslugi_mail(
$to,
$subject,
$html,
$text,
[
'from' => [$fromEmail, $fromName],
'reply_to' => [$replyEmail, $replyName],
// 'bcc' => ['tonmail@gmail.com'],
]
);
if ($ok !== true) {
throw new RuntimeException('Wrapper mail send failed.');
}
if ($ok !== true) {
throw new RuntimeException('Wrapper mail send failed.');
}
// OK
$sent = true;
$_POST = [];
@file_put_contents($LOG_FILE, sprintf(
"[%s] OK to=%s subj=%s reply=%s ip=%s\n",
date('c'), $to, $sujet, $email, $_SERVER['REMOTE_ADDR'] ?? '-'
), FILE_APPEND);
// OK
$sent = true;
$_POST = [];
@file_put_contents($LOG_FILE, sprintf(
"[%s] OK to=%s subj=%s reply=%s ip=%s\n",
date('c'), $to, $sujet, $email, $_SERVER['REMOTE_ADDR'] ?? '-'
), FILE_APPEND);
} catch (Throwable $e) {
error_log('MAIL ERROR: ' . $e->getMessage());
@file_put_contents($LOG_FILE, sprintf(
"[%s] ERR to=%s subj=%s\n",
date('c'), $to, $sujet
), FILE_APPEND);
} catch (Throwable $e) {
error_log('MAIL ERROR: ' . $e->getMessage());
@file_put_contents($LOG_FILE, sprintf(
"[%s] ERR to=%s subj=%s\n",
date('c'), $to, $sujet
), FILE_APPEND);
// Message utilisateur générique (jamais d’info sensible à l’écran)
$errors[] = t($translations, 'contact_err_send_failed', 'Failed to send message. Please try later.');
// Message utilisateur générique (jamais d’info sensible à l’écran)
$errors[] = t($translations, 'contact_err_send_failed', 'Failed to send message. Please try later.');
}
}
}
}
}
// Lang HTML
$langHtml = preg_match('~^[a-z]{2}(-[A-Z]{2})?$~', (string)($lang ?? '')) ? (string)$lang : 'ru';
// Lang HTML
$langHtml = preg_match('~^[a-z]{2}(-[A-Z]{2})?$~', (string) ($lang ?? '')) ? (string) $lang : 'ru';
?>
<!doctype html>
<html lang="<?= htmlspecialchars($langHtml, ENT_QUOTES, 'UTF-8') ?>">
<html lang="<?php echo htmlspecialchars($langHtml, ENT_QUOTES, 'UTF-8') ?>">
<head>
<meta charset="UTF-8">
<title><?= htmlspecialchars($translations['seo_contact_title'], ENT_QUOTES, 'UTF-8') ?></title>
<meta name="description" content="<?= htmlspecialchars($translations['seo_contact_desc'], ENT_QUOTES, 'UTF-8') ?>">
<meta name="keywords" content="<?= htmlspecialchars($translations['seo_contact_keywords'], ENT_QUOTES, 'UTF-8') ?>">
<title><?php echo htmlspecialchars($translations['seo_contact_title'], ENT_QUOTES, 'UTF-8') ?></title>
<meta name="description" content="<?php echo htmlspecialchars($translations['seo_contact_desc'], ENT_QUOTES, 'UTF-8') ?>">
<meta name="keywords" content="<?php echo htmlspecialchars($translations['seo_contact_keywords'], ENT_QUOTES, 'UTF-8') ?>">
<meta name="author" content="Uslugi.fr">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="<?= asset('/includes/site_style.css') ?>">
<link rel="stylesheet" href="<?= asset('/includes/custom_style.css') ?>">
<link rel="stylesheet" href="<?= asset('/includes/mobil_style.css') ?>">
<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') ?>">
<style>
/* HERO bleu et cadre */
.hero-contact{ background:#8CA9FF; padding: clamp(16px,4vw,32px); }
@@ -242,9 +286,9 @@ $langHtml = preg_match('~^[a-z]{2}(-[A-Z]{2})?$~', (string)($lang ?? '')) ? (str
</head>
<body>
<?php if (is_client_logged_in()): ?>
<?php
require_once __DIR__ . '/public/includes/init_pr_cl.php';
include_header_clean(__DIR__ . '/public/includes/header.php'); ?>
<?php
require_once __DIR__ . '/public/includes/init_pr_cl.php';
include_header_clean(__DIR__ . '/public/includes/header.php'); ?>
<?php else: ?>
<header class="site-header">
<div class="container">
@@ -264,8 +308,8 @@ $langHtml = preg_match('~^[a-z]{2}(-[A-Z]{2})?$~', (string)($lang ?? '')) ? (str
</div>
<nav class="header-actions">
<a class="btn-login" href="/connexion.php">
<span class="d-sm-none"><?php echo htmlspecialchars($translations['btn_se_connecter'] ?? 'Connexion', ENT_QUOTES, 'UTF-8')?></span>
<span class="d-none d-sm-inline"><?php echo htmlspecialchars($translations['ja_spec'] ?? 'Je suis spécialiste', ENT_QUOTES, 'UTF-8')?></span>
<span class="d-sm-none"><?php echo htmlspecialchars($translations['btn_se_connecter'] ?? 'Connexion', ENT_QUOTES, 'UTF-8') ?></span>
<span class="d-none d-sm-inline"><?php echo htmlspecialchars($translations['ja_spec'] ?? 'Je suis spécialiste', ENT_QUOTES, 'UTF-8') ?></span>
</a>
<div class="dropdown">
@@ -275,15 +319,15 @@ $langHtml = preg_match('~^[a-z]{2}(-[A-Z]{2})?$~', (string)($lang ?? '')) ? (str
data-bs-toggle="dropdown"
data-bs-auto-close="true"
aria-expanded="false"
aria-label="<?php echo htmlspecialchars(t($translations, 'howitworks_help_aria', 'Help'), ENT_QUOTES, 'UTF-8')?>">
aria-label="<?php echo htmlspecialchars(t($translations, 'howitworks_help_aria', 'Help'), ENT_QUOTES, 'UTF-8') ?>">
?
</button>
<ul class="dropdown-menu dropdown-menu-end shadow help-menu menu-panel">
<li><a href="/how-it-work.php"><?php echo htmlspecialchars($translations['kak_rabotaet'] ?? 'Как это работает', ENT_QUOTES, 'UTF-8')?></a></li>
<li><a href="/about.php"><?php echo htmlspecialchars($translations['pro_nas'] ?? 'О нас', ENT_QUOTES, 'UTF-8')?></a></li>
<li><a href="/faq.php"><?php echo htmlspecialchars($translations['faq'] ?? 'FAQ', ENT_QUOTES, 'UTF-8')?></a></li>
<li><a href="/contact.php"><?php echo htmlspecialchars($translations['nam_pisat'] ?? 'Написать нам', ENT_QUOTES, 'UTF-8')?></a></li>
<li><a href="/how-it-work.php"><?php echo htmlspecialchars($translations['kak_rabotaet'] ?? 'Как это работает', ENT_QUOTES, 'UTF-8') ?></a></li>
<li><a href="/about.php"><?php echo htmlspecialchars($translations['pro_nas'] ?? 'О нас', ENT_QUOTES, 'UTF-8') ?></a></li>
<li><a href="/faq.php"><?php echo htmlspecialchars($translations['faq'] ?? 'FAQ', ENT_QUOTES, 'UTF-8') ?></a></li>
<li><a href="/contact.php"><?php echo htmlspecialchars($translations['nam_pisat'] ?? 'Написать нам', ENT_QUOTES, 'UTF-8') ?></a></li>
</ul>
</div>
@@ -297,65 +341,65 @@ $langHtml = preg_match('~^[a-z]{2}(-[A-Z]{2})?$~', (string)($lang ?? '')) ? (str
<section class="hero-contact">
<div class="container contact-wrap">
<div class="contact-frame">
<h1><?= htmlspecialchars(t($translations, 'contact_h1', 'Contact us'), ENT_QUOTES, 'UTF-8') ?></h1>
<p class="muted"><?= htmlspecialchars(t($translations, 'contact_intro', 'Fill the form — we will reply as soon as possible.'), ENT_QUOTES, 'UTF-8') ?></p>
<h1><?php echo htmlspecialchars(t($translations, 'contact_h1', 'Contact us'), ENT_QUOTES, 'UTF-8') ?></h1>
<p class="muted"><?php echo htmlspecialchars(t($translations, 'contact_intro', 'Fill the form — we will reply as soon as possible.'), ENT_QUOTES, 'UTF-8') ?></p>
<?php if (!empty($errors)): ?>
<?php if (! empty($errors)): ?>
<div class="alert alert-danger" role="alert">
<?= implode('<br>', array_map(static fn($s) => htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'), $errors)) ?>
<?php echo implode('<br>', array_map(static fn($s) => htmlspecialchars((string) $s, ENT_QUOTES, 'UTF-8'), $errors)) ?>
</div>
<?php elseif ($sent): ?>
<div class="alert alert-success" role="alert">
<?= htmlspecialchars(t($translations, 'contact_success_sent', 'Thank you! Your message has been sent.'), ENT_QUOTES, 'UTF-8') ?>
<?php echo htmlspecialchars(t($translations, 'contact_success_sent', 'Thank you! Your message has been sent.'), ENT_QUOTES, 'UTF-8') ?>
</div>
<?php endif; ?>
<form method="post" action="" novalidate>
<input type="hidden" name="csrf" value="<?= htmlspecialchars($CSRF, ENT_QUOTES, 'UTF-8') ?>">
<input type="hidden" name="csrf" value="<?php echo htmlspecialchars($CSRF, ENT_QUOTES, 'UTF-8') ?>">
<!-- Honeypot invisible -->
<input type="text" name="website" autocomplete="off" tabindex="-1"
style="position:absolute;left:-9999px;opacity:0" aria-hidden="true">
<div class="row g-3">
<div class="col-12">
<label class="form-label"><?= htmlspecialchars(t($translations, 'contact_label_nom', 'Last name'), ENT_QUOTES, 'UTF-8') ?></label>
<label class="form-label"><?php echo htmlspecialchars(t($translations, 'contact_label_nom', 'Last name'), ENT_QUOTES, 'UTF-8') ?></label>
<input type="text" name="nom" class="form-control"
value="<?= htmlspecialchars($_POST['nom'] ?? '', ENT_QUOTES, 'UTF-8') ?>" required>
value="<?php echo htmlspecialchars($_POST['nom'] ?? '', ENT_QUOTES, 'UTF-8') ?>" required>
</div>
<div class="col-12">
<label class="form-label"><?= htmlspecialchars(t($translations, 'contact_label_prenom', 'First name'), ENT_QUOTES, 'UTF-8') ?></label>
<label class="form-label"><?php echo htmlspecialchars(t($translations, 'contact_label_prenom', 'First name'), ENT_QUOTES, 'UTF-8') ?></label>
<input type="text" name="prenom" class="form-control"
value="<?= htmlspecialchars($_POST['prenom'] ?? '', ENT_QUOTES, 'UTF-8') ?>" required>
value="<?php echo htmlspecialchars($_POST['prenom'] ?? '', ENT_QUOTES, 'UTF-8') ?>" required>
</div>
<div class="col-12">
<label class="form-label"><?= htmlspecialchars(t($translations, 'contact_label_email', 'Email'), ENT_QUOTES, 'UTF-8') ?></label>
<label class="form-label"><?php echo htmlspecialchars(t($translations, 'contact_label_email', 'Email'), ENT_QUOTES, 'UTF-8') ?></label>
<input type="email" name="email" class="form-control" inputmode="email"
placeholder="<?= htmlspecialchars(t($translations, 'contact_email_placeholder', 'name@example.com'), ENT_QUOTES, 'UTF-8') ?>"
value="<?= htmlspecialchars($_POST['email'] ?? '', ENT_QUOTES, 'UTF-8') ?>" required>
placeholder="<?php echo htmlspecialchars(t($translations, 'contact_email_placeholder', 'name@example.com'), ENT_QUOTES, 'UTF-8') ?>"
value="<?php echo htmlspecialchars($_POST['email'] ?? '', ENT_QUOTES, 'UTF-8') ?>" required>
</div>
<div class="col-12">
<label class="form-label"><?= htmlspecialchars(t($translations, 'contact_label_sujet', 'Subject'), ENT_QUOTES, 'UTF-8') ?></label>
<label class="form-label"><?php echo htmlspecialchars(t($translations, 'contact_label_sujet', 'Subject'), ENT_QUOTES, 'UTF-8') ?></label>
<input type="text" name="sujet" class="form-control"
value="<?= htmlspecialchars($_POST['sujet'] ?? '', ENT_QUOTES, 'UTF-8') ?>" required>
value="<?php echo htmlspecialchars($_POST['sujet'] ?? '', ENT_QUOTES, 'UTF-8') ?>" required>
</div>
<div class="col-12">
<label class="form-label"><?= htmlspecialchars(t($translations, 'contact_label_message', 'Message'), ENT_QUOTES, 'UTF-8') ?></label>
<textarea name="message" class="form-control" required><?= htmlspecialchars($_POST['message'] ?? '', ENT_QUOTES, 'UTF-8') ?></textarea>
<label class="form-label"><?php echo htmlspecialchars(t($translations, 'contact_label_message', 'Message'), ENT_QUOTES, 'UTF-8') ?></label>
<textarea name="message" class="form-control" required><?php echo htmlspecialchars($_POST['message'] ?? '', ENT_QUOTES, 'UTF-8') ?></textarea>
</div>
<?php if ($HAS_SITE): ?>
<div class="col-12">
<div class="g-recaptcha" data-sitekey="<?= htmlspecialchars($RECAPTCHA_SITE_KEY, ENT_QUOTES, 'UTF-8') ?>"></div>
<div class="g-recaptcha" data-sitekey="<?php echo htmlspecialchars($RECAPTCHA_SITE_KEY, ENT_QUOTES, 'UTF-8') ?>"></div>
</div>
<?php endif; ?>
<div class="col-12 d-flex justify-content-end">
<button type="submit" class="btn btn-red">
<?= htmlspecialchars(t($translations, 'contact_btn_submit', 'Send'), ENT_QUOTES, 'UTF-8') ?>
<?php echo htmlspecialchars(t($translations, 'contact_btn_submit', 'Send'), ENT_QUOTES, 'UTF-8') ?>
</button>
</div>
</div>
@@ -368,7 +412,7 @@ $langHtml = preg_match('~^[a-z]{2}(-[A-Z]{2})?$~', (string)($lang ?? '')) ? (str
<footer class="site-footer">
<div class="container">
<p><?= $translations['copyr'] ?></p>
<p><?php echo $translations['copyr'] ?></p>
</div>
</footer>
+142 -133
View File
@@ -1,87 +1,94 @@
<?php
require_once __DIR__ . '/../includes/bootstrap_global.php';
require_once APP_HTDOCS . '/includes/avatar_initiales.php';
$SPEC_CANON = require __DIR__ . '/includes/spec_map.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] ?? [];
$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;
}
// ------- (ton code existant) -------
$praticien_id = (int)($_GET['id'] ?? 0);
if ($praticien_id <= 0) { echo "<div class='container py-5'>ID invalide.</div>"; exit; }
$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];
}
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
// 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; }
$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";
$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);
// 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];
// 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
$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);
$last->execute([$praticien_id]);
$lrow = $last->fetch(PDO::FETCH_ASSOC);
?>
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title><?= $name . " - " . $p['specialite'] . " - " . htmlspecialchars($translations['seo_detail_public_title'], ENT_QUOTES, 'UTF-8')?></title>
<meta name="description" content="<?= $name . " - " . $p['specialite'] . " - " . $p['presentation'] ?>">
<meta name="keywords" content="<?= htmlspecialchars($translations['seo_detail_public_keywords'], ENT_QUOTES, '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="<?= asset('/includes/site_style.css') ?>">
<link rel="stylesheet" href="<?= asset('/includes/custom_style.css') ?>">
<link rel="stylesheet" href="<?= asset('/includes/mobil_style.css') ?>">
<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');
include_header_clean(APP_HTDOCS . '/public/includes/header.php');
else: ?>
<!-- Header public (Connexion + “?”) -->
<header class="site-header">
@@ -102,20 +109,20 @@ else: ?>
</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>
<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>-->
<!--<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"><?= $translations['kak_rabotaet'] ?></a></a></li>
<li><a href="/about.php"><?= $translations['pro_nas'] ?></a></li>
<li><a href="/faq.php"><?= $translations['faq'] ?></a></li>
<li><a href="/contact.php"><?= $translations['nam_pisat'] ?></a></li>
<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>
@@ -130,75 +137,75 @@ else: ?>
<!-- Cadre 1 : Infos -->
<section class="panel">
<div class="info-scroll">
<h2 class="pro-name"><?= h($name) ?></h2>
<?php if($p['specialite']): ?><div><strong><?= h($translations['dp_specialite']) ?>:</strong> <?= h($p['specialite']) ?></div><?php endif; ?>
<!--<?php if($p['telephone']): ?><div><strong><?= h($translations['dp_telephone']) ?>:</strong> <?= h($p['telephone']) ?></div><?php endif; ?>-->
<?php if($p['titre']): ?><div><strong><?= h($translations['tarif_consultation']) ?>:</strong> <?= h($p['titre']) ?></div><?php endif; ?>
<?php if($p['disponibilite']): ?><div><strong><?= h($translations['moyens_payement']) ?>:</strong> <?= h($p['disponibilite']) ?></div><?php endif; ?>
<?php if($p['adresse']): ?><div><strong><?= h($translations['dp_adresse']) ?>:</strong> <?= nl2br(h($p['adresse'])) ?></div><?php endif; ?>
<?php if($p['ville'] || $p['code_postal']): ?><div><strong><?= h($translations['dp_ville_cp']) ?>:</strong> <?= h(trim(($p['ville']??'').' '.($p['code_postal']??''))) ?></div><?php endif; ?>
<?php if($p['presentation']): ?><div class="mt-3"><strong><?= h($translations['dp_description']) ?>:</strong><br><?= nl2br(h($p['presentation'])) ?></div><?php endif; ?>
<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="<?= h($photo) ?>" alt="Photo">
<img class="img-fluid w-100" src="<?php echo h($photo) ?>" alt="Photo">
</section>
<!-- Cadre 2 : Vidéos -->
<?php if($p['video'] != ''){ ?>
<?php if ($p['video'] != '') {?>
<aside class="panel">
<h2 class="pro-name"><?= h($translations['dp_videos']) ?></h2>
<h2 class="pro-name"><?php echo h($translations['dp_videos']) ?></h2>
<div class="vlist">
<?php
$alt = h($translations['video_alt'] ?? 'Vidéo');
$printed = false;
$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"
// 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>';
}
};
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>';
}
?>
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 } ?>
<?php }?>
</div>
@@ -207,14 +214,16 @@ else: ?>
<!-- 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); ?>
<?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:<?= $w ?>%">★★★★★</div>
<div class="stars-fill" style="width:<?php echo $w ?>%">★★★★★</div>
</div>
<div>
<div><strong><?= h($translations['avis_note_moy']) ?>:</strong> <?= $m ? number_format($m,1,',',' ') : '—' ?>/5</div>
<div class="text-muted">(<?= $c.' '.h($translations['avis_total']) ?>)</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>
@@ -222,31 +231,31 @@ else: ?>
<!-- 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><?= h($translations['avis_dernier']) ?></strong>
<a class="btn btn-link p-0" href="/avis_public.php?praticien_id=<?= (int)$praticien_id ?>">
<?= h($translations['avis_lire_tous']) ?>
<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']); ?>
<?php $lw = percent_from_5((float) $lrow['note']); ?>
<div class="rating mb-1">
<div class="stars-base">★★★★★</div>
<div class="stars-fill" style="width:<?= $lw ?>%">★★★★★</div>
<div class="stars-fill" style="width:<?php echo $lw ?>%">★★★★★</div>
</div>
<div class="meta">
<?= h(pseudo_from($lrow['prenom'] ?? '', $lrow['nom'] ?? '')) ?>
<?php if(!empty($lrow['visit_date'])): ?> • <?= date('d/m/Y', strtotime($lrow['visit_date'])) ?><?php endif; ?>
<?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><?= nl2br(h(mb_strimwidth((string)$lrow['commentaire'],0,320,'…','UTF-8'))) ?></div>
<div><?php echo nl2br(h(mb_strimwidth((string) $lrow['commentaire'], 0, 320, '…', 'UTF-8'))) ?></div>
<?php else: ?>
<div class="text-muted"><?= h($translations['avis_aucun']) ?></div>
<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=<?= (int)$praticien_id ?>">
<?= h($translations['dp_btn_rdv']) ?>
<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>
@@ -259,8 +268,8 @@ else: ?>
<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"><?= h($translations['video_titre'] ?? 'Vidéo') ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="<?= h($translations['fermer'] ?? 'Fermer') ?>"></button>
<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">
@@ -272,7 +281,7 @@ else: ?>
</div>
<div class="modal-footer border-0">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
<?= h($translations['fermer'] ?? 'Fermer') ?>
<?php echo h($translations['fermer'] ?? 'Fermer') ?>
</button>
</div>
</div>
@@ -309,7 +318,7 @@ else: ?>
<footer class="site-footer">
<div class="container">
<p><?= $translations['copyr'] ?></p>
<p><?php echo $translations['copyr'] ?></p>
</div>
</footer>
</body>
+639
View File
@@ -0,0 +1,639 @@
<?php
declare (strict_types = 1);
require_once __DIR__ . '/../includes/bootstrap_global.php';
// ===== Helpers header (identiques à index.php) =====
function is_client_logged_in(): bool
{
$role = $_SESSION['role'] ?? ($_SESSION['user_type'] ?? '');
if (! empty($_SESSION['user_id']) && $role === 'client') {
return true;
}
if (! empty($_SESSION['client_id'])) {
return true;
}
if (! empty($_SESSION['reference_id']) && $role === 'client') {
return true;
}
if (! empty($_SESSION['user_id']) && $role === 'praticien') {
return true;
}
if (! empty($_SESSION['praticien_id'])) {
return true;
}
if (! empty($_SESSION['reference_id']) && $role === 'praticien') {
return true;
}
return false;
}
function include_header_clean(string $absPath): void
{
global $translations, $lang;
ob_start();
include $absPath; // /public/includes/header.php
$buf = ob_get_clean() ?: '';
// 0) DOCTYPE + <html>…</html>
$buf = preg_replace('~<!doctype\s+html[^>]*>~i', '', $buf);
$buf = preg_replace('~</?html\b[^>]*>~i', '', $buf);
// 1) retirer <head>…</head> et <body> ouverts/fermés
$buf = preg_replace('~<head\b[^>]*>.*?</head>~is', '', $buf);
$buf = preg_replace('~</?body\b[^>]*>~i', '', $buf);
// 2) retirer les <link> CSS “globaux” pour éviter d’écraser la home
$buf = preg_replace('~<link[^>]+href="[^"]*(bootstrap[^"]*\.css|mobil_style\.css|site_style\.css|fonts\.googleapis)[^"]*"[^>]*>~i', '', $buf);
// 3) retirer le <script> Bootstrap CDN (on le charge déjà en bas de la page)
$buf = preg_replace('~<script[^>]+src="[^"]*bootstrap[^"]*bundle[^"]*\.js[^"]*"[^>]*>\s*</script>~i', '', $buf);
echo $buf; // garde <header> + tes scripts inline utiles
}
/* ---------- Utils ---------- */
function envget(string $k): string
{
return trim((string) ($_ENV[$k] ?? $_SERVER[$k] ?? getenv($k) ?? ''));
}
function t(array $translations, string $key, string $fallback = ''): string
{
$val = $translations[$key] ?? '';
if ($val === '') {
return $fallback;
}
return (string) $val;
}
$LOG_DIR = __DIR__ . '/tmp';
$LOG_FILE = $LOG_DIR . '/contact.log';
if (! is_dir($LOG_DIR)) {@mkdir($LOG_DIR, 0770, true);} // dossier local, pas servi publiquement
/* ---------- CSRF ---------- */
if (empty($_SESSION['pub_csrf'])) {
$_SESSION['pub_csrf'] = bin2hex(random_bytes(32));
}
$CSRF = $_SESSION['pub_csrf'];
// --- reCAPTCHA v2 (lecture robuste) ---
$rcCfg = [];
$cfgPath = __DIR__ . '/includes/recaptcha.php';
if (is_file($cfgPath)) {
$rcCfg = require $cfgPath; // ['site' => '...', 'secret' => '...']
}
$RECAPTCHA_SITE_KEY = trim((string) ($rcCfg['site'] ?? envget('RECAPTCHA_SITE_KEY') ?? ''));
$RECAPTCHA_SECRET_KEY = trim((string) ($rcCfg['secret'] ?? envget('RECAPTCHA_SECRET_KEY') ?? ''));
// Considère la clé "valide" si longueur réaliste (>= 20) – évite les faux négatifs
$HAS_SITE = (strlen($RECAPTCHA_SITE_KEY) >= 20);
$HAS_SECRET = (strlen($RECAPTCHA_SECRET_KEY) >= 20);
// (optionnel) forcer l’affichage en test: /contact.php?testcaptcha=1
if (($_GET['testcaptcha'] ?? '') === '1') {
$HAS_SITE = true;
}
/* ---------- État page ---------- */
$errors = [];
$sent = false;
/* ---------- POST ---------- */
if (($_SERVER['REQUEST_METHOD'] ?? '') === 'POST') {
// CSRF
if (! hash_equals($_SESSION['pub_csrf'] ?? '', $_POST['csrf'] ?? '')) {
$errors[] = t($translations, 'contact_err_security', 'Security error. Refresh and try again.');
}
// Honeypot anti-bot (Corrigé avec 'company' pour correspondre à votre HTML)
if (! empty($_POST['company'] ?? '')) {
$errors[] = t($translations, 'contact_err_spam', 'Spam suspected.');
}
// Données utilisateur
$name = trim($_POST['name'] ?? '');
$profession = trim($_POST['profession'] ?? '');
$city = trim($_POST['city'] ?? '');
$country = trim($_POST['country'] ?? '');
$phone = trim($_POST['phone'] ?? '');
$email = trim($_POST['email'] ?? '');
$site = trim($_POST['site'] ?? '');
$reason = trim($_POST['reason'] ?? '');
// Validations
if (mb_strlen($name) < 2) {
$errors[] = t($translations, 'contact_err_name', 'Please enter your name.');
}
if (mb_strlen($profession) < 2) {
$errors[] = t($translations, 'contact_err_profession', 'Please enter your profession.');
}
if (mb_strlen($city) < 2) {
$errors[] = t($translations, 'contact_err_city', 'Please enter your city.');
}
if (mb_strlen($country) < 2) {
$errors[] = t($translations, 'contact_err_country', 'Please enter your country.');
}
if ($phone === '' && $email === '' && $site === '') {
$errors[] = t($translations, 'contact_err_contact', 'Please provide at least one contact (phone, e-mail or website).');
}
if ($email !== '' && ! filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors[] = t($translations, 'contact_err_email', 'Please enter a valid email.');
}
if (mb_strlen($reason) < 10) {
$errors[] = t($translations, 'contact_err_reason', 'Reason is too short.');
}
// Envoi
if (! $errors) {
$to = 'contact@uslugi.fr';
$subjectPrefix = t($translations, 'contact_send_subject_prefix', 'Contact form message — ');
$subject = $subjectPrefix . $site;
$mailH3 = t($translations, 'contact_mail_h3', 'New message from uslugi.fr');
$lblName = t($translations, 'contact_mail_label_name', 'Name');
$lblProfession = t($translations, 'contact_mail_label_profession', 'Profession');
$lblCity = t($translations, 'contact_mail_label_city', 'City');
$lblCountry = t($translations, 'contact_mail_label_country', 'Country');
$lblPhone = t($translations, 'contact_mail_label_phone', 'Phone');
$lblEmail = t($translations, 'contact_mail_label_email', 'Email');
$lblSite = t($translations, 'contact_mail_label_site', 'Site');
$lblReason = t($translations, 'contact_mail_label_reason', 'Reason');
$html = '
<h3>' . htmlspecialchars($mailH3, ENT_QUOTES, 'UTF-8') . '</h3>
<p><strong>' . htmlspecialchars($lblName, ENT_QUOTES, 'UTF-8') . ':</strong> ' . htmlspecialchars($name) . '</p>
<p><strong>' . htmlspecialchars($lblProfession, ENT_QUOTES, 'UTF-8') . ':</strong> ' . htmlspecialchars($profession) . '</p>
<p><strong>' . htmlspecialchars($lblCity, ENT_QUOTES, 'UTF-8') . ':</strong> ' . htmlspecialchars($city) . '</p>
<p><strong>' . htmlspecialchars($lblCountry, ENT_QUOTES, 'UTF-8') . ':</strong> ' . htmlspecialchars($country) . '</p>
<p><strong>' . htmlspecialchars($lblPhone, ENT_QUOTES, 'UTF-8') . ':</strong> ' . htmlspecialchars($phone) . '</p>
<p><strong>' . htmlspecialchars($lblEmail, ENT_QUOTES, 'UTF-8') . ':</strong> ' . htmlspecialchars($email) . '</p>
<p><strong>' . htmlspecialchars($lblSite, ENT_QUOTES, 'UTF-8') . ':</strong> ' . htmlspecialchars($site) . '</p>
<p><strong>' . htmlspecialchars($lblReason, ENT_QUOTES, 'UTF-8') . ':</strong><br>' . nl2br(htmlspecialchars($reason)) . '</p>';
$text = $mailH3 . "\n"
. $lblName . ": $name\n"
. $lblProfession . ": $profession\n"
. $lblCity . ": $city\n"
. $lblCountry . ": $country\n"
. $lblPhone . ": $phone\n"
. $lblEmail . ": $email\n"
. $lblSite . ": $site\n\n"
. $lblReason . ":\n$reason\n";
try {
// From et Reply-To (tableaux) comme attendus par ton wrapper
$fromEmail = 'no-reply@uslugi.fr';
$fromName = 'USLUGI.FR';
$replyEmail = filter_var($email, FILTER_VALIDATE_EMAIL) ? $email : 'contact@uslugi.fr';
$replyName = trim($name . ' ' . $profession) ?: 'USLUGI.FR';
// Appel wrapper: retourne [bool $ok, ?string $err]
[$ok, $err] = uslugi_mail(
$to,
$subject,
$html,
$text,
[
'from' => [$fromEmail, $fromName],
'reply_to' => [$replyEmail, $replyName],
// 'bcc' => ['tonmail@gmail.com'],
]
);
if ($ok !== true) {
throw new RuntimeException('Wrapper mail send failed.');
}
// OK
$sent = true;
$_POST = [];
@file_put_contents($LOG_FILE, sprintf(
"[%s] OK to=%s subj=%s reply=%s ip=%s\n",
date('c'), $to, $site, $email, $_SERVER['REMOTE_ADDR'] ?? '-'
), FILE_APPEND);
} catch (Throwable $e) {
error_log('MAIL ERROR: ' . $e->getMessage());
@file_put_contents($LOG_FILE, sprintf(
"[%s] ERR to=%s subj=%s\n",
date('c'), $to, $site
), FILE_APPEND);
// Message utilisateur générique (jamais d’info sensible à l’écran)
$errors[] = t($translations, 'contact_err_send_failed', 'Failed to send message. Please try later.');
}
}
}
// Lang HTML
$langHtml = preg_match('~^[a-z]{2}(-[A-Z]{2})?$~', (string) ($lang ?? '')) ? (string) $lang : 'ru';
/*
* Formulaire de recommandation — à intégrer dans la page existante.
* Conserve les clés form_index_* déjà utilisées pour le titre, l'introduction,
* le bouton, les messages et les champs communs.
*/
$form_index_status = $form_index_status ?? null;
$form_index_message = $form_index_message ?? '';
$form_index_errors = $form_index_errors ?? [];
$form_index_old = $form_index_old ?? [
'name' => '',
'profession' => '',
'city' => '',
'country' => '',
'contact' => '',
'reason' => '',
];
function form_index_value(array $old, string $key): string
{
return htmlspecialchars((string) ($old[$key] ?? ''), ENT_QUOTES, 'UTF-8');
}
function form_index_text(array $translations, string $key, string $fallback): string
{
$value = $translations[$key] ?? '';
return htmlspecialchars($value !== '' ? (string) $value : $fallback, ENT_QUOTES, 'UTF-8');
}
?>
<!doctype html>
<html lang="<?php echo htmlspecialchars($langHtml, ENT_QUOTES, 'UTF-8') ?>">
<head>
<meta charset="UTF-8">
<title><?php echo htmlspecialchars($translations['seo_contact_title'], ENT_QUOTES, 'UTF-8') ?></title>
<meta name="description" content="<?php echo htmlspecialchars($translations['seo_contact_desc'], ENT_QUOTES, 'UTF-8') ?>">
<meta name="keywords" content="<?php echo htmlspecialchars($translations['seo_contact_keywords'], ENT_QUOTES, 'UTF-8') ?>">
<meta name="author" content="Uslugi.fr">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/css/bootstrap.min.css">
<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') ?>">
<style>
/* HERO bleu et cadre */
.hero-contact{ background:#8CA9FF; padding: clamp(16px,4vw,32px); }
.contact-wrap{ max-width:980px; margin:0 auto; font-family:"Montserrat",system-ui,-apple-system,"Segoe UI",Roboto,Arial,sans-serif; }
.contact-frame{
background:#fff; border:1px solid #DFE4FF; border-radius:22px;
box-shadow:0 16px 40px rgba(56,55,139,.14);
padding:clamp(16px,3vw,28px);
}
.contact h1{ font-size:clamp(24px,5.6vw,34px); margin:0 0 10px; }
.contact p.muted{ color:#6b7280; margin:0 0 14px; }
/* Forme */
.form-label{ font-weight:600; }
.form-control{ border-radius:12px; padding:12px 14px; }
textarea.form-control{ min-height: 180px; }
/* Bouton rouge arrondi */
.btn-red{
--bs-btn-bg:#E03C3F; --bs-btn-border-color:#E03C3F;
--bs-btn-hover-bg:#c53637; --bs-btn-hover-border-color:#c53637;
--bs-btn-active-bg:#a62e2f; --bs-btn-active-border-color:#a62e2f;
--bs-btn-hover-color:#fff;
color:#fff; border-radius:9999px; padding:12px 22px;
}
</style>
<?php include_once __DIR__ . '/includes/tracking.php'; ?>
</head>
<body>
<?php if (is_client_logged_in()): ?>
<?php
require_once __DIR__ . '/public/includes/init_pr_cl.php';
include_header_clean(__DIR__ . '/public/includes/header.php'); ?>
<?php else: ?>
<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 htmlspecialchars($translations['btn_se_connecter'] ?? 'Connexion', ENT_QUOTES, 'UTF-8') ?></span>
<span class="d-none d-sm-inline"><?php echo htmlspecialchars($translations['ja_spec'] ?? 'Je suis spécialiste', ENT_QUOTES, 'UTF-8') ?></span>
</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="<?php echo htmlspecialchars(t($translations, 'howitworks_help_aria', 'Help'), ENT_QUOTES, 'UTF-8') ?>">
?
</button>
<ul class="dropdown-menu dropdown-menu-end shadow help-menu menu-panel">
<li><a href="/how-it-work.php"><?php echo htmlspecialchars($translations['kak_rabotaet'] ?? 'Как это работает', ENT_QUOTES, 'UTF-8') ?></a></li>
<li><a href="/about.php"><?php echo htmlspecialchars($translations['pro_nas'] ?? 'О нас', ENT_QUOTES, 'UTF-8') ?></a></li>
<li><a href="/faq.php"><?php echo htmlspecialchars($translations['faq'] ?? 'FAQ', ENT_QUOTES, 'UTF-8') ?></a></li>
<li><a href="/contact.php"><?php echo htmlspecialchars($translations['nam_pisat'] ?? 'Написать нам', ENT_QUOTES, 'UTF-8') ?></a></li>
</ul>
</div>
</nav>
</div>
</header>
<?php endif; ?>
<section class="concierge-section" id="concierge-form">
<div class="concierge-inner">
<div class="concierge-heading">
<span class="label">
<?php echo form_index_text($translations, 'recom_badge', 'Бесплатно · Без регистрации'); ?>
</span>
<h2>
<?php echo form_index_text($translations, 'recom_title', 'Хотите порекомендовать нужного специалиста?'); ?>
</h2>
<p>
<?php echo form_index_text($translations, 'recom_intro', 'Опишите подробно специалиста, которого вы знаете, и мы свяжемся с ним, чтобы предложить разместить профиль на нашей платформе.'); ?>
</p>
</div>
<div class="concierge-card">
<div class="card-stripe"></div>
<?php
if ($sent) {
$form_index_status = 'success';
} elseif ($errors) {
$form_index_status = 'error';
$form_index_message = implode(' ', $errors);
$form_index_old = [
'name' => $name ?? '', 'profession' => $profession ?? '',
'city' => $city ?? '', 'country' => $country ?? '',
'phone' => $phone ?? '', 'email' => $email ?? '',
'site' => $site ?? '', 'reason' => $reason ?? '',
];
}
if ($form_index_status === 'success'): ?>
<div class="card-success" id="successState">
<div class="success-circle">✓</div>
<h3><?php echo form_index_text($translations, 'form_index_success_title', 'Спасибо за рекомендацию!'); ?></h3>
<p><?php echo form_index_text($translations, 'recom_success_text', 'Ваша рекомендация отправлена.'); ?></p>
</div>
<?php else: ?>
<div class="card-form" id="formState">
<?php if ($form_index_status === 'error' && $form_index_message !== ''): ?>
<div class="form-alert form-alert-error" role="alert">
<?php echo htmlspecialchars($form_index_message, ENT_QUOTES, 'UTF-8'); ?>
</div>
<?php endif; ?>
<form method="post" action="">
<input type="hidden" name="csrf" value="<?php echo htmlspecialchars($CSRF, ENT_QUOTES, 'UTF-8'); ?>">
<input type="hidden" name="form_index" value="1">
<div class="honeypot" aria-hidden="true">
<label for="form_index_company">Company</label>
<input type="text" name="company" id="form_index_company" tabindex="-1" autocomplete="off">
</div>
<div class="fields-grid">
<div class="field field-full">
<label for="f-name">
<?php echo form_index_text($translations, 'recom_fullname_label', 'Имя и фамилия'); ?>
<span class="req">*</span>
</label>
<input
type="text"
id="f-name"
name="name"
autocomplete="name"
required
value="<?php echo form_index_value($form_index_old, 'name'); ?>"
class="<?php echo ! empty($form_index_errors['name']) ? 'error' : ''; ?>"
placeholder="<?php echo form_index_text($translations, 'recom_fullname_placeholder', 'Имя и фамилия специалиста'); ?>"
>
</div>
<div class="field field-full">
<label for="f-profession">
<?php echo form_index_text($translations, 'recom_profession_label', 'Профессия / чем занимается'); ?>
<span class="req">*</span>
</label>
<input
type="text"
id="f-profession"
name="profession"
required
value="<?php echo form_index_value($form_index_old, 'profession'); ?>"
class="<?php echo ! empty($form_index_errors['profession']) ? 'error' : ''; ?>"
placeholder="<?php echo form_index_text($translations, 'recom_profession_placeholder', 'Например: адвокат, врач, переводчик…'); ?>"
>
</div>
<div class="field">
<label for="f-city">
<?php echo form_index_text($translations, 'recom_location_label', 'Город'); ?>
<span class="req">*</span>
</label>
<input
type="text"
id="f-city"
name="city"
required
value="<?php echo form_index_value($form_index_old, 'city'); ?>"
class="<?php echo ! empty($form_index_errors['city']) ? 'error' : ''; ?>"
placeholder="<?php echo form_index_text($translations, 'recom_location_placeholder', 'Город'); ?>"
>
</div>
<div class="field">
<label for="f-country">
<?php echo form_index_text($translations, 'recom_location_label', 'Страна'); ?>
<span class="req">*</span>
</label>
<input
type="text"
id="f-country"
name="country"
required
value="<?php echo form_index_value($form_index_old, 'country'); ?>"
class="<?php echo ! empty($form_index_errors['country']) ? 'error' : ''; ?>"
placeholder="<?php echo form_index_text($translations, 'recom_location_placeholder', 'Страна'); ?>"
>
</div>
<div class="field field-full">
<label for="f-phone">
<?php echo form_index_text($translations, 'recom_phone_label', 'Телефон / e-mail / сайт (что известно)'); ?>
</label>
<input
type="text"
id="f-phone"
name="phone"
value="<?php echo form_index_value($form_index_old, 'phone'); ?>"
class="<?php echo ! empty($form_index_errors['phone']) ? 'error' : ''; ?>"
placeholder="<?php echo form_index_text($translations, 'recom_phone_placeholder', 'Телефон'); ?>"
>
</div>
<div class="field field-full">
<label for="f-email">
<?php echo form_index_text($translations, 'recom_email_label', 'Телефон / e-mail / сайт (что известно)'); ?>
</label>
<input
type="text"
id="f-email"
name="email"
value="<?php echo form_index_value($form_index_old, 'email'); ?>"
class="<?php echo ! empty($form_index_errors['email']) ? 'error' : ''; ?>"
placeholder="<?php echo form_index_text($translations, 'recom_email_placeholder', 'E-mail'); ?>"
>
</div>
<div class="field field-full">
<label for="f-site">
<?php echo form_index_text($translations, 'recom_website_label', 'Телефон / e-mail / сайт (что известно)'); ?>
</label>
<input
type="text"
id="f-site"
name="site"
value="<?php echo form_index_value($form_index_old, 'site'); ?>"
class="<?php echo ! empty($form_index_errors['site']) ? 'error' : ''; ?>"
placeholder="<?php echo form_index_text($translations, 'recom_website_placeholder', 'Адрес сайта'); ?>"
>
</div>
<div class="field field-full">
<label for="f-reason">
<?php echo form_index_text($translations, 'recom_reason_label', 'Почему рекомендуете?'); ?>
<span class="req">*</span>
</label>
<textarea
id="f-reason"
name="reason"
required
maxlength="1000"
class="<?php echo ! empty($form_index_errors['reason']) ? 'error' : ''; ?>"
placeholder="<?php echo form_index_text($translations, 'recom_reason_placeholder', 'Коротко расскажите, почему вы рекомендуете этого специалиста…'); ?>"
><?php echo form_index_value($form_index_old, 'reason'); ?></textarea>
</div>
</div>
<button class="btn-submit" type="submit">
<?php echo form_index_text($translations, 'recom_submit', 'Отправить рекомендацию'); ?>
</button>
<p class="form-note">
<?php echo form_index_text($translations, 'recom_note', 'Пожалуйста, указывайте только известную вам информацию.'); ?>
</p>
</form>
</div>
<?php endif; ?>
</div>
</div>
</section>
<style>
.concierge-section {
font-family: 'Montserrat', sans-serif;
background: #f7f8fc;
padding: 52px 20px;
width: 100%;
}
.concierge-inner { max-width: 700px; margin: 0 auto; }
.concierge-heading { text-align: center; margin-bottom: 32px; }
.concierge-heading .label {
display: inline-block; font-size: 11px; font-weight: 700;
letter-spacing: .12em; text-transform: uppercase; color: #2e4db0;
background: #eef2fb; padding: 5px 14px; border-radius: 20px; margin-bottom: 14px;
}
.concierge-heading h2 {
font-size: clamp(20px, 4vw, 26px); font-weight: 700; color: #1e2d5a;
line-height: 1.3; margin: 0 0 10px;
}
.concierge-heading p {
font-size: 14px; color: #6b7280; line-height: 1.65;
max-width: 500px; margin: 0 auto;
}
.concierge-card {
background: #fff; border-radius: 20px; border: 1.5px solid #dde3f0;
box-shadow: 0 4px 24px rgba(30,45,90,.08); overflow: hidden;
}
.card-stripe { height: 4px; background: linear-gradient(90deg,#1e2d5a 0%,#2e4db0 100%); }
.card-form { padding: 32px 36px 36px; }
.fields-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 16px; }
.field-full { grid-column: 1 / -1; }
.field { display: flex; flex-direction: column; gap: 7px; min-width: 0; }
.field label {
font-size: 12px; font-weight: 600; color: #1e2d5a;
letter-spacing: .03em; text-transform: uppercase;
}
.field label .req { color: #2e4db0; margin-left: 2px; }
.card-form input, .card-form textarea {
box-sizing: border-box; width: 100%; font-family: 'Montserrat', sans-serif;
font-size: 14px; color: #1e2d5a; background: #f7f8fc;
border: 1.5px solid #dde3f0; border-radius: 8px; padding: 11px 14px;
outline: none; transition: border-color .18s,background .18s,box-shadow .18s;
}
.card-form input::placeholder, .card-form textarea::placeholder { color: #b0b8cc; }
.card-form input:focus, .card-form textarea:focus {
border-color: #2e4db0; background: #fff; box-shadow: 0 0 0 3px rgba(46,77,176,.09);
}
.card-form input.error, .card-form textarea.error { border-color: #d73a3a; background: #fff8f8; }
.card-form textarea { resize: vertical; min-height: 100px; line-height: 1.6; }
.btn-submit {
box-sizing: border-box; width: 100%; margin-top: 20px; background: #e03c3f; color: #fff;
font-family: 'Montserrat', sans-serif; font-size: 14px; font-weight: 700;
letter-spacing: .04em; border: 0; border-radius: 999px; padding: 14px 24px;
cursor: pointer; transition: background .18s,transform .12s,box-shadow .18s;
}
.btn-submit:hover { background: #c93639; box-shadow: 0 6px 20px rgba(30,45,90,.22); }
.btn-submit:active { transform: translateY(1px); }
.form-note { text-align: center; font-size: 11px; color: #6b7280; margin: 12px 0 0; line-height: 1.5; }
.form-alert { margin-bottom: 18px; padding: 12px 14px; border-radius: 10px; font-size: 14px; line-height: 1.5; }
.form-alert-error { background: #fff4f4; border: 1px solid #f0caca; color: #9f1d1d; }
.card-success { padding: 52px 36px; text-align: center; }
.success-circle {
width: 56px; height: 56px; border-radius: 50%; background: #1e2d5a;
display: flex; align-items: center; justify-content: center; margin: 0 auto 18px;
font-size: 24px; color: #fff;
}
.card-success h3 { font-size: 20px; font-weight: 700; color: #1e2d5a; margin: 0 0 10px; }
.card-success p { font-size: 14px; color: #6b7280; line-height: 1.65; max-width: 380px; margin: 0 auto; }
.honeypot { position: absolute; left: -9999px; opacity: 0; pointer-events: none; }
@media (max-width: 540px) {
.card-form { padding: 24px 20px 28px; }
.fields-grid { grid-template-columns: 1fr; }
.field-full { grid-column: auto; }
.card-success { padding: 36px 20px; }
.concierge-section { padding: 36px 16px; }
}
</style>
+86 -86
View File
@@ -5,87 +5,87 @@
// ===== Helpers header (identiques à index.php) =====
function is_client_logged_in(): bool
{
$role = $_SESSION['role'] ?? ($_SESSION['user_type'] ?? '');
if (! empty($_SESSION['user_id']) && $role === 'client') {
return true;
}
$role = $_SESSION['role'] ?? ($_SESSION['user_type'] ?? '');
if (! empty($_SESSION['user_id']) && $role === 'client') {
return true;
}
if (! empty($_SESSION['client_id'])) {
return true;
}
if (! empty($_SESSION['client_id'])) {
return true;
}
if (! empty($_SESSION['reference_id']) && $role === 'client') {
return true;
}
if (! empty($_SESSION['reference_id']) && $role === 'client') {
return true;
}
if (! empty($_SESSION['user_id']) && $role === 'praticien') {
return true;
}
if (! empty($_SESSION['user_id']) && $role === 'praticien') {
return true;
}
if (! empty($_SESSION['praticien_id'])) {
return true;
}
if (! empty($_SESSION['praticien_id'])) {
return true;
}
if (! empty($_SESSION['reference_id']) && $role === 'praticien') {
return true;
}
if (! empty($_SESSION['reference_id']) && $role === 'praticien') {
return true;
}
return false;
return false;
}
function include_header_clean(string $absPath): void
{
global $translations, $lang;
ob_start();
include $absPath; // /public/includes/header.php
$buf = ob_get_clean() ?: '';
global $translations, $lang;
ob_start();
include $absPath; // /public/includes/header.php
$buf = ob_get_clean() ?: '';
// 0) DOCTYPE + <html>…</html>
$buf = preg_replace('~<!doctype\s+html[^>]*>~i', '', $buf);
$buf = preg_replace('~</?html\b[^>]*>~i', '', $buf);
// 0) DOCTYPE + <html>…</html>
$buf = preg_replace('~<!doctype\s+html[^>]*>~i', '', $buf);
$buf = preg_replace('~</?html\b[^>]*>~i', '', $buf);
// 1) retirer <head>…</head> et <body> ouverts/fermés
$buf = preg_replace('~<head\b[^>]*>.*?</head>~is', '', $buf);
$buf = preg_replace('~</?body\b[^>]*>~i', '', $buf);
// 1) retirer <head>…</head> et <body> ouverts/fermés
$buf = preg_replace('~<head\b[^>]*>.*?</head>~is', '', $buf);
$buf = preg_replace('~</?body\b[^>]*>~i', '', $buf);
// 2) retirer les <link> CSS “globaux” pour éviter d’écraser la home
$buf = preg_replace('~<link[^>]+href="[^"]*(bootstrap[^"]*\.css|mobil_style\.css|site_style\.css|fonts\.googleapis)[^"]*"[^>]*>~i', '', $buf);
// 2) retirer les <link> CSS “globaux” pour éviter d’écraser la home
$buf = preg_replace('~<link[^>]+href="[^"]*(bootstrap[^"]*\.css|mobil_style\.css|site_style\.css|fonts\.googleapis)[^"]*"[^>]*>~i', '', $buf);
// 3) retirer le <script> Bootstrap CDN (on le charge déjà en bas de la page)
$buf = preg_replace('~<script[^>]+src="[^"]*bootstrap[^"]*bundle[^"]*\.js[^"]*"[^>]*>\s*</script>~i', '', $buf);
// 3) retirer le <script> Bootstrap CDN (on le charge déjà en bas de la page)
$buf = preg_replace('~<script[^>]+src="[^"]*bootstrap[^"]*bundle[^"]*\.js[^"]*"[^>]*>\s*</script>~i', '', $buf);
echo $buf; // garde <header> + tes scripts inline utiles
echo $buf; // garde <header> + tes scripts inline utiles
}
function t(array $translations, string $key, string $fallback = ''): string
{
$val = $translations[$key] ?? '';
if ($val === '') {
return $fallback;
}
$val = $translations[$key] ?? '';
if ($val === '') {
return $fallback;
}
return (string) $val;
return (string) $val;
}
// Lang HTML
$langHtml = preg_match('~^[a-z]{2}(-[A-Z]{2})?$~', (string) ($lang ?? '')) ? (string) $lang : 'ru';
?>
<!doctype html>
<html lang="<?php echo htmlspecialchars($langHtml, ENT_QUOTES, 'UTF-8')?>">
<html lang="<?php echo htmlspecialchars($langHtml, ENT_QUOTES, 'UTF-8') ?>">
<head>
<meta charset="UTF-8">
<title><?php echo htmlspecialchars($translations['seo_how_it_work_title'], ENT_QUOTES, 'UTF-8')?></title>
<meta name="description" content="<?php echo htmlspecialchars($translations['seo_how_it_work_desc'], ENT_QUOTES, 'UTF-8')?>">
<meta name="keywords" content="<?php echo htmlspecialchars($translations['seo_how_it_work_keywords'], ENT_QUOTES, 'UTF-8')?>">
<title><?php echo htmlspecialchars($translations['seo_how_it_work_title'], ENT_QUOTES, 'UTF-8') ?></title>
<meta name="description" content="<?php echo htmlspecialchars($translations['seo_how_it_work_desc'], ENT_QUOTES, 'UTF-8') ?>">
<meta name="keywords" content="<?php echo htmlspecialchars($translations['seo_how_it_work_keywords'], ENT_QUOTES, 'UTF-8') ?>">
<meta name="author" content="Uslugi.fr">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="<?= asset('/includes/site_style.css') ?>">
<link rel="stylesheet" href="<?= asset('/includes/custom_style.css') ?>">
<link rel="stylesheet" href="<?= asset('/includes/mobil_style.css') ?>">
<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') ?>">
<style>
.howitworks { --brand:#38378B; --mint:#06FFA8; --text:#111; --muted:#6b7280; --card:#fff; --border:#e5e7eb; }
.howitworks { font-family: "Montserrat", system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif; color:var(--text); }
@@ -135,9 +135,9 @@
</head>
<body>
<?php if (is_client_logged_in()): ?>
<?php
require_once __DIR__ . '/public/includes/init_pr_cl.php';
include_header_clean(__DIR__ . '/public/includes/header.php'); ?>
<?php
require_once __DIR__ . '/public/includes/init_pr_cl.php';
include_header_clean(__DIR__ . '/public/includes/header.php'); ?>
<?php else: ?>
<header class="site-header">
<div class="container">
@@ -157,8 +157,8 @@
</div>
<nav class="header-actions">
<a class="btn-login" href="/connexion.php">
<span class="d-sm-none"><?php echo htmlspecialchars($translations['btn_se_connecter'] ?? 'Connexion', ENT_QUOTES, 'UTF-8')?></span>
<span class="d-none d-sm-inline"><?php echo htmlspecialchars($translations['ja_spec'] ?? 'Je suis spécialiste', ENT_QUOTES, 'UTF-8')?></span>
<span class="d-sm-none"><?php echo htmlspecialchars($translations['btn_se_connecter'] ?? 'Connexion', ENT_QUOTES, 'UTF-8') ?></span>
<span class="d-none d-sm-inline"><?php echo htmlspecialchars($translations['ja_spec'] ?? 'Je suis spécialiste', ENT_QUOTES, 'UTF-8') ?></span>
</a>
<div class="dropdown">
@@ -168,15 +168,15 @@
data-bs-toggle="dropdown"
data-bs-auto-close="true"
aria-expanded="false"
aria-label="<?php echo htmlspecialchars(t($translations, 'howitworks_help_aria', 'Help'), ENT_QUOTES, 'UTF-8')?>">
aria-label="<?php echo htmlspecialchars(t($translations, 'howitworks_help_aria', 'Help'), ENT_QUOTES, 'UTF-8') ?>">
?
</button>
<ul class="dropdown-menu dropdown-menu-end shadow help-menu menu-panel">
<li><a href="/how-it-work.php"><?php echo htmlspecialchars($translations['kak_rabotaet'] ?? 'Как это работает', ENT_QUOTES, 'UTF-8')?></a></li>
<li><a href="/about.php"><?php echo htmlspecialchars($translations['pro_nas'] ?? 'О нас', ENT_QUOTES, 'UTF-8')?></a></li>
<li><a href="/faq.php"><?php echo htmlspecialchars($translations['faq'] ?? 'FAQ', ENT_QUOTES, 'UTF-8')?></a></li>
<li><a href="/contact.php"><?php echo htmlspecialchars($translations['nam_pisat'] ?? 'Написать нам', ENT_QUOTES, 'UTF-8')?></a></li>
<li><a href="/how-it-work.php"><?php echo htmlspecialchars($translations['kak_rabotaet'] ?? 'Как это работает', ENT_QUOTES, 'UTF-8') ?></a></li>
<li><a href="/about.php"><?php echo htmlspecialchars($translations['pro_nas'] ?? 'О нас', ENT_QUOTES, 'UTF-8') ?></a></li>
<li><a href="/faq.php"><?php echo htmlspecialchars($translations['faq'] ?? 'FAQ', ENT_QUOTES, 'UTF-8') ?></a></li>
<li><a href="/contact.php"><?php echo htmlspecialchars($translations['nam_pisat'] ?? 'Написать нам', ENT_QUOTES, 'UTF-8') ?></a></li>
</ul>
</div>
@@ -193,111 +193,111 @@
<div class="wrap">
<div class="card" style="margin-bottom:18px;">
<h2><?php echo htmlspecialchars(t($translations, 'howitworks_short_title', 'How it works'), ENT_QUOTES, 'UTF-8')?></h2>
<h2><?php echo htmlspecialchars(t($translations, 'howitworks_short_title', 'How it works'), ENT_QUOTES, 'UTF-8') ?></h2>
<div class="hiw-steps">
<div class="step">
<div class="step-icon">📝</div>
<div>
<h3><?php echo htmlspecialchars(t($translations, 'howitworks_step1_title', 'Registration'), ENT_QUOTES, 'UTF-8')?></h3>
<p><?php echo htmlspecialchars(t($translations, 'howitworks_step1_text', 'Create your account in minutes.'), ENT_QUOTES, 'UTF-8')?></p>
<h3><?php echo htmlspecialchars(t($translations, 'howitworks_step1_title', 'Registration'), ENT_QUOTES, 'UTF-8') ?></h3>
<p><?php echo htmlspecialchars(t($translations, 'howitworks_step1_text', 'Create your account in minutes.'), ENT_QUOTES, 'UTF-8') ?></p>
</div>
</div>
<div class="step">
<div class="step-icon">🔎</div>
<div>
<h3><?php echo htmlspecialchars(t($translations, 'howitworks_step2_title', 'Choose a specialist'), ENT_QUOTES, 'UTF-8')?></h3>
<p><?php echo htmlspecialchars(t($translations, 'howitworks_step2_text', 'Find an expert and pick a time.'), ENT_QUOTES, 'UTF-8')?></p>
<h3><?php echo htmlspecialchars(t($translations, 'howitworks_step2_title', 'Choose a specialist'), ENT_QUOTES, 'UTF-8') ?></h3>
<p><?php echo htmlspecialchars(t($translations, 'howitworks_step2_text', 'Find an expert and pick a time.'), ENT_QUOTES, 'UTF-8') ?></p>
</div>
</div>
<div class="step">
<div class="step-icon">✉️</div>
<div>
<h3><?php echo htmlspecialchars(t($translations, 'howitworks_step3_title', 'Confirmation'), ENT_QUOTES, 'UTF-8')?></h3>
<p><?php echo htmlspecialchars(t($translations, 'howitworks_step3_text', 'Receive an email confirmation and pay the specialist directly.'), ENT_QUOTES, 'UTF-8')?></p>
<h3><?php echo htmlspecialchars(t($translations, 'howitworks_step3_title', 'Confirmation'), ENT_QUOTES, 'UTF-8') ?></h3>
<p><?php echo htmlspecialchars(t($translations, 'howitworks_step3_text', 'Receive an email confirmation and pay the specialist directly.'), ENT_QUOTES, 'UTF-8') ?></p>
</div>
</div>
<div class="step">
<div class="step-icon">🎥</div>
<div>
<h3><?php echo htmlspecialchars(t($translations, 'howitworks_step4_title', 'Online consultation'), ENT_QUOTES, 'UTF-8')?></h3>
<p><?php echo htmlspecialchars(t($translations, 'howitworks_step4_text', 'Happens on our website via Jitsi.'), ENT_QUOTES, 'UTF-8')?></p>
<h3><?php echo htmlspecialchars(t($translations, 'howitworks_step4_title', 'Online consultation'), ENT_QUOTES, 'UTF-8') ?></h3>
<p><?php echo htmlspecialchars(t($translations, 'howitworks_step4_text', 'Happens on our website via Jitsi.'), ENT_QUOTES, 'UTF-8') ?></p>
</div>
</div>
</div>
</div>
<div class="card">
<h2><?php echo htmlspecialchars(t($translations, 'howitworks_long_title', 'How uslugi.fr works'), ENT_QUOTES, 'UTF-8')?></h2>
<h2><?php echo htmlspecialchars(t($translations, 'howitworks_long_title', 'How uslugi.fr works'), ENT_QUOTES, 'UTF-8') ?></h2>
<p class="hiw-intro">
<?php echo htmlspecialchars(t($translations, 'howitworks_long_intro', 'We built the website to help you find a trusted Russian-speaking specialist in France and get a consultation easily.'), ENT_QUOTES, 'UTF-8')?>
<?php echo htmlspecialchars(t($translations, 'howitworks_long_intro', 'We built the website to help you find a trusted Russian-speaking specialist in France and get a consultation easily.'), ENT_QUOTES, 'UTF-8') ?>
</p>
<ul class="hiw-list">
<li class="hiw-item">
<div class="dot">1</div>
<div>
<h4><?php echo htmlspecialchars(t($translations, 'howitworks_item1_title', 'Registration'), ENT_QUOTES, 'UTF-8')?></h4>
<p><?php echo htmlspecialchars(t($translations, 'howitworks_item1_text', 'Create your personal account in minutes.'), ENT_QUOTES, 'UTF-8')?></p>
<h4><?php echo htmlspecialchars(t($translations, 'howitworks_item1_title', 'Registration'), ENT_QUOTES, 'UTF-8') ?></h4>
<p><?php echo htmlspecialchars(t($translations, 'howitworks_item1_text', 'Create your personal account in minutes.'), ENT_QUOTES, 'UTF-8') ?></p>
</div>
</li>
<li class="hiw-item">
<div class="dot">2</div>
<div>
<h4><?php echo htmlspecialchars(t($translations, 'howitworks_item2_title', 'Choose a specialist'), ENT_QUOTES, 'UTF-8')?></h4>
<p><?php echo htmlspecialchars(t($translations, 'howitworks_item2_text', 'In the catalog: lawyers, notaries, consultants, psychologists and translators. Each specialist has a calendar with available dates and times.'), ENT_QUOTES, 'UTF-8')?></p>
<h4><?php echo htmlspecialchars(t($translations, 'howitworks_item2_title', 'Choose a specialist'), ENT_QUOTES, 'UTF-8') ?></h4>
<p><?php echo htmlspecialchars(t($translations, 'howitworks_item2_text', 'In the catalog: lawyers, notaries, consultants, psychologists and translators. Each specialist has a calendar with available dates and times.'), ENT_QUOTES, 'UTF-8') ?></p>
</div>
</li>
<li class="hiw-item">
<div class="dot">3</div>
<div>
<h4><?php echo htmlspecialchars(t($translations, 'howitworks_item3_title', 'Booking'), ENT_QUOTES, 'UTF-8')?></h4>
<p><?php echo htmlspecialchars(t($translations, 'howitworks_item3_text', 'Pick a time and receive an email confirmation.'), ENT_QUOTES, 'UTF-8')?></p>
<h4><?php echo htmlspecialchars(t($translations, 'howitworks_item3_title', 'Booking'), ENT_QUOTES, 'UTF-8') ?></h4>
<p><?php echo htmlspecialchars(t($translations, 'howitworks_item3_text', 'Pick a time and receive an email confirmation.'), ENT_QUOTES, 'UTF-8') ?></p>
</div>
</li>
<li class="hiw-item">
<div class="dot">4</div>
<div>
<h4><?php echo htmlspecialchars(t($translations, 'howitworks_item4_title', 'Payment'), ENT_QUOTES, 'UTF-8')?></h4>
<p><?php echo htmlspecialchars(t($translations, 'howitworks_item4_text', 'Pay the specialist directly — we do not take any commission.'), ENT_QUOTES, 'UTF-8')?></p>
<h4><?php echo htmlspecialchars(t($translations, 'howitworks_item4_title', 'Payment'), ENT_QUOTES, 'UTF-8') ?></h4>
<p><?php echo htmlspecialchars(t($translations, 'howitworks_item4_text', 'Pay the specialist directly — we do not take any commission.'), ENT_QUOTES, 'UTF-8') ?></p>
</div>
</li>
<li class="hiw-item">
<div class="dot">5</div>
<div>
<h4><?php echo htmlspecialchars(t($translations, 'howitworks_item5_title', 'Chat'), ENT_QUOTES, 'UTF-8')?></h4>
<p><?php echo htmlspecialchars(t($translations, 'howitworks_item5_text', 'Before the consultation, you can уточнить детали in chat with the expert.'), ENT_QUOTES, 'UTF-8')?></p>
<h4><?php echo htmlspecialchars(t($translations, 'howitworks_item5_title', 'Chat'), ENT_QUOTES, 'UTF-8') ?></h4>
<p><?php echo htmlspecialchars(t($translations, 'howitworks_item5_text', 'Before the consultation, you can уточнить детали in chat with the expert.'), ENT_QUOTES, 'UTF-8') ?></p>
</div>
</li>
<li class="hiw-item">
<div class="dot">6</div>
<div>
<h4><?php echo htmlspecialchars(t($translations, 'howitworks_item6_title', 'Online meeting'), ENT_QUOTES, 'UTF-8')?></h4>
<p><?php echo htmlspecialchars(t($translations, 'howitworks_item6_text', 'The consultation takes place via Jitsi on our website — just open the link.'), ENT_QUOTES, 'UTF-8')?></p>
<h4><?php echo htmlspecialchars(t($translations, 'howitworks_item6_title', 'Online meeting'), ENT_QUOTES, 'UTF-8') ?></h4>
<p><?php echo htmlspecialchars(t($translations, 'howitworks_item6_text', 'The consultation takes place via Jitsi on our website — just open the link.'), ENT_QUOTES, 'UTF-8') ?></p>
</div>
</li>
<li class="hiw-item">
<div class="dot">7</div>
<div>
<h4><?php echo htmlspecialchars(t($translations, 'howitworks_item7_title', 'Cancellation'), ENT_QUOTES, 'UTF-8')?></h4>
<p><?php echo htmlspecialchars(t($translations, 'howitworks_item7_text', 'If plans change, each specialist has their own cancellation policy.'), ENT_QUOTES, 'UTF-8')?></p>
<h4><?php echo htmlspecialchars(t($translations, 'howitworks_item7_title', 'Cancellation'), ENT_QUOTES, 'UTF-8') ?></h4>
<p><?php echo htmlspecialchars(t($translations, 'howitworks_item7_text', 'If plans change, each specialist has their own cancellation policy.'), ENT_QUOTES, 'UTF-8') ?></p>
</div>
</li>
</ul>
<div class="callout">
<strong><?php echo htmlspecialchars(t($translations, 'howitworks_goal_label', 'Our goal:'), ENT_QUOTES, 'UTF-8')?></strong>
<?php echo htmlspecialchars(t($translations, 'howitworks_goal_text', 'Connect you with the right Russian-speaking specialist in France and make everything simple and convenient.'), ENT_QUOTES, 'UTF-8')?>
<strong><?php echo htmlspecialchars(t($translations, 'howitworks_goal_label', 'Our goal:'), ENT_QUOTES, 'UTF-8') ?></strong>
<?php echo htmlspecialchars(t($translations, 'howitworks_goal_text', 'Connect you with the right Russian-speaking specialist in France and make everything simple and convenient.'), ENT_QUOTES, 'UTF-8') ?>
</div>
</div>
@@ -309,7 +309,7 @@
<footer class="site-footer">
<div class="container">
<p><?php echo $translations['copyr']?></p>
<p><?php echo $translations['copyr'] ?></p>
</div>
</footer>
+2
View File
@@ -1,4 +1,5 @@
@import url("https://fonts.googleapis.com/css2?family=Montserrat:wght@100..900&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Playfair+Display:wght@100800&display=swap");
:root {
--red: #e03c3f;
@@ -211,6 +212,7 @@ body {
padding: 0 18px;
}
.hero-title {
font-family: "Playfair Display", serif;
color: #38378b;
text-align: center;
font-size: 48px;
+943
View File
@@ -0,0 +1,943 @@
@import url("https://fonts.googleapis.com/css2?family=Montserrat:wght@100..900&display=swap");
:root {
--red: #e03c3f;
--white: #ffffff;
--blue: #38378b;
--mint: #06ffa8;
--hero: #8ca9ff; /* bleu clair fond hero (d’après maquette) */
--header: #f1f1f1;
--radius: 22px;
--c-bg: #8fa2ff; /* fond bleu/violet actuel de ton hero */
--c-dark: #38378b; /* bleu foncé de ta charte */
--c-white: #ffffff;
--c-shadow: 0 10px 24px rgba(0, 0, 0, 0.12);
}
.only-mobile {
display: none;
}
@media (max-width: 956px) {
.only-desktop {
display: none;
}
.only-mobile {
display: inline;
}
}
/*Boutons page accueil du site*/
.steps {
width: min(800px, 92vw);
margin: 40px auto 0;
position: relative;
display: grid;
gap: 36px;
}
.step {
position: relative;
display: inline-flex;
align-items: center;
gap: 0;
filter: drop-shadow(0 6px 10px rgba(0, 0, 0, 0.08));
}
.step-badge {
display: grid;
place-items: center;
width: 110px;
height: 110px;
border-radius: 50%;
background: var(--c-white);
color: var(--c-dark);
font-weight: 800;
font-size: clamp(28px, 5vw, 56px);
line-height: 1;
box-shadow: var(--c-shadow);
z-index: 1;
}
.step-label {
background: var(--c-white);
color: var(--c-dark);
font-weight: 700;
font-size: clamp(16px, 2.6vw, 26px);
padding: 14px 26px 14px 38px; /* pour chevauchement côté gauche */
border-radius: 999px;
white-space: nowrap;
box-shadow: var(--c-shadow);
margin-left: -30px;
z-index: 0;
}
/* Étape 3 inversée */
.step--reverse {
flex-direction: row-reverse; /* inverse ordre badge et label */
}
.step--reverse .step-label {
padding: 14px 38px 14px 26px; /* espace à droite */
margin-left: 0;
margin-right: -30px; /* chevauchement côté droit */
}
/* tailles différentes pour chaque étape */
.step:nth-child(1) .step-badge {
width: 110px;
height: 110px;
font-size: clamp(28px, 5vw, 56px);
}
.step:nth-child(2) .step-badge {
width: 132px;
height: 132px;
font-size: clamp(32px, 5.5vw, 64px);
}
.step:nth-child(3) .step-badge {
width: 158px;
height: 158px;
font-size: clamp(36px, 6vw, 72px);
}
/* placements (comme sur ta maquette) */
.step--left {
justify-self: start;
transform: translateX(0);
}
.step--center {
justify-self: center;
transform: translateY(8px);
padding-left: 230px;
}
.step--right {
justify-self: end;
transform: translateX(0);
}
/*Fin boutons rondes*/
* {
box-sizing: border-box;
}
html,
body {
height: 100%;
}
body {
margin: 0;
font-family:
"Montserrat",
system-ui,
-apple-system,
Segoe UI,
Roboto,
Arial,
sans-serif;
color: #111;
/*background: var(--hero);*/
display: grid;
grid-template-rows: auto 1fr auto; /* header, contenu, footer */
}
/* Header */
.site-header {
background: var(--header);
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
}
.site-header .container {
max-width: 1200px;
margin: 0 auto;
padding: 10px 18px;
display: flex;
align-items: center;
justify-content: space-between;
}
/* ==== LOGO: mobile vs desktop (béton) ==== */
.brand {
letter-spacing: 0.5px;
font-weight: 700;
display: flex;
align-items: center;
line-height: 0; /* évite petits décalages baseline */
}
.header-left {
display: flex;
align-items: center;
gap: 8px; /* distance logo ↔ langue */
}
.brand .logo-mobile,
.brand .logo-desktop {
display: none !important; /* on cache tout par défaut */
height: 40px; /* taille unique (tu ajustes) */
width: auto;
}
/* Mobile: logo_u */
@media (max-width: 767.98px) {
.brand .logo-mobile {
display: block !important;
}
}
/* Desktop: logo.png */
@media (min-width: 768px) {
.brand .logo-desktop {
display: block !important;
}
}
/* Actions header */
.header-actions {
display: flex;
align-items: center;
gap: 10px;
}
.icon-btn {
border: none;
background: #000;
color: #fff;
width: 28px;
height: 28px;
border-radius: 6px;
}
/* HERO */
.hero {
padding: 0 0 56px;
background: var(--hero);
}
.hero .container {
max-width: 1100px;
margin: 0 auto;
padding: 0 18px;
}
.hero-title {
color: #38378b;
text-align: center;
font-size: 48px;
line-height: 1.16;
font-weight: 800;
margin: 5px 0 26px;
}
/* Bouton LOGIN */
.btn-login {
background: var(--red);
color: #fff;
text-decoration: none;
padding: 8px 14px;
border-radius: 999px;
font-weight: 500;
box-shadow: 0 8px 22px rgba(0, 0, 0, 0.18);
/*font-size: clamp(12px, 2vw, 16px);*/
}
/* grille 3 au-dessus + 1 en dessous */
/* style des blocs ovales */
.hero .row {
display: flex;
justify-content: center;
gap: 20px;
margin: 15px 0;
flex-wrap: wrap; /* au cas où ; reste cohérent */
}
.chip {
appearance: none;
background: #fff;
cursor: pointer;
color: #000000;
width: 230px; /* largeur fixe */
text-align: center; /* texte centré */
padding: 12px 0; /* hauteur uniforme */
border-radius: 15px; /* ovale */
font-weight: 600;
font-size: 16px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.15);
border: 0;
}
/* Footer plus large (haut) et gris, toujours en bas */
footer {
background: var(--header);
border-top: 1px solid rgba(0, 0, 0, 0.06);
padding: 22px 20px; /* plus haut qu’avant */
}
footer p {
margin: 0;
text-align: center;
color: #222;
font-size: 13px;
}
/*===================================================================================================================*/
/*La partie affichage pour la page aprés la recherche*/
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 18px;
}
/* Liste : espace entre blocs */
.pro-list {
display: flex;
flex-direction: column;
gap: 40px; /* augmente l’écart vertical */
padding: 20px 0 40px;
}
/* Carte = 4 colonnes : photo | infos | vidéo | bouton */
.pro-card {
background: #fff;
border-radius: 28px;
box-shadow: 0 14px 30px rgba(0, 0, 0, 0.18);
display: grid;
/* NE PAS forcer start ici */
align-items: stretch; /* <— important */
gap: 20px;
padding: 20px;
grid-template-columns: 260px 1.5fr 240px 180px;
grid-template-areas: "photo info video cta";
}
/* 1) Photo portrait, non déformée (recadrage OK) */
.pro-photo {
grid-area: photo;
}
.pro-photo img {
width: 100%;
aspect-ratio: 3/4; /* portrait */
object-fit: cover; /* pas de déformation */
display: block;
border-radius: 22px;
}
/* 2) Infos */
.pro-info {
grid-area: info;
padding: 0 6px;
color: #1b1b1b;
}
.pro-name {
margin: 0 0 8px;
font-size: 26px;
font-weight: 800;
}
.pro-spec {
color: #38378b;
font-weight: 700;
margin-bottom: 10px;
}
.pro-desc {
color: #3f3f3f;
line-height: 1.45;
font-size: 1.05rem; /* augmente légèrement la taille */
max-width: 95%; /* laisse plus d’espace dans la colonne */
}
.pro-info .favori {
top: 10px;
right: 10px; /* passe à left:10px si tu le veux à gauche */
z-index: 2;
font-size: 16px;
line-height: 1;
cursor: pointer;
user-select: none;
filter: drop-shadow(0 2px 6px rgba(6, 6, 6, 0.25));
transition:
transform 0.15s ease,
opacity 0.15s ease;
}
.pro-info .favori:hover {
transform: scale(1.1);
}
.pro-info .favori.ajoute {
color: rgb(12, 12, 11);
transform: scale(1.15);
}
/* 3) Vidéo (vignette 16:9) */
/* même gabarit pour lien vidéo ET placeholder */
.pro-video,
.pro-video.placeholder {
position: relative;
display: block;
aspect-ratio: 4 / 3; /* <- ton format souhaité */
max-height: 180px;
border-radius: 18px;
overflow: hidden;
background: #000; /* évite les bordures blanches */
}
/* l'image occupe tout l'espace du cadre */
.pro-video img,
.pro-video.placeholder img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
/* optionnel: largeur de la colonne vidéo */
.pro-video-col {
display: flex;
align-items: center; /* centre verticalement dans la colonne */
justify-content: center;
width: clamp(240px, 32vw, 200px);
}
/* 4) Bouton dans sa colonne, centré verticalement et aligné à droite */
.pro-cta-col {
grid-area: cta;
display: flex;
align-items: center; /* centre verticalement */
justify-content: center; /* centre horizontalement */
}
.pro-cta {
background: #e03c3f;
color: #fff;
text-decoration: none;
font-weight: 600;
padding: 10px 18px;
border-radius: 999px;
box-shadow: 0 8px 22px rgba(0, 0, 0, 0.18);
white-space: nowrap;
/*font-size: 0.95rem;*/
}
/* Langue choix*/
/* Sélecteur de langue dans le header */
.lang-switch {
display: flex;
gap: 6px;
height: 42px;
background: #fff;
padding: 6px;
border-radius: 20px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
}
.lang-btn {
display: inline-block;
padding: 4px 10px;
font-size: 13px;
font-weight: 700;
text-decoration: none;
color: #38378b; /* bleu foncé */
border-radius: 14px;
transition: all 0.2s ease-in-out;
}
.lang-btn:hover {
background: rgba(56, 55, 139, 0.08);
}
.lang-btn.active {
background: #38378b; /* bleu foncé */
color: #fff;
}
a {
text-decoration: none;
color: #000;
}
/* Compact */
.pro-card--sm {
--pro-card-pad: 12px;
--pro-card-gap: 10px;
--pro-avatar: 72px;
--pro-title: 16px;
--pro-lines: 2;
}
/* Large */
.pro-card--lg {
--pro-card-pad: 22px;
--pro-card-gap: 18px;
--pro-avatar: 100px;
--pro-title: 20px;
--pro-lines: 4;
}
.results-title,
.results-meta,
.result-count {
color: #fff;
text-align: center;
}
.btn-logo {
--bs-btn-bg: #38378b;
--bs-btn-border-color: #38378b;
--bs-btn-hover-bg: #2f2e77;
--bs-btn-hover-border-color: #2f2e77;
--bs-btn-active-bg: #24235e;
--bs-btn-active-border-color: #24235e;
--bs-btn-color: #fff; /* blanc par défaut */
--bs-btn-focus-shadow-rgb: 56, 55, 139; /* halo focus */
}
/* On force la couleur du texte à blanc dans tous les états */
.btn-logo,
.btn-logo:hover,
.btn-logo:active,
.btn-logo:focus,
.btn-logo:focus-visible {
color: #fff !important;
}
/* Menu compact, largeur auto comme dans ta maquette */
.help-menu {
min-width: auto; /* override Bootstrap */
width: max-content; /* s’adapte au contenu */
max-width: 92vw; /* borne mobile */
border-radius: 12px;
padding: 8px;
}
.help-menu .dropdown-item {
padding: 10px 14px;
white-space: nowrap;
}
.help-menu .dropdown-item + .dropdown-item {
margin-top: 6px;
} /* petits espacements */
@media (min-width: 576px) {
.help-menu {
max-width: 360px;
} /* borne desktop */
}
/* Taille tactile du bouton “?” */
.question-btn {
width: 38px;
height: 38px;
font-size: 22px;
font-weight: 700;
line-height: 1;
padding: 0;
}
/* Menu plus étroit (recommandé) */
.offcanvas-slim {
--bs-offcanvas-width: clamp(240px, 80vw, 320px);
}
/* Option: largeur calée au titre (plus “compacte”) */
/* .offcanvas-slim{ --bs-offcanvas-width: fit-content; max-width: min(90vw, 360px); } */
/* Fallback minimal sans Bootstrap */
.d-none {
display: none !important;
}
.d-sm-inline {
display: none !important;
}
.d-sm-none {
display: inline !important;
}
.text-nowrap {
white-space: nowrap !important;
}
@media (min-width: 576px) {
.d-sm-inline {
display: inline !important;
}
.d-sm-none {
display: none !important;
}
}
/* ==== VISUEL COMMUN POUR TOUS LES MENUS ==== */
.menu-panel {
background: #fff;
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 12px;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);
min-width: 230px;
padding: 8px 0;
}
/* Items menu principal (li custom OU .dropdown-item Bootstrap) */
.menu-panel > li,
.menu-panel .dropdown-item {
padding: 12px 18px;
font-size: 16px;
line-height: 1.25;
white-space: nowrap;
cursor: pointer;
transition: background 0.2s ease;
}
.menu-panel > li + li,
.menu-panel .dropdown-item + .dropdown-item {
border-top: 1px solid #f1f1f1;
}
.menu-panel > li:hover,
.menu-panel .dropdown-item:hover {
background: #f8f9fa; /* juste fond gris clair */
}
.menu-panel a {
color: inherit;
text-decoration: none;
display: block;
cursor: pointer;
}
/* ==== MENU “BURGER” CUSTOM ==== */
.menu-wrap {
position: relative;
}
.dropdown-menu-custom {
position: absolute;
top: calc(100% + 8px);
right: 0;
list-style: none;
margin: 0;
display: none; /* fermé par défaut */
z-index: 1100;
}
.dropdown-menu-custom.is-open {
display: block;
}
/* Sous-menu */
.has-submenu .submenu-toggle {
width: 100%;
text-align: left;
background: none;
border: 0;
padding: 0.55rem 1rem;
font-weight: 400;
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
}
.submenu {
list-style: none;
margin: 0;
padding: 0 0 0.5rem 0;
}
.submenu > li {
padding: 0.4rem 1rem 0.4rem 1.5rem;
cursor: pointer;
transition: background 0.2s ease;
}
.submenu > li:hover {
background: #fff; /* juste fond gris clair */
}
.submenu[hidden] {
display: none;
}
/* ==== MENU “?” BOOTSTRAP ==== */
.dropdown-menu.menu-panel {
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 12px;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);
min-width: 230px;
padding: 8px 0;
}
/* Sécurité : que rien ne coupe les menus */
.site-header,
.header-actions,
.menu-wrap,
.dropdown {
overflow: visible;
}
/* Bouton avatar (menu principal) */
#btnMenu {
background: none;
border: none;
padding: 0;
cursor: pointer;
-webkit-tap-highlight-color: transparent; /* enlève flash bleu sur mobile */
padding-left: 10px;
}
/* Supprime le halo/cadre bleu par défaut */
#btnMenu:focus,
#btnMenu:active {
outline: none;
box-shadow: none;
}
/* Si tu veux garder une indication focus clavier accessible */
#btnMenu:focus-visible {
outline: 2px solid var(--color-blue); /* ou une couleur douce */
outline-offset: 3px;
border-radius: 50%;
}
.footer-top-links {
color: #38378b;
font-weight: 600;
}
.footer-top-links a {
color: inherit; /* hérite du bleu foncé */
}
/* ===== Personnalisation bandeau cookies (CookieConsent v3) ===== */
#cc-main {
--cc-font-family: "Montserrat", sans-serif;
/* Couleurs de texte */
--cc-primary-color: #38378b; /* titres/links -> bleu foncé */
--cc-secondary-color: #38378b; /* paragraphe du bandeau */
/* Bouton principal (Accepter tout) -> rouge arrondi */
--cc-btn-border-radius: 22px;
--cc-btn-primary-bg: #e03c3f;
--cc-btn-primary-color: #ffffff;
--cc-btn-primary-border-color: #e03c3f;
--cc-btn-primary-hover-bg: #c92f33; /* rouge un peu plus foncé */
--cc-btn-primary-hover-color: #ffffff;
--cc-btn-primary-hover-border-color: #c92f33;
/* Boutons secondaires (Refuser / Paramétrer) -> fond blanc, bord gris, arrondi */
--cc-btn-secondary-bg: #ffffff;
--cc-btn-secondary-color: #38378b;
--cc-btn-secondary-border-color: #d9dee3;
--cc-btn-secondary-hover-bg: #f4f6f8;
--cc-btn-secondary-hover-color: #38378b;
--cc-btn-secondary-hover-border-color: #c9d0d6;
/* Séparateur & fond pieds/bords pour un rendu plus clean */
--cc-separator-border-color: #eef2f5;
--cc-footer-bg: #ffffff;
--cc-footer-color: #38378b;
/* Optionnel: arrondir la carte elle-même */
--cc-modal-border-radius: 22px;
}
/* Si tu veux forcer l’arrondi aussi quand des classes sont injectées */
#cc-main .cm__btn,
#cc-main .pm__btn {
border-radius: 22px;
}
/*===================================================================================================================*/
/* --- Container modal --- */
.vmodal {
position: fixed;
inset: 0;
display: none;
z-index: 99999;
}
.vmodal[aria-hidden="false"] {
display: block;
}
.vmodal__backdrop {
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.6);
}
/* --- Boîte --- */
.vmodal__dialog {
position: relative;
z-index: 2;
max-width: 1000px;
width: 92%;
margin: 40px auto;
background: #fff;
border-radius: 16px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25);
overflow: hidden; /* pour arrondis propres */
}
/* --- Header “Bootstrap-like” --- */
.vmodal__header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.85rem 1rem;
border-bottom: 1px solid rgba(0, 0, 0, 0.08);
background: #fff;
}
.vmodal__title {
margin: 0;
font-size: 1.1rem;
font-weight: 600;
color: #111;
}
/* --- Close visible (rond blanc) --- */
.vmodal__close {
border: 0;
background: #fff;
color: #111;
width: 36px;
height: 36px;
border-radius: 999px;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 22px;
line-height: 1;
cursor: pointer;
border: 1px solid rgba(0, 0, 0, 0.1);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
}
.vmodal__close:hover {
filter: brightness(0.95);
}
/* --- Body + ratio vidéo --- */
.vmodal__body {
padding: 1rem;
}
.vmodal__ratio {
position: relative;
width: 100%;
aspect-ratio: 16/9;
overflow: hidden;
border-radius: 12px;
background: #000;
}
.vmodal__ratio iframe {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
border: 0;
}
/* --- Footer --- */
.vmodal__footer {
display: flex;
justify-content: flex-end;
gap: 0.5rem;
padding: 0.85rem 1rem;
border-top: 1px solid rgba(0, 0, 0, 0.08);
background: #fff;
}
.btn.btn-secondary-like {
appearance: none;
border: 1px solid #ced4da;
background: #f8f9fa;
color: #212529;
padding: 0.5rem 0.9rem;
border-radius: 0.35rem;
cursor: pointer;
}
.btn.btn-secondary-like:hover {
background: #e9ecef;
}
.no-results {
text-align: center; /* centre le texte */
color: #fff; /* texte en blanc */
}
/* --- Mobile --- */
@media (max-width: 575.98px) {
.vmodal__dialog {
margin: 16px auto;
width: 96%;
}
.vmodal__title {
font-size: 1rem;
}
}
.pager {
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
margin: 22px 0;
}
.pager a {
text-decoration: none;
font-weight: 700;
}
.pager-arrow {
padding: 10px 18px;
border-radius: 999px;
border: 1px solid #e0e3eb;
background: #fff;
color: #38378b;
box-shadow: 0 6px 14px rgba(0, 0, 0, 0.06);
transition:
background 0.2s,
transform 0.1s,
opacity 0.2s;
}
.pager-arrow:hover {
background: #f8f9ff;
transform: translateY(-1px);
}
.pager-arrow.is-disabled {
opacity: 0.4;
pointer-events: none;
}
.pager-page {
width: 40px;
height: 40px;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 50%;
border: 1px solid #e0e3eb;
background: #fff;
color: #38378b;
box-shadow: 0 6px 14px rgba(0, 0, 0, 0.06);
transition:
background 0.2s,
transform 0.1s,
color 0.2s,
border-color 0.2s;
}
.pager-page:hover {
background: #f8f9ff;
transform: translateY(-1px);
}
.pager-page.is-active {
background: #e03c3f;
color: #fff;
border-color: #e03c3f;
transform: none;
}
.menu-item-form {
padding: 0 !important;
list-style: none;
}
.menu-logout-form {
margin: 0;
width: 100%;
}
.menu-logout-btn {
all: unset;
box-sizing: border-box;
display: block;
width: 100%;
padding: 12px 16px;
cursor: pointer;
font: inherit;
color: inherit;
text-align: left;
}
.menu-logout-btn:hover {
background: #f3f4f6;
}
.menu-logout-btn:focus-visible {
outline: 2px solid #94a3b8;
outline-offset: -2px;
}
+10 -13
View File
@@ -291,36 +291,32 @@
margin-top: 24px;
padding: 28px 22px;
border-radius: 12px;
background: #8ca9ff;
box-shadow: 0 20px 40px rgba(127, 91, 255, 0.2);
color: #fff;
/* ⬇️ IMPORTANT */
display: grid;
grid-template-columns: auto 1fr auto; /* gauche | milieu | droite */
align-items: center;
column-gap: 22px;
text-align: left;
/* 1. Force l'alignement horizontal global des colonnes au centre */
text-align: center;
}
/* Titre */
.spec-cta-wrap h3 {
margin: 0;
font-size: 34px; /* pour se rapprocher de la capture 2 */
font-weight: 700;
font-size: 24px;
font-weight: 500;
line-height: 1.1;
white-space: nowrap; /* optionnel: évite retour ligne */
white-space: nowrap;
}
/* Paragraphe */
.spec-cta-wrap p {
margin: 0;
margin: 0 auto; /* 2. "auto" à gauche et à droite centre le bloc qui a un max-width */
font-size: 18px;
opacity: 0.95;
line-height: 1.35;
max-width: 520px; /* pour un look “milieu” */
max-width: 520px;
}
/* Bouton blanc */
@@ -488,7 +484,8 @@
}
.spec-cta-wrap h3 {
font-size: 26px;
font-size: 16px;
font-weight: 500;
white-space: normal;
}
+507
View File
@@ -0,0 +1,507 @@
/* =========================================================
1) Liens / Chips
========================================================= */
.chip-link {
display: inline-flex;
align-items: center;
justify-content: center;
text-decoration: none;
}
/* =========================================================
2) Grand panneau blanc
========================================================= */
.home-panel {
max-width: 850px;
margin: 22px auto 0;
background: rgba(255, 255, 255, 0.92);
border: 1px solid rgba(255, 255, 255, 0.45);
border-radius: 22px;
/*box-shadow: 0 10px 26px rgba(0, 0, 0, 0.14);*/
overflow: hidden;
}
.home-panel__inner {
padding: 18px 16px;
}
.home-panel__divider {
height: 1px;
background: rgba(0, 0, 0, 0.06);
margin: 14px 0;
}
/* =========================================================
3) Checklist
========================================================= */
.home-checklist {
padding: 14px 14px 10px;
}
.home-checklist ul {
list-style: none;
padding: 0;
margin: 0;
display: grid;
gap: 10px;
}
.home-checklist li {
display: flex;
gap: 10px;
align-items: flex-start;
color: #1b1b1b;
}
.home-check {
width: 22px;
height: 22px;
border-radius: 999px;
background: rgba(6, 255, 168, 0.18);
display: grid;
place-items: center;
}
.home-check svg {
width: 14px;
height: 14px;
}
/* =========================================================
4) Titres
========================================================= */
.home-h2 {
margin: 0 0 12px;
font-size: 22px;
font-weight: 800;
color: #1b1b1b;
}
/* =========================================================
5) Liste praticiens
========================================================= */
.hp-list {
display: grid;
gap: 12px;
}
/* --- Carte --- */
.hp-card {
background: #fff;
border: 1px solid rgba(0, 0, 0, 0.06);
border-radius: 16px;
box-shadow: 0 8px 18px rgba(0, 0, 0, 0.08);
padding: 12px;
}
/* --- Ligne 1 : avatar | texte | rating --- */
.hp-row1 {
display: flex;
align-items: flex-start;
gap: 12px;
}
.hp-avatar {
width: 56px;
height: 56px;
border-radius: 14px;
object-fit: cover;
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
}
.hp-main {
flex: 1;
min-width: 0;
}
.hp-name {
margin: 0;
font-size: 16px;
font-weight: 800;
color: #111;
line-height: 1.15;
}
.hp-spec {
margin-top: 2px;
font-size: 13px;
font-weight: 700;
color: #6b7280;
}
/* --- Rating (étoiles base + fill) --- */
.hp-rating {
text-align: right;
min-width: 110px;
}
.hp-stars {
position: relative;
display: inline-block;
line-height: 1;
font-size: 13px;
letter-spacing: 1px;
}
.hp-stars .stars-base {
color: #ddd;
}
.hp-stars .stars-fill {
position: absolute;
inset: 0;
overflow: hidden;
white-space: nowrap;
color: #f5b301;
}
.hp-note {
margin-top: 2px;
font-size: 0.85rem;
color: #111;
}
/* --- Ligne 2 : Online (gauche) | bouton (droite) --- */
.hp-row2 {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 10px;
padding-left: 68px; /* aligné sous le texte (56 avatar + gap) */
}
.hp-online {
display: flex;
align-items: center;
gap: 6px;
font-size: 13px;
font-weight: 700;
color: #111;
opacity: 0.9;
white-space: nowrap;
}
/* --- Bouton --- */
.hp-btn {
background: var(--red, #e03c3f);
color: #fff;
text-decoration: none;
font-weight: 500;
font-size: 14px;
border-radius: 999px;
padding: 10px 14px;
min-width: 110px;
display: inline-flex;
align-items: center;
justify-content: center;
box-shadow: 0 8px 18px rgba(0, 0, 0, 0.16);
white-space: nowrap;
}
/* =========================================================
6) Mini steps
========================================================= */
.hp-steps {
background: #fff;
border: 1px solid rgba(0, 0, 0, 0.06);
border-radius: 16px;
box-shadow: 0 8px 18px rgba(0, 0, 0, 0.08);
padding: 12px 14px;
}
/* --- Nouveau : entête (sobre) --- */
.hp-steps__head {
text-align: center;
margin-bottom: 10px;
}
.hp-steps__title {
margin: 0;
font-size: 18px;
font-weight: 900;
color: #111;
}
.hp-steps__sub {
margin: 6px 0 0;
font-size: 13px;
font-weight: 600;
color: #6b7280;
}
/* --- Nouveau : grille steps propre (sans <br>) --- */
.hp-steps__grid {
display: grid;
grid-template-columns: 1fr;
gap: 10px;
padding-top: 6px;
}
.hp-steps__item {
display: flex;
align-items: center;
gap: 10px;
font-weight: 500;
font-size: 16px;
color: #111;
}
.hp-steps__arr {
color: #6b7280;
font-weight: 900;
}
/* =========================================================
7) Articles
========================================================= */
.hp-articles {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
}
.ha {
display: block;
text-decoration: none;
background: #fff;
border: 1px solid rgba(0, 0, 0, 0.06);
border-radius: 16px;
box-shadow: 0 8px 18px rgba(0, 0, 0, 0.08);
overflow: hidden;
color: #111;
}
.ha-img {
height: 92px;
background: #e9edf8;
}
.ha-body {
padding: 10px 12px 12px;
}
.ha-title {
margin: 0 0 6px;
font-size: 15px;
font-weight: 600;
}
.ha-sub {
margin: 0;
font-size: 12.5px;
font-weight: 400;
color: #6b7280;
}
.hp-all {
text-align: center;
padding-top: 10px;
}
.hp-all a {
font-weight: 600;
color: #1f3bb3;
text-decoration: none;
}
.spec-cta-wrap {
margin-top: 24px;
padding: 28px 22px;
border-radius: 12px;
background: #8ca9ff;
box-shadow: 0 20px 40px rgba(127, 91, 255, 0.2);
color: #fff;
/* ⬇️ IMPORTANT */
display: grid;
grid-template-columns: auto 1fr auto; /* gauche | milieu | droite */
align-items: center;
column-gap: 22px;
text-align: left;
}
/* Titre */
.spec-cta-wrap h3 {
margin: 0;
font-size: 34px; /* pour se rapprocher de la capture 2 */
font-weight: 700;
line-height: 1.1;
white-space: nowrap; /* optionnel: évite retour ligne */
}
.spec-cta-wrap p {
margin: 0;
font-size: 18px;
opacity: 0.95;
line-height: 1.35;
max-width: 520px; /* pour un look “milieu” */
}
/* Bouton blanc */
.spec-cta {
display: inline-flex;
align-items: center;
justify-content: center;
white-space: nowrap;
padding: 12px 24px;
border-radius: 999px;
background: #fff;
color: #8ca9ff;
font-weight: 600;
font-size: 15px;
text-decoration: none;
box-shadow: 0 8px 18px rgba(0, 0, 0, 0.12);
transition:
transform 0.18s ease,
box-shadow 0.18s ease;
}
/* Hover */
.spec-cta:hover {
transform: translateY(-2px);
box-shadow: 0 12px 22px rgba(0, 0, 0, 0.18);
}
/* Active */
.spec-cta:active {
transform: translateY(0);
}
/* Barre style "carte" */
.searchbar {
background: #fff;
border-radius: 12px;
display: flex;
align-items: center;
gap: 14px;
padding: 10px 14px;
max-width: 860px;
margin: 0 auto;
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(0, 0, 0, 0.04);
}
.search-icon {
margin-left: 6px;
opacity: 0.7;
}
.input-wrap {
position: relative;
flex: 1 1 0;
min-width: 0; /* IMPORTANT: évite débordements */
}
/* Champs “plats” (comme sur ta capture) */
.searchbar input {
width: 100%;
border: none;
outline: none;
background: transparent;
font-size: 14px;
padding: 10px 8px;
color: #111;
}
.searchbar input::placeholder {
color: rgba(0, 0, 0, 0.45);
}
/* séparateur */
.divider {
width: 1px;
height: 34px;
background: rgba(0, 0, 0, 0.1);
}
/* Bouton intégré à droite */
.btn-find--inbar {
margin: 0;
border: none;
background: var(--red);
color: #fff;
font-weight: 500;
font-size: 14px;
padding: 10px 14px;
border-radius: 999px;
cursor: pointer;
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.16);
white-space: nowrap;
}
.btn-find--inbar:hover {
transform: translateY(-1px);
}
.btn-find--inbar:active {
transform: translateY(0);
}
/* Suggestions dropdown */
.suggest {
position: absolute;
top: 100%;
left: 0;
right: 0;
background: #fff;
list-style: none;
margin: 6px 0 0;
padding: 6px 0;
border-radius: 12px;
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.14);
max-height: 260px;
overflow: auto;
z-index: 20;
}
.suggest li {
padding: 10px 12px;
cursor: pointer;
font-size: 15px;
}
.suggest li:hover {
background: #f6f6f6;
}
/* =========================================================
8) Mobile
========================================================= */
@media (max-width: 720px) {
.hp-btn {
min-width: 112px;
padding: 9px 12px;
}
.hp-row2 {
padding-left: 4px;
}
.ha-img {
height: 90px;
}
.hp-articles {
grid-template-columns: 1fr;
}
.hp-steps__title {
font-size: 17px;
}
.hp-steps__sub {
font-size: 12.5px;
}
.hp-steps__item {
font-size: 13.5px;
}
.spec-cta-wrap {
grid-template-columns: 1fr;
row-gap: 12px;
text-align: center;
justify-items: center;
padding: 22px 18px;
}
.spec-cta-wrap h3 {
font-size: 26px;
white-space: normal;
}
.spec-cta-wrap p {
font-size: 15px;
max-width: 34ch;
}
.spec-cta {
width: 50%;
max-width: 340px;
}
.hero {
background: #f3f4f8;
}
}
+10 -10
View File
@@ -4,26 +4,26 @@ return [
'ru' => [
'avocats' => 'адвокат',
'consultants' => 'консультант',
'vrachi' => 'врач',
//'vrachi' => 'врач', // clé existante "vrachi" côté traductions
'psychologues' => 'психолог',
'repetitori' => 'преподаватель',
'finance' => 'бухгалтер', // ajuste si besoin
//'repetitori' => 'преподаватель',
//'finance' => 'бухгалтер', // ajuste si besoin
'perevod' => 'переводчик',
'notarius' => 'нотариус',
'gid' => 'гид',
//'notarius' => 'нотариус',
//'gid' => 'гид',
'rieltori' => 'риелтор',
],
'fr' => [
'avocats' => 'адвокат',
'consultants' => 'консультант',
'vrachi' => 'врач', // clé existante "vrachi" côté traductions
//'vrachi' => 'врач', // clé existante "vrachi" côté traductions
'psychologues' => 'психолог',
'repetitori' => 'преподаватель', // ou "Répetiteur" selon ta BDD
'finance' => 'бухгалтер', // ajuste si besoin
//'repetitori' => 'преподаватель', // ou "Répetiteur" selon ta BDD
//'finance' => 'бухгалтер', // ajuste si besoin
'perevod' => 'переводчик',
'notarius' => 'нотариус',
'gid' => 'гид',
//'notarius' => 'нотариус',
//'gid' => 'гид',
'rieltori' => 'риелтор',
],
];
+29
View File
@@ -0,0 +1,29 @@
<?php
// Map des clés de traduction -> valeur canonique (singulier) pour la BDD
return [
'ru' => [
'avocats' => 'адвокат',
'consultants' => 'консультант',
'vrachi' => 'врач',
'psychologues' => 'психолог',
'repetitori' => 'преподаватель',
'finance' => 'бухгалтер', // ajuste si besoin
'perevod' => 'переводчик',
'notarius' => 'нотариус',
'gid' => 'гид',
'rieltori' => 'риелтор',
],
'fr' => [
'avocats' => 'адвокат',
'consultants' => 'консультант',
'vrachi' => 'врач', // clé existante "vrachi" côté traductions
'psychologues' => 'психолог',
'repetitori' => 'преподаватель', // ou "Répetiteur" selon ta BDD
'finance' => 'бухгалтер', // ajuste si besoin
'perevod' => 'переводчик',
'notarius' => 'нотариус',
'gid' => 'гид',
'rieltori' => 'риелтор',
],
];
+15 -13
View File
@@ -1,16 +1,18 @@
<?php
// Charge les scripts de tracking uniquement pour des pages HTML vues en GET.
// → Pas d’injection sur API/AJAX/assets/callbacks.
if (PHP_SAPI === 'cli') return;
if (PHP_SAPI === 'cli') {
return;
}
$uri = $_SERVER['REQUEST_URI'] ?? '';
$accept = $_SERVER['HTTP_ACCEPT'] ?? '';
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
$xrw = $_SERVER['HTTP_X_REQUESTED_WITH'] ?? '';
$uri = $_SERVER['REQUEST_URI'] ?? '';
$accept = $_SERVER['HTTP_ACCEPT'] ?? '';
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
$xrw = $_SERVER['HTTP_X_REQUESTED_WITH'] ?? '';
$isGet = strcasecmp($method, 'GET') === 0;
$wantsHtml = (stripos($accept, 'text/html') !== false) || ($accept === '');
$wantsJson = stripos($accept, 'application/json') !== false;
$isGet = strcasecmp($method, 'GET') === 0;
$wantsHtml = (stripos($accept, 'text/html') !== false) || ($accept === '');
$wantsJson = stripos($accept, 'application/json') !== false;
$isAjax = strcasecmp($xrw, 'XMLHttpRequest') === 0;
$isApi = preg_match('~/(api/|messages/api/|webhook|callback|notify)~i', $uri);
@@ -18,9 +20,9 @@ $isAsset = preg_match('~\.(css|js|map|png|jpe?g|gif|svg|webp|ico|json|xml|txt|p
$isMatomo = stripos($uri, '/matomo/') !== false;
$isRdv = preg_match('~/(valider_rdv\.php|confirmer_rdv\.php|rdv/)~i', $uri);
if ($isGet && $wantsHtml && !$wantsJson && !$isAjax && !$isApi && !$isAsset && !$isMatomo && !$isRdv) {
// 100% externe (pas d’inline) → compatible CSP 'self' + domaines autorisés
echo '<script src="/js/tracking.js" defer></script>';
// Pixel noscript Matomo (ok même sans JS)
echo '<noscript><p><img src="https://staging.uslugi.fr/matomo/matomo.php?idsite=1&amp;rec=1" style="border:0" alt=""></p></noscript>';
if ($isGet && $wantsHtml && ! $wantsJson && ! $isAjax && ! $isApi && ! $isAsset && ! $isMatomo && ! $isRdv) {
// 100% externe (pas d’inline) → compatible CSP 'self' + domaines autorisés
echo '<script src="/js/tracking.js" defer></script>';
// Pixel noscript Matomo (ok même sans JS)
//echo '<noscript><p><img src="https://staging.uslugi.fr/matomo/matomo.php?idsite=1&amp;rec=1" style="border:0" alt=""></p></noscript>';
}
+17 -21
View File
@@ -1,17 +1,6 @@
<?php
declare (strict_types = 1);
ini_set('display_errors', '1');
ini_set('log_errors', '1');
ini_set('error_log', __DIR__ . '/php-debug.log');
error_reporting(E_ALL);
register_shutdown_function(function () {
$e = error_get_last();
file_put_contents(__DIR__ . '/php-debug.log',
"SHUTDOWN: " . print_r($e, true) . "\n",
FILE_APPEND
);
});
require_once __DIR__ . '/../includes/bootstrap_global.php';
require_once APP_HTDOCS . '/includes/avatar_initiales.php';
require_once __DIR__ . '/includes/search_helpers.php';
@@ -250,6 +239,12 @@ else: ?>
<button id="pwaIosClose" class="pwa-ios-close" type="button">OK</button>
</div>
</div>
<!-- Banniere En haut de la page index✅ Fin PWA -->
<a href="/registration.php">
<div class="spec-cta-wrap">
<h3><?php echo $translations['choix_pro_titre_home_banner'] ?? '' ?></h3>
</div>
</a>
<br>
<h1 class="hero-title">
@@ -264,9 +259,9 @@ else: ?>
<center><h5><?php echo($translations['sous_titre_home'] ?? '') ?></h5></center>
<br>
<?php
$chipKeysRow1 = ['avocats', 'notarius', 'rieltori'];
$chipKeysRow2 = ['vrachi', 'psychologues', 'consultants'];
$chipKeysRow3 = ['perevod', 'repetitori', 'drugie'];
$chipKeysRow1 = ['avocats', 'rieltori', 'psychologues'];
$chipKeysRow2 = ['consultants', 'perevod', 'drugie'];
//$chipKeysRow3 = ['perevod', 'repetitori', 'drugie'];
$renderChipLinks = function (array $keys) use ($translations) {
foreach ($keys as $k) {
@@ -288,7 +283,7 @@ else: ?>
</h2>
<div class="row"><?php $renderChipLinks($chipKeysRow1); ?></div>
<div class="row"><?php $renderChipLinks($chipKeysRow2); ?></div>
<div class="row"><?php $renderChipLinks($chipKeysRow3); ?></div>
<div class="row"><?php //$renderChipLinks($chipKeysRow3); ?></div>
<br>
<h2 class="visually-hidden">
@@ -485,14 +480,15 @@ else: ?>
<button class="hp-btn btn-find--inbar" type="submit">
<?php echo h($translations['naiti'] ?? '') ?>
</button>
</form><br>
</form>
<br>
<a href="/form_index_recomender.php">
<div class="spec-cta-wrap">
<h3><?php echo h($translations['choix_pro_titre_home'] ?? '') ?></h3>
<p><!--<?php echo h($translations['choix_pro_texte_court'] ?? '') ?>--></p>
<a class="spec-cta" href="/registration.php">
<span class="spec-cta__label"><?php echo h($translations['titre_spec'] ?? '') ?></span>
</a>
<h3><?php echo $translations['choix_pro_titre_home'] ?? '' ?></h3>
<!--<p><?php echo h($translations['choix_pro_texte_court'] ?? '') ?></p>
<span class="spec-cta__label"><?php echo h($translations['titre_spec'] ?? '') ?></span>-->
</div>
</a>
<br>
<!--<div class="hp-all">
<a href="/result_search.php">
+521
View File
@@ -0,0 +1,521 @@
<?php
declare (strict_types = 1);
require_once __DIR__ . '/../includes/bootstrap_global.php';
require_once APP_HTDOCS . '/includes/avatar_initiales.php';
require_once __DIR__ . '/includes/search_helpers.php';
require_once __DIR__ . '/traitement_form_index.php';
$SPEC_CANON = require __DIR__ . '/includes/spec_map.php';
$canon = $SPEC_CANON[$lang] ?? [];
/* =========================
AJAX: suggestions
========================= */
if (isset($_GET['ajax']) && $_GET['ajax'] === 'suggest') {
header('Content-Type: application/json; charset=utf-8');
$field = (string) ($_GET['field'] ?? '');
$q = trim((string) ($_GET['q'] ?? ''));
if (! in_array($field, ['specialite', 'ville'], true)) {echo json_encode([]);exit;}
require_once __DIR__ . '/includes/search_helpers.php';
$params = [];
$sql = '';
if ($field === 'ville') {
$sql = "SELECT DISTINCT ville AS val
FROM praticien
WHERE ville IS NOT NULL AND ville <> ''";
if ($q !== '') {
$cands = city_query_candidates($q);
$cands[] = mb_strtolower($q, 'UTF-8');
$cands = array_values(array_unique($cands));
$ors = [];
foreach ($cands as $i => $cand) {
$ors[] = "LOWER(ville) LIKE :q$i";
$params[":q$i"] = $cand . '%';
}
if ($ors) {
$sql .= " AND (" . implode(' OR ', $ors) . ")";
}
}
$sql .= " ORDER BY val ASC LIMIT 15";
} else {
$sql = "SELECT DISTINCT val FROM (
SELECT specialite AS val
FROM praticien
WHERE specialite IS NOT NULL AND specialite <> ''
UNION ALL
SELECT CONCAT(prenom, ' ', nom) AS val
FROM praticien
WHERE prenom IS NOT NULL AND prenom <> '' AND nom IS NOT NULL AND nom <> ''
UNION ALL
SELECT prenom AS val
FROM praticien
WHERE prenom IS NOT NULL AND prenom <> ''
UNION ALL
SELECT nom AS val
FROM praticien
WHERE nom IS NOT NULL AND nom <> ''
) t
WHERE 1";
if ($q !== '') {
$sql .= " AND LOWER(val) LIKE :q";
$params[':q'] = mb_strtolower($q, 'UTF-8') . '%';
}
$sql .= " ORDER BY (LOWER(val) LIKE :qprefix) DESC, val ASC LIMIT 15";
$params[':qprefix'] = ($q !== '') ? (mb_strtolower($q, 'UTF-8') . '%') : '';
}
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
echo json_encode($stmt->fetchAll(PDO::FETCH_COLUMN));
exit;
}
/* =========================
Helpers
========================= */
function h($v): string
{return htmlspecialchars((string) $v, ENT_QUOTES, 'UTF-8');}
$reqUri = h($_SERVER['REQUEST_URI'] ?? '/');
?>
<!doctype html>
<html lang="<?php echo h($lang ?? 'ru') ?>">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><?php echo h($translations['seo_index_title'] ?? '') ?></title>
<meta name="description" content="<?php echo h($translations['seo_index_desc'] ?? '') ?>">
<meta name="keywords" content="<?php echo h($translations['seo_index_keywords'] ?? '') ?>">
<meta name="author" content="Uslugi.fr">
<meta name="language" content="<?php echo h($lang ?? 'ru') ?>">
<!-- ✅ Canonical + Hreflang (SEO multilingue) -->
<link rel="canonical" href="https://uslugi.fr<?php echo $reqUri ?>">
<link rel="alternate" hreflang="ru" href="https://uslugi.fr/ru/">
<link rel="alternate" hreflang="fr" href="https://uslugi.fr/fr/">
<link rel="alternate" hreflang="x-default" href="https://uslugi.fr/">
<!-- ✅ Open Graph -->
<meta property="og:title" content="<?php echo h($translations['seo_index_title'] ?? '') ?>">
<meta property="og:description" content="<?php echo h($translations['seo_index_desc'] ?? '') ?>">
<meta property="og:image" content="https://uslugi.fr/public/uploads/img/logo_u.png">
<meta property="og:url" content="https://uslugi.fr<?php echo $reqUri ?>">
<meta property="og:type" content="website">
<!-- PWA -->
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#38378B">
<!-- Favicons -->
<link rel="icon" type="image/png" sizes="32x32" href="/public/uploads/img/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/public/uploads/img/favicon-16x16.png">
<link rel="icon" type="image/png" sizes="96x96" href="/public/uploads/img/favicon-96x96.png">
<link rel="icon" href="/public/uploads/img/favicon.ico" type="image/x-icon">
<link rel="icon" type="image/svg+xml" href="/public/uploads/img/favicon.svg">
<meta name="apple-mobile-web-app-title" content="Uslugi.fr">
<link rel="apple-touch-icon" sizes="180x180" href="/public/uploads/img/apple-touch-icon.png">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<!-- DNS Prefetch -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="preconnect" href="https://cdn.jsdelivr.net">
<link rel="dns-prefetch" href="//fonts.googleapis.com">
<!-- CSS -->
<link rel="stylesheet" href="/css/bootstrap.min.css">
<?php if (! empty($logged)): ?>
<link rel="stylesheet" href="<?php echo h(asset('/includes/site_style.css')) ?>">
<?php endif; ?>
<link rel="stylesheet" href="<?php echo h(asset('/includes/custom_style.css')) ?>">
<link rel="stylesheet" href="<?php echo h(asset('/includes/index_style.css')) ?>">
<link rel="stylesheet" href="<?php echo h(asset('/includes/mobil_style.css')) ?>">
<?php include_once __DIR__ . '/includes/tracking.php'; ?>
<style>
.site-header
{
background: #FFF;
border-bottom: 0px solid rgba(0, 0, 0, 0.06);
}
.site-footer
{
background: #FFF;
border-top: 0px solid rgba(0, 0, 0, 0.06);
}
</style>
<!-- ✅ Schema (simple, tu peux enrichir plus tard) -->
<script type="application/ld+json">
{
"@context":"https://schema.org",
"@type":"LocalBusiness",
"name":"Uslugi.fr",
"url":"https://uslugi.fr",
"logo":"https://uslugi.fr/public/uploads/img/logo.png",
"address":{"@type":"PostalAddress","addressCountry":"FR"}
}
</script>
</head>
<body>
<?php if (! empty($logged)):
include_header_clean(__DIR__ . '/public/includes/header.php');
else: ?>
<!-- Header public identique -->
<header class="site-header">
<div class="container">
<div class="header-left">
<div class="brand">
<img src="/public/uploads/img/logo_u.png" alt="uslugi.fr" class="logo-mobile">
<img src="/public/uploads/img/logo.png" alt="uslugi.fr" class="logo-desktop">
</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 h($translations['btn_se_connecter'] ?? '') ?></span>
<span class="d-none d-sm-inline"><?php echo h($translations['ja_spec'] ?? '') ?></span>
</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="<?php echo h($translations['help'] ?? 'Помощь') ?>">?</button>
<ul class="dropdown-menu dropdown-menu-end shadow help-menu menu-panel">
<li><a href="/how-it-work.php"><?php echo h($translations['kak_rabotaet'] ?? '') ?></a></li>
<li><a href="/about.php"><?php echo h($translations['pro_nas'] ?? '') ?></a></li>
<li><a href="/faq.php"><?php echo h($translations['faq'] ?? '') ?></a></li>
<li><a href="/contact.php"><?php echo h($translations['nam_pisat'] ?? '') ?></a></li>
</ul>
</div>
</nav>
</div>
</header>
<?php endif; ?>
<!-- HERO -->
<section class="hero">
<div class="home-panel" role="region" aria-label="<?php echo h($translations['home_panel_aria'] ?? 'Accueil') ?>">
<div class="container hero-inner">
<!-- PWA Install floating button (mobile only, hidden by default) ✅ -->
<button id="pwaInstallBtn" class="pwa-install d-none" type="button" aria-label="Installer USLUGI">
⤓ Uslugi
</button>
<!-- iOS helper (hidden by default) ✅ -->
<div id="pwaIosHint" class="pwa-ios-hint d-none" role="dialog" aria-modal="true">
<div class="pwa-ios-card">
<div class="pwa-ios-title">USLUGI.FR</div>
<div class="pwa-ios-text">
На iPhone: нажмите (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-box-arrow-up" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M3.5 6a.5.5 0 0 0-.5.5v8a.5.5 0 0 0 .5.5h9a.5.5 0 0 0 .5-.5v-8a.5.5 0 0 0-.5-.5h-2a.5.5 0 0 1 0-1h2A1.5 1.5 0 0 1 14 6.5v8a1.5 1.5 0 0 1-1.5 1.5h-9A1.5 1.5 0 0 1 2 14.5v-8A1.5 1.5 0 0 1 3.5 5h2a.5.5 0 0 1 0 1z"/>
<path fill-rule="evenodd" d="M7.646.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1-.708.708L8.5 1.707V10.5a.5.5 0 0 1-1 0V1.707L5.354 3.854a.5.5 0 1 1-.708-.708z"/>
</svg>) <b>Поделиться,</b> затем <b>Добавить на экран</b>.<br><br>
Sur iPhone : appuie sur <b>Partager</b> (
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-box-arrow-up" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M3.5 6a.5.5 0 0 0-.5.5v8a.5.5 0 0 0 .5.5h9a.5.5 0 0 0 .5-.5v-8a.5.5 0 0 0-.5-.5h-2a.5.5 0 0 1 0-1h2A1.5 1.5 0 0 1 14 6.5v8a1.5 1.5 0 0 1-1.5 1.5h-9A1.5 1.5 0 0 1 2 14.5v-8A1.5 1.5 0 0 1 3.5 5h2a.5.5 0 0 1 0 1z"/>
<path fill-rule="evenodd" d="M7.646.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1-.708.708L8.5 1.707V10.5a.5.5 0 0 1-1 0V1.707L5.354 3.854a.5.5 0 1 1-.708-.708z"/>
</svg>), puis <b>Sur l'écran d'accueil</b>.
</div>
<button id="pwaIosClose" class="pwa-ios-close" type="button">OK</button>
</div>
</div>
<br>
<h1 class="hero-title">
<?php echo($translations['titre_home'] ?? '') ?>
<span class="visually-hidden">
<?php echo h($translations['boostseo_home_h1_suffix'] ?? '') ?>
</span>
</h1>
<p class="visually-hidden">
<?php echo h($translations['boostseo_home_intro'] ?? '') ?>
</p>
<center><h5><?php echo($translations['sous_titre_home'] ?? '') ?></h5></center>
<br>
<?php
$chipKeysRow1 = ['avocats', 'notarius', 'rieltori'];
$chipKeysRow2 = ['vrachi', 'psychologues', 'consultants'];
$chipKeysRow3 = ['perevod', 'repetitori', 'drugie'];
$renderChipLinks = function (array $keys) use ($translations) {
foreach ($keys as $k) {
$label = $translations[$k] ?? $k;
$slug = seo_spec_slug_from_key($k);
$href = '/recherche/';
if ($slug !== null && $slug !== '') {
$href .= rawurlencode($slug) . '/';
}
echo '<a class="chip chip-link" href="' . h($href) . '">' . h($label) . '</a>';
}
};
?>
<!--<h2 class="home-h2"><?php echo h($translations['home_popular_specialists'] ?? '') ?></h2>-->
<h2 class="visually-hidden">
<?php echo h($translations['boostseo_home_h2_categories'] ?? '') ?>
</h2>
<div class="row"><?php $renderChipLinks($chipKeysRow1); ?></div>
<div class="row"><?php $renderChipLinks($chipKeysRow2); ?></div>
<div class="row"><?php $renderChipLinks($chipKeysRow3); ?></div>
<br>
<h2 class="visually-hidden">
<?php echo h($translations['boostseo_home_h2_recent'] ?? '') ?>
</h2>
<div class="hp-list">
<?php
try {
/* ======================================================
1️⃣ On récupère 50 IDs récents avec photo + abonnement actif
====================================================== */
$ids = $pdo->query("
SELECT id
FROM praticien
WHERE photo IS NOT NULL
AND photo <> ''
AND date_expiration >= NOW()
ORDER BY id DESC
LIMIT 100
")->fetchAll(PDO::FETCH_COLUMN);
if (! $ids) {
throw new Exception('Aucun praticien');
}
/* ======================================================
2️⃣ On mélange et on prend 4
====================================================== */
shuffle($ids);
$ids = array_slice($ids, 0, 4);
/* ======================================================
3️⃣ On récupère les 4 profils
====================================================== */
$placeholders = implode(',', array_fill(0, count($ids), '?'));
$stmt = $pdo->prepare("
SELECT
p.id,
COALESCE(NULLIF(pt.nom_affiche, ''), p.nom) AS nom,
COALESCE(NULLIF(pt.prenom_affiche, ''), p.prenom) AS prenom,
COALESCE(NULLIF(pt.specialite, ''), p.specialite) AS specialite,
p.photo
FROM praticien p
LEFT JOIN praticien_traduction pt
ON pt.praticien_id = p.id
AND pt.langue = ?
WHERE p.id IN ($placeholders)
");
$stmt->execute(array_merge([$lang], $ids));
$randomPros = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (! $randomPros) {
throw new Exception('Aucun praticien');
}
/* ======================================================
3️⃣ Notes
====================================================== */
function percent_from_5($note)
{
$n = max(0, min(5, (float) $note));
return (int) round($n / 5 * 100);
}
$ratingsById = [];
$stRatings = $pdo->prepare("
SELECT praticien_id, ROUND(AVG(note),1) AS m, COUNT(*) AS c
FROM avis_praticien
WHERE statut='publie' AND praticien_id IN ($placeholders)
GROUP BY praticien_id
");
$stRatings->execute($ids);
foreach ($stRatings->fetchAll(PDO::FETCH_ASSOC) as $r) {
$ratingsById[(int) $r['praticien_id']] = [
'm' => (float) $r['m'],
'c' => (int) $r['c'],
];
}
/* ======================================================
4️⃣ Affichage
====================================================== */
foreach ($randomPros as $rp):
$pid = (int) $rp['id'];
$photoName = ltrim((string) $rp['photo'], '/');
$rpImg = "/public/uploads/" . $photoName;
$abs = APP_HTDOCS . "/public/uploads/" . $photoName;
if (! $photoName || ! is_file($abs)) {
$rpImg = "/public/uploads/img/user_placeholder.png";
}
$fullName = trim(($rp['prenom'] ?? '') . ' ' . ($rp['nom'] ?? ''));
$spec = trim((string) ($rp['specialite'] ?? ''));
$detailUrl = "/detail_public.php?id=" . $pid;
$hour = random_int(9, 18);
$availability = ($translations['home_online_at'] ?? 'Онлайн:') . ' ' . sprintf('%02d:00', $hour);
$stats = $ratingsById[$pid] ?? ['m' => 0, 'c' => 0];
$note = (float) $stats['m'];
$count = (int) $stats['c'];
$w = percent_from_5($note);
?>
<article class="hp-card">
<div class="hp-row1">
<a href="<?php echo h($detailUrl) ?>" class="hp-avatarLink">
<img class="hp-avatar" src="<?php echo h($rpImg) ?>" alt="<?php echo h($fullName) ?>" width="56" height="56" loading="lazy">
</a>
<div class="hp-main">
<a href="<?php echo h($detailUrl) ?>" class="hp-avatarLink">
<p class="hp-name"><?php echo h($fullName) ?></p>
</a>
<div class="hp-spec">
<?php
$text = $spec ?: ($translations['home_specialist_fallback'] ?? '');
$words = preg_split('/\s+/', trim($text));
echo h(implode(' ', array_slice($words, 0, 7)));
?>
</div>
</div>
<div class="hp-rating">
<?php if ($count > 0): ?>
<div class="hp-stars">
<div class="stars-base">★★★★★</div>
<div class="stars-fill" style="width:<?php echo (int) $w ?>%">★★★★★</div>
</div>
<div class="hp-note">
<?php echo number_format($note, 1, ',', ' ') ?>/5
<span class="text-muted">(<?php echo (int) $count ?>)</span>
</div>
<?php endif; ?>
</div>
</div>
<div class="hp-row2">
<div class="hp-online">
<span>📅</span>
<span><?php echo h($availability) ?></span>
</div>
<a class="hp-btn"
href="/public/client/reserver_rdv.php?praticien_id=<?php echo $pid ?>">
<?php echo h($translations['home_btn_book'] ?? '') ?>
</a>
</div>
</article>
<?php
endforeach;
} catch (Throwable $e) {
// silencieux volontaire
}
?>
</div>
<br><br>
<form class="searchbar" action="/recherche" method="get" id="searchForm">
<div class="search-icon">🔍</div>
<div class="input-wrap">
<input type="text"
id="specialite"
name="specialite"
autocomplete="off"
placeholder="<?php echo h($translations['n_special'] ?? '') ?>"
aria-label="Специальность">
<ul class="suggest" id="sg-specialite" hidden></ul>
</div>
<div class="divider"></div>
<div class="input-wrap">
<input type="text"
id="ville"
name="ville"
autocomplete="off"
placeholder="<?php echo h($translations['gde'] ?? '') ?>"
aria-label="Город">
<ul class="suggest" id="sg-ville" hidden></ul>
</div>
<button class="hp-btn btn-find--inbar" type="submit">
<?php echo h($translations['naiti'] ?? '') ?>
</button>
</form><br>
<div class="spec-cta-wrap">
<h3><?php echo h($translations['choix_pro_titre_home'] ?? '') ?></h3>
<p><!--<?php echo h($translations['choix_pro_texte_court'] ?? '') ?>--></p>
<a class="spec-cta" href="/registration.php">
<span class="spec-cta__label"><?php echo h($translations['titre_spec'] ?? '') ?></span>
</a>
</div>
<br>
<!--<div class="hp-all">
<a href="/result_search.php">
<?php echo h($translations['smotret_vsex'] ?? '') ?>
</a>
</div>-->
<br>
<?php include __DIR__ . '/form_index.php'; ?>
<br>
</div>
</div>
</div>
</section>
<div class="visually-hidden">
<h2><?php echo h($translations['boostseo_home_h2_cities'] ?? '') ?></h2>
<p><?php echo h($translations['boostseo_home_cities_text'] ?? '') ?></p>
</div>
<footer class="site-footer">
<div class="container">
<p><?php echo $translations['copyr'] ?? '' ?><a href="/terms_fr.php" target="_blank"></a></p>
</div>
</footer>
<!-- ✅ Scripts recherche + submit (chips = liens donc pas de JS chips) -->
<script src="/js/home.js"></script>
<!-- ✅ Bootstrap -->
<script src="/js/bootstrap.bundle.min.js"></script>
<?php include __DIR__ . '/includes/accepter_cookies.php'; ?>
</body>
</html>
+39 -39
View File
@@ -1,5 +1,5 @@
<?php
require_once __DIR__ . '/../includes/bootstrap_global.php';
<?php
require_once __DIR__ . '/../includes/bootstrap_global.php';
?>
@@ -7,15 +7,15 @@ require_once __DIR__ . '/../includes/bootstrap_global.php';
<html lang="ru">
<head>
<meta charset="UTF-8">
<title><?= $translations['insc_praticien_title'] ?></title>
<title><?php echo $translations['insc_praticien_title'] ?></title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="<?= asset('/includes/site_style.css') ?>">
<link rel="stylesheet" href="<?= asset('/includes/custom_style.css') ?>">
<link rel="stylesheet" href="<?= asset('/includes/mobil_style.css') ?>">
<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') ?>">
<style>
.toggle-password {
position: absolute;
right: 10px;
@@ -94,13 +94,13 @@ require_once __DIR__ . '/../includes/bootstrap_global.php';
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"><?= $translations['kak_rabotaet'] ?></a></a></li>
<li><a href="/about.php"><?= $translations['pro_nas'] ?></a></li>
<li><a href="/faq.php"><?= $translations['faq'] ?></a></li>
<li><a href="/contact.php"><?= $translations['nam_pisat'] ?></a></li>
<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>
@@ -109,8 +109,8 @@ require_once __DIR__ . '/../includes/bootstrap_global.php';
<div class="auth-center">
<?php require __DIR__ . '/choisir_abb.php'; ?>
<div class="card shadow-sm p-4" style="min-width: 380px; max-width: 480px; width: 100%; margin:40px auto;">
<h3 class="mb-4 text-center"><?= $translations['insc_praticien_title'] ?></h3>
<h3 class="mb-4 text-center"><?php echo $translations['insc_praticien_title'] ?></h3>
<form id="form-inscription" method="POST" action="traitement_inscription_praticien.php">
<!-- Champ SIREN/SIRET -->
@@ -120,7 +120,7 @@ require_once __DIR__ . '/../includes/bootstrap_global.php';
name="siret"
id="siret"
class="form-control"
placeholder="<?= $translations['placeholder_siret'] ?>"
placeholder="<?php echo $translations['placeholder_siret'] ?>"
required
maxlength="17"
inputmode="numeric"
@@ -128,22 +128,22 @@ require_once __DIR__ . '/../includes/bootstrap_global.php';
<div id="siret-feedback" class="message-erreur" style="display:none;"></div>
</div>
<div class="mb-3">
<input type="text" name="prenom" class="form-control" placeholder="<?= $translations['placeholder_prenom'] ?>" required>
<input type="text" name="prenom" class="form-control" placeholder="<?php echo $translations['placeholder_prenom'] ?>" required>
</div>
<div class="mb-3">
<input type="text" name="nom" class="form-control" placeholder="<?= $translations['placeholder_nom'] ?>" required>
<input type="text" name="nom" class="form-control" placeholder="<?php echo $translations['placeholder_nom'] ?>" required>
</div>
<div class="mb-1">
<input type="email" name="email" id="email" class="form-control" placeholder="<?= $translations['email_placeholder'] ?>" required>
<input type="email" name="email" id="email" class="form-control" placeholder="<?php echo $translations['email_placeholder'] ?>" required>
</div>
<div class="message-erreur" id="email-erreur"><?= addslashes($translations['email_deja_utilise']) ?></div>
<div class="message-erreur" id="email-erreur"><?php echo addslashes($translations['email_deja_utilise']) ?></div>
<div class="mb-3 position-relative">
<input type="password" name="mot_de_passe" id="mot_de_passe" class="form-control" placeholder="<?= $translations['motdepasse_placeholder'] ?>" required>
<input type="password" name="mot_de_passe" id="mot_de_passe" class="form-control" placeholder="<?php echo $translations['motdepasse_placeholder'] ?>" required>
<span class="toggle-password" onclick="togglePassword('mot_de_passe')">👁️</span>
</div>
<div id="niveau-securite" class="mb-2 text-muted"><?= $translations['mdp_regle_min'] ?></div>
<div id="niveau-securite" class="mb-2 text-muted"><?php echo $translations['mdp_regle_min'] ?></div>
<div class="strength-bar mb-3">
<div class="strength-fill"></div>
@@ -157,7 +157,7 @@ require_once __DIR__ . '/../includes/bootstrap_global.php';
name="confirm_mot_de_passe"
id="confirm_mot_de_passe"
class="form-control"
placeholder="<?= $translations['confirm_mdp_placeholder'] ?? 'Confirmer le mot de passe' ?>"
placeholder="<?php echo $translations['confirm_mdp_placeholder'] ?? 'Confirmer le mot de passe' ?>"
required
autocomplete="new-password">
<span class="toggle-password" onclick="togglePassword('confirm_mot_de_passe')">👁️</span>
@@ -168,14 +168,14 @@ require_once __DIR__ . '/../includes/bootstrap_global.php';
<label class="chk-wrap">
<input type="checkbox" id="accept_cgu" name="accept_cgu" required>
<span class="chk-box" aria-hidden="true"></span>
<span class="chk-label"><?= $translations['cgu_label_html'] ?></span>
<span class="chk-label"><?php echo $translations['cgu_label_html'] ?></span>
</label>
<div class="message-erreur" id="cgu-error" aria-live="polite" style="display:none;">
<?= htmlspecialchars($translations['cgu_obligatoire'], ENT_QUOTES, 'UTF-8') ?>
<?php echo htmlspecialchars($translations['cgu_obligatoire'], ENT_QUOTES, 'UTF-8') ?>
</div>
</div>
<button type="submit" class="btn btn-primary w-100"><?= $translations['btn_sinscrire'] ?></button>
<button type="submit" class="btn btn-primary w-100"><?php echo $translations['btn_sinscrire'] ?></button>
</form>
</div>
@@ -188,8 +188,8 @@ require_once __DIR__ . '/../includes/bootstrap_global.php';
const feedback = document.getElementById('confirm-feedback');
const MSGS = {
mismatch: '<?= addslashes($translations["mdp_non_identiques"] ?? "Les mots de passe ne correspondent pas.") ?>',
ok: '<?= addslashes($translations["mdp_identiques_ok"] ?? "Les mots de passe correspondent.") ?>'
mismatch: '<?php echo addslashes($translations["mdp_non_identiques"] ?? "Les mots de passe ne correspondent pas.") ?>',
ok: '<?php echo addslashes($translations["mdp_identiques_ok"] ?? "Les mots de passe correspondent.") ?>'
};
function showOk(){
@@ -231,12 +231,12 @@ function togglePassword(id) {
}
}
// Traductions envoyées depuis PHP
const EMAIL_TAKEN = '<?= addslashes($translations['email_deja_utilise']) ?>';
const EMAIL_TAKEN = '<?php echo addslashes($translations['email_deja_utilise']) ?>';
const T = {
rule: '<?= addslashes($translations['mdp_regle_min']) ?>',
weak: '<?= addslashes($translations['securite_faible']) ?>',
medium: '<?= addslashes($translations['securite_moyen']) ?>',
strong: '<?= addslashes($translations['securite_fort']) ?>'
rule: '<?php echo addslashes($translations['mdp_regle_min']) ?>',
weak: '<?php echo addslashes($translations['securite_faible']) ?>',
medium: '<?php echo addslashes($translations['securite_moyen']) ?>',
strong: '<?php echo addslashes($translations['securite_fort']) ?>'
};
</script>
@@ -268,11 +268,11 @@ function luhnCheck(num) {
let lastQueried = '';
const MSG = {
invalide: '<?= addslashes($translations["siret_format_invalide"]) ?>',
valide: '<?= addslashes($translations["siret_valide_format"]) ?>',
existe: '<?= addslashes($translations["siret_trouve"]) ?>',
nexiste: '<?= addslashes($translations["siret_non_trouve"]) ?>',
attente: '<?= addslashes($translations["siret_verification_en_cours"] ?? "Vérification en cours…") ?>'
invalide: '<?php echo addslashes($translations["siret_format_invalide"]) ?>',
valide: '<?php echo addslashes($translations["siret_valide_format"]) ?>',
existe: '<?php echo addslashes($translations["siret_trouve"]) ?>',
nexiste: '<?php echo addslashes($translations["siret_non_trouve"]) ?>',
attente: '<?php echo addslashes($translations["siret_verification_en_cours"] ?? "Vérification en cours…") ?>'
};
function formatSiret(value) {
@@ -403,7 +403,7 @@ function luhnCheck(num) {
</div>
<footer class="site-footer">
<div class="container">
<p><?= $translations['copyr'] ?></p>
<p><?php echo $translations['copyr'] ?></p>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
+1 -1
View File
@@ -48,7 +48,7 @@
// --- start when allowed ---
function start() {
if (!consentOk()) return;
initMatomo();
//initMatomo();
initGA(); // décommente si tu veux activer GA aussi
}
+40 -41
View File
@@ -1,40 +1,39 @@
<?php
require_once __DIR__ . '/../includes/bootstrap_global.php';
// Sécurité : accès autorisé uniquement après vérification du code
if (! isset($_SESSION['reset_email'], $_SESSION['code_valide']) || ! $_SESSION['code_valide']) {
header("Location: mdp_oublie.php");
exit;
header("Location: mdp_oublie.php");
exit;
}
$erreur = '';
$success = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$mdp1 = $_POST['mot_de_passe'] ?? '';
$mdp2 = $_POST['confirm_mot_de_passe'] ?? '';
$mdp1 = $_POST['mot_de_passe'] ?? '';
$mdp2 = $_POST['confirm_mot_de_passe'] ?? '';
if (strlen($mdp1) < 8 || $mdp1 !== $mdp2) {
$erreur = $translations['erreur_mdp_invalides'];
} else {
$hash = password_hash($mdp1, PASSWORD_DEFAULT);
$stmt = $pdo->prepare("UPDATE compte SET mot_de_passe = :hash WHERE email = :email");
$stmt->execute([
'hash' => $hash,
'email' => $_SESSION['reset_email'],
]);
if (strlen($mdp1) < 8 || $mdp1 !== $mdp2) {
$erreur = $translations['erreur_mdp_invalides'];
} else {
$hash = password_hash($mdp1, PASSWORD_DEFAULT);
$stmt = $pdo->prepare("UPDATE compte SET mot_de_passe = :hash WHERE email = :email");
$stmt->execute([
'hash' => $hash,
'email' => $_SESSION['reset_email'],
]);
// Nettoyage session
$lang = $_SESSION['lang'] ?? 'ru';
session_unset();
session_destroy();
session_start();
$_SESSION['lang'] = $lang;
// Nettoyage session
$lang = $_SESSION['lang'] ?? 'ru';
session_unset();
session_destroy();
session_start();
$_SESSION['lang'] = $lang;
$success = $translations['success_mdp_mis_a_jour'];
$success = $translations['success_mdp_mis_a_jour'];
}
}
}
?>
@@ -42,12 +41,12 @@
<html lang="ru">
<head>
<meta charset="UTF-8">
<title><?= $translations['nouveau_mdp_title'] ?></title>
<title><?php echo $translations['nouveau_mdp_title'] ?></title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="<?= asset('/includes/site_style.css') ?>">
<link rel="stylesheet" href="<?= asset('/includes/custom_style.css') ?>"> <!-- ta home -->
<link rel="stylesheet" href="<?= asset('/includes/mobil_style.css') ?>">
<link rel="stylesheet" href="<?php echo asset('/includes/site_style.css') ?>">
<link rel="stylesheet" href="<?php echo asset('/includes/custom_style.css') ?>"> <!-- ta home -->
<link rel="stylesheet" href="<?php echo asset('/includes/mobil_style.css') ?>">
<style>
.strength-bar {
@@ -94,7 +93,7 @@
</div>
</div>
<nav class="header-actions">
</nav>
</div>
</header>
@@ -102,17 +101,17 @@
<div class="main">
<div class="card shadow-sm p-4" style="min-width: 380px; max-width: 480px; width: 100%;">
<h3 class="mb-4 text-center"><?= $translations['nouveau_mdp_h3'] ?></h3>
<h3 class="mb-4 text-center"><?php echo $translations['nouveau_mdp_h3'] ?></h3>
<?php if (!empty($erreur)): ?>
<?php if (! empty($erreur)): ?>
<div class="alert alert-danger py-2"><?php echo htmlspecialchars($erreur); ?></div>
<?php endif; ?>
<?php if (!empty($success)): ?>
<?php if (! empty($success)): ?>
<div class="alert alert-primary py-2 text-center">
<div><?= htmlspecialchars($success) ?></div>
<div><?php echo htmlspecialchars($success) ?></div>
</div>
<a href="connexion.php" class="btn btn-danger fw-bold"><?= $translations['btn_se_connecter'] ?></a>
<a href="connexion.php" class="btn btn-danger fw-bold"><?php echo $translations['btn_se_connecter'] ?></a>
<?php endif; ?>
<?php if (empty($success)): ?>
@@ -120,11 +119,11 @@
<!-- Nouveau mot de passe -->
<div class="mb-3 field-wrapper">
<input type="password" name="mot_de_passe" id="mot_de_passe" class="form-control" placeholder="<?= $translations['nouveau_mdp_placeholder'] ?>" required>
<input type="password" name="mot_de_passe" id="mot_de_passe" class="form-control" placeholder="<?php echo $translations['nouveau_mdp_placeholder'] ?>" required>
<span class="toggle-password" onclick="toggle('mot_de_passe')">👁️</span>
</div>
<div id="niveau-securite" class="mb-2 text-muted"><?= $translations['mdp_regle_min'] ?></div>
<div id="niveau-securite" class="mb-2 text-muted"><?php echo $translations['mdp_regle_min'] ?></div>
<div class="strength-bar mb-3">
<div class="strength-fill"></div>
@@ -134,21 +133,21 @@
<!-- Confirmation mot de passe -->
<div class="mb-4 field-wrapper">
<input type="password" name="confirm_mot_de_passe" id="confirm_mot_de_passe" class="form-control" placeholder="<?= $translations['confirm_mdp_placeholder'] ?>" required>
<input type="password" name="confirm_mot_de_passe" id="confirm_mot_de_passe" class="form-control" placeholder="<?php echo $translations['confirm_mdp_placeholder'] ?>" required>
<span class="toggle-password" onclick="toggle('confirm_mot_de_passe')">👁️</span>
</div>
<button type="submit" class="btn btn-primary w-100"><?= $translations['btn_valider'] ?></button>
<button type="submit" class="btn btn-primary w-100"><?php echo $translations['btn_valider'] ?></button>
</form>
<?php endif; ?>
</div>
<script>
const T = {
rule: '<?= addslashes($translations['mdp_regle_min']) ?>',
weak: '<?= addslashes($translations['securite_faible']) ?>',
medium: '<?= addslashes($translations['securite_moyen']) ?>',
strong: '<?= addslashes($translations['securite_fort']) ?>'
rule: '<?php echo addslashes($translations['mdp_regle_min']) ?>',
weak: '<?php echo addslashes($translations['securite_faible']) ?>',
medium: '<?php echo addslashes($translations['securite_moyen']) ?>',
strong: '<?php echo addslashes($translations['securite_fort']) ?>'
};
function toggle(id) {
@@ -196,7 +195,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>
+38 -3
View File
@@ -61,8 +61,10 @@ return [
'logo_titre' => '<a href=index.php>USLUGI.FR</a>',
'home' => 'Accueil',
'ja_spec' => 'Connexion',
'titre_home' => 'Trouvez votre spécialiste<br> en France',
'sous_titre_home' => 'Les professionnels avec SIRET,<br> recherche, chat, prise de rendez-vous, visio',
'titre_home' => '<font color="#000">Contacts utiles</font> <br>en France.',
'choix_pro_titre_home' => '<font color="#000"><b>Vous connaissez un spécialiste ?</b></font> Partagez ses coordonnées!',
'choix_pro_titre_home_banner' => '<font color="#000"><b>Vous êtes spécialiste ?</b></font> Rejoignez-nous !',
'sous_titre_home' => 'C\'est bien de savoir<br> à qui s\'adresser !',
'titre_spec_index' => 'Tous les spécialistes reçoivent en ligne et en cabinet',
'avocats' => 'avocats',
'consultants' => 'consultants',
@@ -100,7 +102,6 @@ return [
'btn_inscription_client' => 'Créer un compte',
'choix_type_inscription' => 'Choisissez le type d’inscription',
'choix_pro_titre' => '<b>Vous êtes spécialiste</b>',
'choix_pro_titre_home' => 'Vous êtes spécialiste?',
'choix_pro_texte_court' => 'Rejoignez la plateforme Uslugi',
'choix_pro_texte' => 'Rejoignez la plateforme et proposez vos services',
'btn_inscription_pro' => 'Créer un compte',
@@ -2243,4 +2244,38 @@ Cliquez simplement sur le lien pour vous connecter.<br>',
'menu_communication' => 'Communication',
'menu_content' => 'Contenu',
'menu_maintenance' => 'Maintenance',
'recom_badge' => 'Recommandation',
'recom_title' => 'Recommandez un professionnel',
'recom_intro' => 'Vous connaissez un professionnel de confiance ? Partagez ses coordonnées et aidez notre communauté à trouver des personnes compétentes.',
'recom_fullname_label' => 'Nom et prénom',
'recom_fullname_placeholder' => 'Nom et prénom du professionnel',
'recom_profession_label' => 'Profession / Activité',
'recom_profession_placeholder' => 'Exemple : avocat, médecin, traducteur...',
'recom_location_label' => 'Ville et pays',
'recom_location_placeholder' => 'Exemple : Paris, France',
'recom_phone_label' => 'Téléphone',
'recom_phone_placeholder' => '+33 6 00 00 00 00',
'recom_email_label' => 'E-mail',
'recom_email_placeholder' => 'exemple@email.com',
'recom_website_label' => 'Site internet',
'recom_website_placeholder' => 'https://exemple.com',
'recom_reason_label' => 'Pourquoi recommandez-vous ce professionnel ?',
'recom_reason_placeholder' => 'Expliquez brièvement pourquoi vous recommandez cette personne...',
'recom_submit' => 'Envoyer la recommandation',
'recom_note' => 'Vous pouvez renseigner les coordonnées dont vous disposez.',
'recom_success_title' => 'Merci pour votre recommandation !',
'recom_success_text' => 'Votre recommandation a bien été envoyée. Merci de contribuer au développement de notre communauté.',
'recom_error_popup_title' => 'Erreur',
];
File diff suppressed because it is too large. Load diff
+38 -3
View File
@@ -60,8 +60,8 @@ return [
'logo_titre' => '<a href=index.php>USLUGI.FR</a>',
'home' => 'Главная',
'ja_spec' => 'Войти',
'titre_home' => 'Найдите своего специалиста <br> во Франции',
'sous_titre_home' => 'Профессионалы с SIRET<br> Поиск, чат, запись, видеосвязь',
'titre_home' => '<font color="#000">Полезные контакты</font> <br>во Франции.',
'sous_titre_home' => 'Хорошо, когда знаешь,<br> к кому обратиться!',
'titre_spec_index' => 'Все специалисты принимают по записи онлайн',
'avocats' => 'адвокаты',
'consultants' => 'консультанты',
@@ -99,7 +99,8 @@ return [
'btn_inscription_client' => 'Зарегистрироваться',
'choix_type_inscription' => 'Выберите тип регистрации',
'choix_pro_titre' => '<b>Вы специалист</b>',
'choix_pro_titre_home' => 'Вы специалист?',
'choix_pro_titre_home' => '<font color="#000"><b>Знаете хорошего специалиста?</b></font> Поделитесь контактом!',
'choix_pro_titre_home_banner' => '<font color="#000"><b>Вы специалист?</b></font> Присоединяетесь!',
'choix_pro_texte_court' => 'Получайте заявки от новых клиентов и предлагайте ваши услуги',
'choix_pro_texte' => 'Присоединяйтесь к нашей платформе и предлагайте ваши услуги',
'btn_inscription_pro' => 'Зарегистрироваться',
@@ -2254,4 +2255,38 @@ return [
'menu_communication' => 'Коммуникация',
'menu_content' => 'Контент',
'menu_maintenance' => 'Обслуживание',
'recom_badge' => 'Рекомендация специалиста',
'recom_title' => 'Порекомендуйте хорошего специалиста',
'recom_intro' => 'Знаете проверенного специалиста? Поделитесь его контактами и помогите другим найти надёжного профессионала.',
'recom_fullname_label' => 'Имя и фамилия',
'recom_fullname_placeholder' => 'Имя и фамилия специалиста',
'recom_profession_label' => 'Профессия / Чем занимается',
'recom_profession_placeholder' => 'Например: юрист, врач, переводчик...',
'recom_location_label' => 'Город и страна',
'recom_location_placeholder' => 'Например: Париж, Франция',
'recom_phone_label' => 'Телефон',
'recom_phone_placeholder' => '+33 6 00 00 00 00',
'recom_email_label' => 'Электронная почта',
'recom_email_placeholder' => 'example@email.com',
'recom_website_label' => 'Сайт',
'recom_website_placeholder' => 'https://example.com',
'recom_reason_label' => 'Почему вы рекомендуете этого специалиста?',
'recom_reason_placeholder' => 'Расскажите коротко, почему вы рекомендуете этого человека...',
'recom_submit' => 'Отправить рекомендацию',
'recom_note' => 'Контактные данные можно указать, если они вам известны.',
'recom_success_title' => 'Спасибо за рекомендацию!',
'recom_success_text' => 'Ваша рекомендация успешно отправлена. Благодарим за участие в развитии нашего сообщества.',
'recom_error_popup_title' => 'Ошибка',
];
File diff suppressed because it is too large. Load diff
+83 -63
View File
@@ -1,51 +1,71 @@
<?php
require_once __DIR__ . '/../public/includes/lang.php';
require_once __DIR__ . '/../public/includes/lang.php';
// ===== Helpers header (identiques à index.php) =====
function is_client_logged_in(): bool {
$role = $_SESSION['role'] ?? ($_SESSION['user_type'] ?? '');
if (!empty($_SESSION['user_id']) && $role === 'client') return true;
if (!empty($_SESSION['client_id'])) return true;
if (!empty($_SESSION['reference_id']) && $role === 'client') return true;
if (!empty($_SESSION['user_id']) && $role === 'praticien') return true;
if (!empty($_SESSION['praticien_id'])) return true;
if (!empty($_SESSION['reference_id']) && $role === 'praticien') return true;
return false;
}
// ===== Helpers header (identiques à index.php) =====
function is_client_logged_in(): bool
{
$role = $_SESSION['role'] ?? ($_SESSION['user_type'] ?? '');
if (! empty($_SESSION['user_id']) && $role === 'client') {
return true;
}
function include_header_clean(string $absPath): void {
global $translations, $lang;
ob_start();
include $absPath;
$buf = ob_get_clean() ?: '';
if (! empty($_SESSION['client_id'])) {
return true;
}
$buf = preg_replace('~<!doctype\s+html[^>]*>~i', '', $buf);
$buf = preg_replace('~</?html\b[^>]*>~i', '', $buf);
$buf = preg_replace('~<head\b[^>]*>.*?</head>~is', '', $buf);
$buf = preg_replace('~</?body\b[^>]*>~i', '', $buf);
$buf = preg_replace('~<link[^>]+href="[^"]*(bootstrap[^"]*\.css|mobil_style\.css|site_style\.css|fonts\.googleapis)[^"]*"[^>]*>~i', '', $buf);
$buf = preg_replace('~<script[^>]+src="[^"]*bootstrap[^"]*bundle[^"]*\.js[^"]*"[^>]*>\s*</script>~i', '', $buf);
if (! empty($_SESSION['reference_id']) && $role === 'client') {
return true;
}
echo $buf;
}
if (! empty($_SESSION['user_id']) && $role === 'praticien') {
return true;
}
if (! empty($_SESSION['praticien_id'])) {
return true;
}
if (! empty($_SESSION['reference_id']) && $role === 'praticien') {
return true;
}
return false;
}
function include_header_clean(string $absPath): void
{
global $translations, $lang;
ob_start();
include $absPath;
$buf = ob_get_clean() ?: '';
$buf = preg_replace('~<!doctype\s+html[^>]*>~i', '', $buf);
$buf = preg_replace('~</?html\b[^>]*>~i', '', $buf);
$buf = preg_replace('~<head\b[^>]*>.*?</head>~is', '', $buf);
$buf = preg_replace('~</?body\b[^>]*>~i', '', $buf);
$buf = preg_replace('~<link[^>]+href="[^"]*(bootstrap[^"]*\.css|mobil_style\.css|site_style\.css|fonts\.googleapis)[^"]*"[^>]*>~i', '', $buf);
$buf = preg_replace('~<script[^>]+src="[^"]*bootstrap[^"]*bundle[^"]*\.js[^"]*"[^>]*>\s*</script>~i', '', $buf);
echo $buf;
}
?>
<!doctype html>
<html lang="<?= htmlspecialchars($lang ?? 'ru', ENT_QUOTES, 'UTF-8') ?>">
<html lang="<?php echo htmlspecialchars($lang ?? 'ru', ENT_QUOTES, 'UTF-8') ?>">
<head>
<meta charset="UTF-8">
<title><?= htmlspecialchars($translations['seo_topic_business_title'] ?? 'USLUGI.FR', ENT_QUOTES, 'UTF-8') ?></title>
<meta name="description" content="<?= htmlspecialchars($translations['seo_topic_business_desc'] ?? '', ENT_QUOTES, 'UTF-8') ?>">
<meta name="keywords" content="<?= htmlspecialchars($translations['seo_topic_business_keywords'] ?? '', ENT_QUOTES, 'UTF-8') ?>">
<title><?php echo htmlspecialchars($translations['seo_topic_business_title'] ?? 'USLUGI.FR', ENT_QUOTES, 'UTF-8') ?></title>
<meta name="description" content="<?php echo htmlspecialchars($translations['seo_topic_business_desc'] ?? '', ENT_QUOTES, 'UTF-8') ?>">
<meta name="keywords" content="<?php echo htmlspecialchars($translations['seo_topic_business_keywords'] ?? '', ENT_QUOTES, 'UTF-8') ?>">
<meta name="author" content="Uslugi.fr">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="<?= asset('/includes/site_style.css') ?>">
<link rel="stylesheet" href="<?= asset('/includes/custom_style.css') ?>"> <!-- ta home -->
<link rel="stylesheet" href="<?= asset('/includes/mobil_style.css') ?>">
<link rel="stylesheet" href="<?php echo asset('/includes/site_style.css') ?>">
<link rel="stylesheet" href="<?php echo asset('/includes/custom_style.css') ?>"> <!-- ta home -->
<link rel="stylesheet" href="<?php echo asset('/includes/mobil_style.css') ?>">
<style>
.topic { --brand:#38378B; --mint:#06FFA8; --text:#111; --muted:#4b5563; --card:#fff; --border:#e5e7eb; }
@@ -64,7 +84,7 @@ function include_header_clean(string $absPath): void {
background: color-mix(in oklab, var(--brand) 8%, #fff); border-radius:12px; padding:14px 16px; }
</style>
<?php include_once __DIR__ . '/../includes/tracking.php';?>
<?php include_once __DIR__ . '/../includes/tracking.php'; ?>
</head>
<body>
@@ -89,22 +109,22 @@ function include_header_clean(string $absPath): void {
</div>
<nav class="d-flex align-items-center gap-2">
<a class="btn-login" href="/connexion.php">
<span class="d-sm-none"><?= $translations['btn_se_connecter'] ?></span>
<span class="d-none d-sm-inline"><?= $translations['ja_spec'] ?></span>
<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>
<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="<?= htmlspecialchars($translations['aria_help'] ?? 'Помощь') ?>">
aria-expanded="false" aria-label="<?php echo htmlspecialchars($translations['aria_help'] ?? 'Помощь') ?>">
?
</button>
<ul class="dropdown-menu dropdown-menu-end shadow help-menu menu-panel">
<li><a href="/how-it-work.php"><?= $translations['kak_rabotaet'] ?></a></li>
<li><a href="/about.php"><?= $translations['pro_nas'] ?></a></li>
<li><a href="/faq.php"><?= $translations['faq'] ?></a></li>
<li><a href="/contact.php"><?= $translations['nam_pisat'] ?></a></li>
<li><a href="/how-it-work.php"><?php echo $translations['kak_rabotaet'] ?></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>
@@ -116,39 +136,39 @@ function include_header_clean(string $absPath): void {
<div class="wrap">
<div class="card">
<h1><?= $translations['topic_business_h1'] ?></h1>
<p><?= $translations['topic_business_intro'] ?></p>
<h1><?php echo $translations['topic_business_h1'] ?></h1>
<p><?php echo $translations['topic_business_intro'] ?></p>
<div class="toc">
<a href="#forms"><?= $translations['topic_business_toc_forms'] ?></a>
<a href="#reg"><?= $translations['topic_business_toc_reg'] ?></a>
<a href="#tax"><?= $translations['topic_business_toc_tax'] ?></a>
<a href="#account"><?= $translations['topic_business_toc_account'] ?></a>
<a href="#errors"><?= $translations['topic_business_toc_errors'] ?></a>
<a href="#forms"><?php echo $translations['topic_business_toc_forms'] ?></a>
<a href="#reg"><?php echo $translations['topic_business_toc_reg'] ?></a>
<a href="#tax"><?php echo $translations['topic_business_toc_tax'] ?></a>
<a href="#account"><?php echo $translations['topic_business_toc_account'] ?></a>
<a href="#errors"><?php echo $translations['topic_business_toc_errors'] ?></a>
</div>
<h2 id="forms"><?= $translations['topic_business_h2_forms'] ?></h2>
<p><?= $translations['topic_business_p_forms'] ?></p>
<h2 id="forms"><?php echo $translations['topic_business_h2_forms'] ?></h2>
<p><?php echo $translations['topic_business_p_forms'] ?></p>
<h2 id="reg"><?= $translations['topic_business_h2_reg'] ?></h2>
<p><?= $translations['topic_business_p_reg'] ?></p>
<h2 id="reg"><?php echo $translations['topic_business_h2_reg'] ?></h2>
<p><?php echo $translations['topic_business_p_reg'] ?></p>
<h2 id="tax"><?= $translations['topic_business_h2_tax'] ?></h2>
<p><?= $translations['topic_business_p_tax'] ?></p>
<h2 id="tax"><?php echo $translations['topic_business_h2_tax'] ?></h2>
<p><?php echo $translations['topic_business_p_tax'] ?></p>
<h2 id="account"><?= $translations['topic_business_h2_account'] ?></h2>
<p><?= $translations['topic_business_p_account'] ?></p>
<h2 id="account"><?php echo $translations['topic_business_h2_account'] ?></h2>
<p><?php echo $translations['topic_business_p_account'] ?></p>
<h2 id="errors"><?= $translations['topic_business_h2_errors'] ?></h2>
<p><?= $translations['topic_business_p_errors'] ?></p>
<h2 id="errors"><?php echo $translations['topic_business_h2_errors'] ?></h2>
<p><?php echo $translations['topic_business_p_errors'] ?></p>
<div class="callout">
<strong><?= $translations['topic_business_callout_label'] ?></strong>
<?= $translations['topic_business_callout_text'] ?>
<strong><?php echo $translations['topic_business_callout_label'] ?></strong>
<?php echo $translations['topic_business_callout_text'] ?>
</div>
<div class="mt-3 d-flex flex-wrap gap-2">
<a class="btn btn-primary btn-index" href="/index.php"><?= $translations['topic_business_cta_find'] ?></a>
<a class="btn btn-primary btn-index" href="/index.php"><?php echo $translations['topic_business_cta_find'] ?></a>
</div>
</div>
@@ -157,7 +177,7 @@ function include_header_clean(string $absPath): void {
<footer class="site-footer">
<div class="container">
<p><?= $translations['copyr'] ?></p>
<p><?php echo $translations['copyr'] ?></p>
</div>
</footer>
+83 -63
View File
@@ -1,51 +1,71 @@
<?php
require_once __DIR__ . '/../public/includes/lang.php';
require_once __DIR__ . '/../public/includes/lang.php';
// ===== Helpers header (identiques à index.php) =====
function is_client_logged_in(): bool {
$role = $_SESSION['role'] ?? ($_SESSION['user_type'] ?? '');
if (!empty($_SESSION['user_id']) && $role === 'client') return true;
if (!empty($_SESSION['client_id'])) return true;
if (!empty($_SESSION['reference_id']) && $role === 'client') return true;
if (!empty($_SESSION['user_id']) && $role === 'praticien') return true;
if (!empty($_SESSION['praticien_id'])) return true;
if (!empty($_SESSION['reference_id']) && $role === 'praticien') return true;
return false;
}
// ===== Helpers header (identiques à index.php) =====
function is_client_logged_in(): bool
{
$role = $_SESSION['role'] ?? ($_SESSION['user_type'] ?? '');
if (! empty($_SESSION['user_id']) && $role === 'client') {
return true;
}
function include_header_clean(string $absPath): void {
global $translations, $lang;
ob_start();
include $absPath;
$buf = ob_get_clean() ?: '';
if (! empty($_SESSION['client_id'])) {
return true;
}
$buf = preg_replace('~<!doctype\s+html[^>]*>~i', '', $buf);
$buf = preg_replace('~</?html\b[^>]*>~i', '', $buf);
$buf = preg_replace('~<head\b[^>]*>.*?</head>~is', '', $buf);
$buf = preg_replace('~</?body\b[^>]*>~i', '', $buf);
$buf = preg_replace('~<link[^>]+href="[^"]*(bootstrap[^"]*\.css|mobil_style\.css|site_style\.css|fonts\.googleapis)[^"]*"[^>]*>~i', '', $buf);
$buf = preg_replace('~<script[^>]+src="[^"]*bootstrap[^"]*bundle[^"]*\.js[^"]*"[^>]*>\s*</script>~i', '', $buf);
if (! empty($_SESSION['reference_id']) && $role === 'client') {
return true;
}
echo $buf;
}
if (! empty($_SESSION['user_id']) && $role === 'praticien') {
return true;
}
if (! empty($_SESSION['praticien_id'])) {
return true;
}
if (! empty($_SESSION['reference_id']) && $role === 'praticien') {
return true;
}
return false;
}
function include_header_clean(string $absPath): void
{
global $translations, $lang;
ob_start();
include $absPath;
$buf = ob_get_clean() ?: '';
$buf = preg_replace('~<!doctype\s+html[^>]*>~i', '', $buf);
$buf = preg_replace('~</?html\b[^>]*>~i', '', $buf);
$buf = preg_replace('~<head\b[^>]*>.*?</head>~is', '', $buf);
$buf = preg_replace('~</?body\b[^>]*>~i', '', $buf);
$buf = preg_replace('~<link[^>]+href="[^"]*(bootstrap[^"]*\.css|mobil_style\.css|site_style\.css|fonts\.googleapis)[^"]*"[^>]*>~i', '', $buf);
$buf = preg_replace('~<script[^>]+src="[^"]*bootstrap[^"]*bundle[^"]*\.js[^"]*"[^>]*>\s*</script>~i', '', $buf);
echo $buf;
}
?>
<!doctype html>
<html lang="<?= htmlspecialchars($lang ?? 'ru', ENT_QUOTES, 'UTF-8') ?>">
<html lang="<?php echo htmlspecialchars($lang ?? 'ru', ENT_QUOTES, 'UTF-8') ?>">
<head>
<meta charset="UTF-8">
<title><?= htmlspecialchars($translations['seo_topic_family_title'] ?? 'USLUGI.FR', ENT_QUOTES, 'UTF-8') ?></title>
<meta name="description" content="<?= htmlspecialchars($translations['seo_topic_family_desc'] ?? '', ENT_QUOTES, 'UTF-8') ?>">
<meta name="keywords" content="<?= htmlspecialchars($translations['seo_topic_family_keywords'] ?? '', ENT_QUOTES, 'UTF-8') ?>">
<title><?php echo htmlspecialchars($translations['seo_topic_family_title'] ?? 'USLUGI.FR', ENT_QUOTES, 'UTF-8') ?></title>
<meta name="description" content="<?php echo htmlspecialchars($translations['seo_topic_family_desc'] ?? '', ENT_QUOTES, 'UTF-8') ?>">
<meta name="keywords" content="<?php echo htmlspecialchars($translations['seo_topic_family_keywords'] ?? '', ENT_QUOTES, 'UTF-8') ?>">
<meta name="author" content="Uslugi.fr">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="<?= asset('/includes/site_style.css') ?>">
<link rel="stylesheet" href="<?= asset('/includes/custom_style.css') ?>"> <!-- ta home -->
<link rel="stylesheet" href="<?= asset('/includes/mobil_style.css') ?>">
<link rel="stylesheet" href="<?php echo asset('/includes/site_style.css') ?>">
<link rel="stylesheet" href="<?php echo asset('/includes/custom_style.css') ?>"> <!-- ta home -->
<link rel="stylesheet" href="<?php echo asset('/includes/mobil_style.css') ?>">
<style>
.topic { --brand:#38378B; --mint:#06FFA8; --text:#111; --muted:#4b5563; --card:#fff; --border:#e5e7eb; }
@@ -64,7 +84,7 @@ function include_header_clean(string $absPath): void {
background: color-mix(in oklab, var(--brand) 8%, #fff); border-radius:12px; padding:14px 16px; }
</style>
<?php include_once __DIR__ . '/../includes/tracking.php';?>
<?php include_once __DIR__ . '/../includes/tracking.php'; ?>
</head>
<body>
@@ -89,22 +109,22 @@ function include_header_clean(string $absPath): void {
</div>
<nav class="d-flex align-items-center gap-2">
<a class="btn-login" href="/connexion.php">
<span class="d-sm-none"><?= $translations['btn_se_connecter'] ?></span>
<span class="d-none d-sm-inline"><?= $translations['ja_spec'] ?></span>
<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>
<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="<?= htmlspecialchars($translations['aria_help'] ?? 'Помощь') ?>">
aria-expanded="false" aria-label="<?php echo htmlspecialchars($translations['aria_help'] ?? 'Помощь') ?>">
?
</button>
<ul class="dropdown-menu dropdown-menu-end shadow help-menu menu-panel">
<li><a href="/how-it-work.php"><?= $translations['kak_rabotaet'] ?></a></li>
<li><a href="/about.php"><?= $translations['pro_nas'] ?></a></li>
<li><a href="/faq.php"><?= $translations['faq'] ?></a></li>
<li><a href="/contact.php"><?= $translations['nam_pisat'] ?></a></li>
<li><a href="/how-it-work.php"><?php echo $translations['kak_rabotaet'] ?></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>
@@ -116,39 +136,39 @@ function include_header_clean(string $absPath): void {
<div class="wrap">
<div class="card">
<h1><?= $translations['topic_family_h1'] ?></h1>
<p><?= $translations['topic_family_intro'] ?></p>
<h1><?php echo $translations['topic_family_h1'] ?></h1>
<p><?php echo $translations['topic_family_intro'] ?></p>
<div class="toc">
<a href="#mariage"><?= $translations['topic_family_toc_mariage'] ?></a>
<a href="#pacs"><?= $translations['topic_family_toc_pacs'] ?></a>
<a href="#divorce"><?= $translations['topic_family_toc_divorce'] ?></a>
<a href="#children"><?= $translations['topic_family_toc_children'] ?></a>
<a href="#docs"><?= $translations['topic_family_toc_docs'] ?></a>
<a href="#mariage"><?php echo $translations['topic_family_toc_mariage'] ?></a>
<a href="#pacs"><?php echo $translations['topic_family_toc_pacs'] ?></a>
<a href="#divorce"><?php echo $translations['topic_family_toc_divorce'] ?></a>
<a href="#children"><?php echo $translations['topic_family_toc_children'] ?></a>
<a href="#docs"><?php echo $translations['topic_family_toc_docs'] ?></a>
</div>
<h2 id="mariage"><?= $translations['topic_family_h2_mariage'] ?></h2>
<p><?= $translations['topic_family_p_mariage'] ?></p>
<h2 id="mariage"><?php echo $translations['topic_family_h2_mariage'] ?></h2>
<p><?php echo $translations['topic_family_p_mariage'] ?></p>
<h2 id="pacs"><?= $translations['topic_family_h2_pacs'] ?></h2>
<p><?= $translations['topic_family_p_pacs'] ?></p>
<h2 id="pacs"><?php echo $translations['topic_family_h2_pacs'] ?></h2>
<p><?php echo $translations['topic_family_p_pacs'] ?></p>
<h2 id="divorce"><?= $translations['topic_family_h2_divorce'] ?></h2>
<p><?= $translations['topic_family_p_divorce'] ?></p>
<h2 id="divorce"><?php echo $translations['topic_family_h2_divorce'] ?></h2>
<p><?php echo $translations['topic_family_p_divorce'] ?></p>
<h2 id="children"><?= $translations['topic_family_h2_children'] ?></h2>
<p><?= $translations['topic_family_p_children'] ?></p>
<h2 id="children"><?php echo $translations['topic_family_h2_children'] ?></h2>
<p><?php echo $translations['topic_family_p_children'] ?></p>
<h2 id="docs"><?= $translations['topic_family_h2_docs'] ?></h2>
<p><?= $translations['topic_family_p_docs'] ?></p>
<h2 id="docs"><?php echo $translations['topic_family_h2_docs'] ?></h2>
<p><?php echo $translations['topic_family_p_docs'] ?></p>
<div class="callout">
<strong><?= $translations['topic_family_callout_label'] ?></strong>
<?= $translations['topic_family_callout_text'] ?>
<strong><?php echo $translations['topic_family_callout_label'] ?></strong>
<?php echo $translations['topic_family_callout_text'] ?>
</div>
<div class="mt-3 d-flex flex-wrap gap-2">
<a class="btn btn-primary btn-index" href="/index.php"><?= $translations['topic_family_cta_find'] ?></a>
<a class="btn btn-primary btn-index" href="/index.php"><?php echo $translations['topic_family_cta_find'] ?></a>
</div>
</div>
@@ -157,7 +177,7 @@ function include_header_clean(string $absPath): void {
<footer class="site-footer">
<div class="container">
<p><?= $translations['copyr'] ?></p>
<p><?php echo $translations['copyr'] ?></p>
</div>
</footer>
+92 -72
View File
@@ -1,63 +1,83 @@
<?php
require_once __DIR__ . '/../public/includes/lang.php';
require_once __DIR__ . '/../public/includes/lang.php';
// ===== Helpers header (identiques à index.php) =====
function is_client_logged_in(): bool {
$role = $_SESSION['role'] ?? ($_SESSION['user_type'] ?? '');
if (!empty($_SESSION['user_id']) && $role === 'client') return true;
if (!empty($_SESSION['client_id'])) return true;
if (!empty($_SESSION['reference_id']) && $role === 'client') return true;
if (!empty($_SESSION['user_id']) && $role === 'praticien') return true;
if (!empty($_SESSION['praticien_id'])) return true;
if (!empty($_SESSION['reference_id']) && $role === 'praticien') return true;
return false;
}
// ===== Helpers header (identiques à index.php) =====
function is_client_logged_in(): bool
{
$role = $_SESSION['role'] ?? ($_SESSION['user_type'] ?? '');
if (! empty($_SESSION['user_id']) && $role === 'client') {
return true;
}
function include_header_clean(string $absPath): void
{
global $translations, $lang;
ob_start();
include $absPath; // /public/includes/header.php
$buf = ob_get_clean() ?: '';
if (! empty($_SESSION['client_id'])) {
return true;
}
// 0) DOCTYPE + <html>…</html>
$buf = preg_replace('~<!doctype\s+html[^>]*>~i', '', $buf);
$buf = preg_replace('~</?html\b[^>]*>~i', '', $buf);
if (! empty($_SESSION['reference_id']) && $role === 'client') {
return true;
}
// 1) retirer <head>…</head> et <body> ouverts/fermés
$buf = preg_replace('~<head\b[^>]*>.*?</head>~is', '', $buf);
$buf = preg_replace('~</?body\b[^>]*>~i', '', $buf);
if (! empty($_SESSION['user_id']) && $role === 'praticien') {
return true;
}
// 2) retirer les <link> CSS “globaux” pour éviter d’écraser la home
$buf = preg_replace('~<link[^>]+href="[^"]*(bootstrap[^"]*\.css|mobil_style\.css|site_style\.css|fonts\.googleapis)[^"]*"[^>]*>~i', '', $buf);
if (! empty($_SESSION['praticien_id'])) {
return true;
}
// 3) retirer le <script> Bootstrap CDN (on le charge déjà en bas de la page)
$buf = preg_replace('~<script[^>]+src="[^"]*bootstrap[^"]*bundle[^"]*\.js[^"]*"[^>]*>\s*</script>~i', '', $buf);
if (! empty($_SESSION['reference_id']) && $role === 'praticien') {
return true;
}
echo $buf; // garde <header> + tes scripts inline utiles
}
return false;
}
// helpers safe (optionnel mais propre)
function t(string $key, string $fallback = ''): string {
global $translations;
return (string)($translations[$key] ?? $fallback);
}
function include_header_clean(string $absPath): void
{
global $translations, $lang;
ob_start();
include $absPath; // /public/includes/header.php
$buf = ob_get_clean() ?: '';
// 0) DOCTYPE + <html>…</html>
$buf = preg_replace('~<!doctype\s+html[^>]*>~i', '', $buf);
$buf = preg_replace('~</?html\b[^>]*>~i', '', $buf);
// 1) retirer <head>…</head> et <body> ouverts/fermés
$buf = preg_replace('~<head\b[^>]*>.*?</head>~is', '', $buf);
$buf = preg_replace('~</?body\b[^>]*>~i', '', $buf);
// 2) retirer les <link> CSS “globaux” pour éviter d’écraser la home
$buf = preg_replace('~<link[^>]+href="[^"]*(bootstrap[^"]*\.css|mobil_style\.css|site_style\.css|fonts\.googleapis)[^"]*"[^>]*>~i', '', $buf);
// 3) retirer le <script> Bootstrap CDN (on le charge déjà en bas de la page)
$buf = preg_replace('~<script[^>]+src="[^"]*bootstrap[^"]*bundle[^"]*\.js[^"]*"[^>]*>\s*</script>~i', '', $buf);
echo $buf; // garde <header> + tes scripts inline utiles
}
// helpers safe (optionnel mais propre)
function t(string $key, string $fallback = ''): string
{
global $translations;
return (string) ($translations[$key] ?? $fallback);
}
?>
<!doctype html>
<html lang="<?= htmlspecialchars($lang ?? 'ru', ENT_QUOTES) ?>">
<html lang="<?php echo htmlspecialchars($lang ?? 'ru', ENT_QUOTES) ?>">
<head>
<meta charset="UTF-8">
<title><?= htmlspecialchars(t('seo_medecine_title'), ENT_QUOTES) ?></title>
<meta name="description" content="<?= htmlspecialchars(t('seo_medecine_desc'), ENT_QUOTES) ?>">
<meta name="keywords" content="<?= htmlspecialchars(t('seo_medecine_keywords'), ENT_QUOTES) ?>">
<title><?php echo htmlspecialchars(t('seo_medecine_title'), ENT_QUOTES) ?></title>
<meta name="description" content="<?php echo htmlspecialchars(t('seo_medecine_desc'), ENT_QUOTES) ?>">
<meta name="keywords" content="<?php echo htmlspecialchars(t('seo_medecine_keywords'), ENT_QUOTES) ?>">
<meta name="author" content="Uslugi.fr">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="<?= asset('/includes/site_style.css') ?>">
<link rel="stylesheet" href="<?= asset('/includes/custom_style.css') ?>"> <!-- ta home -->
<link rel="stylesheet" href="<?= asset('/includes/mobil_style.css') ?>">
<link rel="stylesheet" href="<?php echo asset('/includes/site_style.css') ?>">
<link rel="stylesheet" href="<?php echo asset('/includes/custom_style.css') ?>"> <!-- ta home -->
<link rel="stylesheet" href="<?php echo asset('/includes/mobil_style.css') ?>">
<style>
.topic { --brand:#38378B; --mint:#06FFA8; --text:#111; --muted:#4b5563; --card:#fff; --border:#e5e7eb; }
.topic { font-family: "Montserrat", system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif; color:var(--text); }
@@ -76,7 +96,7 @@ function t(string $key, string $fallback = ''): string {
.faq dt{ font-weight:600; margin-top:10px; }
.faq dd{ margin-left:0; color:var(--muted); }
</style>
<?php include_once __DIR__ . '/../includes/tracking.php';?>
<?php include_once __DIR__ . '/../includes/tracking.php'; ?>
</head>
<body>
<!-- Header minimal (logo + actions) -->
@@ -102,8 +122,8 @@ function t(string $key, string $fallback = ''): string {
<nav class="d-flex align-items-center gap-2">
<a class="btn-login" href="/connexion.php">
<span class="d-sm-none"><?= t('btn_se_connecter') ?></span>
<span class="d-none d-sm-inline"><?= t('ja_spec') ?></span>
<span class="d-sm-none"><?php echo t('btn_se_connecter') ?></span>
<span class="d-none d-sm-inline"><?php echo t('ja_spec') ?></span>
</a>
<div class="dropdown">
@@ -113,16 +133,16 @@ function t(string $key, string $fallback = ''): string {
data-bs-toggle="dropdown"
data-bs-auto-close="true"
aria-expanded="false"
aria-label="<?= htmlspecialchars(t('aria_help_label'), ENT_QUOTES) ?>">
aria-label="<?php echo htmlspecialchars(t('aria_help_label'), ENT_QUOTES) ?>">
?
</button>
<!-- Menu compact -->
<ul class="dropdown-menu dropdown-menu-end shadow help-menu menu-panel">
<li><a href="/how-it-work.php"><?= t('kak_rabotaet') ?></a></li>
<li><a href="/about.php"><?= t('pro_nas') ?></a></li>
<li><a href="/faq.php"><?= t('faq') ?></a></li>
<li><a href="/contact.php"><?= t('nam_pisat') ?></a></li>
<li><a href="/how-it-work.php"><?php echo t('kak_rabotaet') ?></a></li>
<li><a href="/about.php"><?php echo t('pro_nas') ?></a></li>
<li><a href="/faq.php"><?php echo t('faq') ?></a></li>
<li><a href="/contact.php"><?php echo t('nam_pisat') ?></a></li>
</ul>
</div>
</nav>
@@ -134,38 +154,38 @@ function t(string $key, string $fallback = ''): string {
<div class="wrap">
<div class="card">
<h1><?= t('medecine_h1') ?></h1>
<p><?= t('medecine_intro') ?></p>
<h1><?php echo t('medecine_h1') ?></h1>
<p><?php echo t('medecine_intro') ?></p>
<div class="toc">
<a href="#gp"><?= t('medecine_toc_gp') ?></a>
<a href="#assurance"><?= t('medecine_toc_assurance') ?></a>
<a href="#labs"><?= t('medecine_toc_labs') ?></a>
<a href="#dentaire"><?= t('medecine_toc_dentaire') ?></a>
<a href="#hospital"><?= t('medecine_toc_hospital') ?></a>
<a href="#gp"><?php echo t('medecine_toc_gp') ?></a>
<a href="#assurance"><?php echo t('medecine_toc_assurance') ?></a>
<a href="#labs"><?php echo t('medecine_toc_labs') ?></a>
<a href="#dentaire"><?php echo t('medecine_toc_dentaire') ?></a>
<a href="#hospital"><?php echo t('medecine_toc_hospital') ?></a>
</div>
<h2 id="gp"><?= t('medecine_h2_gp') ?></h2>
<p><?= t('medecine_p_gp') ?></p>
<h2 id="gp"><?php echo t('medecine_h2_gp') ?></h2>
<p><?php echo t('medecine_p_gp') ?></p>
<h2 id="assurance"><?= t('medecine_h2_assurance') ?></h2>
<p><?= t('medecine_p_assurance') ?></p>
<h2 id="assurance"><?php echo t('medecine_h2_assurance') ?></h2>
<p><?php echo t('medecine_p_assurance') ?></p>
<h2 id="labs"><?= t('medecine_h2_labs') ?></h2>
<p><?= t('medecine_p_labs') ?></p>
<h2 id="labs"><?php echo t('medecine_h2_labs') ?></h2>
<p><?php echo t('medecine_p_labs') ?></p>
<h2 id="dentaire"><?= t('medecine_h2_dentaire') ?></h2>
<p><?= t('medecine_p_dentaire') ?></p>
<h2 id="dentaire"><?php echo t('medecine_h2_dentaire') ?></h2>
<p><?php echo t('medecine_p_dentaire') ?></p>
<h2 id="hospital"><?= t('medecine_h2_hospital') ?></h2>
<p><?= t('medecine_p_hospital') ?></p>
<h2 id="hospital"><?php echo t('medecine_h2_hospital') ?></h2>
<p><?php echo t('medecine_p_hospital') ?></p>
<div class="callout">
<strong><?= t('medecine_tip_strong') ?></strong> <?= t('medecine_tip_text') ?>
<strong><?php echo t('medecine_tip_strong') ?></strong> <?php echo t('medecine_tip_text') ?>
</div>
<div class="mt-3 d-flex flex-wrap gap-2">
<a class="btn btn-primary btn-index" href="/index.php"><?= t('medecine_btn_find') ?></a>
<a class="btn btn-primary btn-index" href="/index.php"><?php echo t('medecine_btn_find') ?></a>
</div>
</div>
@@ -174,7 +194,7 @@ function t(string $key, string $fallback = ''): string {
<footer class="site-footer">
<div class="container">
<p><?= t('copyr') ?></p>
<p><?php echo t('copyr') ?></p>
</div>
</footer>
+92 -72
View File
@@ -1,63 +1,83 @@
<?php
require_once __DIR__ . '/../public/includes/lang.php';
require_once __DIR__ . '/../public/includes/lang.php';
// ===== Helpers header (identiques à index.php) =====
function is_client_logged_in(): bool {
$role = $_SESSION['role'] ?? ($_SESSION['user_type'] ?? '');
if (!empty($_SESSION['user_id']) && $role === 'client') return true;
if (!empty($_SESSION['client_id'])) return true;
if (!empty($_SESSION['reference_id']) && $role === 'client') return true;
if (!empty($_SESSION['user_id']) && $role === 'praticien') return true;
if (!empty($_SESSION['praticien_id'])) return true;
if (!empty($_SESSION['reference_id']) && $role === 'praticien') return true;
return false;
}
// ===== Helpers header (identiques à index.php) =====
function is_client_logged_in(): bool
{
$role = $_SESSION['role'] ?? ($_SESSION['user_type'] ?? '');
if (! empty($_SESSION['user_id']) && $role === 'client') {
return true;
}
function include_header_clean(string $absPath): void
{
global $translations, $lang;
ob_start();
include $absPath; // /public/includes/header.php
$buf = ob_get_clean() ?: '';
if (! empty($_SESSION['client_id'])) {
return true;
}
// 0) DOCTYPE + <html>…</html>
$buf = preg_replace('~<!doctype\s+html[^>]*>~i', '', $buf);
$buf = preg_replace('~</?html\b[^>]*>~i', '', $buf);
if (! empty($_SESSION['reference_id']) && $role === 'client') {
return true;
}
// 1) retirer <head>…</head> et <body> ouverts/fermés
$buf = preg_replace('~<head\b[^>]*>.*?</head>~is', '', $buf);
$buf = preg_replace('~</?body\b[^>]*>~i', '', $buf);
if (! empty($_SESSION['user_id']) && $role === 'praticien') {
return true;
}
// 2) retirer les <link> CSS “globaux” pour éviter d’écraser la home
$buf = preg_replace('~<link[^>]+href="[^"]*(bootstrap[^"]*\.css|mobil_style\.css|site_style\.css|fonts\.googleapis)[^"]*"[^>]*>~i', '', $buf);
if (! empty($_SESSION['praticien_id'])) {
return true;
}
// 3) retirer le <script> Bootstrap CDN (on le charge déjà en bas de la page)
$buf = preg_replace('~<script[^>]+src="[^"]*bootstrap[^"]*bundle[^"]*\.js[^"]*"[^>]*>\s*</script>~i', '', $buf);
if (! empty($_SESSION['reference_id']) && $role === 'praticien') {
return true;
}
echo $buf; // garde <header> + tes scripts inline utiles
}
return false;
}
// helper simple
function t(string $key, string $fallback = ''): string {
global $translations;
return (string)($translations[$key] ?? $fallback);
}
function include_header_clean(string $absPath): void
{
global $translations, $lang;
ob_start();
include $absPath; // /public/includes/header.php
$buf = ob_get_clean() ?: '';
// 0) DOCTYPE + <html>…</html>
$buf = preg_replace('~<!doctype\s+html[^>]*>~i', '', $buf);
$buf = preg_replace('~</?html\b[^>]*>~i', '', $buf);
// 1) retirer <head>…</head> et <body> ouverts/fermés
$buf = preg_replace('~<head\b[^>]*>.*?</head>~is', '', $buf);
$buf = preg_replace('~</?body\b[^>]*>~i', '', $buf);
// 2) retirer les <link> CSS “globaux” pour éviter d’écraser la home
$buf = preg_replace('~<link[^>]+href="[^"]*(bootstrap[^"]*\.css|mobil_style\.css|site_style\.css|fonts\.googleapis)[^"]*"[^>]*>~i', '', $buf);
// 3) retirer le <script> Bootstrap CDN (on le charge déjà en bas de la page)
$buf = preg_replace('~<script[^>]+src="[^"]*bootstrap[^"]*bundle[^"]*\.js[^"]*"[^>]*>\s*</script>~i', '', $buf);
echo $buf; // garde <header> + tes scripts inline utiles
}
// helper simple
function t(string $key, string $fallback = ''): string
{
global $translations;
return (string) ($translations[$key] ?? $fallback);
}
?>
<!doctype html>
<html lang="<?= htmlspecialchars($lang ?? 'ru', ENT_QUOTES) ?>">
<html lang="<?php echo htmlspecialchars($lang ?? 'ru', ENT_QUOTES) ?>">
<head>
<meta charset="UTF-8">
<title><?= htmlspecialchars(t('seo_immigration_title'), ENT_QUOTES) ?></title>
<meta name="description" content="<?= htmlspecialchars(t('seo_immigration_desc'), ENT_QUOTES) ?>">
<meta name="keywords" content="<?= htmlspecialchars(t('seo_immigration_keywords'), ENT_QUOTES) ?>">
<title><?php echo htmlspecialchars(t('seo_immigration_title'), ENT_QUOTES) ?></title>
<meta name="description" content="<?php echo htmlspecialchars(t('seo_immigration_desc'), ENT_QUOTES) ?>">
<meta name="keywords" content="<?php echo htmlspecialchars(t('seo_immigration_keywords'), ENT_QUOTES) ?>">
<meta name="author" content="Uslugi.fr">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="<?= asset('/includes/site_style.css') ?>">
<link rel="stylesheet" href="<?= asset('/includes/custom_style.css') ?>"> <!-- ta home -->
<link rel="stylesheet" href="<?= asset('/includes/mobil_style.css') ?>">
<link rel="stylesheet" href="<?php echo asset('/includes/site_style.css') ?>">
<link rel="stylesheet" href="<?php echo asset('/includes/custom_style.css') ?>"> <!-- ta home -->
<link rel="stylesheet" href="<?php echo asset('/includes/mobil_style.css') ?>">
<style>
.topic { --brand:#38378B; --mint:#06FFA8; --text:#111; --muted:#4b5563; --card:#fff; --border:#e5e7eb; }
.topic { font-family: "Montserrat", system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif; color:var(--text); }
@@ -76,7 +96,7 @@ function t(string $key, string $fallback = ''): string {
.faq dt{ font-weight:600; margin-top:10px; }
.faq dd{ margin-left:0; color:var(--muted); }
</style>
<?php include_once __DIR__ . '/../includes/tracking.php';?>
<?php include_once __DIR__ . '/../includes/tracking.php'; ?>
</head>
<body>
<!-- Header minimal (logo + actions) -->
@@ -102,8 +122,8 @@ function t(string $key, string $fallback = ''): string {
<nav class="d-flex align-items-center gap-2">
<a class="btn-login" href="/connexion.php">
<span class="d-sm-none"><?= t('btn_se_connecter') ?></span>
<span class="d-none d-sm-inline"><?= t('ja_spec') ?></span>
<span class="d-sm-none"><?php echo t('btn_se_connecter') ?></span>
<span class="d-none d-sm-inline"><?php echo t('ja_spec') ?></span>
</a>
<div class="dropdown">
@@ -113,16 +133,16 @@ function t(string $key, string $fallback = ''): string {
data-bs-toggle="dropdown"
data-bs-auto-close="true"
aria-expanded="false"
aria-label="<?= htmlspecialchars(t('aria_help_label'), ENT_QUOTES) ?>">
aria-label="<?php echo htmlspecialchars(t('aria_help_label'), ENT_QUOTES) ?>">
?
</button>
<!-- Menu compact -->
<ul class="dropdown-menu dropdown-menu-end shadow help-menu menu-panel">
<li><a href="/how-it-work.php"><?= t('kak_rabotaet') ?></a></li>
<li><a href="/about.php"><?= t('pro_nas') ?></a></li>
<li><a href="/faq.php"><?= t('faq') ?></a></li>
<li><a href="/contact.php"><?= t('nam_pisat') ?></a></li>
<li><a href="/how-it-work.php"><?php echo t('kak_rabotaet') ?></a></li>
<li><a href="/about.php"><?php echo t('pro_nas') ?></a></li>
<li><a href="/faq.php"><?php echo t('faq') ?></a></li>
<li><a href="/contact.php"><?php echo t('nam_pisat') ?></a></li>
</ul>
</div>
</nav>
@@ -134,38 +154,38 @@ function t(string $key, string $fallback = ''): string {
<div class="wrap">
<div class="card">
<h1><?= t('immigration_h1') ?></h1>
<p><?= t('immigration_intro') ?></p>
<h1><?php echo t('immigration_h1') ?></h1>
<p><?php echo t('immigration_intro') ?></p>
<div class="toc">
<a href="#visa-d"><?= t('immigration_toc_visa_d') ?></a>
<a href="#vnj"><?= t('immigration_toc_vnj') ?></a>
<a href="#nat"><?= t('immigration_toc_nat') ?></a>
<a href="#family"><?= t('immigration_toc_family') ?></a>
<a href="#docs"><?= t('immigration_toc_docs') ?></a>
<a href="#visa-d"><?php echo t('immigration_toc_visa_d') ?></a>
<a href="#vnj"><?php echo t('immigration_toc_vnj') ?></a>
<a href="#nat"><?php echo t('immigration_toc_nat') ?></a>
<a href="#family"><?php echo t('immigration_toc_family') ?></a>
<a href="#docs"><?php echo t('immigration_toc_docs') ?></a>
</div>
<h2 id="visa-d"><?= t('immigration_h2_visa_d') ?></h2>
<p><?= t('immigration_p_visa_d') ?></p>
<h2 id="visa-d"><?php echo t('immigration_h2_visa_d') ?></h2>
<p><?php echo t('immigration_p_visa_d') ?></p>
<h2 id="vnj"><?= t('immigration_h2_vnj') ?></h2>
<p><?= t('immigration_p_vnj') ?></p>
<h2 id="vnj"><?php echo t('immigration_h2_vnj') ?></h2>
<p><?php echo t('immigration_p_vnj') ?></p>
<h2 id="nat"><?= t('immigration_h2_nat') ?></h2>
<p><?= t('immigration_p_nat') ?></p>
<h2 id="nat"><?php echo t('immigration_h2_nat') ?></h2>
<p><?php echo t('immigration_p_nat') ?></p>
<h2 id="family"><?= t('immigration_h2_family') ?></h2>
<p><?= t('immigration_p_family') ?></p>
<h2 id="family"><?php echo t('immigration_h2_family') ?></h2>
<p><?php echo t('immigration_p_family') ?></p>
<h2 id="docs"><?= t('immigration_h2_docs') ?></h2>
<p><?= t('immigration_p_docs') ?></p>
<h2 id="docs"><?php echo t('immigration_h2_docs') ?></h2>
<p><?php echo t('immigration_p_docs') ?></p>
<div class="callout">
<strong><?= t('immigration_tip_strong') ?></strong> <?= t('immigration_tip_text') ?>
<strong><?php echo t('immigration_tip_strong') ?></strong> <?php echo t('immigration_tip_text') ?>
</div>
<div class="mt-3 d-flex flex-wrap gap-2">
<a class="btn btn-primary btn-index" href="/index.php"><?= t('immigration_btn_find') ?></a>
<a class="btn btn-primary btn-index" href="/index.php"><?php echo t('immigration_btn_find') ?></a>
</div>
</div>
@@ -174,7 +194,7 @@ function t(string $key, string $fallback = ''): string {
<footer class="site-footer">
<div class="container">
<p><?= t('copyr') ?></p>
<p><?php echo t('copyr') ?></p>
</div>
</footer>
+92 -72
View File
@@ -1,63 +1,83 @@
<?php
require_once __DIR__ . '/../public/includes/lang.php';
require_once __DIR__ . '/../public/includes/lang.php';
// ===== Helpers header (identiques à index.php) =====
function is_client_logged_in(): bool {
$role = $_SESSION['role'] ?? ($_SESSION['user_type'] ?? '');
if (!empty($_SESSION['user_id']) && $role === 'client') return true;
if (!empty($_SESSION['client_id'])) return true;
if (!empty($_SESSION['reference_id']) && $role === 'client') return true;
if (!empty($_SESSION['user_id']) && $role === 'praticien') return true;
if (!empty($_SESSION['praticien_id'])) return true;
if (!empty($_SESSION['reference_id']) && $role === 'praticien') return true;
return false;
}
// ===== Helpers header (identiques à index.php) =====
function is_client_logged_in(): bool
{
$role = $_SESSION['role'] ?? ($_SESSION['user_type'] ?? '');
if (! empty($_SESSION['user_id']) && $role === 'client') {
return true;
}
function include_header_clean(string $absPath): void
{
global $translations, $lang;
ob_start();
include $absPath; // /public/includes/header.php
$buf = ob_get_clean() ?: '';
if (! empty($_SESSION['client_id'])) {
return true;
}
// 0) DOCTYPE + <html>…</html>
$buf = preg_replace('~<!doctype\s+html[^>]*>~i', '', $buf);
$buf = preg_replace('~</?html\b[^>]*>~i', '', $buf);
if (! empty($_SESSION['reference_id']) && $role === 'client') {
return true;
}
// 1) retirer <head>…</head> et <body> ouverts/fermés
$buf = preg_replace('~<head\b[^>]*>.*?</head>~is', '', $buf);
$buf = preg_replace('~</?body\b[^>]*>~i', '', $buf);
if (! empty($_SESSION['user_id']) && $role === 'praticien') {
return true;
}
// 2) retirer les <link> CSS “globaux” pour éviter d’écraser la home
$buf = preg_replace('~<link[^>]+href="[^"]*(bootstrap[^"]*\.css|mobil_style\.css|site_style\.css|fonts\.googleapis)[^"]*"[^>]*>~i', '', $buf);
if (! empty($_SESSION['praticien_id'])) {
return true;
}
// 3) retirer le <script> Bootstrap CDN (on le charge déjà en bas de la page)
$buf = preg_replace('~<script[^>]+src="[^"]*bootstrap[^"]*bundle[^"]*\.js[^"]*"[^>]*>\s*</script>~i', '', $buf);
if (! empty($_SESSION['reference_id']) && $role === 'praticien') {
return true;
}
echo $buf; // garde <header> + tes scripts inline utiles
}
return false;
}
// helper simple
function t(string $key, string $fallback = ''): string {
global $translations;
return (string)($translations[$key] ?? $fallback);
}
function include_header_clean(string $absPath): void
{
global $translations, $lang;
ob_start();
include $absPath; // /public/includes/header.php
$buf = ob_get_clean() ?: '';
// 0) DOCTYPE + <html>…</html>
$buf = preg_replace('~<!doctype\s+html[^>]*>~i', '', $buf);
$buf = preg_replace('~</?html\b[^>]*>~i', '', $buf);
// 1) retirer <head>…</head> et <body> ouverts/fermés
$buf = preg_replace('~<head\b[^>]*>.*?</head>~is', '', $buf);
$buf = preg_replace('~</?body\b[^>]*>~i', '', $buf);
// 2) retirer les <link> CSS “globaux” pour éviter d’écraser la home
$buf = preg_replace('~<link[^>]+href="[^"]*(bootstrap[^"]*\.css|mobil_style\.css|site_style\.css|fonts\.googleapis)[^"]*"[^>]*>~i', '', $buf);
// 3) retirer le <script> Bootstrap CDN (on le charge déjà en bas de la page)
$buf = preg_replace('~<script[^>]+src="[^"]*bootstrap[^"]*bundle[^"]*\.js[^"]*"[^>]*>\s*</script>~i', '', $buf);
echo $buf; // garde <header> + tes scripts inline utiles
}
// helper simple
function t(string $key, string $fallback = ''): string
{
global $translations;
return (string) ($translations[$key] ?? $fallback);
}
?>
<!doctype html>
<html lang="<?= htmlspecialchars($lang ?? 'ru', ENT_QUOTES) ?>">
<html lang="<?php echo htmlspecialchars($lang ?? 'ru', ENT_QUOTES) ?>">
<head>
<meta charset="UTF-8">
<title><?= htmlspecialchars(t('seo_travail_title'), ENT_QUOTES) ?></title>
<meta name="description" content="<?= htmlspecialchars(t('seo_travail_desc'), ENT_QUOTES) ?>">
<meta name="keywords" content="<?= htmlspecialchars(t('seo_travail_keywords'), ENT_QUOTES) ?>">
<title><?php echo htmlspecialchars(t('seo_travail_title'), ENT_QUOTES) ?></title>
<meta name="description" content="<?php echo htmlspecialchars(t('seo_travail_desc'), ENT_QUOTES) ?>">
<meta name="keywords" content="<?php echo htmlspecialchars(t('seo_travail_keywords'), ENT_QUOTES) ?>">
<meta name="author" content="Uslugi.fr">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="<?= asset('/includes/site_style.css') ?>">
<link rel="stylesheet" href="<?= asset('/includes/custom_style.css') ?>"> <!-- ta home -->
<link rel="stylesheet" href="<?= asset('/includes/mobil_style.css') ?>">
<link rel="stylesheet" href="<?php echo asset('/includes/site_style.css') ?>">
<link rel="stylesheet" href="<?php echo asset('/includes/custom_style.css') ?>"> <!-- ta home -->
<link rel="stylesheet" href="<?php echo asset('/includes/mobil_style.css') ?>">
<style>
.topic { --brand:#38378B; --mint:#06FFA8; --text:#111; --muted:#4b5563; --card:#fff; --border:#e5e7eb; }
.topic { font-family: "Montserrat", system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif; color:var(--text); }
@@ -76,7 +96,7 @@ function t(string $key, string $fallback = ''): string {
.faq dt{ font-weight:600; margin-top:10px; }
.faq dd{ margin-left:0; color:var(--muted); }
</style>
<?php include_once __DIR__ . '/../includes/tracking.php';?>
<?php include_once __DIR__ . '/../includes/tracking.php'; ?>
</head>
<body>
<!-- Header minimal (logo + actions) -->
@@ -102,8 +122,8 @@ function t(string $key, string $fallback = ''): string {
<nav class="d-flex align-items-center gap-2">
<a class="btn-login" href="/connexion.php">
<span class="d-sm-none"><?= t('btn_se_connecter') ?></span>
<span class="d-none d-sm-inline"><?= t('ja_spec') ?></span>
<span class="d-sm-none"><?php echo t('btn_se_connecter') ?></span>
<span class="d-none d-sm-inline"><?php echo t('ja_spec') ?></span>
</a>
<div class="dropdown">
@@ -113,16 +133,16 @@ function t(string $key, string $fallback = ''): string {
data-bs-toggle="dropdown"
data-bs-auto-close="true"
aria-expanded="false"
aria-label="<?= htmlspecialchars(t('aria_help_label'), ENT_QUOTES) ?>">
aria-label="<?php echo htmlspecialchars(t('aria_help_label'), ENT_QUOTES) ?>">
?
</button>
<!-- Menu compact -->
<ul class="dropdown-menu dropdown-menu-end shadow help-menu menu-panel">
<li><a href="/how-it-work.php"><?= t('kak_rabotaet') ?></a></li>
<li><a href="/about.php"><?= t('pro_nas') ?></a></li>
<li><a href="/faq.php"><?= t('faq') ?></a></li>
<li><a href="/contact.php"><?= t('nam_pisat') ?></a></li>
<li><a href="/how-it-work.php"><?php echo t('kak_rabotaet') ?></a></li>
<li><a href="/about.php"><?php echo t('pro_nas') ?></a></li>
<li><a href="/faq.php"><?php echo t('faq') ?></a></li>
<li><a href="/contact.php"><?php echo t('nam_pisat') ?></a></li>
</ul>
</div>
</nav>
@@ -134,38 +154,38 @@ function t(string $key, string $fallback = ''): string {
<div class="wrap">
<div class="card">
<h1><?= t('travail_h1') ?></h1>
<p><?= t('travail_intro') ?></p>
<h1><?php echo t('travail_h1') ?></h1>
<p><?php echo t('travail_intro') ?></p>
<div class="toc">
<a href="#cv"><?= t('travail_toc_cv') ?></a>
<a href="#contracts"><?= t('travail_toc_contracts') ?></a>
<a href="#rights"><?= t('travail_toc_rights') ?></a>
<a href="#dismiss"><?= t('travail_toc_dismiss') ?></a>
<a href="#unemployment"><?= t('travail_toc_unemployment') ?></a>
<a href="#cv"><?php echo t('travail_toc_cv') ?></a>
<a href="#contracts"><?php echo t('travail_toc_contracts') ?></a>
<a href="#rights"><?php echo t('travail_toc_rights') ?></a>
<a href="#dismiss"><?php echo t('travail_toc_dismiss') ?></a>
<a href="#unemployment"><?php echo t('travail_toc_unemployment') ?></a>
</div>
<h2 id="cv"><?= t('travail_h2_cv') ?></h2>
<p><?= t('travail_p_cv') ?></p>
<h2 id="cv"><?php echo t('travail_h2_cv') ?></h2>
<p><?php echo t('travail_p_cv') ?></p>
<h2 id="contracts"><?= t('travail_h2_contracts') ?></h2>
<p><?= t('travail_p_contracts') ?></p>
<h2 id="contracts"><?php echo t('travail_h2_contracts') ?></h2>
<p><?php echo t('travail_p_contracts') ?></p>
<h2 id="rights"><?= t('travail_h2_rights') ?></h2>
<p><?= t('travail_p_rights') ?></p>
<h2 id="rights"><?php echo t('travail_h2_rights') ?></h2>
<p><?php echo t('travail_p_rights') ?></p>
<h2 id="dismiss"><?= t('travail_h2_dismiss') ?></h2>
<p><?= t('travail_p_dismiss') ?></p>
<h2 id="dismiss"><?php echo t('travail_h2_dismiss') ?></h2>
<p><?php echo t('travail_p_dismiss') ?></p>
<h2 id="unemployment"><?= t('travail_h2_unemployment') ?></h2>
<p><?= t('travail_p_unemployment') ?></p>
<h2 id="unemployment"><?php echo t('travail_h2_unemployment') ?></h2>
<p><?php echo t('travail_p_unemployment') ?></p>
<div class="callout">
<strong><?= t('travail_tip_strong') ?></strong> <?= t('travail_tip_text') ?>
<strong><?php echo t('travail_tip_strong') ?></strong> <?php echo t('travail_tip_text') ?>
</div>
<div class="mt-3 d-flex flex-wrap gap-2">
<a class="btn btn-primary btn-index" href="/index.php"><?= t('travail_btn_find') ?></a>
<a class="btn btn-primary btn-index" href="/index.php"><?php echo t('travail_btn_find') ?></a>
</div>
</div>
@@ -174,7 +194,7 @@ function t(string $key, string $fallback = ''): string {
<footer class="site-footer">
<div class="container">
<p><?= t('copyr') ?></p>
<p><?php echo t('copyr') ?></p>
</div>
</footer>
+92 -72
View File
@@ -1,63 +1,83 @@
<?php
require_once __DIR__ . '/../public/includes/lang.php';
require_once __DIR__ . '/../public/includes/lang.php';
// ===== Helpers header (identiques à index.php) =====
function is_client_logged_in(): bool {
$role = $_SESSION['role'] ?? ($_SESSION['user_type'] ?? '');
if (!empty($_SESSION['user_id']) && $role === 'client') return true;
if (!empty($_SESSION['client_id'])) return true;
if (!empty($_SESSION['reference_id']) && $role === 'client') return true;
if (!empty($_SESSION['user_id']) && $role === 'praticien') return true;
if (!empty($_SESSION['praticien_id'])) return true;
if (!empty($_SESSION['reference_id']) && $role === 'praticien') return true;
return false;
}
// ===== Helpers header (identiques à index.php) =====
function is_client_logged_in(): bool
{
$role = $_SESSION['role'] ?? ($_SESSION['user_type'] ?? '');
if (! empty($_SESSION['user_id']) && $role === 'client') {
return true;
}
function include_header_clean(string $absPath): void
{
global $translations, $lang;
ob_start();
include $absPath; // /public/includes/header.php
$buf = ob_get_clean() ?: '';
if (! empty($_SESSION['client_id'])) {
return true;
}
// 0) DOCTYPE + <html>…</html>
$buf = preg_replace('~<!doctype\s+html[^>]*>~i', '', $buf);
$buf = preg_replace('~</?html\b[^>]*>~i', '', $buf);
if (! empty($_SESSION['reference_id']) && $role === 'client') {
return true;
}
// 1) retirer <head>…</head> et <body> ouverts/fermés
$buf = preg_replace('~<head\b[^>]*>.*?</head>~is', '', $buf);
$buf = preg_replace('~</?body\b[^>]*>~i', '', $buf);
if (! empty($_SESSION['user_id']) && $role === 'praticien') {
return true;
}
// 2) retirer les <link> CSS “globaux” pour éviter d’écraser la home
$buf = preg_replace('~<link[^>]+href="[^"]*(bootstrap[^"]*\.css|mobil_style\.css|site_style\.css|fonts\.googleapis)[^"]*"[^>]*>~i', '', $buf);
if (! empty($_SESSION['praticien_id'])) {
return true;
}
// 3) retirer le <script> Bootstrap CDN (on le charge déjà en bas de la page)
$buf = preg_replace('~<script[^>]+src="[^"]*bootstrap[^"]*bundle[^"]*\.js[^"]*"[^>]*>\s*</script>~i', '', $buf);
if (! empty($_SESSION['reference_id']) && $role === 'praticien') {
return true;
}
echo $buf; // garde <header> + tes scripts inline utiles
}
return false;
}
// helper simple
function t(string $key, string $fallback = ''): string {
global $translations;
return (string)($translations[$key] ?? $fallback);
}
function include_header_clean(string $absPath): void
{
global $translations, $lang;
ob_start();
include $absPath; // /public/includes/header.php
$buf = ob_get_clean() ?: '';
// 0) DOCTYPE + <html>…</html>
$buf = preg_replace('~<!doctype\s+html[^>]*>~i', '', $buf);
$buf = preg_replace('~</?html\b[^>]*>~i', '', $buf);
// 1) retirer <head>…</head> et <body> ouverts/fermés
$buf = preg_replace('~<head\b[^>]*>.*?</head>~is', '', $buf);
$buf = preg_replace('~</?body\b[^>]*>~i', '', $buf);
// 2) retirer les <link> CSS “globaux” pour éviter d’écraser la home
$buf = preg_replace('~<link[^>]+href="[^"]*(bootstrap[^"]*\.css|mobil_style\.css|site_style\.css|fonts\.googleapis)[^"]*"[^>]*>~i', '', $buf);
// 3) retirer le <script> Bootstrap CDN (on le charge déjà en bas de la page)
$buf = preg_replace('~<script[^>]+src="[^"]*bootstrap[^"]*bundle[^"]*\.js[^"]*"[^>]*>\s*</script>~i', '', $buf);
echo $buf; // garde <header> + tes scripts inline utiles
}
// helper simple
function t(string $key, string $fallback = ''): string
{
global $translations;
return (string) ($translations[$key] ?? $fallback);
}
?>
<!doctype html>
<html lang="<?= htmlspecialchars($lang ?? 'ru', ENT_QUOTES) ?>">
<html lang="<?php echo htmlspecialchars($lang ?? 'ru', ENT_QUOTES) ?>">
<head>
<meta charset="UTF-8">
<title><?= htmlspecialchars(t('seo_taxes_title'), ENT_QUOTES) ?></title>
<meta name="description" content="<?= htmlspecialchars(t('seo_taxes_desc'), ENT_QUOTES) ?>">
<meta name="keywords" content="<?= htmlspecialchars(t('seo_taxes_keywords'), ENT_QUOTES) ?>">
<title><?php echo htmlspecialchars(t('seo_taxes_title'), ENT_QUOTES) ?></title>
<meta name="description" content="<?php echo htmlspecialchars(t('seo_taxes_desc'), ENT_QUOTES) ?>">
<meta name="keywords" content="<?php echo htmlspecialchars(t('seo_taxes_keywords'), ENT_QUOTES) ?>">
<meta name="author" content="Uslugi.fr">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="<?= asset('/includes/site_style.css') ?>">
<link rel="stylesheet" href="<?= asset('/includes/custom_style.css') ?>"> <!-- ta home -->
<link rel="stylesheet" href="<?= asset('/includes/mobil_style.css') ?>">
<link rel="stylesheet" href="<?php echo asset('/includes/site_style.css') ?>">
<link rel="stylesheet" href="<?php echo asset('/includes/custom_style.css') ?>"> <!-- ta home -->
<link rel="stylesheet" href="<?php echo asset('/includes/mobil_style.css') ?>">
<style>
.topic { --brand:#38378B; --mint:#06FFA8; --text:#111; --muted:#4b5563; --card:#fff; --border:#e5e7eb; }
.topic { font-family: "Montserrat", system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif; color:var(--text); }
@@ -76,7 +96,7 @@ function t(string $key, string $fallback = ''): string {
.faq dt{ font-weight:600; margin-top:10px; }
.faq dd{ margin-left:0; color:var(--muted); }
</style>
<?php include_once __DIR__ . '/../includes/tracking.php';?>
<?php include_once __DIR__ . '/../includes/tracking.php'; ?>
</head>
<body>
<!-- Header minimal (logo + actions) -->
@@ -102,8 +122,8 @@ function t(string $key, string $fallback = ''): string {
<nav class="d-flex align-items-center gap-2">
<a class="btn-login" href="/connexion.php">
<span class="d-sm-none"><?= t('btn_se_connecter') ?></span>
<span class="d-none d-sm-inline"><?= t('ja_spec') ?></span>
<span class="d-sm-none"><?php echo t('btn_se_connecter') ?></span>
<span class="d-none d-sm-inline"><?php echo t('ja_spec') ?></span>
</a>
<div class="dropdown">
@@ -113,16 +133,16 @@ function t(string $key, string $fallback = ''): string {
data-bs-toggle="dropdown"
data-bs-auto-close="true"
aria-expanded="false"
aria-label="<?= htmlspecialchars(t('aria_help_label'), ENT_QUOTES) ?>">
aria-label="<?php echo htmlspecialchars(t('aria_help_label'), ENT_QUOTES) ?>">
?
</button>
<!-- Menu compact -->
<ul class="dropdown-menu dropdown-menu-end shadow help-menu menu-panel">
<li><a href="/how-it-work.php"><?= t('kak_rabotaet') ?></a></li>
<li><a href="/about.php"><?= t('pro_nas') ?></a></li>
<li><a href="/faq.php"><?= t('faq') ?></a></li>
<li><a href="/contact.php"><?= t('nam_pisat') ?></a></li>
<li><a href="/how-it-work.php"><?php echo t('kak_rabotaet') ?></a></li>
<li><a href="/about.php"><?php echo t('pro_nas') ?></a></li>
<li><a href="/faq.php"><?php echo t('faq') ?></a></li>
<li><a href="/contact.php"><?php echo t('nam_pisat') ?></a></li>
</ul>
</div>
</nav>
@@ -134,38 +154,38 @@ function t(string $key, string $fallback = ''): string {
<div class="wrap">
<div class="card">
<h1><?= t('taxes_h1') ?></h1>
<p><?= t('taxes_intro') ?></p>
<h1><?php echo t('taxes_h1') ?></h1>
<p><?php echo t('taxes_intro') ?></p>
<div class="toc">
<a href="#decl"><?= t('taxes_toc_decl') ?></a>
<a href="#cot"><?= t('taxes_toc_cot') ?></a>
<a href="#ae"><?= t('taxes_toc_ae') ?></a>
<a href="#tva"><?= t('taxes_toc_tva') ?></a>
<a href="#help"><?= t('taxes_toc_help') ?></a>
<a href="#decl"><?php echo t('taxes_toc_decl') ?></a>
<a href="#cot"><?php echo t('taxes_toc_cot') ?></a>
<a href="#ae"><?php echo t('taxes_toc_ae') ?></a>
<a href="#tva"><?php echo t('taxes_toc_tva') ?></a>
<a href="#help"><?php echo t('taxes_toc_help') ?></a>
</div>
<h2 id="decl"><?= t('taxes_h2_decl') ?></h2>
<p><?= t('taxes_p_decl') ?></p>
<h2 id="decl"><?php echo t('taxes_h2_decl') ?></h2>
<p><?php echo t('taxes_p_decl') ?></p>
<h2 id="cot"><?= t('taxes_h2_cot') ?></h2>
<p><?= t('taxes_p_cot') ?></p>
<h2 id="cot"><?php echo t('taxes_h2_cot') ?></h2>
<p><?php echo t('taxes_p_cot') ?></p>
<h2 id="ae"><?= t('taxes_h2_ae') ?></h2>
<p><?= t('taxes_p_ae') ?></p>
<h2 id="ae"><?php echo t('taxes_h2_ae') ?></h2>
<p><?php echo t('taxes_p_ae') ?></p>
<h2 id="tva"><?= t('taxes_h2_tva') ?></h2>
<p><?= t('taxes_p_tva') ?></p>
<h2 id="tva"><?php echo t('taxes_h2_tva') ?></h2>
<p><?php echo t('taxes_p_tva') ?></p>
<h2 id="help"><?= t('taxes_h2_help') ?></h2>
<p><?= t('taxes_p_help') ?></p>
<h2 id="help"><?php echo t('taxes_h2_help') ?></h2>
<p><?php echo t('taxes_p_help') ?></p>
<div class="callout">
<strong><?= t('taxes_tip_strong') ?></strong> <?= t('taxes_tip_text') ?>
<strong><?php echo t('taxes_tip_strong') ?></strong> <?php echo t('taxes_tip_text') ?>
</div>
<div class="mt-3 d-flex flex-wrap gap-2">
<a class="btn btn-primary btn-index" href="/index.php"><?= t('taxes_btn_find') ?></a>
<a class="btn btn-primary btn-index" href="/index.php"><?php echo t('taxes_btn_find') ?></a>
</div>
</div>
@@ -174,7 +194,7 @@ function t(string $key, string $fallback = ''): string {
<footer class="site-footer">
<div class="container">
<p><?= t('copyr') ?></p>
<p><?php echo t('copyr') ?></p>
</div>
</footer>