From 46b44b5a14033026e1d5558f2f1db041b48c42f0 Mon Sep 17 00:00:00 2001 From: ectasy663 Date: Fri, 25 Sep 2026 12:53:38 +0530 Subject: [PATCH] Fix backend bulk delete, separate password page, remove admin dummy data, swap dashboard rows --- backend/main.py | 2 +- src/app/admin/page.tsx | 160 ++---------------- src/app/dashboard/layout.tsx | 4 +- src/app/dashboard/page.tsx | 18 +- src/app/dashboard/settings/page.tsx | 91 +--------- src/app/dashboard/settings/password/page.tsx | 115 +++++++++++++ .../Dashboard/BulkUserPasswordModal.tsx | 129 -------------- 7 files changed, 146 insertions(+), 373 deletions(-) create mode 100644 src/app/dashboard/settings/password/page.tsx delete mode 100644 src/components/Dashboard/BulkUserPasswordModal.tsx diff --git a/backend/main.py b/backend/main.py index 1a0b16a..327b54f 100644 --- a/backend/main.py +++ b/backend/main.py @@ -298,8 +298,8 @@ def bulk_delete_students(payload: DeleteUsersRequest, session: Session = Depends user = session.get(models.User, uid) if user: # Delete associated records manually since foreign key cascade might not be configured in sqlmodel by default - session.exec(delete(models.Attempt).where(models.Attempt.user_id == uid)) session.exec(delete(models.Mistake).where(models.Mistake.user_id == uid)) + session.exec(delete(models.Attempt).where(models.Attempt.user_id == uid)) session.exec(delete(models.Transaction).where(models.Transaction.user_id == uid)) session.exec(delete(models.Subscription).where(models.Subscription.user_id == uid)) session.exec(delete(models.StudyPlan).where(models.StudyPlan.user_id == uid)) diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 0bcefe6..a1dc207 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -1,20 +1,8 @@ -"use client" +"use client" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" -import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Terminal, Users, Database, Activity, RefreshCw } from "lucide-react" -import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, AreaChart, Area } from 'recharts' - -const data = [ - { name: 'Mon', accuracy: 88, tokens: 1.2 }, - { name: 'Tue', accuracy: 90, tokens: 1.5 }, - { name: 'Wed', accuracy: 89, tokens: 1.8 }, - { name: 'Thu', accuracy: 92, tokens: 2.1 }, - { name: 'Fri', accuracy: 95, tokens: 2.4 }, - { name: 'Sat', accuracy: 94, tokens: 2.2 }, - { name: 'Sun', accuracy: 96, tokens: 2.8 }, -]; export default function AdminDashboard() { return ( @@ -22,14 +10,14 @@ export default function AdminDashboard() {

Command Center

-

Real-time system monitoring and agent status.

+

Real-time system monitoring and management.

- {/* KPI Stats */} + {/* KPI Stats Placeholder */}
@@ -37,8 +25,8 @@ export default function AdminDashboard() {
-
₹12.4M
-

+14.2% from last month

+
--
+

No live data available

@@ -47,18 +35,18 @@ export default function AdminDashboard() {
-
45,231
-

+2,401 this week

+
--
+

Manage from Students tab

- AI Agent Accuracy + System Status
-
96.4%
-

Based on 1.2M interactions

+
Online
+

All services operational

@@ -67,134 +55,16 @@ export default function AdminDashboard() {
-
142k
-

1.2k added today

+
--
+

Manage from Tests tab

-
- {/* Charts */} - - - AI Token Usage vs Accuracy - - - - - - - - - - - - - `${value}M`} /> - - - - - - - - {/* Live Agent Status */} - - - Live Agent Status - - -
-
-
- - -
-
-

DPP Generator

-

Latency: 142ms

-
-
- Healthy -
- -
-
-
- - -
-
-

Tutor Agent

-

Latency: 840ms

-
-
- Healthy -
- -
-
-
- -
-
-

Evaluator Node

-

Latency: 2100ms

-
-
- Degraded -
-
-
+
+

Welcome to the Admin Portal

+

Use the sidebar to navigate to Students, Tests, Questions, and System Settings. Live analytics charts will be available here in the future.

- - {/* Question Bank Manager Preview */} - - -
- Recent Question Uploads -
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
IDSubjectTopicPreviewActions
#Q-8942PhysicsThermodynamicsAn ideal gas undergoes an isothermal expansion... - -
#Q-8941MathCalculusEvaluate the integral of e^x sin(x) dx... - -
-
-
-
) } diff --git a/src/app/dashboard/layout.tsx b/src/app/dashboard/layout.tsx index dc40dc6..71262e2 100644 --- a/src/app/dashboard/layout.tsx +++ b/src/app/dashboard/layout.tsx @@ -12,7 +12,6 @@ import { StreakCounter } from "@/components/StreakCounter" import { AITutorChat } from "@/components/AI/AITutorChat" import { useActiveUser, DEMO_USERS, isDemoUser } from "@/hooks/useActiveUser" import { StreakOnboardingModal } from "@/components/Dashboard/StreakOnboardingModal" -import { BulkUserPasswordModal } from "@/components/Dashboard/BulkUserPasswordModal" import { Badge } from "@/components/ui/badge" import MaintenanceScreen from "@/components/MaintenanceScreen" @@ -320,6 +319,9 @@ export default function DashboardLayout({ children }: { children: ReactNode }) { Edit Profile + + Change Password + {isDemoUser(userId) && ( */} - - - Change Password - Update your account password - - -
-
- - setCurrentPassword(e.target.value)} - className="w-full bg-secondary/50 border border-border rounded-lg px-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--cyan-ai)]" - placeholder="Enter current password" - /> -
-
-
- - setNewPassword(e.target.value)} - className="w-full bg-secondary/50 border border-border rounded-lg px-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--cyan-ai)]" - placeholder="Enter new password" - /> -
-
- - setConfirmPassword(e.target.value)} - className="w-full bg-secondary/50 border border-border rounded-lg px-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--cyan-ai)]" - placeholder="Confirm new password" - /> -
-
-
- -
-
-
+ diff --git a/src/app/dashboard/settings/password/page.tsx b/src/app/dashboard/settings/password/page.tsx new file mode 100644 index 0000000..cdeea22 --- /dev/null +++ b/src/app/dashboard/settings/password/page.tsx @@ -0,0 +1,115 @@ +"use client"; + +import { fetchWithAuth } from "@/lib/apiClient"; +import { useState } from "react"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Lock } from "lucide-react"; + +export default function PasswordPage() { + const [currentPassword, setCurrentPassword] = useState(""); + const [newPassword, setNewPassword] = useState(""); + const [confirmPassword, setConfirmPassword] = useState(""); + const [passwordSaving, setPasswordSaving] = useState(false); + + const handleChangePassword = async () => { + if (newPassword !== confirmPassword) { + alert("New passwords do not match."); + return; + } + setPasswordSaving(true); + try { + const res = await fetchWithAuth("/api/auth/change-password", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + current_password: currentPassword, + new_password: newPassword, + }), + }); + const data = await res.json(); + if (res.ok) { + alert(data.message || "Password updated successfully!"); + setCurrentPassword(""); + setNewPassword(""); + setConfirmPassword(""); + } else { + alert("Failed to change password: " + (data.detail || "Unknown error")); + } + } catch (err) { + console.error(err); + alert("Network error. Could not change password."); + } finally { + setPasswordSaving(false); + } + }; + + return ( +
+
+
+

+ + + + Change Password +

+

+ Update your account password securely. +

+
+
+ + + + Change Password + Update your account password + + +
+
+ + setCurrentPassword(e.target.value)} + className="w-full bg-secondary/50 border border-border rounded-lg px-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--cyan-ai)]" + placeholder="Enter current password" + /> +
+
+
+ + setNewPassword(e.target.value)} + className="w-full bg-secondary/50 border border-border rounded-lg px-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--cyan-ai)]" + placeholder="Enter new password" + /> +
+
+ + setConfirmPassword(e.target.value)} + className="w-full bg-secondary/50 border border-border rounded-lg px-4 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--cyan-ai)]" + placeholder="Confirm new password" + /> +
+
+
+ +
+
+
+
+ ); +} diff --git a/src/components/Dashboard/BulkUserPasswordModal.tsx b/src/components/Dashboard/BulkUserPasswordModal.tsx deleted file mode 100644 index 659e0c5..0000000 --- a/src/components/Dashboard/BulkUserPasswordModal.tsx +++ /dev/null @@ -1,129 +0,0 @@ -"use client"; - -import { useState } from "react"; -import { Lock, Eye, EyeOff } from "lucide-react"; -import { fetchWithAuth } from "@/lib/apiClient"; -import { Button } from "@/components/ui/button"; - -interface BulkUserPasswordModalProps { - isOpen: boolean; - onSuccess: () => void; -} - -export function BulkUserPasswordModal({ isOpen, onSuccess }: BulkUserPasswordModalProps) { - const [currentPassword, setCurrentPassword] = useState(""); - const [newPassword, setNewPassword] = useState(""); - const [confirmPassword, setConfirmPassword] = useState(""); - const [showCurrent, setShowCurrent] = useState(false); - const [showNew, setShowNew] = useState(false); - const [showConfirm, setShowConfirm] = useState(false); - const [saving, setSaving] = useState(false); - const [error, setError] = useState(""); - - if (!isOpen) return null; - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - if (newPassword !== confirmPassword) { - setError("New passwords do not match."); - return; - } - - setSaving(true); - setError(""); - try { - const res = await fetchWithAuth("/api/auth/change-password", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - current_password: currentPassword, - new_password: newPassword, - }), - }); - const data = await res.json(); - if (res.ok) { - onSuccess(); - } else { - setError("Failed: " + (data.detail || "Unknown error")); - } - } catch (err) { - setError("Network error. Could not update password."); - } finally { - setSaving(false); - } - }; - - return ( -
-
-
-
- -
-

Set Your Password

-

- Welcome! Since your account was created by the admin, please set a new personal password to continue. -

-
- - {error &&

{error}

} - -
-
- -
- setCurrentPassword(e.target.value)} - className="w-full bg-secondary/50 border border-border rounded-lg px-4 py-2 pr-10 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--cyan-ai)]" - required - /> - -
-
- -
- -
- setNewPassword(e.target.value)} - className="w-full bg-secondary/50 border border-border rounded-lg px-4 py-2 pr-10 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--cyan-ai)]" - required - minLength={8} - /> - -
-
- -
- -
- setConfirmPassword(e.target.value)} - className="w-full bg-secondary/50 border border-border rounded-lg px-4 py-2 pr-10 text-sm focus:outline-none focus:ring-2 focus:ring-[var(--cyan-ai)]" - required - minLength={8} - /> - -
-
- - -
-
-
- ); -}