From caebbaee924c0ea18a0bd04f4b7f0c32728ea12e Mon Sep 17 00:00:00 2001 From: ectasy663 Date: Tue, 22 Sep 2026 17:46:57 +0530 Subject: [PATCH] Fix dashboard share card by replacing htmlToImage with dedicated OG API route --- src/app/api/og/dashboard/route.tsx | 96 ++++++++++++++++++++++++++++++ src/app/dashboard/page.tsx | 36 +++++++---- 2 files changed, 121 insertions(+), 11 deletions(-) create mode 100644 src/app/api/og/dashboard/route.tsx diff --git a/src/app/api/og/dashboard/route.tsx b/src/app/api/og/dashboard/route.tsx new file mode 100644 index 0000000..172bb50 --- /dev/null +++ b/src/app/api/og/dashboard/route.tsx @@ -0,0 +1,96 @@ +import { ImageResponse } from '@vercel/og'; +import { NextRequest } from 'next/server'; + +export const runtime = 'edge'; + +export async function GET(req: NextRequest) { + try { + const { searchParams } = new URL(req.url); + + // Read metrics + const score = searchParams.get('score') || '0 / 0'; + const accuracy = searchParams.get('accuracy') || '0%'; + const qs = searchParams.get('qs') || '0'; + const rank = searchParams.get('rank') || '#--'; + + // Read user info + const name = searchParams.get('name') || 'Student'; + const target = searchParams.get('target') || 'JEE'; + const plan = searchParams.get('plan') || 'Free'; + + return new ImageResponse( + ( +
+ {/* Header */} +
+
+
+ PRAGATIVEER +
+
+ Performance Overview +
+
+ + {/* Main Content */} +
+

Dashboard Stats

+ + {/* 2x2 Grid */} +
+
+ {score} + Today's Score +
+
+ {accuracy} + Accuracy +
+
+ {qs} + Qs Attempted +
+
+ {rank} + City Rank +
+
+
+ + {/* Footer */} +
+
+
{name}
+
{plan} Plan
+
{target} Aspirant
+
+
+ contact@pragativeer.com +
+
+
+ ), + { + width: 1200, + height: 630, + } + ); + } catch (e: any) { + return new Response(`Failed to generate image`, { + status: 500, + }); + } +} diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index 4768d1a..d9a33a2 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -5,7 +5,6 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { BrainCircuit, Play, ChevronRight, Activity, Target, CheckCircle2, AlertTriangle, TrendingUp, Calendar, Zap, LayoutDashboard, Share2, Trophy, Lock, ArrowRight, Clock } from "lucide-react" -import * as htmlToImage from 'html-to-image' import { MistakeHeatmap } from "@/components/AI/MistakeHeatmap" import { AdaptiveStudyPlan } from "@/components/AI/AdaptiveStudyPlan" import { useActiveUser } from "@/hooks/useActiveUser" @@ -33,16 +32,31 @@ export default function DashboardPage() { }, [user?.id]) const handleExport = async () => { - if (progressRef.current) { - try { - const dataUrl = await htmlToImage.toPng(progressRef.current, { backgroundColor: '#09090b' }) - const link = document.createElement('a') - link.download = 'pragativeer-progress.png' - link.href = dataUrl - link.click() - } catch (err) { - console.error("Failed to export image", err) - } + try { + const score = isNew ? "0 / 0" : `${userStats?.today_score || 0} / ${userStats?.today_max_score || 60}` + const accuracy = isNew ? "0%" : `${userStats?.overall_accuracy || 0}%` + const qs = isNew ? "0" : (userStats?.total_questions_attempted || 0).toLocaleString() + const rank = isNew ? "#--" : `#${userStats?.city_rank || 1} / ${userStats?.city_total || 50}` + + const target = user?.target_exam === "NEET" ? "NEET" : "JEE" + const plan = user?.tier === "Al_Coach" ? "AI Coach" : user?.tier || "Free" + const name = user?.name || "Student" + + const url = `/api/og/dashboard?score=${encodeURIComponent(score)}&accuracy=${encodeURIComponent(accuracy)}&qs=${encodeURIComponent(qs)}&rank=${encodeURIComponent(rank)}&name=${encodeURIComponent(name)}&target=${target}&plan=${encodeURIComponent(plan)}` + + const res = await fetch(url) + const blob = await res.blob() + const blobUrl = window.URL.createObjectURL(blob) + + const link = document.createElement('a') + link.download = 'pragativeer-dashboard.png' + link.href = blobUrl + document.body.appendChild(link) + link.click() + document.body.removeChild(link) + window.URL.revokeObjectURL(blobUrl) + } catch (err) { + console.error("Failed to export image", err) } }