Skip to content

UI assessments #289

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 45 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
a774d6d
feat: set up assessment page and AssessmentResults
kristi-h Feb 5, 2025
6b43075
feat: add ButtonController and QuizButton
kristi-h Feb 5, 2025
6903f7f
feat: organize container structure, modify padding and widths
kristi-h Feb 5, 2025
c6d630c
feat: adjust styles for buttons, add hero icons
kristi-h Feb 5, 2025
11e12fb
feat: add ConfettiScreen behind main content on AssessmentResults
kristi-h Feb 6, 2025
608eaf6
feat: add AssessmentForm, import and style RadioGroupItems
kristi-h Feb 6, 2025
cb2634d
feat: import Button to AssessmentForm and customize for 'Back' and 'C…
kristi-h Feb 6, 2025
1ae1523
feat: add Header with Exit Button, modify RadioInput padding
kristi-h Feb 6, 2025
3567d86
feat: add analyzing_results.png, add ResultsLoading component
kristi-h Feb 6, 2025
32e49bc
feat: add custom bounce to tailwind.config, add animation to ResultsL…
kristi-h Feb 6, 2025
d7e5f4f
feat: get rid of border outline on AssessmentResults buttons
kristi-h Feb 6, 2025
576be0b
feat: fix TierDisplay width, make ConfettiScreen trigger just once on…
kristi-h Feb 6, 2025
3a320c5
feat: trim tailwind with shorthand, reorder imports, replace img with…
kristi-h Feb 6, 2025
d21a89a
feat: fix errors
kristi-h Feb 6, 2025
382e28d
feat: add AssessmentPage
kristi-h Feb 6, 2025
720051e
Merge branch 'dev' of https://github.com/chingu-x/chingu-dashboard in…
kristi-h Feb 6, 2025
73315f9
refactor: adjust styles in main layout,move max width and padding to …
Dan-Y-Ko Feb 7, 2025
3c8c686
feat: apply tile design, update fonts
kristi-h Feb 7, 2025
a4deeb5
feat: fix header and header-intro
kristi-h Feb 7, 2025
96d75f9
feat: add all images for assessment-home-icon, apply styles to each i…
kristi-h Feb 7, 2025
cd7a61b
feat: fix assessment/home icon image and styling on header
kristi-h Feb 7, 2025
d41ac7c
feat: replace custom animation in tailwind.config with framer motion …
kristi-h Feb 7, 2025
22a7b4b
feat: clean up unused import
kristi-h Feb 7, 2025
57d0735
feat: replace alt with aria-label
kristi-h Feb 7, 2025
2f3ca8a
feat: leave in alt for Image tag
kristi-h Feb 7, 2025
10885c1
Merge branch 'ui-assessments'
kristi-h Feb 8, 2025
12ad22a
feat: uncomment ResultsLoading
kristi-h Feb 8, 2025
ce61742
feat: add ConfettiScreen prop
kristi-h Feb 8, 2025
3e0fd2b
feat: adjust RadioGroupItem styles
kristi-h Feb 9, 2025
01079ff
fix: buttons and add in margins for form
kristi-h Feb 10, 2025
046105f
fix: assessmentResults styling
kristi-h Feb 11, 2025
b11c925
feat: add conditional for loading state
kristi-h Feb 12, 2025
d480c28
feat: add stepper component
kristi-h Feb 13, 2025
2cfcce6
feat: implement stepper into header
kristi-h Feb 14, 2025
d1d5310
fix: style errors and add links to buttons
kristi-h Feb 15, 2025
8d9b11a
feat: add QuizData file
kristi-h Feb 16, 2025
de0f16c
feat: replace static form with dynamically rendered form from QuizData
kristi-h Feb 17, 2025
4c716f6
refactor: add currentIndex and only show currentQuestion, add btn han…
kristi-h Feb 17, 2025
fc1cd7c
fix: file structure for assessments from under app>components to app>…
kristi-h Feb 19, 2025
b9142d8
refactor: make style adjustments on Header and AssessmentStepper to b…
kristi-h Feb 19, 2025
48944c2
refactor: remove 'relative' class from wrapper div and apply it to ma…
kristi-h Feb 21, 2025
e328f6b
Merge branch 'dev' of https://github.com/chingu-x/chingu-dashboard in…
kristi-h Feb 21, 2025
494dfea
refactor: add condition & error to next btn, clear prev selection fo…
kristi-h Feb 24, 2025
3017e32
fix: add typeof for level to fix ts error
kristi-h Feb 25, 2025
9f83915
Merge branch 'dev' into ui-assessments
Dan-Y-Ko Feb 28, 2025
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
Binary file added public/img/assessment/analyzing_results.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/img/assessment/home.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/lotties/assessment_confetti.json

