generated from muhtadeetaron/nextjs-template
chore(capacitor): refactor codebase for capacitor entry
This commit is contained in:
@ -1,18 +1,38 @@
|
||||
import React, { JSX } from "react";
|
||||
|
||||
interface DestructibleAlertProps {
|
||||
variant?: "error" | "warning" | "alert";
|
||||
text: string;
|
||||
icon?: JSX.Element;
|
||||
}
|
||||
|
||||
const DestructibleAlert: React.FC<DestructibleAlertProps> = ({
|
||||
variant,
|
||||
text,
|
||||
icon,
|
||||
}) => {
|
||||
return (
|
||||
<div className=" bg-red-200 rounded-3xl py-6 flex flex-col items-center justify-center gap-2 w-full ">
|
||||
<div
|
||||
className={`${
|
||||
variant === "error"
|
||||
? "bg-red-200"
|
||||
: variant === "warning"
|
||||
? "bg-yellow-200"
|
||||
: "bg-green-200"
|
||||
} rounded-3xl py-6 flex flex-col items-center justify-center gap-2 w-full `}
|
||||
>
|
||||
<div>{icon}</div>
|
||||
<p className="text-lg font-bold text-center text-red-800">{text}</p>
|
||||
<p
|
||||
className={`text-lg font-bold text-center ${
|
||||
variant === "error"
|
||||
? "text-red-800"
|
||||
: variant === "warning"
|
||||
? "text-yellow-800"
|
||||
: "text-green-800"
|
||||
}`}
|
||||
>
|
||||
{text}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -2,13 +2,10 @@
|
||||
|
||||
import React from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { ChevronLeft, Layers, Loader } from "lucide-react";
|
||||
import { useTimer } from "@/context/TimerContext";
|
||||
import { ChevronLeft, Layers } from "lucide-react";
|
||||
import styles from "@/css/Header.module.css";
|
||||
import { useExam } from "@/context/ExamContext";
|
||||
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
|
||||
import { useModal } from "@/context/ModalContext";
|
||||
import { useAuth } from "@/context/AuthContext";
|
||||
import { useAuthStore } from "@/stores/authStore";
|
||||
import { useTimerStore } from "@/stores/timerStore";
|
||||
import { useExamStore } from "@/stores/examStore";
|
||||
|
||||
@ -9,9 +9,9 @@ interface QuestionItemProps {
|
||||
index: number;
|
||||
selectedAnswer: Answer;
|
||||
onSelect: (answer: Answer) => void;
|
||||
userAnswer?: Answer; // new
|
||||
correctAnswer?: Answer; // new
|
||||
showResults?: boolean; // control whether to highlight or not
|
||||
userAnswer?: Answer;
|
||||
correctAnswer?: Answer;
|
||||
showResults?: boolean;
|
||||
}
|
||||
|
||||
const letters = ["A", "B", "C", "D"]; // extend if needed
|
||||
@ -40,39 +40,20 @@ const QuestionItem: React.FC<QuestionItemProps> = ({
|
||||
|
||||
<div className="flex flex-col gap-3">
|
||||
{question.options.map((opt, optIdx) => {
|
||||
const isSelected =
|
||||
question.type === "Single"
|
||||
? selectedAnswer === optIdx
|
||||
: Array.isArray(selectedAnswer) &&
|
||||
selectedAnswer.includes(optIdx);
|
||||
const isSelected = selectedAnswer === optIdx;
|
||||
|
||||
// ✅ logic for coloring after results
|
||||
// ✅ logic for coloring
|
||||
let btnClasses = "bg-gray-100 text-gray-900 border-gray-400";
|
||||
if (isSelected) {
|
||||
btnClasses = "bg-blue-600 text-white border-blue-600";
|
||||
}
|
||||
|
||||
if (showResults && correctAnswer !== undefined) {
|
||||
if (question.type === "Single") {
|
||||
if (userAnswer === optIdx && userAnswer !== correctAnswer) {
|
||||
btnClasses = "bg-red-500 text-white border-red-600"; // wrong
|
||||
}
|
||||
if (correctAnswer === optIdx) {
|
||||
btnClasses = "bg-green-500 text-white border-green-600"; // correct
|
||||
}
|
||||
} else {
|
||||
// Multi-select case
|
||||
const userSelected =
|
||||
Array.isArray(userAnswer) && userAnswer.includes(optIdx);
|
||||
const isCorrect =
|
||||
Array.isArray(correctAnswer) && correctAnswer.includes(optIdx);
|
||||
|
||||
if (userSelected && !isCorrect) {
|
||||
btnClasses = "bg-red-500 text-white border-red-600";
|
||||
}
|
||||
if (isCorrect) {
|
||||
btnClasses = "bg-green-500 text-white border-green-600";
|
||||
}
|
||||
if (userAnswer === optIdx && userAnswer !== correctAnswer) {
|
||||
btnClasses = "bg-red-500 text-white border-red-600"; // wrong
|
||||
}
|
||||
if (correctAnswer === optIdx) {
|
||||
btnClasses = "bg-green-500 text-white border-green-600"; // correct
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,20 +61,8 @@ const QuestionItem: React.FC<QuestionItemProps> = ({
|
||||
<div key={optIdx} className="flex items-center gap-3">
|
||||
<button
|
||||
onClick={() => {
|
||||
if (showResults) return; // disable changes in results mode
|
||||
if (question.type === "Single") {
|
||||
onSelect(optIdx);
|
||||
} else {
|
||||
let newAnswers = Array.isArray(selectedAnswer)
|
||||
? [...selectedAnswer]
|
||||
: [];
|
||||
if (newAnswers.includes(optIdx)) {
|
||||
newAnswers = newAnswers.filter((a) => a !== optIdx);
|
||||
} else {
|
||||
newAnswers.push(optIdx);
|
||||
}
|
||||
onSelect(newAnswers);
|
||||
}
|
||||
if (showResults) return; // disable selection in results mode
|
||||
onSelect(optIdx); // always a number
|
||||
}}
|
||||
className={`w-7 h-7 rounded-full border font-bold
|
||||
flex items-center justify-center
|
||||
|
||||
@ -5,7 +5,6 @@ import React, {
|
||||
useCallback,
|
||||
UIEvent,
|
||||
} from "react";
|
||||
import styles from "../css/SlidingGallery.module.css";
|
||||
import { GalleryViews } from "@/types/gallery";
|
||||
|
||||
interface SlidingGalleryProps {
|
||||
@ -120,8 +119,10 @@ const SlidingGallery = ({
|
||||
|
||||
if (!views || views.length === 0) {
|
||||
return (
|
||||
<div className={`${styles.gallery} ${className}`}>
|
||||
<div className={styles.emptyState}>
|
||||
<div
|
||||
className={`relative w-full h-screen overflow-hidden flex flex-col ${className}`}
|
||||
>
|
||||
<div className="flex-1 flex items-center justify-center text-slate-400 text-lg">
|
||||
<p>No content to display</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -130,12 +131,12 @@ const SlidingGallery = ({
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`${styles.gallery} ${className}`}
|
||||
className={`relative w-full h-screen overflow-hidden flex flex-col ${className}`}
|
||||
ref={galleryRef}
|
||||
style={{ height }}
|
||||
>
|
||||
<div
|
||||
className={styles.scrollContainer}
|
||||
className="flex-1 flex overflow-x-auto"
|
||||
ref={scrollRef}
|
||||
onScroll={handleScroll}
|
||||
style={{
|
||||
@ -143,16 +144,20 @@ const SlidingGallery = ({
|
||||
height: "100%",
|
||||
overflowX: "scroll",
|
||||
display: "flex",
|
||||
scrollSnapType: "x mandatory",
|
||||
scrollbarWidth: "none",
|
||||
msOverflowStyle: "none",
|
||||
}}
|
||||
>
|
||||
{views.map((item) => (
|
||||
<div
|
||||
key={item.id}
|
||||
className={styles.slide}
|
||||
className="min-w-full flex items-center justify-center px-2 box-border"
|
||||
style={{
|
||||
width: dimensions.width,
|
||||
height: "100%",
|
||||
flexShrink: 0,
|
||||
scrollSnapAlign: "start",
|
||||
}}
|
||||
>
|
||||
{item.content}
|
||||
@ -161,15 +166,14 @@ const SlidingGallery = ({
|
||||
</div>
|
||||
|
||||
{showPagination && views.length > 1 && (
|
||||
<div className={styles.pagination}>
|
||||
<div className="absolute bottom-[15px] left-1/2 -translate-x-1/2 flex gap-1.5 z-10">
|
||||
{views.map((_, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`${styles.dot} ${
|
||||
activeIdx === index ? styles.activeDot : styles.inactiveDot
|
||||
className={`w-2 h-2 rounded-full transition-all duration-300 ease-in ${
|
||||
activeIdx === index ? "bg-[#113768]" : "bg-[#b1d3ff]"
|
||||
}`}
|
||||
onClick={() => handleDotClick(index)}
|
||||
style={{ cursor: "pointer" }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user