From 32af32569b193002cbb8aec16e107709c77fc5a5 Mon Sep 17 00:00:00 2001 From: King Omar Date: Fri, 10 Jul 2026 13:31:32 +1000 Subject: [PATCH] Fix dashboard to show all visa tracker tools MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Main /dashboard now uses dashWrap sidebar (same as all tool pages), replacing the old isolated dashboardPage template. Overview shows quick-stat cards for points/timeline/expiring docs/inquiries, a full 12-tool grid, expiry alerts, and recent inquiries — all in one unified layout. Co-Authored-By: Claude Sonnet 4.6 --- src/index.js | 29 +++++++++-- src/visa-tracker.js | 117 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+), 5 deletions(-) diff --git a/src/index.js b/src/index.js index 1f8d7ad..7c35b17 100644 --- a/src/index.js +++ b/src/index.js @@ -8,7 +8,8 @@ import { } from './templates.js'; import { pointsPage, timelinePage, documentsPage, feesPage, - occupationsPage, stateCriteriaPage, processingTimesPage, englishPage, studentFundPage + occupationsPage, stateCriteriaPage, processingTimesPage, englishPage, studentFundPage, + dashboardOverview } from './visa-tracker.js'; const app = new Hono(); @@ -111,10 +112,28 @@ app.get('/courses', async c => { app.get('/dashboard', async c => { const user = c.get('user'); if (!user) return c.redirect('/login?redirect=/dashboard'); - const { results } = await c.env.DB.prepare( - 'SELECT * FROM inquiries WHERE user_id = ? ORDER BY created_at DESC LIMIT 20' - ).bind(user.id).all(); - return c.html(dashboardPage(user, results)); + const [inquiriesRes, profileRes, docsRes, timelineRes] = await Promise.all([ + c.env.DB.prepare('SELECT * FROM inquiries WHERE user_id=? ORDER BY created_at DESC LIMIT 10').bind(user.id).all(), + c.env.DB.prepare('SELECT * FROM visa_profiles WHERE user_id=?').bind(user.id).first(), + c.env.DB.prepare('SELECT * FROM document_expiries WHERE user_id=? ORDER BY expiry_date ASC LIMIT 5').bind(user.id).all(), + c.env.DB.prepare('SELECT * FROM case_timelines WHERE user_id=?').bind(user.id).all(), + ]); + const { calcPoints } = await import('./visa-data.js'); + const points = profileRes ? calcPoints(profileRes) : null; + const completedStages = (timelineRes.results||[]).filter(s => s.milestone_date).length; + const today = new Date(); + const expiringDocs = (docsRes.results||[]).filter(d => { + const days = Math.round((new Date(d.expiry_date) - today) / 86400000); + return days <= 180; + }); + return c.html(layout('Dashboard', dashboardOverview(user, { + inquiries: inquiriesRes.results||[], + profile: profileRes, + points, + completedStages, + totalStages: 7, + expiringDocs, + }), user)); }); app.get('/dashboard/save', async c => { diff --git a/src/visa-tracker.js b/src/visa-tracker.js index 243fb8e..f57220c 100644 --- a/src/visa-tracker.js +++ b/src/visa-tracker.js @@ -615,3 +615,120 @@ export function studentFundPage(user) { return dashWrap(user, 'student-fund', body); } + +// ── DASHBOARD OVERVIEW (replaces old dashboardPage) ────────────────────────── +export function dashboardOverview(user, { inquiries, profile, points, completedStages, totalStages, expiringDocs }) { + const today = new Date(); + + const quickStats = [ + { + label: 'Migration Points', + value: points ? `${points.total} pts` : '—', + sub: points ? (points.total >= 90 ? 'Competitive' : points.total >= 65 ? 'Getting there' : 'Below threshold') : 'Not calculated', + color: points ? (points.total >= 90 ? '#16a34a' : points.total >= 65 ? '#d97706' : '#dc2626') : '#94a3b8', + href: '/dashboard/points', + icon: '🔢', + }, + { + label: 'Visa Timeline', + value: `${completedStages} / ${totalStages}`, + sub: completedStages === totalStages ? '🎉 Visa granted!' : completedStages === 0 ? 'Not started' : 'In progress', + color: '#1a5bb8', + href: '/dashboard/timeline', + icon: '📅', + }, + { + label: 'Expiring Documents', + value: expiringDocs.length > 0 ? expiringDocs.length : '✓', + sub: expiringDocs.length > 0 ? 'Need attention' : 'All clear', + color: expiringDocs.length > 0 ? '#dc2626' : '#16a34a', + href: '/dashboard/documents', + icon: '📄', + }, + { + label: 'Inquiries', + value: inquiries.length, + sub: 'Total submitted', + color: '#1a5bb8', + href: '/contact', + icon: '📝', + }, + ]; + + const tools = [ + { href: '/dashboard/points', icon: '🔢', label: 'Points Calculator', desc: 'Calculate your skilled migration points score' }, + { href: '/dashboard/timeline', icon: '📅', label: 'Visa Timeline', desc: 'Track your case from skills assessment to grant' }, + { href: '/dashboard/documents', icon: '📄', label: 'Document Expiry', desc: 'Passport, visa, English test, skills assessment' }, + { href: '/dashboard/fees', icon: '💰', label: 'VAC Fee Calculator', desc: 'Estimate your Visa Application Charge' }, + { href: '/dashboard/occupations', icon: '🔍', label: 'Occupation Search', desc: 'MLTSSL/STSOL list with visa eligibility' }, + { href: '/dashboard/state-criteria', icon: '🗺️', label: 'State Criteria', desc: 'SC 190 & 491 min points by state' }, + { href: '/dashboard/processing-times', icon: '⏱️', label: 'Processing Times', desc: 'P25/P50/P75/P90 percentile estimates' }, + { href: '/dashboard/english', icon: '🗣️', label: 'English Requirements', desc: 'IELTS/PTE/TOEFL/OET by visa subclass' }, + { href: '/dashboard/student-fund', icon: '🎓', label: 'Student Fund Calc', desc: 'Minimum savings for student visa' }, + { href: '/courses', icon: '🔎', label: 'CRICOS Course Search', desc: 'Search 26K+ registered courses' }, + { href: '/contact', icon: '📞', label: 'Book Consultation', desc: 'Talk to a Careers Gateway expert' }, + { href: '/health-insurance', icon: '🏥', label: 'Health Insurance', desc: 'Compare OSHC & OVHC policies' }, + ]; + + const body = ` +
+
Welcome back, ${esc(user.full_name.split(' ')[0])}! 👋
+
Your migration dashboard — everything in one place
+
+ +
+ ${quickStats.map(s => ` + +
+
${s.icon}
+
${s.value}
+
${s.label}
+
${s.sub}
+
+
`).join('')} +
+ + ${expiringDocs.length > 0 ? ` +
+
⚠️
+
+
Documents expiring soon
+ ${expiringDocs.map(d => { + const days = Math.round((new Date(d.expiry_date) - today) / 86400000); + return `
${esc(d.doc_label)} — ${days < 0 ? 'EXPIRED' : `expires in ${days} days`}
`; + }).join('')} + Manage documents → +
+
` : ''} + +
+
🧰 Migration Tools
+
+ ${tools.map(t => ` + + ${t.icon} +
+
${t.label}
+
${t.desc}
+
+
`).join('')} +
+
+ + ${inquiries.length > 0 ? ` +
+
📋 Recent Inquiries
+ ${inquiries.slice(0,5).map(i => ` +
+
+
${esc(i.service||'General Inquiry')}${i.cricos_course_name ? ` — ${esc(i.cricos_course_name)}` : ''}
+
${new Date(i.created_at).toLocaleDateString('en-AU',{day:'numeric',month:'short',year:'numeric'})}
+
+ ${i.kondesk_sent?'✓ Processing':'Received'} +
`).join('')} +
` : ''}`; + + return dashWrap(user, 'overview', body); +} + +export { dashWrap };