Large diffs are not rendered by default.

555 changes: 555 additions & 0 deletions src/app/(main)/assessment/QuizData.tsx

Large diffs are not rendered by default.

100 changes: 100 additions & 0 deletions src/app/(main)/assessment/form/AssessmentForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
"use client";
import { useState } from "react";
import { ArrowLeftIcon, ArrowRightIcon } from "@heroicons/react/20/solid";
import Header from "@/app/(main)/assessment/ui/Header";
import RadioGroupItem from "@/components/inputs/RadioGroup/RadioGroupItem";
import Button from "@/components/Button";
import { quiz } from "@/app/(main)/assessment/QuizData";

export default function AssessmentForm() {
const [currentIndex, setCurrentIndex] = useState(0);
const [selectedOption, setSelectedOption] = useState<string | null>(null);
const [errorMessage, setErrorMessage] = useState("");

const handleNext = () => {
if (!selectedOption) {
setErrorMessage("Select an option before moving onto the next question");
return;
}
setErrorMessage("");
if (currentIndex < quiz.length - 1) {
setCurrentIndex((prevIndex) => prevIndex + 1);
setSelectedOption(null);
}
};

const handlePrev = () => {
if (currentIndex > 0) {
setCurrentIndex(currentIndex - 1);
}
};

const currentQuestion = quiz[currentIndex];

return (
<div>
<Header />
<div
aria-label="question-container"
className="mb-[42px] mt-[80px] w-full max-w-[812px] gap-[24px] rounded-[16px] bg-[#F5F5F5] p-[40px]"
>
<p
aria-label="question"
className="mb-[32px] max-w-[650px] text-[25px] font-semibold leading-[30px] text-[#16171A]"
>
{currentQuestion.question}
</p>

<div
aria-label="radio-buttons"
className="flex w-[650px] flex-col justify-center gap-[24px]"
>
{["none", "beginner", "intermediate", "advanced"].map((level) => (
<RadioGroupItem
key={level}
className={`w-full gap-[16px] rounded-[8px] border p-[16px] shadow-md ${
selectedOption === level
? "border-[#217A56]"
: "border-[#9CA1AA]"
}`}
id={level}
label={
<div>
<strong>
{level.charAt(0).toUpperCase() + level.slice(1)}
</strong>
<p>
{currentQuestion[level as keyof typeof currentQuestion]}
</p>
</div>
}
checked={selectedOption === level}
onChange={() => setSelectedOption(level)}
/>
))}
</div>

{errorMessage && <p className="mt-4 text-red-500">{errorMessage}</p>}
</div>

<div className="flex w-[386px] items-center justify-center gap-[40px]">
<Button
className="h-[60px] w-full rounded-[8px] border border-[#9CA1AA] !bg-[#F5F5F5]/70 px-[26px] py-[18px] text-black"
disabled={currentIndex === 0}
onClick={handlePrev}
>
<ArrowLeftIcon className="mr-2 h-4 w-4" />
Back
</Button>
<Button
className="h-[60px] w-full rounded-[8px] border border-[#9CA1AA] !bg-[#217A56] px-[26px] py-[18px] text-white"
disabled={currentIndex === quiz.length - 1}
onClick={handleNext}
>
Continue
<ArrowRightIcon className="ml-2 h-4 w-4 text-white" />
</Button>
</div>
</div>
);
}
93 changes: 93 additions & 0 deletions src/app/(main)/assessment/home/AssessmentPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import Image from "next/image";
import Button from "@/components/Button";

