'
. htmlspecialchars($translations['non_autorise'] ?? 'Доступ запрещён.', ENT_QUOTES, 'UTF-8')
. '
';
return;
}
$mustReauth=function(int $ttl=600){$t=(int)($_SESSION['admin_reauth_at']??0);return ($t===0||(time()-$t)>$ttl);};
if ($mustReauth()){ $qs=http_build_query(['page'=>'reauth','redir'=>($_SERVER['REQUEST_URI']??'index.php?page=maintenance')]); header('Location:?'.$qs); exit; }
// -- PDO si absent
// DB
// CSRF
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
$CSRF = $_SESSION['csrf_token'];
// helpers
function e($s) {
return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8');
}
// ---- Параметры фильтрации ----
$q = trim($_GET['q'] ?? '');
$role = $_GET['role'] ?? 'all'; // all|client|praticien|secretaire
$period = $_GET['period'] ?? 'today'; // today|week|month|30days|custom
$dateFrom = trim($_GET['date_from'] ?? '');
$dateTo = trim($_GET['date_to'] ?? '');
// ❗ Pagination: utiliser "p" pour НЕ конфликтовать с ?page=new_inscrits (router)
$pageNum = max(1, (int)($_GET['p'] ?? 1));
$perPage = 25;
$validRoles = ['client', 'praticien', 'secretaire'];
// Период: если указаны даты "С/По", считаем custom
if ($dateFrom !== '' || $dateTo !== '') {
$period = 'custom';
}
// Диапазон дат по cree_le
$now = new DateTimeImmutable('now');
switch ($period) {
case 'today':
default:
$start = (new DateTimeImmutable('today'))->setTime(0,0,0);
$end = $start->modify('+1 day');
break;
case 'week':
$start = (new DateTimeImmutable('monday this week'))->setTime(0,0,0);
$end = $start->modify('+1 week');
break;
case 'month':
$start = (new DateTimeImmutable('first day of this month'))->setTime(0,0,0);
$end = $start->modify('first day of next month');
break;
case '30days':
$end = $now->setTime(23,59,59);
$start = $end->modify('-30 days')->setTime(0,0,0);
break;
case 'custom':
if ($dateFrom !== '') {
$tmp = DateTimeImmutable::createFromFormat('Y-m-d', $dateFrom) ?: new DateTimeImmutable('today');
$start = $tmp->setTime(0,0,0);
} else {
$start = (new DateTimeImmutable('2000-01-01'))->setTime(0,0,0);
}
if ($dateTo !== '') {
$tmp = DateTimeImmutable::createFromFormat('Y-m-d', $dateTo) ?: $now;
$end = $tmp->modify('+1 day')->setTime(0,0,0);
} else {
$end = $now->modify('+1 day')->setTime(0,0,0);
}
break;
}
$dtFrom = $start->format('Y-m-d H:i:s');
$dtTo = $end->format('Y-m-d H:i:s');
// ---- Сортировка ----
$allowedSort = [
'nom' => 'nom',
'prenom' => 'prenom',
'email' => 'email',
'telephone' => 'telephone',
'role' => 'role',
'cree_le' => 'cree_le',
];
$sort = $_GET['sort'] ?? 'cree_le';
$dir = strtolower($_GET['dir'] ?? 'desc');
if (!isset($allowedSort[$sort])) {
$sort = 'cree_le';
}
if (!in_array($dir, ['asc','desc'], true)) {
$dir = 'desc';
}
$orderBySql = $allowedSort[$sort] . ' ' . strtoupper($dir);
// ---- WHERE + параметры ----
$where = [];
$params = [];
// только client, praticien, secretaire
$where[] = "c.role IN ('client','praticien','secretaire')";
if (in_array($role, $validRoles, true)) {
$where[] = "c.role = :role";
$params[':role'] = $role;
}
// поиск по строке
if ($q !== '') {
$where[] = "(
COALESCE(p.nom, cl.nom, '') LIKE :q_nom
OR COALESCE(p.prenom, cl.prenom, '') LIKE :q_prenom
OR c.email LIKE :q_email
OR COALESCE(p.telephone, cl.telephone, '') LIKE :q_tel
)";
$like = '%' . $q . '%';
$params[':q_nom'] = $like;
$params[':q_prenom'] = $like;
$params[':q_email'] = $like;
$params[':q_tel'] = $like;
// 👉 Опция: когда ищем по строке, НЕ ограничиваем по дате
} else {
// фильтр по периоду только если нет q
$where[] = "c.cree_le >= :from AND c.cree_le < :to";
$params[':from'] = $dtFrom;
$params[':to'] = $dtTo;
}
$whereSql = $where ? ('WHERE ' . implode(' AND ', $where)) : '';
// ---- Подсчет общего количества ----
$sqlCount = "
SELECT COUNT(*) AS cnt
FROM compte c
LEFT JOIN praticien p ON (c.role IN ('praticien','secretaire') AND c.reference_id = p.id)
LEFT JOIN client cl ON (c.role = 'client' AND c.reference_id = cl.id)
$whereSql
";
try {
$st = $pdo->prepare($sqlCount);
foreach ($params as $k=>$v) {
$st->bindValue($k, $v);
}
$st->execute();
$totalRows = (int)$st->fetchColumn();
} catch (Throwable $e) {
echo ''.e($translations['admin_new_clients_sql_err_count'] ?? 'Ошибка SQL (count): ').e($e->getMessage()).'
';
return;
}
$totalPages = max(1, (int)ceil($totalRows / $perPage));
if ($pageNum > $totalPages) {
$pageNum = $totalPages;
}
$offset = ($pageNum - 1) * $perPage;
// ---- Основной SELECT ----
$sql = "
SELECT
c.id AS compte_id,
c.email,
c.role,
c.cree_le,
c.email_valide,
c.token_validation,
COALESCE(p.nom, cl.nom) AS nom,
COALESCE(p.prenom, cl.prenom) AS prenom,
COALESCE(p.telephone, cl.telephone) AS telephone,
CASE
WHEN c.role='praticien' THEN p.accepted_cgu
WHEN c.role='client' THEN cl.accepted_cgu
ELSE NULL
END AS accepted_cgu
FROM compte c
LEFT JOIN praticien p ON (c.role IN ('praticien','secretaire') AND c.reference_id = p.id)
LEFT JOIN client cl ON (c.role = 'client' AND c.reference_id = cl.id)
$whereSql
ORDER BY $orderBySql
LIMIT :limit OFFSET :offset
";
try {
$st = $pdo->prepare($sql);
foreach ($params as $k=>$v) {
$st->bindValue($k, $v);
}
$st->bindValue(':limit', (int)$perPage, PDO::PARAM_INT);
$st->bindValue(':offset', (int)$offset, PDO::PARAM_INT);
$st->execute();
$rows = $st->fetchAll(PDO::FETCH_ASSOC);
} catch (Throwable $e) {
echo ''.e($translations['admin_new_clients_sql_err_select'] ?? 'Ошибка SQL (select): ').e($e->getMessage()).'
';
return;
}
// параметры для ссылок сортировки/пагинации (без sort/dir/p)
$baseParams = [
'q' => $q,
'role' => $role,
'period' => $period,
'date_from' => $dateFrom,
'date_to' => $dateTo,
];
// helper для построения URL сортировки
function sortLink($field, $label, $currentSort, $currentDir, $extraParams) {
$params = $extraParams;
$params['sort'] = $field;
if ($currentSort === $field) {
$params['dir'] = ($currentDir === 'asc') ? 'desc' : 'asc';
} else {
$params['dir'] = 'asc';
}
$url = admin_url('new_inscrits', $params);
$arrow = '';
if ($currentSort === $field) {
$arrow = $currentDir === 'asc' ? ' ▲' : ' ▼';
}
return ''.e($label.$arrow).' ';
}
?>
= e($translations['admin_new_clients_title'] ?? 'Новые регистрации') ?>
= e($translations['admin_new_clients_found'] ?? 'Найдено записей:') ?>
= (int)$totalRows ?> .
= e($translations['admin_new_clients_page'] ?? 'Страница') ?>
= (int)$pageNum ?>
= e($translations['admin_new_clients_page_of'] ?? 'из') ?>
= (int)$totalPages ?>.
= sortLink('nom', ($translations['admin_new_clients_th_nom'] ?? 'Фамилия'), $sort, $dir, $baseParams + ['p'=>$pageNum]) ?>
= sortLink('prenom', ($translations['admin_new_clients_th_prenom'] ?? 'Имя'), $sort, $dir, $baseParams + ['p'=>$pageNum]) ?>
= sortLink('email', ($translations['admin_new_clients_th_email'] ?? 'E-mail'), $sort, $dir, $baseParams + ['p'=>$pageNum]) ?>
= sortLink('telephone', ($translations['admin_new_clients_th_telephone'] ?? 'Телефон'), $sort, $dir, $baseParams + ['p'=>$pageNum]) ?>
= sortLink('role', ($translations['admin_new_clients_th_role'] ?? 'Роль'), $sort, $dir, $baseParams + ['p'=>$pageNum]) ?>
= sortLink('cree_le', ($translations['admin_new_clients_th_cree_le'] ?? 'Дата регистрации'), $sort, $dir, $baseParams + ['p'=>$pageNum]) ?>
= e($translations['admin_new_clients_th_email_status'] ?? 'E-mail') ?>
= e($translations['admin_new_clients_th_cgu'] ?? 'CGU') ?>
= e($translations['admin_new_clients_th_actions'] ?? 'Действия') ?>
= e($translations['admin_new_clients_empty'] ?? 'Нет регистраций за выбранный период.') ?>
format('d.m.Y H:i') : '';
?>
= e($r['nom']) ?>
= e($r['prenom']) ?>
= e($r['email']) ?>
= e($r['telephone']) ?>
= e($roleLabel) ?>
= e($creeLe) ?>
= e($translations['admin_new_clients_email_ok'] ?? 'Подтверждён') ?>
= e($translations['admin_new_clients_email_ko'] ?? 'KO') ?>
= e($translations['admin_new_clients_dash'] ?? '—') ?>
= e($translations['admin_new_clients_cgu_yes'] ?? 'Приняты') ?>
= e($translations['admin_new_clients_cgu_no'] ?? 'Не приняты') ?>
= e($translations['admin_new_clients_details'] ?? 'Подробно') ?>
1): ?>