feat: Add JWT authentication to backend, configure frontend API client, fix streak layout

This commit is contained in:
2026-09-23 12:11:44 +05:30
parent ea03846b9c
commit a3e430cb67
27 changed files with 210 additions and 120 deletions

View File

@@ -1,5 +1,6 @@
"use client"
import { fetchWithAuth } from "@/lib/apiClient";
import { Button } from "@/components/ui/button"
import { Card, CardContent } from "@/components/ui/card"
import { BrainCircuit, Play, CheckCircle2, Download, Filter, Lock, FileText, Eye, ShieldAlert, X, Sparkles, Share2, Maximize2, Minimize2 } from "lucide-react"
@@ -25,14 +26,14 @@ export default function AIDailyPracticePage() {
try {
const pattern = user.target_exam || "JEE_Main";
// Also fetch from the correct Next.js proxied route instead of localhost:8000
const res = await fetch(`/api/tests?type=DPS&exam_pattern=${pattern}`);
const res = await fetchWithAuth(`/api/tests?type=DPS&exam_pattern=${pattern}`);
if (res.ok) {
const data = await res.json()
setDpps(data)
}
if (userId) {
const attemptsRes = await fetch(`/api/users/${userId}/attempts`);
const attemptsRes = await fetchWithAuth(`/api/users/${userId}/attempts`);
if (attemptsRes.ok) {
const attemptsData = await attemptsRes.json();
setAttempts(attemptsData);

View File

@@ -1,5 +1,6 @@
"use client";
import { fetchWithAuth } from "@/lib/apiClient";
import { useEffect, useState } from "react"
import { MistakeHeatmap } from "@/components/AI/MistakeHeatmap"
import { StudyPlanCard } from "@/components/AI/StudyPlanCard"
@@ -39,7 +40,7 @@ export default function AICoachDashboard() {
useEffect(() => {
if (!userLoading && userId) {
fetch(`/api/users/${userId}/stats`)
fetchWithAuth(`/api/users/${userId}/stats`)
.then(res => res.ok ? res.json() : null)
.then(data => setStats(data))
.catch(() => setStats(null))

View File

@@ -1,5 +1,6 @@
"use client";
import { fetchWithAuth } from "@/lib/apiClient";
import { useEffect, useState } from "react";
import Link from "next/link";
import { Button } from "@/components/ui/button";
@@ -37,7 +38,7 @@ export default function CBTPage() {
async function loadUser() {
try {
const userRes = await fetch(`/api/users/${userId}`);
const userRes = await fetchWithAuth(`/api/users/${userId}`);
if (!userRes.ok) throw new Error("Failed to load user target exam");
const userData = await userRes.json();
const pattern = userData.target_exam;
@@ -75,7 +76,7 @@ export default function CBTPage() {
setExams(testsData);
}
const attemptsRes = await fetch(`/api/users/${userId}/attempts`);
const attemptsRes = await fetchWithAuth(`/api/users/${userId}/attempts`);
if (attemptsRes.ok) {
const attemptsData = await attemptsRes.json();
setAttempts(attemptsData);

View File

@@ -1,5 +1,6 @@
"use client"
import { fetchWithAuth } from "@/lib/apiClient";
import { Button } from "@/components/ui/button"
import { Card, CardContent } from "@/components/ui/card"
import { BrainCircuit, Play, CheckCircle2, Download, Filter, Lock, FileText, Eye, ShieldAlert, X, Sparkles, Share2, Maximize2, Minimize2 } from "lucide-react"
@@ -25,14 +26,14 @@ export default function DPPPage() {
try {
const pattern = user.target_exam || "JEE_Main";
// Also fetch from the correct Next.js proxied route instead of localhost:8000
const res = await fetch(`/api/tests?type=DPS&exam_pattern=${pattern}`);
const res = await fetchWithAuth(`/api/tests?type=DPS&exam_pattern=${pattern}`);
if (res.ok) {
const data = await res.json()
setDpps(data)
}
if (userId) {
const attemptsRes = await fetch(`/api/users/${userId}/attempts`);
const attemptsRes = await fetchWithAuth(`/api/users/${userId}/attempts`);
if (attemptsRes.ok) {
const attemptsData = await attemptsRes.json();
setAttempts(attemptsData);

View File

@@ -335,7 +335,7 @@ export default function DashboardLayout({ children }: { children: ReactNode }) {
<button
type="button"
onClick={() => window.dispatchEvent(new CustomEvent("pragativeer-show-streak-animation"))}
className="hover:opacity-85 transition-opacity cursor-pointer border-none bg-transparent p-0"
className="flex items-center justify-center hover:opacity-85 transition-opacity cursor-pointer border-none bg-transparent p-0"
title="View Streak Celebration"
>
<StreakCounter streak={user.streak_count} />

View File

@@ -1,5 +1,6 @@
"use client"
import { fetchWithAuth } from "@/lib/apiClient";
import { useRef, useState, useEffect } from "react"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
@@ -26,7 +27,7 @@ export default function DashboardPage() {
}
async function fetchStats() {
try {
const res = await fetch(`/api/users/${currentUserId}/stats`)
const res = await fetchWithAuth(`/api/users/${currentUserId}/stats`)
if (res.ok) {
const data = await res.json()
setUserStats(data)

View File

@@ -1,5 +1,6 @@
"use client";
import { fetchWithAuth } from "@/lib/apiClient";
import { useEffect, useState } from "react";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
@@ -50,7 +51,7 @@ export default function SettingsPage() {
formData.append("file", file);
try {
const res = await fetch(`/api/users/${userId}/avatar`, {
const res = await fetchWithAuth(`/api/users/${userId}/avatar`, {
method: "POST",
body: formData,
});
@@ -72,7 +73,7 @@ export default function SettingsPage() {
if (!userId) return;
setSaving(true);
try {
const res = await fetch(`/api/users/${userId}`, {
const res = await fetchWithAuth(`/api/users/${userId}`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({

View File

@@ -1,5 +1,6 @@
"use client"
import { fetchWithAuth } from "@/lib/apiClient";
import { useState, useEffect } from "react"
import { Card, CardContent } from "@/components/ui/card"
import { Flame, Gift, Star, Trophy, Target, ArrowRight, CheckCircle2 } from "lucide-react"
@@ -20,7 +21,7 @@ export default function StreaksPage() {
}
async function loadStats() {
try {
const res = await fetch(`/api/users/${user?.id}/stats`)
const res = await fetchWithAuth(`/api/users/${user?.id}/stats`)
if (res.ok) {
const stats = await res.json()
if (!stats.is_new_user) {