feat: apply various dashboard and auth fixes including demo trials, settings UI, and signup options

This commit is contained in:
2026-09-23 16:38:49 +05:30
parent 86a2749360
commit 1d9cdd3f33
18 changed files with 435 additions and 147 deletions

View File

@@ -4,7 +4,6 @@ import { fetchWithAuth } from "@/lib/apiClient";
import { useEffect, useState } from "react"
import { Card, CardContent } from "@/components/ui/card"
import { RefreshCw, TrendingUp, MapPin, Star } from "lucide-react"
import { useActiveUser } from "@/hooks/useActiveUser"
const MOCK_COLLEGES_JEE: Record<string, Array<{ rank: number; name: string; branch: string; match: number; location: string; type: string; starred?: boolean }>> = {
Reach: [
@@ -56,22 +55,28 @@ const MATCH_COLOR = (match: number) => {
export function CollegePredictorCard() {
const [loading, setLoading] = useState(true)
const [activeTab, setActiveTab] = useState("Target")
const { userId, user, loading: userLoading } = useActiveUser()
const [isNeet, setIsNeet] = useState(false)
useEffect(() => {
if (userLoading || !userId) return
// Read userId and target exam from localStorage to avoid SSR issues
const userId = typeof window !== 'undefined' ? localStorage.getItem('activeUserId') : null;
if (!userId) { setLoading(false); return; }
async function fetchData() {
try {
const res = await fetchWithAuth(`/api/ai-coach/readiness/${userId}`)
if (!res.ok) throw new Error("fallback")
const res = await fetchWithAuth(`/api/users/${userId}`);
if (res.ok) {
const userData = await res.json();
setIsNeet(userData?.target_exam === 'NEET');
}
} catch {
// Use mock data — no-op
// Use default (JEE) on error
} finally {
setLoading(false)
}
}
fetchData()
}, [userId, userLoading])
}, [])
if (loading) {
return (
@@ -81,7 +86,6 @@ export function CollegePredictorCard() {
)
}
const isNeet = user?.target_exam === "NEET";
const colleges = (isNeet ? MOCK_COLLEGES_NEET[activeTab] : MOCK_COLLEGES_JEE[activeTab]) || []
const TAB_COLORS: Record<string, string> = {

View File

@@ -0,0 +1,55 @@
"use client"
import React from "react"
import { useActiveUser } from "@/hooks/useActiveUser"
import { Lock, Sparkles, ArrowRight } from "lucide-react"
import Link from "next/link"
interface PremiumGateProps {
featureKey: string;
children: React.ReactNode;
}
export function PremiumGate({ featureKey, children }: PremiumGateProps) {
const { hasAccessTo, loading, user } = useActiveUser();
if (loading || !user) {
return (
<div className="flex-1 min-h-[400px] flex items-center justify-center">
<div className="flex flex-col items-center gap-4">
<div className="w-10 h-10 border-4 border-[var(--cyan-ai-20)] border-t-[var(--cyan-ai)] rounded-full animate-spin"></div>
</div>
</div>
);
}
if (!hasAccessTo(featureKey)) {
return (
<div className="flex-1 min-h-[60vh] flex items-center justify-center p-6">
<div className="max-w-md w-full p-8 rounded-3xl bg-secondary/30 border border-border/50 text-center space-y-6 shadow-2xl backdrop-blur-xl relative overflow-hidden group">
{/* Background Glow */}
<div className="absolute top-0 left-1/2 -translate-x-1/2 w-full h-1/2 bg-[var(--cyan-ai)] opacity-5 blur-[80px] pointer-events-none group-hover:opacity-10 transition-opacity duration-700"></div>
<div className="relative">
<div className="w-16 h-16 mx-auto rounded-2xl bg-[var(--cyan-ai-10)] flex items-center justify-center shadow-[0_0_20px_-5px_var(--cyan-ai)] border border-[var(--cyan-ai-20)] mb-4 animate-in zoom-in duration-500">
<Lock className="text-[var(--cyan-ai)] w-8 h-8" />
</div>
<h2 className="text-2xl font-black tracking-tight text-foreground">Premium Feature</h2>
<p className="text-muted-foreground mt-2 font-medium">
You need an active plan to access this exclusive tool.
</p>
</div>
<Link href="/upgrade" className="inline-flex items-center justify-center gap-2 w-full bg-[var(--cyan-ai)] text-black font-bold py-3.5 px-6 rounded-xl hover:bg-cyan-400 transition-all shadow-[0_0_20px_-5px_var(--cyan-ai)] hover:shadow-[0_0_30px_-5px_var(--cyan-ai)] group/btn">
<Sparkles className="w-4 h-4" />
Upgrade Plan to Unlock
<ArrowRight className="w-4 h-4 group-hover/btn:translate-x-1 transition-transform" />
</Link>
</div>
</div>
);
}
return <>{children}</>;
}