Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
265 changes: 265 additions & 0 deletions app/components/pages/Retentiaquiz.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
"use client";

import { useState } from "react";
import Card from "../ui/Card";
import Button from "../ui/Button";
import ProgressBar from "../ui/Progressbar";
import Timer from "../ui/Timer";
import QuestionNavigation from "../ui/QuestionNavigation";
import { Flag, ChevronRight } from "lucide-react";

export default function Retentiaquiz() {

const totalQuestions = 50;

const [showSubmitModal, setShowSubmitModal] = useState(false);
const [currentQuestion, setCurrentQuestion] = useState(1);
const [answers, setAnswers] = useState<Record<number, string | null>>({});
const [confirmedAnswers, setConfirmedAnswers] = useState<Record<number, boolean>>({});
const [markedReview, setMarkedReview] = useState<Record<number, boolean>>({});
const [skipped, setSkipped] = useState<Record<number, boolean>>({});

const answeredCount = Object.keys(confirmedAnswers).length;

const options = [
{ id: "A", text: "Solar power" },
{ id: "B", text: "Wind Power" },
{ id: "C", text: "Natural Gas" },
{ id: "D", text: "Hydroelectric Power" },
];

Comment thread
ABHISHEKUPAI marked this conversation as resolved.
const confirmSubmit = () => {
setShowSubmitModal(false);

console.log("Quiz submitted successfully");

};

const handleOptionClick = (optionId: string) => {

setAnswers((prev) => {

const current = prev[currentQuestion];

return {
...prev,
[currentQuestion]: current === optionId ? null : optionId,
};

});

setSkipped((prev) => {
const updated = { ...prev };
delete updated[currentQuestion];
return updated;
});

};

const handleNext = () => {

if (answers[currentQuestion]) {

setConfirmedAnswers((prev) => ({
...prev,
[currentQuestion]: true,
}));

setSkipped((prev) => {
const updated = { ...prev };
delete updated[currentQuestion];
return updated;
});

} else {

setSkipped((prev) => ({
...prev,
[currentQuestion]: true,
}));

setConfirmedAnswers((prev) => {
const updated = { ...prev };
delete updated[currentQuestion];
return updated;
});

}

if (currentQuestion < totalQuestions) {
setCurrentQuestion((prev) => prev + 1);
}

};

const toggleReview = () => {

setMarkedReview((prev) => ({
...prev,
[currentQuestion]: !prev[currentQuestion],
}));

setSkipped((prev) => {
const updated = { ...prev };
delete updated[currentQuestion];
return updated;
});

};
const handleSubmit = () => {
setShowSubmitModal(true);
};

return (

<main className="min-h-screen flex flex-col justify-center bg-background py-10
px-4 sm:px-10 md:px-20 lg:px-80">

<div className="grid grid-cols-3 items-center mt-3 gap-4">

<div></div>

<div className="flex justify-center">
<Timer totalQuestions={totalQuestions} />
</div>

<div className="flex justify-center sm:justify-end">
<Button
variant="default"
className="bg-answered px-6 py-2 text-white"
onClick={handleSubmit}
>
Submit
</Button>
</div>

</div>

<div className="mb-10 mt-10">
<ProgressBar
answered={answeredCount}
total={totalQuestions}
/>
</div>

<QuestionNavigation
currentQuestion={currentQuestion}
totalQuestions={totalQuestions}
onQuestionChange={setCurrentQuestion}
confirmedAnswers={confirmedAnswers}
markedReview={markedReview}
skipped={skipped}
/>
Comment thread
ItsAbhinavM marked this conversation as resolved.

<Card
variant="primary"
className="w-full max-h-212.5 px-4 sm:px-6 md:px-10"
>

<Card
variant="secondary"
className="w-full mb-15 flex items-center justify-center"
>
<p className="text-xl sm:text-2xl md:text-3xl font-bold leading-relaxed p-6 sm:p-10 md:p-15 text-center">
Which of the following energy sources cannot be
replenished naturally on a human timescale?
</p>
</Card>

<div className="space-y-5 text-lg sm:text-xl">

{options.map((option) => {

const isSelected = answers[currentQuestion] === option.id;
const isAnswered = confirmedAnswers[currentQuestion];

let colorClass = "";

if (isAnswered && isSelected) colorClass = "border-secondary ";
else if (isSelected) colorClass = "border-secondary";

return (

<Button
key={option.id}
variant="opt_btn"
onClick={() => handleOptionClick(option.id)}
className={`${colorClass}`}
>

<div className="flex items-center justify-center w-8 h-8 rounded-full bg-white text-black font-semibold">
{option.id}
</div>

<span className="flex-1 text-left">
{option.text}
</span>

</Button>

);
})}

</div>

</Card>

<div className="flex flex-col sm:flex-row justify-end items-center gap-5 mt-20 mb-5">

<Button
variant="default"
onClick={toggleReview}
className="bg-purple-600 text-white px-6 py-2 flex items-center gap-2 w-full sm:w-auto justify-center"
>
<Flag size={18} />
Mark For Review
</Button>

<Button
variant="default"
onClick={handleNext}
className="bg-secondary px-6 py-2 flex text-white items-center gap-2 w-full sm:w-auto justify-center"
>
Next Question
<ChevronRight size={18} />
</Button>

</div>
{showSubmitModal && (
<div className="fixed inset-0 bg-background flex items-center justify-center z-50">
<Card variant="primary" className="p-8 max-w-md w-full text-center">

<h2 className="text-xl font-bold mb-4">
Submit Quiz?
</h2>

<p className="text-text mb-6">
Are you sure you want to submit the quiz?
</p>

<div className="flex justify-center gap-4">

<Button
variant="default"
onClick={() => setShowSubmitModal(false)}
>
Cancel
</Button>

<Button
variant="default"
className="bg-answered text-text"
onClick={confirmSubmit}
>
Submit
</Button>

</div>

</Card>
</div>
)}

</main>
);
}
30 changes: 23 additions & 7 deletions app/components/ui/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,35 @@
type ButtonProps = {
children: React.ReactNode;
variant?: "default" | "sidebar_btn" ;
variant?: "default" | "sidebar_btn" | "opt_btn";
className?: string;
onClick?: () => void;
};

