generated from muhtadeetaron/nextjs-template
fix(ts): fix interfaces for type safety
This commit is contained in:
@ -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;
|
||||||
|
|||||||
@ -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"
|
||||||
|
|||||||
@ -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 ? (
|
||||||
|
|||||||
@ -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>
|
||||||
|
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
@ -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>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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: (
|
||||||
|
|||||||
Reference in New Issue
Block a user