export default function AssessmentPage() {
return (
<div
aria-label="component-container"
className="left-[250px] mt-[76px] flex h-[547px] w-[1478px] flex-col items-center justify-center gap-[75px] px-[40px]"
>
<div
aria-label="header"
className="flex min-h-[200px] w-[1300px] min-w-[895px] flex-row items-center justify-center gap-[40px] rounded-[16px] text-2xl font-light"
>
<Image
src="/img/assessment/home.png"
alt="home"
width={231}
height={200}
className="h-[200px] w-[231px]"
/>
<div
aria-label="header-intro"
className="flex flex-col items-start justify-center"
>
<p className="h-[40px] w-[700px] text-left text-[39px] leading-[40px]">
Hey there tech Wizard!
</p>
<p className="h-[72px] w-[700px] text-left text-[20px] font-medium leading-[24px] text-[#16171A]">
What&lsquo;s your tech superpower level? Are you a beginner Batman
or an expert Iron Man? Let us know so we can team you up with the
right sidekick.
</p>
</div>
</div>
<div
aria-label="tile-row"
className="flex h-[192px] w-[1398px] flex-row gap-[40px]"
>
<div
aria-label="tile"
className="flex h-[192px] w-[439px] flex-col items-center justify-center gap-[24px] rounded-[16px] bg-[#F5F5F5] p-[24px]"
>
<p
aria-label="tile-name"
className="h-[30px] w-[283px] text-center text-[25px] font-semibold leading-[30px]"
>
Front End Development
</p>
<p className="h-[19px] w-[8px] text-center text-[16px] font-medium leading-[19px] text-[#000000]">
-
</p>
<Button className="h-[47px] w-[207px] gap-[8px] rounded-lg bg-[#217A56] px-[22px] py-[14px] text-[16px] font-semibold leading-[19px] text-[#F5F5F5]">
Take Assessment
</Button>
</div>
<div
aria-label="tile"
className="flex h-[192px] w-[439.33px] flex-col items-center justify-center gap-[24px] rounded-[16px] bg-[#F5F5F5] p-[24px]"
>
<p
aria-label="tile-name"
className="h-[30px] w-[283px] text-center text-[25px] font-semibold leading-[30px]"
>
Back End Development
</p>
<p className="h-[19px] w-[8px] text-center text-[16px] font-medium leading-[19px] text-[#000000]">
-
</p>
<Button className="h-[47px] w-[207px] gap-[8px] rounded-lg bg-[#217A56] px-[22px] py-[14px] text-[16px] font-semibold leading-[19px] text-[#F5F5F5]">
Take Assessment
</Button>
</div>
<div
aria-label="tile"
className="flex h-[192px] w-[439.33px] flex-col items-center justify-center gap-[24px] rounded-[16px] bg-[#E3E5EB] p-[24px]"
>
<p
aria-label="tile-name"
className="h-[30px] w-[283px] text-center text-[25px] font-semibold leading-[30px]"
>
UX Design
</p>
<p className="h-[19px] w-[8px] text-center text-[16px] font-medium leading-[19px] text-[#000000]">
-
</p>
<Button className="h-[47px] w-[207px] gap-[8px] rounded-lg bg-[#217A56] px-[22px] py-[14px] text-[16px] font-semibold leading-[19px] text-[#F5F5F5]">
Coming Soon
</Button>
</div>
</div>
</div>
);
}
14 changes: 14 additions & 0 deletions src/app/(main)/assessment/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from "react";
// import AssessmentResults from "@/app/(main)/assessment/results/AssessmentResults";
import AssessmentForm from "@/app/(main)/assessment/form/AssessmentForm";
// import AssessmentPage from "@/app/(main)/assessment/home/AssessmentPage";

export default function AssessmentDashboard() {
return (
<div>
{/* <AssessmentResults /> */}
<AssessmentForm />
{/* <AssessmentPage /> */}
</div>
);
}
33 changes: 33 additions & 0 deletions src/app/(main)/assessment/results/AssessmentResults.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"use client";
import { useEffect, useState } from "react";
import TierDisplay from "@/app/(main)/assessment/ui/TierDisplay";
import ButtonsController from "@/app/(main)/assessment/ui/ButtonsController";
import ConfettiScreen from "@/app/(main)/assessment/ui/ConfettiScreen";
import ResultsLoading from "@/app/(main)/assessment/ui/ResultsLoading";

export default function AssessmentResultsPage() {
const [showLoading, setShowLoading] = useState(true);

useEffect(() => {
const timer = setTimeout(() => setShowLoading(false), 5000);
return () => clearTimeout(timer);
}, []);

return (
<div className="absolute left-[581px] top-[354px] flex h-[480px] w-[814px] flex-col items-center justify-center gap-[42px]">
{showLoading ? (
<ResultsLoading />
) : (
<>
<ConfettiScreen className="absolute inset-0" />
<div className="flex h-[90px] w-[650px] max-w-[650px] items-center justify-center text-center text-[25px] font-semibold leading-[30px] tracking-normal text-[#16171A]">
After analyzing your results, <br />
We&apos;ve concluded that you are a ... <br />
</div>
<TierDisplay />
<ButtonsController />
</>
)}
</div>
);
}
53 changes: 53 additions & 0 deletions src/app/(main)/assessment/ui/AssessmentStepper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Stepper } from "@chingu-x/components/stepper";
import type { SteppersItem } from "@/components/Stepper";

