prepare(" SELECT * FROM projects WHERE id = ? AND client_id = ? "); $stmt->execute([$project_id, $_SESSION['client_id']]); $project = $stmt->fetch(); if (!$project) { header('Location: projects-list.php'); exit; } // Fetch selections with member counts $stmt = $pdo->prepare(" SELECT ps.*, COUNT(DISTINCT sm.user_id) as actual_selected, SUM(CASE WHEN sm.sample_status = 'pending' THEN 1 ELSE 0 END) as cnt_pending, SUM(CASE WHEN sm.sample_status = 'complete' THEN 1 ELSE 0 END) as cnt_complete, SUM(CASE WHEN sm.sample_status = 'screen_out' THEN 1 ELSE 0 END) as cnt_screen_out, SUM(CASE WHEN sm.sample_status = 'quota_full' THEN 1 ELSE 0 END) as cnt_quota_full, SUM(CASE WHEN sm.sample_status = 'over_quota' THEN 1 ELSE 0 END) as cnt_over_quota FROM project_selections ps LEFT JOIN selection_members sm ON ps.id = sm.selection_id WHERE ps.project_id = ? AND ps.client_id = ? GROUP BY ps.id ORDER BY ps.created_at DESC "); $stmt->execute([$project_id, $_SESSION['client_id']]); $selections = $stmt->fetchAll(); // URL stats per selection + LOI per selection $selUrlStats = []; $selLoiStats = []; $projectLoiStats = ['avg_loi'=>0,'min_loi'=>0,'max_loi'=>0,'total_completes'=>0,'speedsters'=>0,'ip_dups'=>0]; if (!empty($selections)) { $selIds = array_column($selections, 'id'); $ph = implode(',', array_fill(0, count($selIds), '?')); // URL status counts per selection $stmt = $pdo->prepare(" SELECT assigned_to_selection_id as sel_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 FROM survey_urls WHERE assigned_to_selection_id IN ($ph) GROUP BY assigned_to_selection_id "); $stmt->execute($selIds); foreach ($stmt->fetchAll() as $r) $selUrlStats[$r['sel_id']] = $r; // LOI + quality per selection $stmt = $pdo->prepare(" SELECT assigned_to_selection_id as sel_id, AVG(CASE WHEN status='complete' AND actual_loi_seconds IS NOT NULL THEN actual_loi_seconds END) as avg_loi, MIN(CASE WHEN status='complete' AND actual_loi_seconds IS NOT NULL THEN actual_loi_seconds END) as min_loi, MAX(CASE WHEN status='complete' AND actual_loi_seconds IS NOT NULL THEN actual_loi_seconds END) as max_loi, SUM(CASE WHEN quality_flag='speedster' THEN 1 ELSE 0 END) as speedsters, SUM(CASE WHEN quality_flag='ip_duplicate' THEN 1 ELSE 0 END) as ip_dups, SUM(CASE WHEN quality_flag='client_flagged' THEN 1 ELSE 0 END) as flagged FROM survey_urls WHERE assigned_to_selection_id IN ($ph) GROUP BY assigned_to_selection_id "); $stmt->execute($selIds); foreach ($stmt->fetchAll() as $r) $selLoiStats[$r['sel_id']] = $r; // Project-wide stats $stmt = $pdo->prepare(" SELECT COUNT(*) as total_urls, SUM(CASE WHEN status = 'complete' THEN 1 ELSE 0 END) as total_completes, SUM(CASE WHEN status = 'clicked' THEN 1 ELSE 0 END) as total_clicked, SUM(CASE WHEN status IN ('earlyscreenout','latescreenout') THEN 1 ELSE 0 END) as total_screenout, SUM(CASE WHEN status = 'quotafull' THEN 1 ELSE 0 END) as total_quotafull, SUM(CASE WHEN status = 'timeout' THEN 1 ELSE 0 END) as total_timeout, SUM(CASE WHEN status = 'partial' THEN 1 ELSE 0 END) as total_partial, AVG(CASE WHEN status='complete' AND actual_loi_seconds IS NOT NULL THEN actual_loi_seconds END) as avg_loi, MIN(CASE WHEN status='complete' AND actual_loi_seconds IS NOT NULL THEN actual_loi_seconds END) as min_loi, MAX(CASE WHEN status='complete' AND actual_loi_seconds IS NOT NULL THEN actual_loi_seconds END) as max_loi, SUM(CASE WHEN quality_flag='speedster' THEN 1 ELSE 0 END) as speedsters, SUM(CASE WHEN quality_flag='ip_duplicate' THEN 1 ELSE 0 END) as ip_dups, SUM(CASE WHEN quality_flag='client_flagged' THEN 1 ELSE 0 END) as flagged FROM survey_urls WHERE project_id = ? "); $stmt->execute([$project['project_id']]); $ps = $stmt->fetch(PDO::FETCH_ASSOC); if ($ps) $projectLoiStats = $ps; } // Compute totals from selections $total_required = array_sum(array_column($selections, 'required_samples')); $total_selected = array_sum(array_column($selections, 'actual_selected')); $status_colors = [ 'Created' => '#0066cc', 'Targeted' => '#d97706', 'Live' => '#059669', 'On hold' => '#dc2626', 'Closed' => '#6b7280' ]; $color = $status_colors[$project['status']] ?? '#6b7280'; ?> Project <?php echo htmlspecialchars($project['project_id']); ?>

RELEVANT REFLEX

Project Completion Report —
Generated | Client:
Project Information
Project Name
Project ID
Status
Industry
eLOI
min
Sample Size (eN)
Client Reference
Deadline
Created
Completion Dashboard
0 ? min(100, round(($completes / $target) * 100, 1)) : 0; $speedsters = intval($projectLoiStats['speedsters'] ?? 0); $ip_dups = intval($projectLoiStats['ip_dups'] ?? 0); $flagged = intval($projectLoiStats['flagged'] ?? 0); $quality_issues = $speedsters + $ip_dups + $flagged; $screenouts = intval($projectLoiStats['total_screenout'] ?? 0); $quotafull = intval($projectLoiStats['total_quotafull'] ?? 0); $timeouts = intval($projectLoiStats['total_timeout'] ?? 0); $avgLoiMin = ($projectLoiStats['avg_loi'] > 0) ? round($projectLoiStats['avg_loi'] / 60, 1) : '-'; $minLoiMin = ($projectLoiStats['min_loi'] > 0) ? round($projectLoiStats['min_loi'] / 60, 1) : '-'; $maxLoiMin = ($projectLoiStats['max_loi'] > 0) ? round($projectLoiStats['max_loi'] / 60, 1) : '-'; ?>
/
Completes / Target
%
Completion Rate
Avg LOI (min)
LOI Range (min)
Quality Issues
Completion: %
Screen Outs
Quota Full
Timeouts
Speedsters
IP Duplicates
Selections
Selections Breakdown ()
0 ? round($ls['avg_loi'] / 60, 1) . 'm' : '-'; $selSpd = intval($ls['speedsters'] ?? 0); $selIpd = intval($ls['ip_dups'] ?? 0); ?>
Selection Status Required Selected Completes Screen Out Quota Full URLs Sent Avg LOI Speedsters IP Dups Incidence

0 ? '' . $selSpd . '' : '0'; ?> 0 ? '' . $selIpd . '' : '0'; ?> %
Timeline
Created
Last Updated
Made Live
Deadline
Description