redirectToLogin('Session expired. Please log in again.'); } try { $db = new Database(); $pdo = $db->getConnection(); } catch (Exception $e) { logError('DB failed: ' . $e->getMessage()); die('System error.'); } // Award onboarding points if (!$user['onboarding_points_awarded']) { try { $pdo->beginTransaction(); $pdo->prepare("INSERT INTO user_points (user_id, points, total_earned) VALUES (?, 10.00, 10.00) ON DUPLICATE KEY UPDATE points = points + 10.00, total_earned = total_earned + 10.00")->execute([$user['id']]); $pdo->prepare("INSERT INTO point_transactions (user_id, transaction_type, points, source, description) VALUES (?, 'earned', 10.00, 'onboarding', 'Welcome bonus for joining Relevant Reflex')")->execute([$user['id']]); $pdo->prepare("UPDATE users SET onboarding_points_awarded = 1 WHERE id = ?")->execute([$user['id']]); $pdo->commit(); $user = getCurrentUser(); } catch (Exception $e) { $pdo->rollback(); } } $userPoints = ['points' => 0, 'total_earned' => 0, 'total_redeemed' => 0]; try { $stmt = $pdo->prepare("SELECT points, total_earned, total_redeemed FROM user_points WHERE user_id = ?"); $stmt->execute([$user['id']]); $p = $stmt->fetch(); if ($p) $userPoints = $p; } catch (Exception $e) {} $profilerSections = ['personal_background'=>'Personal Background','household_family'=>'Household & Family','shopping_lifestyle'=>'Shopping & Lifestyle','technology_digital'=>'Technology & Digital','travel_transportation'=>'Travel & Transportation','health_fitness'=>'Health & Fitness','entertainment_media'=>'Entertainment & Media','food_dining'=>'Food & Dining','financial_services'=>'Financial Services','communication_payments'=>'Communication & Payments']; $profilerCompletion = []; try { $stmt = $pdo->prepare("SELECT section, completion_percentage, is_completed, points_awarded FROM profiler_completion WHERE user_id = ?"); $stmt->execute([$user['id']]); while ($row = $stmt->fetch()) $profilerCompletion[$row['section']] = $row; } catch (Exception $e) {} $completedSections = 0; foreach ($profilerSections as $k => $n) { if (isset($profilerCompletion[$k]) && $profilerCompletion[$k]['is_completed']) $completedSections++; } $mobileVerified = false; $mobileNumber = ''; try { $stmt = $pdo->prepare("SELECT mobile_number, is_verified FROM mobile_verifications WHERE user_id = ?"); $stmt->execute([$user['id']]); $md = $stmt->fetch(); if ($md) { $mobileVerified = $md['is_verified']; $mobileNumber = $md['mobile_number']; } } catch (Exception $e) {} $upiId = ''; try { $stmt = $pdo->prepare("SELECT response FROM user_profiler WHERE user_id = ? AND section = 'profile' AND question_id = 'upi_id'"); $stmt->execute([$user['id']]); $ud = $stmt->fetch(); if ($ud) $upiId = json_decode($ud['response'], true); } catch (Exception $e) {} if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'update_upi') { $newUpiId = isset($_POST['upi_id']) ? sanitize($_POST['upi_id']) : ''; if (!empty($newUpiId) && preg_match('/^[\w\.\-]+@[\w\.\-]+$/', $newUpiId)) { try { $stmt = $pdo->prepare("INSERT INTO user_profiler (user_id, section, question_id, response) VALUES (?, 'profile', 'upi_id', ?) ON DUPLICATE KEY UPDATE response = ?, updated_at = NOW()"); $j = json_encode($newUpiId); $stmt->execute([$user['id'], $j, $j]); $upiId = $newUpiId; $success_message = "UPI ID updated successfully!"; } catch (Exception $e) { $error_message = "Error updating UPI ID."; } } else { $error_message = "Please enter a valid UPI ID (e.g., yourname@paytm)."; } } $userTickets = []; try { $stmt = $pdo->prepare("SELECT st.*, (SELECT COUNT(*) FROM support_messages sm WHERE sm.ticket_id = st.id) as message_count, (SELECT sm.created_at FROM support_messages sm WHERE sm.ticket_id = st.id ORDER BY sm.created_at DESC LIMIT 1) as last_reply FROM support_tickets st WHERE st.user_id = ? ORDER BY st.created_at DESC LIMIT 10"); $stmt->execute([$user['id']]); $userTickets = $stmt->fetchAll(); } catch (Exception $e) {} $userRedemptions = []; try { $stmt = $pdo->prepare("SELECT * FROM redemption_requests WHERE user_id = ? ORDER BY created_at DESC LIMIT 5"); $stmt->execute([$user['id']]); $userRedemptions = $stmt->fetchAll(); } catch (Exception $e) {} // Survey history from shop DB $surveys = []; $surveyStats = ['total'=>0,'completes'=>0,'pending'=>0,'flagged'=>0]; try { $shopPdo = new PDO("mysql:host=localhost;dbname=u752449863_rrshop;charset=utf8mb4","u752449863_rradmin","S@n@h2016",[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,PDO::ATTR_DEFAULT_FETCH_MODE=>PDO::FETCH_ASSOC]); $cols = array_column($shopPdo->query("SHOW COLUMNS FROM survey_urls")->fetchAll(), 'Field'); $hasQF = in_array('quality_flag', $cols); $hasLoi = in_array('actual_loi_seconds', $cols); $hasCompAt = in_array('completed_at', $cols); $hasQN = in_array('quality_notes', $cols); $pcols = array_column($shopPdo->query("SHOW COLUMNS FROM projects")->fetchAll(), 'Field'); $hasCS = in_array('closure_status', $pcols); $hasSP = in_array('speedster_threshold_pct', $pcols); $qf = $hasQF ? "su.quality_flag" : "'valid' as quality_flag"; $qn = $hasQN ? "su.quality_notes" : "NULL as quality_notes"; $loi = $hasLoi ? "su.actual_loi_seconds" : "NULL as actual_loi_seconds"; $cat = $hasCompAt ? "su.completed_at" : "NULL as completed_at"; $cs = $hasCS ? "p.closure_status" : "'none' as closure_status"; $sp = $hasSP ? "p.speedster_threshold_pct" : "33.33 as speedster_threshold_pct"; $stmt = $shopPdo->prepare(" SELECT su.status as url_status, su.clicked_at, su.created_at as sent_at, $qf, $qn, $loi, $cat, p.project_id, p.project_name, p.eloi, p.industry, p.status as project_status, $cs, $sp FROM survey_urls su INNER JOIN projects p ON su.project_id = p.project_id WHERE su.sent_to_user_id = ? AND su.status NOT IN ('available') ORDER BY su.created_at DESC LIMIT 30 "); $stmt->execute([$user['id']]); $surveys = $stmt->fetchAll(); foreach ($surveys as $s) { $surveyStats['total']++; if ($s['url_status']==='complete') { $surveyStats['completes']++; $q=$s['quality_flag']??'valid'; if (in_array($q,['speedster','ip_duplicate','client_flagged'])) $surveyStats['flagged']++; elseif ($s['project_status']!=='Closed') $surveyStats['pending']++; } } } catch (Exception $e) { error_log("Survey stats: ".$e->getMessage()); } // Get survey-related point transactions from panel DB $surveyPointsByProject = []; try { $stmt = $pdo->prepare("SELECT reference_id, points, description, created_at FROM point_transactions WHERE user_id = ? AND source = 'survey' AND transaction_type = 'earned' ORDER BY created_at DESC"); $stmt->execute([$user['id']]); while ($row = $stmt->fetch()) { if ($row['reference_id']) $surveyPointsByProject[$row['reference_id']] = $row; } } catch (Exception $e) {} $joinDateFormatted = (new DateTime($user['created_at']))->format('M Y'); $profilePct = round(($completedSections / count($profilerSections)) * 100); $firstName = htmlspecialchars($user['first_name'] ?? explode('@',$user['email'])[0]); $initials = strtoupper(substr($user['first_name']??$user['email'],0,1).substr($user['last_name']??'',0,1)); if (strlen($initials)<2) $initials = strtoupper(substr($user['email'],0,2)); function getSurveyLabel($s) { $st=$s['url_status']; $qf=$s['quality_flag']??'valid'; $ps=$s['project_status']; if ($st==='sent') return ['Invited','label-neutral','Invitation sent. Click the survey link in your email to participate.']; if ($st==='clicked') return ['In Progress','label-warn','You started this survey but haven\'t completed it yet.']; if (in_array($st,['earlyscreenout','latescreenout'])) return ['Screened Out','label-neutral','You did not qualify based on screening criteria.']; if ($st==='quotafull') return ['Quota Full','label-neutral','The survey quota was filled before your response was recorded.']; if ($st==='timeout') return ['Timed Out','label-neutral','Session expired before completion.']; if ($st==='partial') return ['Partial','label-info','Your response was partially recorded.']; if ($st==='complete') { if (in_array($qf,['speedster','ip_duplicate','client_flagged'])) return ['Under Review','label-danger','Flagged for quality review. Points held pending admin decision.']; if ($ps==='Closed') return ['Approved','label-ok','Approved and points credited to your account.']; return ['Pending Approval','label-warn','Completed successfully. Points will credit when the project closes.']; } return [ucfirst($st),'label-neutral','']; } function fmtLoi($s){if(!$s)return'-';$m=floor($s/60);$ss=$s%60;return($m?$m.'m ':'').$ss.'s';} function fmtDt($d){if(!$d)return'-';return date('M d, Y g:i A',strtotime($d));} ?> Dashboard - Relevant Reflex
Overview
pts