interface AssessmentStepperProps {
currentStep: number;
goToStep: (step: number) => void;
className: string;
}

export default function AssessmentStepper({
currentStep,
goToStep,
className = "",
}: AssessmentStepperProps) {
const totalQuestions = 60;
const questionsPerStep = 6;
const totalSteps = totalQuestions / questionsPerStep;

function getStatus(
stepId: number,
currentStep: number,
): "completed" | "current" | "remaining" {
if (stepId < currentStep) return "completed";
if (stepId > currentStep) return "remaining";
return "current";
}

const steppers: SteppersItem[] = Array.from(
{ length: totalSteps },
(_, i) => {
const stepNumber = i + 1;
const stepQuestionIndex =
stepNumber * questionsPerStep - (questionsPerStep - 1);

return {
isActive: currentStep === stepQuestionIndex,
name: `Page ${stepNumber}`,
onClickEvent: () => goToStep(stepQuestionIndex),
status: getStatus(stepQuestionIndex, currentStep),
};
},
);

const showStepper = steppers.some((step) => step.isActive);

if (!showStepper) return null;

return (
<div className={`flex justify-center text-black ${className || ""}`}>
<Stepper styleType="chips" stepperWidth="w-fit" steppers={steppers} />
</div>
);
}
29 changes: 29 additions & 0 deletions src/app/(main)/assessment/ui/ButtonsController.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { ArrowLeftIcon, ArrowRightIcon } from "@heroicons/react/20/solid";
import Link from "next/link";
import Button from "@/components/Button";
import QuizButton from "@/app/(main)/assessment/ui/QuizButton";
// import VoyagePageButton from "@/components/sidebar/VoyagePageButton";

export default function ButtonsController() {
return (
<div className="h-[150px] w-full max-w-[814px] gap-[30px]">
<Link href="/assessment/form">
<QuizButton />
</Link>
<div className="flex w-full items-center justify-center gap-[42px] rounded-tl-[16px] pt-[40px]">
<Link href="/assessment/home">
<Button className="w-full gap-[8px] border-[#217A56] !bg-[#F5F5F5] px-[26px] py-[18px] text-[20px] font-semibold text-black">
<ArrowLeftIcon className="mr-2 h-4 w-4" />
Back to Self Assessment Page
</Button>
</Link>
<Link href="/prevoyage">
<Button className="w-full gap-[8px] !bg-[#217A56] px-[26px] py-[18px] text-[20px] font-semibold">
Join an Upcoming Voyage
<ArrowRightIcon className="ml-2 h-4 w-4 text-white" />
</Button>
</Link>
</div>
</div>
);
}
16 changes: 16 additions & 0 deletions src/app/(main)/assessment/ui/ConfettiScreen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"use client";
import dynamic from "next/dynamic";
import confettiAnimation from "@/public/lotties/assessment_confetti.json";

const Lottie = dynamic(() => import("lottie-react"), { ssr: false });
interface ConfettiScreenProps {
className: string;
}

export default function ConfettiScreen({ className }: ConfettiScreenProps) {
return (
<div className={`h-full w-full ${className}`}>
<Lottie animationData={confettiAnimation} loop={false} />
</div>
);
}
26 changes: 26 additions & 0 deletions src/app/(main)/assessment/ui/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { useState } from "react";
import Button from "@/components/Button";
import AssessmentStepper from "@/app/(main)/assessment/ui/AssessmentStepper";

export default function Header() {
const [currentStep, setCurrentStep] = useState(1);

const goToStep = (step: number) => {
setCurrentStep(step);
};

return (
<div className="absolute left-0 top-0 flex w-full items-center justify-between gap-2 px-[24px]">
<Button variant="outline" className="whitespace-nowrap">
Exit Assessment
</Button>

<AssessmentStepper
className="flex h-[80px] items-center justify-center"
currentStep={currentStep}
goToStep={goToStep}
/>
<div className="text-sm text-neutral">Last saved 4 minutes ago</div>
</div>
);
}
9 changes: 9 additions & 0 deletions src/app/(main)/assessment/ui/QuizButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Button from "@/components/Button";

export default function QuizButton() {
return (
<Button className="flex w-full items-center justify-center gap-[8px] rounded-[8px] bg-[#A3CEE9] px-[26px] py-[18px] text-[20px] text-black">
Retake Quiz
</Button>
);
}
Loading