Skip to content

Commit

Permalink
feat: english version of 2024 questions
Browse files Browse the repository at this point in the history
  • Loading branch information
cevou committed Jun 13, 2024
1 parent 875ebfa commit 999ad09
Show file tree
Hide file tree
Showing 26 changed files with 9,736 additions and 154 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"core-js": "^3.8.3",
"i18next": "^23.11.5",
"i18next-browser-languagedetector": "^8.0.0",
"idb": "^5.0.8",
"idb": "^8.0.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-helmet-async": "^2.0.5",
Expand All @@ -45,6 +45,7 @@
"@babel/register": "^7.24.6",
"@loadable/babel-plugin": "^5.13.2",
"@loadable/webpack-plugin": "^5.14.0",
"@types/jest": "^29.5.12",
"@types/loadable__component": "^5.13.1",
"@types/loadable__server": "^5.12.3",
"@types/react": "^18.3.3",
Expand Down
102 changes: 48 additions & 54 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

99 changes: 99 additions & 0 deletions src/components/VersionPicker.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
@import "shared.css";

#version-picker {
display: flex;
position: relative;
margin: 0;
color: var(--darkblue2);
width: 5rem;
height: 2rem;
background-color: var(--white);
border-radius: 0.5rem;
border: 1px solid var(--darkblue1);
box-sizing: border-box;
cursor: pointer;

&.open {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;

& #version-picker-popup {
display: block;
}
}

&:hover {
background-color: var(--grey1);
}

@media (max-width: 48rem) {
width: 4.7rem;
}
}

#version-picker-content {
flex-grow: 1;

@media (max-width: 48rem) {
& img {
margin-right: 0;
}

& span {
display: none;
}
}
}

#version-picker-indicator {
display: flex;
font-size: 1.5rem;
width: 1rem;
margin: 0.25rem 0.5rem;
color: var(--blue3);

& svg {
display: block;
}
}

#version-picker-popup {
display: none;
position: absolute;
top: 2rem;
right: 0;
border: 1px solid var(--darkblue1);
background-color: var(--white);
margin-top: -2px;
margin-right: -1px;
padding: 0;
border-bottom-left-radius: 0.25rem;
border-bottom-right-radius: 0.25rem;
min-width: 100%;
list-style: none;
z-index: 5;

& li {
&[aria-selected=true] {
background-color: var(--grey2);
}

&:hover {
border-radius: 0.25rem;
background-color: var(--grey3);
}
}
}

#version-picker-popup img, #version-picker-content img {
height: 1.325rem;
border-radius: 0.25rem;
margin-right: 0.25rem;
}

#version-picker-popup li, #version-picker-content {
padding: 0.25rem;
line-height: 1.375rem;
display: flex;
align-content: center;
}
87 changes: 87 additions & 0 deletions src/components/VersionPicker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React, {
FunctionComponent, MouseEvent, KeyboardEvent, ReactElement, useState,
} from "react";
import "./VersionPicker.css";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faAngleDown } from "@fortawesome/free-solid-svg-icons";
import classNames from "classnames";
import { useTranslation } from "react-i18next";
import { ItemProps } from "./Item";
import { useRulesTestData } from "../context/TestDataContext";
import { AVAILABLE_LANGUAGES } from "../model/TestDataManager";

interface Props {
children: Array<ReactElement<ItemProps>>;
}

const VersionPicker: FunctionComponent<Props> = ({ children }) => {
const [open, setOpen] = useState(false);
const { t } = useTranslation();
const { version, setVersion } = useRulesTestData();

const handleTogglePopup = (event: MouseEvent) => {
event.preventDefault();
event.stopPropagation();

setOpen(!open);
};

const handleKeyDown = (event: KeyboardEvent) => {
if (event.keyCode === 32) {
setOpen(!open);
} else if (open) {
if (event.keyCode === 27 || event.keyCode === 9) {
setOpen(false);
} else {
return;
}
} else if (event.keyCode === 40) {
setOpen(true);
} else {
return;
}

event.preventDefault();
};

let content = null;
const items = React.Children.map(children, (item: ReactElement<ItemProps>) => {
const isSelected = item.props.code === version;
if (isSelected) {
content = item.props.children;
}

return React.cloneElement(item, {
selected: isSelected,
onClick: () => setVersion!(item.props.code as keyof typeof AVAILABLE_LANGUAGES),
});
});

const className = classNames({
open,
});

return (
<div
id="version-picker"
className={className}
role="listbox"
aria-label={t("app.language")}
tabIndex={0}
onClick={handleTogglePopup}
onKeyDown={handleKeyDown}
>
<div id="version-picker-content">
{content}
</div>
<div id="version-picker-indicator">
<FontAwesomeIcon icon={faAngleDown} />
</div>
<ul id="version-picker-popup">
{items}
</ul>
</div>
);
};

export default VersionPicker;
25 changes: 22 additions & 3 deletions src/components/rules-test/RulesTest.css
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
@import "../shared.css";

#test-header {
height: 1.5rem;
display: flex;
justify-content: space-between;
}

#test-header svg {
#test-header-text {
margin: 0.5rem 0;
}

#test-header svg, #error-message svg {
margin-right: 1rem;
color: #063e67;
}
Expand Down Expand Up @@ -40,12 +45,26 @@
}
}

.box-with-header > div, #test-options > div, #test-header {
.box-with-header > div, #test-options > div, #test-header, #error-message {
background-color: var(--white);
box-shadow: var(--shadow);
padding: 1rem;
}

#test-header {
padding: 0.5rem 1rem;
}

#error-message {
background-color: var(--red2);
color: var(--white);
}

#error-message svg {
color: var(--white);
}


#test-options {
margin-top: 1rem;

Expand Down
37 changes: 29 additions & 8 deletions src/components/rules-test/RulesTest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ import React, { FunctionComponent, useState, MouseEvent } from "react";
import classnames from "classnames";
import "./RulesTest.css";
import { useTranslation } from "react-i18next";
import { faChartPie } from "@fortawesome/free-solid-svg-icons";
import { faChartPie, faCircleExclamation } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useRulesTestData } from "../../context/TestDataContext";
import CheckBox from "../CheckBox";
import useAnalytics from "../../hooks/useAnalytics";
import RelevantRules from "./RelevantRules";
import VersionPicker from "../VersionPicker";
import Item from "../Item";
import us from "../../img/us.svg";
import de from "../../img/de.svg";

const RulesTest: FunctionComponent = () => {
const {
Expand All @@ -19,6 +23,7 @@ const RulesTest: FunctionComponent = () => {
correct: numCorrect,
checked: initialChecked,
reveal,
languageMissing,
} = useRulesTestData();
const [checked, setChecked] = useState<string[]>(initialChecked);

Expand Down Expand Up @@ -69,7 +74,7 @@ const RulesTest: FunctionComponent = () => {
return <div>No more question</div>;
}

const answers = question.answers[language] || [];
const answers = question.answers[languageMissing ? "en" : language] || [];
const options = Object.keys(answers).map((key) => {
const isCorrect = question.correct.includes(key);
const isChecked = checked.includes(key);
Expand All @@ -88,7 +93,7 @@ const RulesTest: FunctionComponent = () => {
/>
</div>
<div id={`test-option-${key}`} className="text">
{question?.answers[language][key]}
{question?.answers[languageMissing ? "en" : language][key]}
</div>
</div>
);
Expand All @@ -109,18 +114,34 @@ const RulesTest: FunctionComponent = () => {
return (
<>
<div id="test-header">
<FontAwesomeIcon icon={faChartPie} />
<span>{`${t("rulestest.overall")} ${numCorrect}/${numAsked} (${percentOverall}%)`}</span>
<span> - </span>
<span>{`${t("rulestest.question")} ${question.numCorrect}/${question.numAsked} (${percentQuestion}%)`}</span>
<div id="test-header-text">
<FontAwesomeIcon icon={faChartPie} />
<span>{`${t("rulestest.overall")} ${numCorrect}/${numAsked} (${percentOverall}%)`}</span>
<span> - </span>
<span>{`${t("rulestest.question")} ${question.numCorrect}/${question.numAsked} (${percentQuestion}%)`}</span>
</div>
<VersionPicker>
<Item code="ihf_05_2024">
<span>2024</span>
</Item>
<Item code="ihf_08_2019">
<span>2019</span>
</Item>
</VersionPicker>
</div>
{ languageMissing && (
<div id="error-message">
<FontAwesomeIcon icon={faCircleExclamation}/>
<span>{`${t("rulestest.language-missing")}`}</span>
</div>
)}
<form id="test-content">
<div id="test-question" className="box-with-header">
<h2>
{`${t("rulestest.question")} ${question.id}`}
</h2>
<div>
{question.question[language]}
{question.question[languageMissing ? "en" : language]}
</div>
</div>
<div id="test-options">
Expand Down
6 changes: 6 additions & 0 deletions src/context/TestDataContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from "react";
import invariant from "ts-invariant";
import Question from "../model/Question";
import { ITestResponse } from "../model";
import { AVAILABLE_LANGUAGES } from "../model/TestDataManager";

export interface TestDataContextValue {
checkAnswers?: (options: string[]) => Promise<ITestResponse>;
Expand All @@ -12,6 +13,9 @@ export interface TestDataContextValue {
checked: string[];
data: {[id: string]: Question };
reveal: boolean;
languageMissing: boolean;
version: keyof typeof AVAILABLE_LANGUAGES;
setVersion?: (version: keyof typeof AVAILABLE_LANGUAGES) => void;
}

let TestDataContext: React.Context<TestDataContextValue>;
Expand All @@ -24,6 +28,8 @@ export function getTestDataContext() {
data: {},
checked: [],
reveal: false,
languageMissing: false,
version: "ihf_05_2024",
});
}
return TestDataContext;
Expand Down
Loading

0 comments on commit 999ad09

Please sign in to comment.