Fix animation inconsistencies on pages with loading spinners
This commit is contained in:
9
backend/check_enum.py
Normal file
9
backend/check_enum.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import asyncio
|
||||||
|
from sqlmodel import create_engine, text
|
||||||
|
|
||||||
|
DATABASE_URL = "postgresql://pragativeer_admin:local_secure_password_2026@postgres:5432/pragativeer_prod"
|
||||||
|
engine = create_engine(DATABASE_URL)
|
||||||
|
|
||||||
|
with engine.connect() as conn:
|
||||||
|
result = conn.execute(text("SELECT unnest(enum_range(NULL::tierenum));"))
|
||||||
|
print(result.fetchall())
|
||||||
9
backend/check_tier.py
Normal file
9
backend/check_tier.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import asyncio
|
||||||
|
from sqlmodel import create_engine, text
|
||||||
|
|
||||||
|
DATABASE_URL = "postgresql://pragativeer_admin:local_secure_password_2026@postgres:5432/pragativeer_prod"
|
||||||
|
engine = create_engine(DATABASE_URL)
|
||||||
|
|
||||||
|
with engine.connect() as conn:
|
||||||
|
result = conn.execute(text("SELECT email, tier FROM \"user\" LIMIT 10;"))
|
||||||
|
print(result.fetchall())
|
||||||
15
backend/find_amit.py
Normal file
15
backend/find_amit.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import asyncio
|
||||||
|
from sqlmodel import create_engine, select, Session
|
||||||
|
import sys
|
||||||
|
sys.path.append('backend')
|
||||||
|
import models
|
||||||
|
|
||||||
|
DATABASE_URL = "postgresql://pragativeer_admin:local_secure_password_2026@postgres:5432/pragativeer_prod"
|
||||||
|
engine = create_engine(DATABASE_URL)
|
||||||
|
|
||||||
|
with Session(engine) as session:
|
||||||
|
amit = session.exec(select(models.User).where(models.User.name == "Amit Kumar")).first()
|
||||||
|
if amit:
|
||||||
|
print(f"Amit Kumar: {amit.id}, {amit.tier}, {amit.target_exam}")
|
||||||
|
else:
|
||||||
|
print("Amit Kumar not found")
|
||||||
10
backend/fix_tier.py
Normal file
10
backend/fix_tier.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import asyncio
|
||||||
|
from sqlmodel import create_engine, text
|
||||||
|
|
||||||
|
DATABASE_URL = "postgresql://pragativeer_admin:local_secure_password_2026@postgres:5432/pragativeer_prod"
|
||||||
|
engine = create_engine(DATABASE_URL)
|
||||||
|
|
||||||
|
with engine.connect() as conn:
|
||||||
|
conn.execute(text("UPDATE \"user\" SET tier = 'AI Coach' WHERE tier = 'Al_Coach';"))
|
||||||
|
conn.commit()
|
||||||
|
print('Updated successfully')
|
||||||
14
backend/list_tests.py
Normal file
14
backend/list_tests.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import asyncio
|
||||||
|
from sqlmodel import create_engine, select, Session
|
||||||
|
import sys
|
||||||
|
sys.path.append('backend')
|
||||||
|
import models
|
||||||
|
|
||||||
|
DATABASE_URL = "postgresql://pragativeer_admin:local_secure_password_2026@postgres:5432/pragativeer_prod"
|
||||||
|
engine = create_engine(DATABASE_URL)
|
||||||
|
|
||||||
|
with Session(engine) as session:
|
||||||
|
tests = session.exec(select(models.Test)).all()
|
||||||
|
print(f"Total Tests: {len(tests)}")
|
||||||
|
for t in tests:
|
||||||
|
print(t.id, t.title)
|
||||||
18
backend/test_api_tests.py
Normal file
18
backend/test_api_tests.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import asyncio
|
||||||
|
from sqlmodel import create_engine, select, Session
|
||||||
|
import sys
|
||||||
|
sys.path.append('backend')
|
||||||
|
import models
|
||||||
|
|
||||||
|
DATABASE_URL = "postgresql://pragativeer_admin:local_secure_password_2026@postgres:5432/pragativeer_prod"
|
||||||
|
engine = create_engine(DATABASE_URL)
|
||||||
|
|
||||||
|
with Session(engine) as session:
|
||||||
|
user = session.exec(select(models.User).where(models.User.name == "Amit Kumar")).first()
|
||||||
|
print(f"User: {user.name}, Tier: {user.tier}, Exam: {user.target_exam}")
|
||||||
|
|
||||||
|
query = select(models.Test).where(models.Test.is_active == True).where(models.Test.type != "DPS")
|
||||||
|
tests = session.exec(query).all()
|
||||||
|
print(f"Tests returned from DB (excluding DPS): {len(tests)}")
|
||||||
|
for t in tests:
|
||||||
|
print(f" - {t.title} ({t.exam_pattern})")
|
||||||
@@ -103,7 +103,7 @@ export default function AIComCBTDPPPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-6 md:p-8 space-y-6 max-w-6xl mx-auto min-h-screen animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500">
|
<div className="p-6 md:p-8 space-y-6 max-w-6xl mx-auto min-h-screen">
|
||||||
{/* Top Header */}
|
{/* Top Header */}
|
||||||
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4 bg-secondary/20 border border-border p-6 rounded-3xl backdrop-blur-xl">
|
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4 bg-secondary/20 border border-border p-6 rounded-3xl backdrop-blur-xl">
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ export default function AIDailyPracticePage() {
|
|||||||
|
|
||||||
{/* ── PROTECTED PDF READER MODAL (FREE TIER) ── */}
|
{/* ── PROTECTED PDF READER MODAL (FREE TIER) ── */}
|
||||||
{selectedPdfDpp && (
|
{selectedPdfDpp && (
|
||||||
<div className={`fixed inset-0 z-50 bg-black/90 backdrop-blur-md flex items-center justify-center ${isFullScreen ? 'p-0' : 'p-4'} animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500`}>
|
<div className={`fixed inset-0 z-50 bg-black/90 backdrop-blur-md flex items-center justify-center ${isFullScreen ? 'p-0' : 'p-4'}`}>
|
||||||
<div className={`bg-background border border-border ${isFullScreen ? 'w-screen h-screen max-w-none max-h-none rounded-none border-0' : 'rounded-3xl w-full max-w-7xl max-h-[95vh]'} flex flex-col overflow-hidden shadow-2xl transition-all duration-300`}>
|
<div className={`bg-background border border-border ${isFullScreen ? 'w-screen h-screen max-w-none max-h-none rounded-none border-0' : 'rounded-3xl w-full max-w-7xl max-h-[95vh]'} flex flex-col overflow-hidden shadow-2xl transition-all duration-300`}>
|
||||||
{/* Modal Header */}
|
{/* Modal Header */}
|
||||||
<div className="p-4 md:p-5 border-b border-border bg-secondary/30 flex items-center justify-between">
|
<div className="p-4 md:p-5 border-b border-border bg-secondary/30 flex items-center justify-between">
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export default function CollegePredictorPage() {
|
|||||||
const maxRank = Math.max(...CUTOFF_TRENDS.map(d => d.rank))
|
const maxRank = Math.max(...CUTOFF_TRENDS.map(d => d.rank))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-6 md:p-8 space-y-8 max-w-7xl mx-auto animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500 min-h-screen">
|
<div className="p-6 md:p-8 space-y-8 animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500 max-w-7xl mx-auto min-h-screen">
|
||||||
{/* Page Header */}
|
{/* Page Header */}
|
||||||
<div className="border-b border-border/50 pb-6">
|
<div className="border-b border-border/50 pb-6">
|
||||||
<div className="flex items-start justify-between gap-4 flex-wrap">
|
<div className="flex items-start justify-between gap-4 flex-wrap">
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ export default function HeatmapPage() {
|
|||||||
const criticalTopics = isDemo ? DEMO_CRITICAL_TOPICS : []
|
const criticalTopics = isDemo ? DEMO_CRITICAL_TOPICS : []
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-6 md:p-8 max-w-7xl mx-auto space-y-8 animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500 min-h-screen">
|
<div className="p-6 md:p-8 max-w-7xl mx-auto space-y-8 min-h-screen">
|
||||||
{/* Page Header */}
|
{/* Page Header */}
|
||||||
<div className="border-b border-border/50 pb-6">
|
<div className="border-b border-border/50 pb-6">
|
||||||
<div className="flex items-start justify-between gap-4 flex-wrap">
|
<div className="flex items-start justify-between gap-4 flex-wrap">
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ export default function AICoachDashboard() {
|
|||||||
|
|
||||||
if (!hasAccessTo("ai-mistake-tracking")) {
|
if (!hasAccessTo("ai-mistake-tracking")) {
|
||||||
return (
|
return (
|
||||||
<div className="max-w-3xl mx-auto text-center py-20 px-8 space-y-8 animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500">
|
<div className="max-w-3xl mx-auto text-center py-20 px-8 space-y-8">
|
||||||
<div className="size-20 rounded-full bg-[var(--cyan-ai-10)] flex items-center justify-center mx-auto text-[var(--cyan-ai)] border border-[var(--cyan-ai-20)] shadow-[0_0_20px_rgba(12,96,96,0.1)]">
|
<div className="size-20 rounded-full bg-[var(--cyan-ai-10)] flex items-center justify-center mx-auto text-[var(--cyan-ai)] border border-[var(--cyan-ai-20)] shadow-[0_0_20px_rgba(12,96,96,0.1)]">
|
||||||
<BrainCircuit size={40} />
|
<BrainCircuit size={40} />
|
||||||
</div>
|
</div>
|
||||||
@@ -89,7 +89,7 @@ export default function AICoachDashboard() {
|
|||||||
const currentStreakDays = `${user?.streak_count || (isDemo ? 12 : 1)} d`
|
const currentStreakDays = `${user?.streak_count || (isDemo ? 12 : 1)} d`
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-6 max-w-6xl mx-auto space-y-8 animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500">
|
<div className="p-6 max-w-6xl mx-auto space-y-8">
|
||||||
|
|
||||||
{/* ── METRICS BAR ── */}
|
{/* ── METRICS BAR ── */}
|
||||||
<div className="flex flex-wrap items-center justify-end gap-2 pt-2">
|
<div className="flex flex-wrap items-center justify-end gap-2 pt-2">
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export default function ReadinessPage() {
|
|||||||
const maxScore = Math.max(1, ...scoreHistory.map(d => d.score))
|
const maxScore = Math.max(1, ...scoreHistory.map(d => d.score))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-6 md:p-8 space-y-8 max-w-7xl mx-auto animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500 min-h-screen">
|
<div className="p-6 md:p-8 space-y-8 animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500 max-w-7xl mx-auto min-h-screen">
|
||||||
{/* Page Header */}
|
{/* Page Header */}
|
||||||
<div className="border-b border-border/50 pb-6">
|
<div className="border-b border-border/50 pb-6">
|
||||||
<div className="flex items-start justify-between gap-4 flex-wrap">
|
<div className="flex items-start justify-between gap-4 flex-wrap">
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export default function StrategyPage() {
|
|||||||
const negMarkingData = isDemo ? DEMO_NEG_MARKING_DATA : ZERO_NEG_MARKING_DATA
|
const negMarkingData = isDemo ? DEMO_NEG_MARKING_DATA : ZERO_NEG_MARKING_DATA
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-6 md:p-8 space-y-8 max-w-7xl mx-auto animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500 min-h-screen">
|
<div className="p-6 md:p-8 space-y-8 animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500 max-w-7xl mx-auto min-h-screen">
|
||||||
{/* Page Header */}
|
{/* Page Header */}
|
||||||
<div className="border-b border-border/50 pb-6">
|
<div className="border-b border-border/50 pb-6">
|
||||||
<div className="flex items-start justify-between gap-4 flex-wrap">
|
<div className="flex items-start justify-between gap-4 flex-wrap">
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export default function StudyPlanPage() {
|
|||||||
const streakCount = user?.streak_count || (isDemo ? 12 : 1)
|
const streakCount = user?.streak_count || (isDemo ? 12 : 1)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-6 md:p-8 space-y-8 max-w-7xl mx-auto animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500 min-h-screen">
|
<div className="p-6 md:p-8 space-y-8 animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500 max-w-7xl mx-auto min-h-screen">
|
||||||
{/* Page Header */}
|
{/* Page Header */}
|
||||||
<div className="border-b border-border/50 pb-6">
|
<div className="border-b border-border/50 pb-6">
|
||||||
<div className="flex items-start justify-between gap-4 flex-wrap">
|
<div className="flex items-start justify-between gap-4 flex-wrap">
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export default function TimeOptimizationPage() {
|
|||||||
]
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-6 md:p-8 max-w-7xl mx-auto space-y-8 animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500 min-h-screen">
|
<div className="p-6 md:p-8 max-w-7xl mx-auto space-y-8 min-h-screen">
|
||||||
{/* Page Header */}
|
{/* Page Header */}
|
||||||
<div className="border-b border-border/50 pb-6">
|
<div className="border-b border-border/50 pb-6">
|
||||||
<div className="flex items-start justify-between gap-4 flex-wrap">
|
<div className="flex items-start justify-between gap-4 flex-wrap">
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const CAPABILITIES = [
|
|||||||
|
|
||||||
export default function TutorChatPage() {
|
export default function TutorChatPage() {
|
||||||
return (
|
return (
|
||||||
<div className="p-6 md:p-8 space-y-6 max-w-7xl mx-auto animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500 min-h-screen">
|
<div className="p-6 md:p-8 space-y-6 animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500 max-w-7xl mx-auto min-h-screen">
|
||||||
{/* Page Header */}
|
{/* Page Header */}
|
||||||
<div className="border-b border-border/50 pb-6">
|
<div className="border-b border-border/50 pb-6">
|
||||||
<div className="flex items-start justify-between gap-4 flex-wrap">
|
<div className="flex items-start justify-between gap-4 flex-wrap">
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export default function WeeklyProgressPage() {
|
|||||||
const syllabusProgress = isDemo ? DEMO_SYLLABUS_PROGRESS : ZERO_SYLLABUS_PROGRESS
|
const syllabusProgress = isDemo ? DEMO_SYLLABUS_PROGRESS : ZERO_SYLLABUS_PROGRESS
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-6 md:p-8 max-w-7xl mx-auto space-y-8 animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500 min-h-screen">
|
<div className="p-6 md:p-8 max-w-7xl mx-auto space-y-8 min-h-screen">
|
||||||
{/* Page Header */}
|
{/* Page Header */}
|
||||||
<div className="border-b border-border/50 pb-6">
|
<div className="border-b border-border/50 pb-6">
|
||||||
<div className="flex items-start justify-between gap-4 flex-wrap">
|
<div className="flex items-start justify-between gap-4 flex-wrap">
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ export default function AttemptHistoryPage({ params }: { params: Promise<{ attem
|
|||||||
const maxScore = attempt.total_questions * 4;
|
const maxScore = attempt.total_questions * 4;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-6xl mx-auto p-8 animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500">
|
<div className="max-w-6xl mx-auto p-8">
|
||||||
<Link href={backRoute} className="inline-flex items-center text-sm text-muted-foreground hover:text-foreground mb-6 transition-colors">
|
<Link href={backRoute} className="inline-flex items-center text-sm text-muted-foreground hover:text-foreground mb-6 transition-colors">
|
||||||
<ArrowLeft size={16} className="mr-2" /> {test?.type === 'DPS' ? 'Back to PrepPilot AI' : 'Back to Tests'}
|
<ArrowLeft size={16} className="mr-2" /> {test?.type === 'DPS' ? 'Back to PrepPilot AI' : 'Back to Tests'}
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -337,7 +337,7 @@ export default function CBTPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{showUpgradeModal && (
|
{showUpgradeModal && (
|
||||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-sm animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500">
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/80 backdrop-blur-sm">
|
||||||
<div className="bg-background border border-border shadow-2xl rounded-2xl w-[450px] p-8 text-center space-y-6 animate-in zoom-in-95 duration-200">
|
<div className="bg-background border border-border shadow-2xl rounded-2xl w-[450px] p-8 text-center space-y-6 animate-in zoom-in-95 duration-200">
|
||||||
<div className="size-16 rounded-full bg-red-500/10 flex items-center justify-center mx-auto text-red-500">
|
<div className="size-16 rounded-full bg-red-500/10 flex items-center justify-center mx-auto text-red-500">
|
||||||
<Lock size={32} />
|
<Lock size={32} />
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ export default function CommunityPage() {
|
|||||||
|
|
||||||
if (!hasAccessTo("doubt-resolution-community")) {
|
if (!hasAccessTo("doubt-resolution-community")) {
|
||||||
return (
|
return (
|
||||||
<div className="p-8 h-full flex flex-col items-center justify-center text-center animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500 max-w-2xl mx-auto">
|
<div className="p-8 h-full flex flex-col items-center justify-center text-center max-w-2xl mx-auto">
|
||||||
<div className="size-20 rounded-full bg-red-500/10 flex items-center justify-center mx-auto text-red-500 mb-6">
|
<div className="size-20 rounded-full bg-red-500/10 flex items-center justify-center mx-auto text-red-500 mb-6">
|
||||||
<Lock size={40} />
|
<Lock size={40} />
|
||||||
</div>
|
</div>
|
||||||
@@ -214,7 +214,7 @@ export default function CommunityPage() {
|
|||||||
|
|
||||||
{/* Expanded Replies Section */}
|
{/* Expanded Replies Section */}
|
||||||
{expandedDoubtId === doubt.id && (
|
{expandedDoubtId === doubt.id && (
|
||||||
<div className="mt-6 pt-4 border-t border-border space-y-4 animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500">
|
<div className="mt-6 pt-4 border-t border-border space-y-4">
|
||||||
<div className="flex gap-3">
|
<div className="flex gap-3">
|
||||||
<div className="h-8 w-8 shrink-0 rounded-full bg-[var(--cyan-ai-10)] text-[var(--cyan-ai)] flex items-center justify-center text-xs font-bold border border-[var(--cyan-ai-30)]">
|
<div className="h-8 w-8 shrink-0 rounded-full bg-[var(--cyan-ai-10)] text-[var(--cyan-ai)] flex items-center justify-center text-xs font-bold border border-[var(--cyan-ai-30)]">
|
||||||
AI
|
AI
|
||||||
@@ -262,7 +262,7 @@ export default function CommunityPage() {
|
|||||||
</div>
|
</div>
|
||||||
{/* Ask Doubt Modal */}
|
{/* Ask Doubt Modal */}
|
||||||
{isAskModalOpen && (
|
{isAskModalOpen && (
|
||||||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-background/80 backdrop-blur-sm animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500">
|
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-background/80 backdrop-blur-sm">
|
||||||
<div className="bg-background border border-border w-full max-w-2xl rounded-2xl shadow-2xl overflow-hidden animate-in zoom-in-95 duration-200">
|
<div className="bg-background border border-border w-full max-w-2xl rounded-2xl shadow-2xl overflow-hidden animate-in zoom-in-95 duration-200">
|
||||||
<div className="flex justify-between items-center p-6 border-b border-border bg-secondary/30">
|
<div className="flex justify-between items-center p-6 border-b border-border bg-secondary/30">
|
||||||
<h2 className="text-2xl font-bold flex items-center gap-2">
|
<h2 className="text-2xl font-bold flex items-center gap-2">
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ export default function DPPPage() {
|
|||||||
|
|
||||||
{/* ── PROTECTED PDF READER MODAL (FREE TIER) ── */}
|
{/* ── PROTECTED PDF READER MODAL (FREE TIER) ── */}
|
||||||
{selectedPdfDpp && (
|
{selectedPdfDpp && (
|
||||||
<div className={`fixed inset-0 z-50 bg-black/90 backdrop-blur-md flex items-center justify-center ${isFullScreen ? 'p-0' : 'p-4'} animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500`}>
|
<div className={`fixed inset-0 z-50 bg-black/90 backdrop-blur-md flex items-center justify-center ${isFullScreen ? 'p-0' : 'p-4'}`}>
|
||||||
<div className={`bg-background border border-border ${isFullScreen ? 'w-screen h-screen max-w-none max-h-none rounded-none border-0' : 'rounded-3xl w-full max-w-7xl max-h-[95vh]'} flex flex-col overflow-hidden shadow-2xl transition-all duration-300`}>
|
<div className={`bg-background border border-border ${isFullScreen ? 'w-screen h-screen max-w-none max-h-none rounded-none border-0' : 'rounded-3xl w-full max-w-7xl max-h-[95vh]'} flex flex-col overflow-hidden shadow-2xl transition-all duration-300`}>
|
||||||
{/* Modal Header */}
|
{/* Modal Header */}
|
||||||
<div className="p-4 md:p-5 border-b border-border bg-secondary/30 flex items-center justify-between">
|
<div className="p-4 md:p-5 border-b border-border bg-secondary/30 flex items-center justify-between">
|
||||||
|
|||||||
@@ -428,7 +428,7 @@ export default function DashboardLayout({ children }: { children: ReactNode }) {
|
|||||||
|
|
||||||
{/* Scrollable page body */}
|
{/* Scrollable page body */}
|
||||||
<main className="flex-1 overflow-y-auto relative bg-background/50">
|
<main className="flex-1 overflow-y-auto relative bg-background/50">
|
||||||
<div key={pathname} className="w-full h-full">
|
<div key={pathname} className="w-full h-full animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500">
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ export default function MaterialsPage() {
|
|||||||
|
|
||||||
{/* ── PROTECTED STUDY MATERIAL PDF READER MODAL ── */}
|
{/* ── PROTECTED STUDY MATERIAL PDF READER MODAL ── */}
|
||||||
{selectedPdf && (
|
{selectedPdf && (
|
||||||
<div className={`fixed inset-0 z-50 bg-black/90 backdrop-blur-md flex items-center justify-center ${isFullScreen ? 'p-0' : 'p-4'} animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500`}>
|
<div className={`fixed inset-0 z-50 bg-black/90 backdrop-blur-md flex items-center justify-center ${isFullScreen ? 'p-0' : 'p-4'}`}>
|
||||||
<div className={`bg-background border border-border ${isFullScreen ? 'w-screen h-screen max-w-none max-h-none rounded-none border-0' : 'rounded-3xl w-full max-w-7xl max-h-[95vh]'} flex flex-col overflow-hidden shadow-2xl transition-all duration-300`}>
|
<div className={`bg-background border border-border ${isFullScreen ? 'w-screen h-screen max-w-none max-h-none rounded-none border-0' : 'rounded-3xl w-full max-w-7xl max-h-[95vh]'} flex flex-col overflow-hidden shadow-2xl transition-all duration-300`}>
|
||||||
{/* Modal Header */}
|
{/* Modal Header */}
|
||||||
<div className="p-4 md:p-5 border-b border-border bg-secondary/30 flex items-center justify-between">
|
<div className="p-4 md:p-5 border-b border-border bg-secondary/30 flex items-center justify-between">
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ export default function DashboardPage() {
|
|||||||
const isNeet = user?.target_exam === "NEET"
|
const isNeet = user?.target_exam === "NEET"
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-8 max-w-7xl mx-auto space-y-10 animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500 slide-in-from-bottom-4">
|
<div className="p-8 max-w-7xl mx-auto space-y-10 animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500">
|
||||||
|
|
||||||
{/* Basic Performance Dashboard (F-05) */}
|
{/* Basic Performance Dashboard (F-05) */}
|
||||||
<section>
|
<section>
|
||||||
@@ -134,7 +134,7 @@ export default function DashboardPage() {
|
|||||||
{downloading ? 'Generating...' : 'Share Card'}
|
{downloading ? 'Generating...' : 'Share Card'}
|
||||||
</Button>
|
</Button>
|
||||||
{shareMenuOpen && (
|
{shareMenuOpen && (
|
||||||
<div className="absolute right-0 top-full mt-2 w-48 bg-white dark:bg-zinc-950 border border-border rounded-xl shadow-xl z-50 overflow-hidden animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-500">
|
<div className="absolute right-0 top-full mt-2 w-48 bg-white dark:bg-zinc-950 border border-border rounded-xl shadow-xl z-50 overflow-hidden">
|
||||||
<button onClick={handleShareFacebook} className="flex items-center w-full px-4 py-3 text-sm hover:bg-secondary text-left transition-colors">
|
<button onClick={handleShareFacebook} className="flex items-center w-full px-4 py-3 text-sm hover:bg-secondary text-left transition-colors">
|
||||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="mr-3 text-blue-600"><path d="M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z"></path></svg>
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="mr-3 text-blue-600"><path d="M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z"></path></svg>
|
||||||
Share on Facebook
|
Share on Facebook
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export function PremiumGate({ featureKey, children }: PremiumGateProps) {
|
|||||||
<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="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="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">
|
<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">
|
||||||
<Lock className="text-[var(--cyan-ai)] w-8 h-8" />
|
<Lock className="text-[var(--cyan-ai)] w-8 h-8" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user