export default function Button({children,variant = "default",className = "", }: ButtonProps) {
const base = "flex items-center cursor-pointer ";
export default function Button({
children,
variant = "default",
className = "",
onClick,
}: ButtonProps) {
const base = "cursor-pointer min-h-[48px]";

const variants = {
default: "text-text text-2xl",
sidebar_btn: "group text-2xl px-4 gap-4 py-2 font-semibold rounded-full hover:bg-primary-light",

default:
"flex p-2 sm:p-3 md:p-4 rounded-2xl items-center text-text text-base sm:text-lg md:text-xl",

sidebar_btn:
"flex items-center group text-lg sm:text-xl md:text-2xl px-2 sm:px-4 gap-2 sm:gap-4 py-2 font-semibold rounded-full hover:bg-primary-light",

opt_btn:
"w-full text-lg sm:text-xl md:text-2xl font-bold rounded-3xl sm:py-6 md:py-8 px-4 sm:px-6 md:px-7 items-start text-left break-words bg-background/70 border-background flex justify-center gap-5 border-2 hover:bg-background/30 hover:border-text/60 transition-colors overflow-y-auto",
};

return (
<button className={`${base} ${variants[variant]} ${className}`}>
<button
type="button"
onClick={onClick}
className={`${base} ${variants[variant]} ${className}`}
>
{children}
</button>
);
Expand Down
23 changes: 23 additions & 0 deletions app/components/ui/Card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
type CardProps = {
children: React.ReactNode;
variant?: "primary" | "secondary";
className?: string;
};

export default function Card({
children,
variant = "primary",
className = "",
}: CardProps) {
const base = "rounded-3xl p-6 ";
const variants = {
primary: "bg-foreground flex overflow-y-auto flex-col text-text",
secondary: "bg-background/70 text-text",
};

return (
<div className={`${base} ${variants[variant]} ${className}`}>
{children}
</div>
);
}
35 changes: 35 additions & 0 deletions app/components/ui/Progressbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
type ProgressBarProps = {
answered: number;
total: number;
className?: string;
};

export default function ProgressBar({
answered,
total,
className = "",
}: ProgressBarProps) {

const progress = total > 0 ? (answered / total) * 100 : 0;

return (
<div className={`w-full ${className}`}>


<div className="flex justify-between text-xl mb-1 text-text/70">
<span>{answered} / {total} answered</span>
</div>


<div className="w-full h-4 rounded-full bg-text overflow-hidden">

<div
className="h-full rounded-full bg-[#22C55E] transition-all duration-300 ease-out"
style={{ width: `${progress}%` }}
/>

</div>

</div>
);
}
Loading
Loading