fix(ts): fix interfaces for type safety

This commit is contained in:
shafin-r
2025-07-27 13:41:02 +06:00
parent 3ef526ec1a
commit e091a78bdb
8 changed files with 54 additions and 31 deletions

View File

@ -7,7 +7,7 @@ import Header from "@/components/Header";
import SlidingGallery from "@/components/SlidingGallery"; import SlidingGallery from "@/components/SlidingGallery";
import BackgroundWrapper from "@/components/BackgroundWrapper"; import BackgroundWrapper from "@/components/BackgroundWrapper";
import DestructibleAlert from "@/components/DestructibleAlert"; import DestructibleAlert from "@/components/DestructibleAlert";
import { ChevronRight } from "lucide-react"; // Using Lucide React for icons import { ChevronRight } from "lucide-react";
import styles from "@/css/Home.module.css"; import styles from "@/css/Home.module.css";
import { API_URL } from "@/lib/auth"; import { API_URL } from "@/lib/auth";
import { Avatar } from "@/components/ui/avatar"; import { Avatar } from "@/components/ui/avatar";
@ -52,6 +52,7 @@ const page = () => {
} }
const fetchedLinkedViews = getLinkedViews(); const fetchedLinkedViews = getLinkedViews();
setLinkedViews(fetchedLinkedViews); setLinkedViews(fetchedLinkedViews);
fetchBoardData();
return () => { return () => {
isMounted = false; isMounted = false;

View File

@ -4,15 +4,22 @@ import BackgroundWrapper from "@/components/BackgroundWrapper";
import Header from "@/components/Header"; import Header from "@/components/Header";
import { Avatar, AvatarFallback } from "@/components/ui/avatar"; import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { API_URL, getToken } from "@/lib/auth"; import { API_URL, getToken } from "@/lib/auth";
import { BoardData, getLeaderboard, getUserData } from "@/lib/leaderboard"; import { BoardData, getLeaderboard } from "@/lib/leaderboard";
import { UserData } from "@/types/auth"; import { UserData } from "@/types/auth";
import Image from "next/image";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
const LeaderboardPage = () => { const LeaderboardPage = () => {
const [boardError, setBoardError] = useState<string | null>(null); const [boardError, setBoardError] = useState<string | null>(null);
const [boardData, setBoardData] = useState<BoardData[]>([]); const [boardData, setBoardData] = useState<BoardData[]>([]);
const [userData, setUserData] = useState<UserData>(); const [userData, setUserData] = useState<UserData>({
name: "",
institution: "",
sscRoll: "",
hscRoll: "",
email: "",
phone: "",
});
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
useEffect(() => { useEffect(() => {
@ -80,6 +87,16 @@ const LeaderboardPage = () => {
return [topThree[1], topThree[0], topThree[2]].filter(Boolean); // Handle missing players 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 }] : [];
};
return ( return (
<BackgroundWrapper> <BackgroundWrapper>
<section> <section>
@ -112,7 +129,7 @@ const LeaderboardPage = () => {
<div className="w-full border-[0.5px] border-[#c5dbf8] bg-[#c5dbf8]"></div> <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 className="border-[1px] border-[#c0dafc] w-full rounded-3xl p-6 space-y-4 mb-20">
<section> <section>
{getUserData(boardData, userData!.name).map((user, idx) => ( {getUserData(boardData, userData.name).map((user, idx) => (
<div <div
key={idx} key={idx}
className="flex bg-[#113768] rounded-[8] py-2 px-4 justify-between items-center" className="flex bg-[#113768] rounded-[8] py-2 px-4 justify-between items-center"

View File

@ -15,7 +15,6 @@ interface Mock {
rating: number; rating: number;
} }
// For App Router (Next.js 13+ with app directory)
export default function PaperScreen() { export default function PaperScreen() {
const router = useRouter(); const router = useRouter();
const searchParams = useSearchParams(); const searchParams = useSearchParams();
@ -58,13 +57,7 @@ export default function PaperScreen() {
return ( return (
<BackgroundWrapper> <BackgroundWrapper>
<div className="min-h-screen"> <div className="min-h-screen">
<Header <Header displayTabTitle={name} />
displaySubject={name}
displayTabTitle={null}
displayUser={false}
image={undefined}
examDuration={undefined}
/>
<div className="overflow-y-auto"> <div className="overflow-y-auto">
<div className="mt-5 px-5"> <div className="mt-5 px-5">
<DestructibleAlert text={errorMsg} extraStyles="" /> <DestructibleAlert text={errorMsg} extraStyles="" />
@ -88,13 +81,7 @@ export default function PaperScreen() {
return ( return (
<BackgroundWrapper> <BackgroundWrapper>
<div> <div>
<Header <Header displayTabTitle={name} />
displayTabTitle={null}
displayUser={false}
displaySubject={name}
image={undefined}
examDuration={undefined}
/>
<div className="mx-10 pt-10 overflow-y-auto"> <div className="mx-10 pt-10 overflow-y-auto">
<div className="border border-[#c0dafc] flex flex-col gap-4 w-full rounded-[25px] p-4"> <div className="border border-[#c0dafc] flex flex-col gap-4 w-full rounded-[25px] p-4">
{questions ? ( {questions ? (

View File

@ -91,7 +91,7 @@ export default function PretestPage() {
<div className="flex-1 overflow-y-auto mb-20"> <div className="flex-1 overflow-y-auto mb-20">
{metadata ? ( {metadata ? (
<div className="mx-10 mt-10 gap-6 pb-6 space-y-6"> <div className="mx-10 mt-10 gap-6 pb-6 space-y-6">
<button onClick={() => router.push("/unit")}> <button onClick={() => router.back()}>
<ArrowLeft size={30} color="black" /> <ArrowLeft size={30} color="black" />
</button> </button>

View File

@ -7,7 +7,7 @@ import React from "react";
import { ArrowLeft } from "lucide-react"; import { ArrowLeft } from "lucide-react";
import SlidingGallery from "@/components/SlidingGallery"; import SlidingGallery from "@/components/SlidingGallery";
import QuestionItem from "@/components/QuestionItem"; import QuestionItem from "@/components/QuestionItem";
import { getResultViews } from "@/lib/resultViews"; import { getResultViews } from "@/lib/gallery-views";
export default function ResultsPage() { export default function ResultsPage() {
const router = useRouter(); const router = useRouter();

View File

@ -12,7 +12,7 @@ import { UserData } from "@/types/auth";
interface HeaderProps { interface HeaderProps {
displayUser?: boolean; displayUser?: boolean;
displaySubject?: string; displaySubject?: string;
displayTabTitle: string; displayTabTitle?: string;
examDuration?: string; examDuration?: string;
} }
@ -109,18 +109,18 @@ const Header = ({
</div> </div>
)} )}
{displaySubject && ( {displayTabTitle && (
<div className={styles.profile}> <div className={styles.profile}>
<button onClick={handleBackClick} className={styles.iconButton}> <button onClick={handleBackClick} className={styles.iconButton}>
<ChevronLeft size={24} color="white" /> <ChevronLeft size={24} color="white" />
</button> </button>
<span className={styles.text}>{displaySubject}</span> <span className={styles.text}>{displayTabTitle}</span>
</div> </div>
)} )}
{displayTabTitle && ( {displaySubject && (
<div className={styles.profile}> <div className={styles.profile}>
<span className={styles.text}>{displayTabTitle}</span> <span className={styles.text}>{displaySubject}</span>
</div> </div>
)} )}

View File

@ -3,6 +3,19 @@ import Link from "next/link";
import Image from "next/image"; import Image from "next/image";
import styles from "../css/SlidingGallery.module.css"; import styles from "../css/SlidingGallery.module.css";
interface SlidingGalleryProps {
views?: {
id: string;
content: React.ReactNode;
}[];
className?: string;
showPagination?: boolean;
autoScroll?: boolean;
autoScrollInterval?: number;
onSlideChange?: (currentIndex: number) => void;
height?: string | number;
}
const SlidingGallery = ({ const SlidingGallery = ({
views = [], views = [],
className = "", className = "",
@ -11,7 +24,7 @@ const SlidingGallery = ({
autoScrollInterval = 5000, autoScrollInterval = 5000,
onSlideChange = () => {}, onSlideChange = () => {},
height = "100vh", height = "100vh",
}) => { }: SlidingGalleryProps) => {
const [activeIdx, setActiveIdx] = useState(0); const [activeIdx, setActiveIdx] = useState(0);
const [dimensions, setDimensions] = useState({ width: 0, height: 0 }); const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
const scrollRef = useRef(null); const scrollRef = useRef(null);
@ -74,7 +87,7 @@ const SlidingGallery = ({
} }
}, [dimensions]); }, [dimensions]);
const handleScroll = (event) => { const handleScroll = (event: { target: { scrollLeft: any } }) => {
handleUserInteraction(); handleUserInteraction();
const scrollLeft = event.target.scrollLeft; const scrollLeft = event.target.scrollLeft;
const slideWidth = dimensions.width; const slideWidth = dimensions.width;

View File

@ -1,5 +1,5 @@
// lib/gallery-views.tsx // lib/gallery-views.tsx
import { Link } from "lucide-react"; import Link from "next/link";
import Image from "next/image"; import Image from "next/image";
interface ExamResults { interface ExamResults {
@ -8,6 +8,11 @@ interface ExamResults {
answers: string[]; answers: string[];
} }
interface LinkedViews {
id: string;
content: React.ReactNode;
}
export const getResultViews = (examResults: ExamResults | null) => [ export const getResultViews = (examResults: ExamResults | null) => [
{ {
id: 1, id: 1,
@ -99,7 +104,7 @@ export const getResultViews = (examResults: ExamResults | null) => [
}, },
]; ];
export const getLinkedViews = () => [ export const getLinkedViews = (): LinkedViews[] => [
{ {
id: "1", id: "1",
content: ( content: (