Welcome back, !

Complete your profile, earn points, and participate in paid surveys.

New to surveys? Read 3 essential rules before taking your first survey to protect your account and maximize rewards.
Available Points
value
Surveys Done
total
Profile
%
sections
Total Earned
Since
Complete Profile
Earn up to 50 points
Redeem Rewards
Convert points to cash
Get Help
Support & FAQs
⚠ Read This Before You Take Any Survey
3 essential rules to protect your account and earn maximum rewards
1
Take your time. Read every question carefully. There are no right or wrong answers — we want your genuine opinion. Think about each question and answer what you truly feel. Surveys that are rushed through too quickly get automatically flagged and your response may be rejected without reward.
2
One attempt per person, per device. Each survey can only be taken once from your IP address or device. Duplicate attempts are automatically detected and flagged. Do not try to retake a survey using a different browser, incognito mode, or VPN — it will be caught and may result in account action.
3
Do not straightline your responses. Straightlining means selecting the same answer option for every question in a row (e.g., choosing "Agree" for all statements). This is a well-known indicator of low-quality responses and is flagged by our system. Only select the same answer repeatedly if that genuinely reflects your opinion.
Why this matters: Research clients review every response for quality. Flagged responses (speeding, duplicates, or straightlining) are rejected and no points are awarded. Repeated violations may lead to fewer survey invitations or account restrictions.
Complete your profile for more surveys. done. Continue →
0):?>
Total
Completed
Pending
0?'Under Review':'Approved';?>
0?$surveyStats['flagged']:$surveyStats['completes']-$surveyStats['pending']-$surveyStats['flagged'];?>
How it works: Click any survey to see full details. Completed surveys are reviewed when the project closes. Points are credited once approved. "Under Review" means quality concerns (e.g., LOI below minimum threshold). = normal LOI, = slow, = below threshold.
Survey History
$s): list($lbl,$cls,$desc)=getSurveyLabel($s); $eloiSec = intval($s['eloi']??0)*60; $thPct = floatval($s['speedster_threshold_pct']??33.33); $thSec = $eloiSec>0 ? $eloiSec*($thPct/100) : 0; $aLoi = $s['actual_loi_seconds'] ? intval($s['actual_loi_seconds']) : null; $loiPct = ($eloiSec>0 && $aLoi) ? min(100,round(($aLoi/$eloiSec)*100)) : 0; $loiCls = 'loi-ok'; if ($aLoi && $thSec>0 && $aLoi<$thSec) $loiCls='loi-fast'; elseif ($loiPct>150) $loiCls='loi-slow'; $pts = $surveyPointsByProject[$s['project_id']] ?? null; $rewardTxt = '-'; if ($s['url_status']==='complete') { if ($pts) $rewardTxt = number_format($pts['points'],0).' pts (₹'.number_format($pts['points']*0.5,2).')'; elseif ($s['project_status']==='Closed') $rewardTxt = 'Credited'; elseif (($s['quality_flag']??'valid')!=='valid') $rewardTxt = 'Held for review'; else $rewardTxt = 'Pending project closure'; } ?>
· ·
Invited On
Started At
Completed At
Your LOI
Expected LOI
min
Min Required LOI
0 ? fmtLoi(round($thSec)).' ('.$thPct.'%)' : '-';?>
Project Status
Reward

No surveys yet.

📊

No Surveys Yet

Complete your profile to receive survey invitations.

Know Me Better

Each section = 5 points. Complete all for 50!

done
Mobile Verification
10 ptsVerify Now
$sn):$c=$profilerCompletion[$sk]??null;$d=$c&&$c['is_completed'];$pct=$c?$c['completion_percentage']:0;$pa=$c&&$c['points_awarded'];$ic=$d?'done':($pct>0?'part':'empty');?>
':round($pct).'%';?>
0?'In progress':'Not started');?>
5 pts0?'Continue':'Start');?>
Available
Total Earned
Redeemed
Redeem Points
=200):?>

Minimum: 200 points (₹100). Cash via UPI.

Redeem Now
Need 200 points (₹100) minimum. You have more needed.
Recent Redemptions
# · pts → ₹
to ·
Account
Email
Gender
Date of Birth
Postcode
Status
Active Verified
Mobile
+91 verified
Not verified
Verify
UPI Details

For reward payments.

e.g. yourname@paytm, yourname@phonepe
UPI: