Skip to content
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

Add Who's branch is it anyway game page #688

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
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
49 changes: 49 additions & 0 deletions __tests__/pages/whos-branch.tests.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from "react";
import { render, screen, fireEvent } from "@testing-library/react";
import "@testing-library/jest-dom/extend-expect";
import WhosBranchPage from "@pages/whos-branch";
import Game from "@components/whos-branch";
import questions from "@data/whos-branch.json";

describe("WhosBranchPage", () => {
test("renders the breadcrumb", () => {
render(<WhosBranchPage />);
expect(screen.getByText("Home")).toBeInTheDocument();
expect(screen.getByText("Who's Branch")).toBeInTheDocument();
});

test("renders the game component", () => {
render(<WhosBranchPage />);
expect(screen.getByText(questions[0].question)).toBeInTheDocument();
});
});

describe("Game Component", () => {
test("renders the first question", () => {
render(<Game />);
expect(screen.getByText(questions[0].question)).toBeInTheDocument();
});

test("handles correct answer", () => {
render(<Game />);
const correctOption = screen.getByText(questions[0].options[0]);
fireEvent.click(correctOption);
expect(screen.getByText(questions[1].question)).toBeInTheDocument();
});

test("handles incorrect answer", () => {
render(<Game />);
const incorrectOption = screen.getByText(questions[0].options[1]);
fireEvent.click(incorrectOption);
expect(screen.getByText(questions[1].question)).toBeInTheDocument();
});

test("displays score at the end", () => {
render(<Game />);
questions.forEach((question) => {
const option = screen.getByText(question.options[0]);
fireEvent.click(option);
});
expect(screen.getByText("Your Score")).toBeInTheDocument();
});
});
14 changes: 13 additions & 1 deletion src/data/menu.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// Types for menu structure
type MenuStatus = "hot" | "coming soon" | "new";

interface MenuItem {
Expand Down Expand Up @@ -118,6 +117,19 @@ const navigation: NavigationItem[] = [
},
],
},
{
id: 7,
label: "Games",
path: "#!",
submenu: [
{
id: 71,
label: "Who's branch is it anyway",
path: "/whos-branch",
status: "new",
},
],
},
];

export default navigation;
82 changes: 82 additions & 0 deletions src/data/whos-branch-is-it-anyway/whos-branch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// data/questions.ts
import { GameData } from '../types';

export const gameData: GameData = {
"branches": [
{
"name": "Army",
"questions": [
{
"question": "What is the primary color of the Army uniform?",
"options": ["Green", "Blue", "White", "Black"],
"answer": "Green"
},
{
"question": "What is the motto of the Army?",
"options": ["Semper Fi", "This We'll Defend", "Aim High", "Always Ready"],
"answer": "This We'll Defend"
}
]
},
{
"name": "Navy",
"questions": [
{
"question": "What is the primary color of the Navy uniform?",
"options": ["Green", "Blue", "White", "Black"],
"answer": "Blue"
},
{
"question": "What is the motto of the Navy?",
"options": ["Semper Fi", "This We'll Defend", "Aim High", "Semper Fortis"],
"answer": "Semper Fortis"
}
]
},
{
"name": "Air Force",
"questions": [
{
"question": "What is the primary color of the Air Force uniform?",
"options": ["Green", "Blue", "White", "Black"],
"answer": "Blue"
},
{
"question": "What is the motto of the Air Force?",
"options": ["Semper Fi", "This We'll Defend", "Aim High", "Always Ready"],
"answer": "Aim High"
}
]
},
{
"name": "Marines",
"questions": [
{
"question": "What is the primary color of the Marines uniform?",
"options": ["Green", "Blue", "White", "Black"],
"answer": "Blue"
},
{
"question": "What is the motto of the Marines?",
"options": ["Semper Fi", "This We'll Defend", "Aim High", "Always Ready"],
"answer": "Semper Fi"
}
]
},
{
"name": "Coast Guard",
"questions": [
{
"question": "What is the primary color of the Coast Guard uniform?",
"options": ["Green", "Blue", "White", "Black"],
"answer": "Blue"
},
{
"question": "What is the motto of the Coast Guard?",
"options": ["Semper Fi", "This We'll Defend", "Aim High", "Always Ready"],
"answer": "Always Ready"
}
]
}
]
};
14 changes: 14 additions & 0 deletions src/lib/whos-branch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// lib/whos-branch.ts
import fs from "fs";
import path from "path";

export const getAllBranches = () => {
const jsonPath = path.join(process.cwd(), "src/data/whos-branch-is-it-anyway/whos-branch.json");
const jsonData = JSON.parse(fs.readFileSync(jsonPath, "utf8"));
return jsonData.branches;
};

export const getBranchByName = (name: string) => {
const branches = getAllBranches();
return branches.find((branch: any) => branch.name.toLowerCase() === name.toLowerCase());
};
6 changes: 6 additions & 0 deletions src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { NextPage } from "next";
import { GetStaticProps } from "next";
import Link from "next/link";
import SEO from "@components/seo/page-seo";
import Layout from "@layout/layout-03";
import Wrapper from "@ui/wrapper/wrapper-02";
Expand Down Expand Up @@ -68,6 +69,11 @@ const Home: PageProps = ({ data }) => {
<BlogArea data={{ ...content?.["blog-area"], blogs: data.blogs }} titleSize="large" />
<BrandArea data={content?.["brand-area"]} />
<NewsletterArea data={content?.["newsletter-area"]} />
<div className="tw-mt-10 tw-text-center">
<Link href="/whos-branch" className="tw-text-lg tw-text-primary tw-underline">
Play "Who's branch is it anyway"
</Link>
</div>
</>
);
};
Expand Down
4 changes: 2 additions & 2 deletions src/pages/subjects/[slug].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ const SingleCourse: PageProps = ({ data: { course, instructor, relatedCourses }
type: "website",
images: [
{
url: `https://maxcoach-react.pages.dev${course.thumbnail.src}`,
url: `https://vetswhocode.io${course.thumbnail.src}`,
width: 800,
height: 600,
alt: course.title,
},
{
url: `https://maxcoach-react.pages.dev${course.thumbnail.src}`,
url: `https://vetswhocode.io${course.thumbnail.src}`,
width: 900,
height: 800,
alt: course.title,
Expand Down
181 changes: 181 additions & 0 deletions src/pages/whos-branch/[branch].tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
// pages/whos-branch/[branch].tsx
import type { GetStaticPaths, NextPage } from "next";
import { useEffect, useState } from "react";
import { useRouter } from "next/router";
import { getAllBranches, getBranchByName } from "../../lib/whos-branch";

interface Question {
question: string;
options: string[];
answer: string;
}

interface Branch {
name: string;
questions: Question[];
}

type TProps = {
data: {
branch: Branch;
};
};

const BranchQuiz: NextPage<TProps> = ({ data: { branch } }) => {
const router = useRouter();
const [players, setPlayers] = useState<string[]>([]);
const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0);
const [selectedPlayer, setSelectedPlayer] = useState<string | null>(null);
const [scores, setScores] = useState<Record<string, number>>({});
const [feedback, setFeedback] = useState("");
const [showNextButton, setShowNextButton] = useState(false);

useEffect(() => {
// Get players from sessionStorage
const storedPlayers = sessionStorage.getItem("players");
if (!storedPlayers) {
router.push("/whos-branch");
return;
}
const playersList = JSON.parse(storedPlayers);
setPlayers(playersList);

// Initialize scores
const initialScores: Record<string, number> = {};
playersList.forEach((player: string) => {
initialScores[player] = 0;
});
setScores(initialScores);
}, [router]);

const handlePlayerSelect = (player: string) => {
setSelectedPlayer(player);
};

const handleAnswerClick = (selectedAnswer: string) => {
if (!selectedPlayer) {
setFeedback("Please select a player first!");
return;
}

const currentQuestion = branch.questions[currentQuestionIndex];
const isCorrect = selectedAnswer === currentQuestion.answer;

if (isCorrect) {
setScores((prev) => ({
...prev,
[selectedPlayer]: prev[selectedPlayer] + 1,
}));
setFeedback("Correct!");
} else {
setFeedback(`Wrong! The correct answer is ${currentQuestion.answer}.`);
}

setShowNextButton(true);
};

const handleNextQuestion = () => {
if (currentQuestionIndex + 1 < branch.questions.length) {
setCurrentQuestionIndex((prev) => prev + 1);
setSelectedPlayer(null);
setFeedback("");
setShowNextButton(false);
} else {
// Game over logic
setFeedback("Game Over!");
}
};

if (!branch) return null;

return (
<div className="game-container">
<h1>Who&apos;s Branch Is It Anyway?</h1>

<div id="game-area">
<p>Select the Player:</p>
<div id="player-buttons">
{players.map((player) => (
<button
key={player}
onClick={() => handlePlayerSelect(player)}
className={selectedPlayer === player ? "active" : ""}
>
{player}
</button>
))}
</div>

<p id="fact">{branch.questions[currentQuestionIndex].question}</p>

<div id="answers">
{branch.questions[currentQuestionIndex].options.map((option) => (
<button
key={option}
className="answer-btn"
onClick={() => handleAnswerClick(option)}
disabled={showNextButton}
>
{option}
</button>
))}
</div>

<p id="feedback">{feedback}</p>

{showNextButton && (
<button id="next-btn" onClick={handleNextQuestion}>
Next Question
</button>
)}

<div id="scores">
{Object.entries(scores).map(([player, score]) => (
<p key={player}>
{player}: {score}
</p>
))}
</div>
</div>
</div>
);
};

export const getStaticPaths: GetStaticPaths = async () => {
const branches = await getAllBranches();

return {
paths: branches.map((branch) => ({
params: {
branch: branch.name.toLowerCase(),
},
})),
fallback: false,
};
};

interface StaticProps {
params: {
branch: string;
};
}

export const getStaticProps = async ({ params }: StaticProps) => {
const branch = await getBranchByName(params.branch);

if (!branch) {
return {
notFound: true,
};
}

return {
props: {
data: {
branch,
},
},
};
};

export default BranchQuiz;
Loading
Loading