chore(capacitor): refactor codebase for capacitor entry

This commit is contained in:
shafin-r
2025-09-08 13:42:15 +06:00
parent 3b2488054c
commit 99d6c15e38
21 changed files with 123 additions and 491 deletions

View File

@ -8,7 +8,6 @@ import BackgroundWrapper from "@/components/BackgroundWrapper";
import FormField from "@/components/FormField";
import { login } from "@/lib/auth";
import DestructibleAlert from "@/components/DestructibleAlert";
import { useAuth } from "@/context/AuthContext";
import { LoginForm } from "@/types/auth";
import { CircleAlert } from "lucide-react";
import { useAuthStore } from "@/stores/authStore";

View File

@ -6,7 +6,6 @@ import Link from "next/link";
import { useRouter } from "next/navigation";
import { register } from "@/lib/auth";
import { useAuth } from "@/context/AuthContext";
import BackgroundWrapper from "@/components/BackgroundWrapper";
import FormField from "@/components/FormField";
import DestructibleAlert from "@/components/DestructibleAlert";

View File

@ -2,16 +2,8 @@
import React, { useState, useEffect } from "react";
import BackgroundWrapper from "@/components/BackgroundWrapper";
import {
Bookmark,
BookmarkCheck,
Check,
ListFilter,
MoveLeft,
OctagonX,
} from "lucide-react";
import { Bookmark, BookmarkCheck, ListFilter, MoveLeft } from "lucide-react";
import { useRouter } from "next/navigation";
import DestructibleAlert from "@/components/DestructibleAlert";
interface Question {
id: number;

View File

@ -7,7 +7,6 @@ import DestructibleAlert from "@/components/DestructibleAlert";
import BackgroundWrapper from "@/components/BackgroundWrapper";
import { API_URL, getToken } from "@/lib/auth";
import { Loader, RefreshCw } from "lucide-react";
import { useAuth } from "@/context/AuthContext";
import { useAuthStore } from "@/stores/authStore";
type Mock = {
@ -74,7 +73,7 @@ export default function MockScreen() {
<Header displayTabTitle="Mocks" />
<div className="overflow-y-auto">
<div className="mt-5 px-5">
<DestructibleAlert text={errorMsg} extraStyles="" />
<DestructibleAlert text={errorMsg} />
</div>
<div className="flex justify-center mt-4">
<button

View File

@ -1,6 +1,5 @@
"use client";
import { useSearchParams } from "next/navigation";
import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import Header from "@/components/Header";
@ -8,8 +7,6 @@ import DestructibleAlert from "@/components/DestructibleAlert";
import BackgroundWrapper from "@/components/BackgroundWrapper";
import { API_URL, getToken } from "@/lib/auth";
import { Loader, RefreshCw } from "lucide-react";
import { useAuth } from "@/context/AuthContext";
import { Question } from "@/types/exam";
import { useAuthStore } from "@/stores/authStore";
type Subject = {

View File

@ -7,7 +7,6 @@ import DestructibleAlert from "@/components/DestructibleAlert";
import BackgroundWrapper from "@/components/BackgroundWrapper";
import { API_URL, getToken } from "@/lib/auth";
import { Loader, RefreshCw } from "lucide-react";
import { useAuth } from "@/context/AuthContext";
import { useAuthStore } from "@/stores/authStore";
type Topic = {

View File

@ -8,68 +8,41 @@ import SlidingGallery from "@/components/SlidingGallery";
import BackgroundWrapper from "@/components/BackgroundWrapper";
import { ChevronRight } from "lucide-react";
import styles from "@/css/Home.module.css";
import { API_URL } from "@/lib/auth";
import { Avatar } from "@/components/ui/avatar";
import { getLinkedViews } from "@/lib/gallery-views";
import { getTopThree } from "@/lib/leaderboard";
import DestructibleAlert from "@/components/DestructibleAlert";
import { GalleryViews } from "@/types/gallery";
interface LeaderboardEntry {
id: string;
name: string;
points: number;
}
import { useAuthStore } from "@/stores/authStore";
import DestructibleAlert from "@/components/DestructibleAlert";
const HomePage = () => {
const router = useRouter();
const [boardData, setBoardData] = useState<LeaderboardEntry[]>([]);
const [boardError, setBoardError] = useState<string | null>(null);
const [linkedViews, setLinkedViews] = useState<GalleryViews[]>();
const { user } = useAuthStore();
useEffect(() => {
// let isMounted = true;
// const fetchBoardData = async () => {
// try {
// const response = await fetch(`${API_URL}/leaderboard`);
// if (!response.ok) {
// throw new Error("Failed to fetch leaderboard data");
// }
// const data: LeaderboardEntry[] = await response.json();
// if (isMounted) setBoardData(data);
// } catch (err) {
// if (isMounted) {
// const message =
// err instanceof Error ? err.message : "An unexpected error occurred";
// setBoardError(message);
// }
// }
// };
const fetchedLinkedViews: GalleryViews[] = getLinkedViews();
setLinkedViews(fetchedLinkedViews);
// fetchBoardData();
// return () => {
// isMounted = false;
// };
}, []);
return (
<BackgroundWrapper>
<div className={styles.container}>
<div className="flex-1 min-h-screen">
<Header displayUser />
<div className={styles.scrollContainer}>
<div className={styles.contentWrapper}>
<div className="overflow-y-auto pt-4 h-[calc(100vh-80px)]">
<div className="pb-40 mx-6">
{!user?.is_verified && (
<DestructibleAlert
text="Please verify your account. Check your email for the verification link."
variant="warning"
/>
)}
<SlidingGallery views={linkedViews} height="23vh" />
<div className={styles.mainContent}>
<div className="flex flex-col gap-9">
{/* Categories Section */}
<div>
<div className={styles.sectionHeader}>
<h2 className={styles.sectionTitle}>Categories</h2>
<div className="flex item-scenter justify-between">
<h2 className="text-2xl font-bold text-[#113768]">
Categories
</h2>
<button
onClick={() => router.push("/categories")}
className={styles.arrowButton}

View File

@ -1,186 +1,9 @@
"use client";
import BackgroundWrapper from "@/components/BackgroundWrapper";
import Header from "@/components/Header";
import DestructibleAlert from "@/components/DestructibleAlert";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { API_URL, getToken } from "@/lib/auth";
import { BoardData, getLeaderboard } from "@/lib/leaderboard";
import { UserData } from "@/types/auth";
import React, { useEffect, useState } from "react";
import { useAuth } from "@/context/AuthContext";
import React from "react";
const LeaderboardPage = () => {
const [boardError, setBoardError] = useState<string | null>(null);
const [boardData, setBoardData] = useState<BoardData[]>([]);
const {user, isLoading} = useAuth()
const [loading, setLoading] = useState(true);
async function fetchBoardData() {
try {
const boardResponse = await fetch(`${API_URL}/leaderboard`, {
method: "GET",
});
if (!boardResponse.ok) {
throw new Error("Failed to fetch leaderboard data");
}
const fetchedBoardData = await boardResponse.json();
if (Array.isArray(fetchedBoardData) && fetchedBoardData.length > 0) {
setBoardData(fetchedBoardData);
} else {
setBoardError("No leaderboard data available.");
setBoardData([]);
}
} catch (error) {
console.error(error);
setBoardError("Something went wrong. Please try again.");
setBoardData([]);
}
}
fetchBoardData();
}
const getTopThree = (boardData: BoardData[]) => {
if (!boardData || !Array.isArray(boardData)) return [];
const sortedData = boardData
.filter((player) => player?.points !== undefined) // Ensure `points` exists
.sort((a, b) => b.points - a.points);
const topThree = sortedData.slice(0, 3).map((player, index) => ({
...player,
rank: index + 1,
height: index === 0 ? 280 : index === 1 ? 250 : 220,
}));
return [topThree[1], topThree[0], topThree[2]].filter(Boolean); // Handle missing players
};
const getUserData = (boardData: BoardData[], name: string) => {
if (!boardData || !Array.isArray(boardData)) return [];
const sortedData = boardData
.filter((player) => player?.name && player?.points !== undefined)
.sort((a, b) => b.points - a.points);
const result = sortedData.find((player) => player.name === name);
return result ? [{ ...result, rank: sortedData.indexOf(result) + 1 }] : [];
};
if (loading) {
return (
<BackgroundWrapper>
<section>
<Header displayTabTitle="Leaderboard" />
<section className="flex flex-col mx-10 pt-10 space-y-4">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-900 mb-4"></div>
<p className="text-lg font-medium text-gray-900">Loading...</p>
</section>
</section>
</BackgroundWrapper>
);
}
if (boardError) {
return (
<BackgroundWrapper>
<section>
<Header displayTabTitle="Leaderboard" />
<section className="flex flex-col mx-10 pt-10 space-y-4">
<DestructibleAlert text={boardError} />
</section>
</section>
</BackgroundWrapper>
);
}
return (
<BackgroundWrapper>
<section>
<Header displayTabTitle={"Leaderboard"} />
<section className="flex flex-col mx-10 pt-10 space-y-4">
<section className="flex justify-evenly items-end">
{getTopThree(boardData).map((student, idx) =>
student ? (
<div
key={idx}
className="w-[100px] flex flex-col bg-[#113768] rounded-t-xl items-center justify-start pt-4 space-y-3"
style={{ height: student.height }}
>
<h3 className="font-bold text-xl text-white">
{student.rank}
</h3>
<Avatar className="bg-slate-300 w-12 h-12">
<AvatarFallback className="text-xl font-semibold">
{student.name.charAt(0).toUpperCase()}
</AvatarFallback>
</Avatar>
<p className="font-bold text-md text-center text-white">
{student.name}
</p>
<p className="text-sm text-white">({student.points}pt)</p>
</div>
) : null
)}
</section>
<div className="w-full border-[0.5px] border-[#c5dbf8] bg-[#c5dbf8]"></div>
<section className="border-[1px] border-[#c0dafc] w-full rounded-3xl p-6 space-y-4 mb-20">
<section>
{getUserData(boardData, userData.name).map((user, idx) => (
<div
key={idx}
className="flex bg-[#113768] rounded-[8] py-2 px-4 justify-between items-center"
>
<div className=" flex gap-3 items-center">
<h2 className="font-medium text-sm text-white">
{user.rank}
</h2>
<Avatar className="bg-slate-300 w-6 h-6">
<AvatarFallback className="text-sm font-semibold">
{user.name.charAt(0).toUpperCase()}
</AvatarFallback>
</Avatar>
<h3 className="font-medium text-sm text-white">You</h3>
</div>
<p className="font-medium text-white/70 text-sm">
{user.points}pt
</p>
</div>
))}
</section>
<div className="w-full border-[0.5px] border-[#c5dbf8] bg-[#c5dbf8]"></div>
<section className="space-y-4">
{getLeaderboard(boardData)
.slice(0, 10)
.map((user, idx) => (
<div
key={idx}
className="flex border-2 border-[#c5dbf8] rounded-[8] py-2 px-4 justify-between items-center"
>
<div className="flex gap-3 items-center">
<h2 className="font-medium text-sm">{idx + 1}</h2>
<Avatar className="bg-slate-300 w-6 h-6">
<AvatarFallback className="text-sm font-semibold">
{user.name.charAt(0).toUpperCase()}
</AvatarFallback>
</Avatar>
<h3 className="font-medium text-sm">
{user.name.split(" ").slice(0, 2).join(" ")}
</h3>
</div>
<p className="font-medium text-[#000]/40 text-sm">
{user.points}pt
</p>
</div>
))}
</section>
</section>
</section>
</section>
</BackgroundWrapper>
);
return <></>;
};
export default LeaderboardPage;

View File

@ -2,7 +2,6 @@
import BackgroundWrapper from "@/components/BackgroundWrapper";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { useAuth } from "@/context/AuthContext";
import { useAuthStore } from "@/stores/authStore";
import {
Bookmark,

View File

@ -1,33 +1,22 @@
"use client";
import React, { useEffect, useCallback, useState } from "react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import React, { useEffect, useState } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import Header from "@/components/Header";
import QuestionItem from "@/components/QuestionItem";
import BackgroundWrapper from "@/components/BackgroundWrapper";
import { useExamStore } from "@/stores/examStore";
import { useTimerStore } from "@/stores/timerStore";
import { useExamExitGuard } from "@/hooks/useExamExitGuard";
export default function ExamPage() {
const router = useRouter();
const pathname = usePathname();
const searchParams = useSearchParams();
const test_id = searchParams.get("test_id") || "";
const type = searchParams.get("type") || "";
const {
setStatus,
test,
answers,
startExam,
setAnswer,
submitExam,
cancelExam,
status,
} = useExamStore();
const { setStatus, test, answers, startExam, setAnswer, submitExam } =
useExamStore();
const { resetTimer, stopTimer } = useTimerStore();
const { showExitDialog } = useExamExitGuard(type);
const [isSubmitting, setIsSubmitting] = useState(false);

View File

@ -126,7 +126,7 @@ function PretestPageContent() {
setStatus("in-progress");
router.push(
`/exam/${id}?type=${type}&test_id=${metadata?.test_id}&attempt_id=${metadata?.attempt_id}`
`/exam/exam-screen?type=${type}&test_id=${metadata?.test_id}&attempt_id=${metadata?.attempt_id}`
);
}
return (

View File

@ -1,8 +1,5 @@
"use client";
import { ExamProvider } from "@/context/ExamContext";
import { TimerProvider } from "@/context/TimerContext";
import { AuthProvider } from "@/context/AuthContext";
import { ModalProvider } from "@/context/ModalContext";
export function Providers({ children }: { children: React.ReactNode }) {