Implement active user tiers, class-based Tailwind theme switcher, 3-tiled static dashboard layout, Minio object storage integration, school & state settings database sync, and streak wishes onboarding modal

This commit is contained in:
2026-07-07 13:43:30 +05:30
parent 426b98ddab
commit 04db17ea0e
24 changed files with 913 additions and 236 deletions

118
src/hooks/useActiveUser.ts Normal file
View File

@@ -0,0 +1,118 @@
"use client";
import { useEffect, useState, useCallback } from "react";
export interface UserProfile {
id: string;
name: string;
email: string | null;
phone: string | null;
class: string;
target_exam: "JEE_Main" | "JEE_Advanced" | "NEET";
medium: "English" | "Hindi" | "Bilingual";
school: string | null;
city: string;
state: string;
tier: "Free" | "Pro" | "Al_Coach"; // Al_Coach in database schema
streak_count: number;
longest_streak: number;
}
export const DEFAULT_USER_ID = "b0e17378-864d-439e-8806-708dc48a891b"; // AI Coach
export const DEMO_USERS = {
FREE: { id: "11111111-1111-1111-1111-111111111111", label: "Amit Kumar (Free Tier)" },
PRO: { id: "22222222-2222-2222-2222-222222222222", label: "Priya Singh (Pro Tier)" },
AI_COACH: { id: DEFAULT_USER_ID, label: "Rahul Sharma (AI Coach)" }
};
export function useActiveUser() {
const [userId, setUserIdState] = useState<string>(() => {
if (typeof window !== "undefined") {
return localStorage.getItem("activeUserId") || DEFAULT_USER_ID;
}
return DEFAULT_USER_ID;
});
const [user, setUser] = useState<UserProfile | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const fetchUserProfile = useCallback(async (id: string) => {
setLoading(true);
setError(null);
try {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) {
throw new Error("Failed to fetch user profile");
}
const data = await res.json();
setUser(data);
} catch (err: any) {
console.error("Error fetching active user profile:", err);
setError(err.message || "Failed to load user");
} finally {
setLoading(false);
}
}, []);
useEffect(() => {
if (typeof window !== "undefined") {
const storedId = localStorage.getItem("activeUserId") || DEFAULT_USER_ID;
setUserIdState(storedId);
fetchUserProfile(storedId);
}
}, [fetchUserProfile]);
const switchUser = useCallback((newId: string) => {
if (typeof window !== "undefined") {
localStorage.setItem("activeUserId", newId);
setUserIdState(newId);
window.location.reload();
}
}, []);
const hasAccessTo = useCallback((feature: string): boolean => {
if (!user) return false;
const tier = user.tier;
// Core restrictions mapping based on PRD feature matrix
switch (feature) {
case "topic-wise-microtests-unlimited":
case "weekly-test-series":
case "full-length-mock-tests":
case "previous-year-papers":
case "detailed-performance-analytics":
case "chapter-wise-progress-tracking":
case "doubt-resolution-community":
case "parent-dashboard":
case "offline-mode":
case "pdf-export":
return tier === "Pro" || tier === "Al_Coach";
case "ai-mistake-tracking":
case "spaced-repetition":
case "personalized-study-plan":
case "ai-tutor-chat":
case "exam-readiness-score":
case "exam-day-strategy":
case "college-predictor":
case "study-time-optimization":
return tier === "Al_Coach";
default:
// Free tier features: DPS (1/day), basic dashboard, basic streak tracking, leaderboard
return true;
}
}, [user]);
return {
userId,
user,
loading,
error,
switchUser,
hasAccessTo,
refreshUser: () => fetchUserProfile(userId)
};
}