prepare(" SELECT status FROM projects WHERE id = ? AND client_id = ? "); $checkStmt->execute([$project_id, $_SESSION['client_id']]); $project = $checkStmt->fetch(); if ($project && $project['status'] !== 'Live') { $deleteStmt = $pdo->prepare("DELETE FROM projects WHERE id = ?"); $deleteStmt->execute([$project_id]); $success = 'Project deleted successfully.'; } else { $error = 'Cannot delete this project. Live projects cannot be deleted.'; } } // Get filter values $filter_status = $_GET['status'] ?? ''; $filter_industry = $_GET['industry'] ?? ''; $filter_from_date = $_GET['from_date'] ?? ''; $filter_to_date = $_GET['to_date'] ?? ''; $filter_min_loi = $_GET['min_loi'] ?? ''; $filter_max_loi = $_GET['max_loi'] ?? ''; // Build query with filters $query = "SELECT * FROM projects WHERE client_id = ?"; $params = [$_SESSION['client_id']]; if ($filter_status) { $query .= " AND status = ?"; $params[] = $filter_status; } if ($filter_industry) { $query .= " AND industry = ?"; $params[] = $filter_industry; } if ($filter_from_date) { $query .= " AND DATE(created_at) >= ?"; $params[] = $filter_from_date; } if ($filter_to_date) { $query .= " AND DATE(created_at) <= ?"; $params[] = $filter_to_date; } if ($filter_min_loi) { $query .= " AND eloi >= ?"; $params[] = intval($filter_min_loi); } if ($filter_max_loi) { $query .= " AND eloi <= ?"; $params[] = intval($filter_max_loi); } $query .= " ORDER BY created_at DESC"; $stmt = $pdo->prepare($query); $stmt->execute($params); $projects = $stmt->fetchAll(); // ─── Per-project stats: aggregate survey_urls counts + avg actual LOI ─── $statsByProject = []; // project_id (varchar) => stats array $estIncByProject = []; // project_id (varchar) => weighted-avg estimated incidence if (!empty($projects)) { $project_id_list = array_map(function($p) { return $p['project_id']; }, $projects); $placeholders = implode(',', array_fill(0, count($project_id_list), '?')); // Aggregate survey_urls by project_id for url counts + avg actual LOI on completes $sStmt = $pdo->prepare(" SELECT project_id, COUNT(*) AS urls_total, SUM(CASE WHEN status = 'sent' THEN 1 ELSE 0 END) AS urls_sent, SUM(CASE WHEN status = 'clicked' THEN 1 ELSE 0 END) AS urls_clicked, SUM(CASE WHEN status = 'complete' THEN 1 ELSE 0 END) AS urls_complete, SUM(CASE WHEN status = 'partial' THEN 1 ELSE 0 END) AS urls_partial, SUM(CASE WHEN status IN ('earlyscreenout','latescreenout') THEN 1 ELSE 0 END) AS urls_screenout, SUM(CASE WHEN status = 'quotafull' THEN 1 ELSE 0 END) AS urls_quotafull, SUM(CASE WHEN status = 'timeout' THEN 1 ELSE 0 END) AS urls_timeout, ROUND(AVG(CASE WHEN status = 'complete' AND actual_loi_seconds > 0 THEN actual_loi_seconds END), 0) AS avg_loi_secs FROM survey_urls WHERE project_id IN ($placeholders) GROUP BY project_id "); $sStmt->execute($project_id_list); foreach ($sStmt->fetchAll(PDO::FETCH_ASSOC) as $row) { $statsByProject[$row['project_id']] = $row; } // Weighted-average estimated incidence per project (using project_selections) // Note: project_selections.project_id is the int FK referencing projects.id $project_pk_list = array_map(function($p) { return (int)$p['id']; }, $projects); $pkPlaceholders = implode(',', array_fill(0, count($project_pk_list), '?')); $eStmt = $pdo->prepare(" SELECT project_id AS pk_id, CASE WHEN SUM(required_samples) > 0 THEN ROUND(SUM(estimated_incidence_rate * required_samples) / SUM(required_samples), 2) ELSE NULL END AS weighted_eir FROM project_selections WHERE project_id IN ($pkPlaceholders) GROUP BY project_id "); $eStmt->execute($project_pk_list); $eByPk = []; foreach ($eStmt->fetchAll(PDO::FETCH_ASSOC) as $row) { $eByPk[(int)$row['pk_id']] = $row['weighted_eir']; } foreach ($projects as $p) { $estIncByProject[$p['project_id']] = $eByPk[(int)$p['id']] ?? null; } } // Helper: format LOI seconds → "Xm Ys" or "Xs" if (!function_exists('fmtLoi')) { function fmtLoi($secs) { if (!$secs || $secs <= 0) return '—'; $secs = (int)$secs; if ($secs < 60) return $secs . 's'; $m = floor($secs / 60); $s = $secs % 60; return $m . 'm' . ($s > 0 ? ' ' . $s . 's' : ''); } } // Helper: returns CSS color for a metric based on healthy/borderline/poor thresholds // $direction: 'higher_better' (response, incidence achievement) or 'lower_better' (screenout) if (!function_exists('metricColor')) { function metricColor($value, $good, $ok, $direction = 'higher_better') { if ($direction === 'higher_better') { if ($value >= $good) return '#059669'; // green if ($value >= $ok) return '#d97706'; // amber return '#dc2626'; // red } else { if ($value <= $good) return '#059669'; if ($value <= $ok) return '#d97706'; return '#dc2626'; } } } // Get industries for filter $industriesStmt = $pdo->query("SELECT DISTINCT industry FROM projects WHERE client_id = " . $_SESSION['client_id'] . " ORDER BY industry"); $industries = $industriesStmt->fetchAll(); include 'client-portal-header.php'; ?>
Manage your survey projects
| Project | Status | Sample target / done |
Sent | Funnel C / P / SO / QF / TO |
Resp % | Inc % vs estimated |
SO % | Avg LOI vs eLOI |
Deadline | Actions |
|---|---|---|---|---|---|---|---|---|---|---|
|
· Ref:
|
0): ?>
done
% of target
—
|
0): ?>
awaiting
|
0): ?>
/
/
/
/
0): ?>
in progress
—
|
0): ?> % — |
0): ?>
%
est %
—
est %
|
0): ?> % — |
0): ?>
est m
—
est m
|
|