' . 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).''; } ?>



($translations['admin_new_clients_period_today'] ?? 'Сегодня'), 'week' => ($translations['admin_new_clients_period_week'] ?? 'Неделя'), 'month' => ($translations['admin_new_clients_period_month'] ?? 'Месяц'), '30days' => ($translations['admin_new_clients_period_30days'] ?? '30 дней'), ]; foreach ($periods as $key=>$lbl): $btnParams = $baseParams; $btnParams['period'] = $key; $btnParams['p'] = 1; $url = admin_url('new_inscrits', $btnParams); ?>
'today', 'role' => 'all', 'p' => 1, ]); ?>
. .
format('d.m.Y H:i') : ''; ?>
$pageNum]) ?> $pageNum]) ?> $pageNum]) ?> $pageNum]) ?> $pageNum]) ?> $pageNum]) ?>
1): ?>