fix(ui): fix ui icons and readability

This commit is contained in:
shafin-r
2025-11-12 15:38:07 +06:00
parent d1947e8e6e
commit 11108ad8cf
12 changed files with 108 additions and 122 deletions

1
.gitignore vendored
View File

@ -16,6 +16,7 @@
# next.js # next.js
/.next/ /.next/
/out/ /out/
android
# production # production
/build /build

View File

@ -1,64 +1,64 @@
"use client"; "use client";
import React, { useState, useEffect } from "react"; import React from "react";
import BackgroundWrapper from "@/components/BackgroundWrapper"; import BackgroundWrapper from "@/components/BackgroundWrapper";
import { Bookmark, BookmarkCheck, ListFilter, MoveLeft } from "lucide-react"; import { ListFilter, MoveLeft } from "lucide-react";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import DestructibleAlert from "@/components/DestructibleAlert"; import DestructibleAlert from "@/components/DestructibleAlert";
interface Question { // interface Question {
id: number; // id: number;
question: string; // question: string;
options: Record<string, string>; // options: Record<string, string>;
} // }
interface QuestionItemProps { // interface QuestionItemProps {
question: Question; // question: Question;
} // }
const QuestionItem = ({ question }: QuestionItemProps) => { // const QuestionItem = ({ question }: QuestionItemProps) => {
const [bookmark, setBookmark] = useState(true); // const [bookmark, setBookmark] = useState(true);
return ( // return (
<div className="border border-[#8abdff]/50 rounded-2xl p-4 flex flex-col gap-7"> // <div className="border border-[#8abdff]/50 rounded-2xl p-4 flex flex-col gap-7">
<h3 className="text-xl font-medium"> // <h3 className="text-xl font-medium">
{question.id + 1}. {question.question} // {question.id + 1}. {question.question}
</h3> // </h3>
<div className="flex justify-between items-center"> // <div className="flex justify-between items-center">
<div></div> // <div></div>
<button onClick={() => setBookmark(!bookmark)}> // <button onClick={() => setBookmark(!bookmark)}>
{bookmark ? ( // {bookmark ? (
<BookmarkCheck size={25} color="#113768" /> // <BookmarkCheck size={25} color="#113768" />
) : ( // ) : (
<Bookmark size={25} color="#113768" /> // <Bookmark size={25} color="#113768" />
)} // )}
</button> // </button>
</div> // </div>
<div className="flex flex-col gap-4 items-start"> // <div className="flex flex-col gap-4 items-start">
{Object.entries(question.options).map(([key, value]) => { // {Object.entries(question.options).map(([key, value]) => {
return ( // return (
<div key={key} className="flex items-center gap-3"> // <div key={key} className="flex items-center gap-3">
<span className="px-2 py-1 flex items-center rounded-full border font-medium text-sm"> // <span className="px-2 py-1 flex items-center rounded-full border font-medium text-sm">
{key.toUpperCase()} // {key.toUpperCase()}
</span> // </span>
<span className="option-description">{value}</span> // <span className="option-description">{value}</span>
</div> // </div>
); // );
})} // })}
</div> // </div>
</div> // </div>
); // );
}; // };
const BookmarkPage = () => { const BookmarkPage = () => {
const router = useRouter(); const router = useRouter();
const [questions, setQuestions] = useState<Question[]>([]); // const [questions, setQuestions] = useState<Question[]>([]);
useEffect(() => { // useEffect(() => {
fetch("/data/bookmark.json") // fetch("/data/bookmark.json")
.then((res) => res.json()) // .then((res) => res.json())
.then((data) => setQuestions(data)) // .then((data) => setQuestions(data))
.catch((err) => console.error("Error loading questions: ", err)); // .catch((err) => console.error("Error loading questions: ", err));
}, []); // }, []);
return ( return (
<BackgroundWrapper> <BackgroundWrapper>

View File

@ -6,7 +6,7 @@ import Header from "@/components/Header";
import DestructibleAlert from "@/components/DestructibleAlert"; import DestructibleAlert from "@/components/DestructibleAlert";
import BackgroundWrapper from "@/components/BackgroundWrapper"; import BackgroundWrapper from "@/components/BackgroundWrapper";
import { API_URL, getToken } from "@/lib/auth"; import { API_URL, getToken } from "@/lib/auth";
import { Loader, RefreshCw, Star, StarHalf } from "lucide-react"; import { Loader, RefreshCw } from "lucide-react";
import { useAuthStore } from "@/stores/authStore"; import { useAuthStore } from "@/stores/authStore";
import { FaStar } from "react-icons/fa"; import { FaStar } from "react-icons/fa";

View File

@ -17,7 +17,7 @@ const tabs = [
href: "/categories", href: "/categories",
component: <HiViewGrid size={30} />, component: <HiViewGrid size={30} />,
}, },
{ name: "Bookmark", href: "/bookmark", component: <FaBookmark size={25} /> }, { name: "Bookmark", href: "/bookmark", component: <FaBookmark size={23} /> },
{ name: "Settings", href: "/settings", component: <HiCog6Tooth size={30} /> }, { name: "Settings", href: "/settings", component: <HiCog6Tooth size={30} /> },
]; ];

View File

@ -44,22 +44,24 @@ const SettingsPage = () => {
<UserCircle2 size={30} color="#113768" /> <UserCircle2 size={30} color="#113768" />
</button> </button>
</section> </section>
<section className="flex flex-col gap-4"> <section className="flex items-center gap-4 bg-blue-100 border-1 border-blue-300/40 rounded-2xl py-5 px-4">
<div className="flex gap-4 items-center">
<Avatar className="bg-[#113768] w-20 h-20"> <Avatar className="bg-[#113768] w-20 h-20">
<AvatarFallback className="text-3xl text-white"> <AvatarFallback className="text-3xl text-white">
{user?.username {user?.username
? user.username.charAt(0).toUpperCase() ? user.username.charAt(0).toUpperCase()
: ""} : "User"}
</AvatarFallback> </AvatarFallback>
</Avatar> </Avatar>
<div className="flex flex-col items-start"> <div className="flex flex-col items-start">
<h1 className="font-semibold text-2xl">{user?.full_name}</h1> <h1 className="font-semibold text-2xl flex gap-1 items-center">
{user?.full_name}
</h1>
<h3 className=" text-md">{user?.email}</h3> <h3 className=" text-md">{user?.email}</h3>
</div> </div>
</div>
</section> </section>
<section className="flex flex-col gap-8"> <section className="flex flex-col gap-8">
{!user?.is_verified && (
<>
<button <button
onClick={() => router.push("/settings/verify")} onClick={() => router.push("/settings/verify")}
className="flex justify-between" className="flex justify-between"
@ -73,6 +75,8 @@ const SettingsPage = () => {
<ChevronRight size={30} color="#113768" /> <ChevronRight size={30} color="#113768" />
</button> </button>
<div className="h-[0.5px] border-[0.1px] w-full border-[#113768]/20"></div> <div className="h-[0.5px] border-[0.1px] w-full border-[#113768]/20"></div>
</>
)}
<button <button
onClick={() => router.push("/profile")} onClick={() => router.push("/profile")}
className="flex justify-between" className="flex justify-between"

View File

@ -9,7 +9,6 @@ import {
InputOTPSlot, InputOTPSlot,
} from "@/components/ui/input-otp"; } from "@/components/ui/input-otp";
import { API_URL } from "@/lib/auth"; import { API_URL } from "@/lib/auth";
import { useAuthStore } from "@/stores/authStore";
import Image from "next/image"; import Image from "next/image";
import React, { useState } from "react"; import React, { useState } from "react";
@ -17,7 +16,6 @@ const VerificationScreen = () => {
const [otp, setOtp] = useState(""); const [otp, setOtp] = useState("");
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const { fetchUser } = useAuthStore();
const handleVerify = async () => { const handleVerify = async () => {
if (otp.length < 6) return; if (otp.length < 6) return;
@ -39,7 +37,6 @@ const VerificationScreen = () => {
} }
// 🔥 Call zustand action to update auth state // 🔥 Call zustand action to update auth state
await fetchUser();
} catch (err: any) { } catch (err: any) {
setError(err.message); setError(err.message);
} finally { } finally {

View File

@ -1,7 +1,7 @@
"use client"; "use client";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { usePathname, useRouter, useSearchParams } from "next/navigation"; import { useRouter, useSearchParams } from "next/navigation";
import Header from "@/components/Header"; import Header from "@/components/Header";
import QuestionItem from "@/components/QuestionItem"; import QuestionItem from "@/components/QuestionItem";
import BackgroundWrapper from "@/components/BackgroundWrapper"; import BackgroundWrapper from "@/components/BackgroundWrapper";
@ -44,6 +44,10 @@ export default function ExamPage() {
}; };
initExam(); initExam();
return () => {
stopTimer();
};
}, [ }, [
type, type,
test_id, test_id,

View File

@ -1,7 +1,7 @@
"use client"; "use client";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import React, { useEffect } from "react"; import React, { useCallback, useEffect } from "react";
import { ArrowLeft } from "lucide-react"; import { ArrowLeft } from "lucide-react";
import { useExamStore } from "@/stores/examStore"; import { useExamStore } from "@/stores/examStore";
import QuestionItem from "@/components/QuestionItem"; import QuestionItem from "@/components/QuestionItem";
@ -12,10 +12,10 @@ export default function ResultsPage() {
const router = useRouter(); const router = useRouter();
const { result, clearResult, setStatus, status } = useExamStore(); const { result, clearResult, setStatus, status } = useExamStore();
function handleBackToHome() { const handleBackToHome = useCallback(() => {
clearResult(); clearResult();
router.replace("/categories"); router.replace("/categories");
} }, [clearResult, router]);
useEffect(() => { useEffect(() => {
const handlePopState = () => { const handlePopState = () => {
@ -28,7 +28,7 @@ export default function ResultsPage() {
return () => { return () => {
window.removeEventListener("popstate", handlePopState); window.removeEventListener("popstate", handlePopState);
}; };
}, [status, router, setStatus]); }, [status, router, setStatus, handleBackToHome]);
if (!result) { if (!result) {
return ( return (

View File

@ -1,10 +1,9 @@
// capacitor.config.ts import type { CapacitorConfig } from "@capacitor/cli";
import { CapacitorConfig } from "@capacitor/cli";
const config: CapacitorConfig = { const config: CapacitorConfig = {
appId: "com.examjam.omukk", appId: "com.examjam.omukk",
appName: "ExamJam", appName: "ExamJam",
webDir: "out", // ✅ point to your Next.js static export webDir: "out",
}; };
export default config; export default config;

View File

@ -1,25 +0,0 @@
"use client";
import { useNavStore } from "@/stores/navStore";
import { useRouter, usePathname } from "next/navigation";
import { useEffect } from "react";
export function ExamGuard({ children }: { children: React.ReactNode }) {
const { examSubmitted, resultsDone } = useNavStore();
const router = useRouter();
const pathname = usePathname();
useEffect(() => {
// Prevent access to /exam after submission
if (pathname === "/exam/exam-screen" && examSubmitted) {
router.replace("/results");
}
// Prevent access to /results after done
if (pathname === "/exam/results" && resultsDone) {
router.replace("/categories"); // or wherever you want them to go
}
}, [pathname, examSubmitted, resultsDone, router]);
return <>{children}</>;
}

View File

@ -2,7 +2,7 @@
import React from "react"; import React from "react";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { BadgeCheck, ChevronLeft, Layers } from "lucide-react"; import { ChevronLeft, Layers, RefreshCcw } from "lucide-react";
import { Avatar, AvatarFallback } from "@/components/ui/avatar"; import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { useModal } from "@/context/ModalContext"; import { useModal } from "@/context/ModalContext";
import { useAuthStore } from "@/stores/authStore"; import { useAuthStore } from "@/stores/authStore";
@ -66,14 +66,19 @@ const Header = ({
)} )}
{displayTabTitle && ( {displayTabTitle && (
<div className="flex justify-between items-center w-full">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<button onClick={handleBackClick} className="bg-none border-none p-1"> <button
onClick={handleBackClick}
className="bg-none border-none p-1"
>
<ChevronLeft size={24} color="white" /> <ChevronLeft size={24} color="white" />
</button> </button>
<span className="text-md font-bold text-white"> <span className="text-md font-bold text-white">
{displayTabTitle} {displayTabTitle}
</span> </span>
</div> </div>
</div>
)} )}
{displaySubject && ( {displaySubject && (

View File

@ -6,7 +6,8 @@
"dev": "next dev --turbopack", "dev": "next dev --turbopack",
"build": "next build ", "build": "next build ",
"start": "next start", "start": "next start",
"lint": "next lint" "lint": "next lint",
"build:export": "npx next build && npm run export"
}, },
"dependencies": { "dependencies": {
"@capacitor/android": "^7.4.2", "@capacitor/android": "^7.4.2",