Skip to content

Commit 4d06b02

Browse files
authored
Merge pull request #2 from roadrules-am/dev
added cards list
2 parents e9f6cd2 + d749cdb commit 4d06b02

6 files changed

Lines changed: 132 additions & 22 deletions

File tree

app/card/card.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export default function Card({
6464
/>
6565
<div className="mt-8">
6666
<TelegramComments
67+
key={cardUuid}
6768
websiteKey={"yqxQuEh8"}
6869
useDarkMode={isDarkMode}
6970
wrapperClassName="TGCommentsWidget"

app/cardsGrid/cardsGrid.tsx

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { useEffect, useState } from "react";
2+
import type { Card, CardStore } from "~/hooks/useCardStore";
3+
4+
type CardsGridProps = {
5+
cards: CardStore;
6+
};
7+
8+
export default function CardsGrid({ cards }: CardsGridProps) {
9+
const [activeTab, setActiveTab] = useState<number | undefined>(undefined);
10+
const cardGroups: { id: number; cards: Card[] }[] = [];
11+
const groups = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
12+
13+
for (const groupId of groups) {
14+
const cardsInGroup = Object.values(cards)
15+
.filter((card) => card.groupId === groupId)
16+
.sort((a, b) => a.cardId - b.cardId);
17+
if (cardsInGroup.length < 0) continue;
18+
cardGroups.push({
19+
id: groupId,
20+
cards: cardsInGroup,
21+
});
22+
}
23+
24+
useEffect(() => {
25+
setActiveTab(cardGroups[0].id);
26+
}, []);
27+
28+
function handleTabClick(groupId: number) {
29+
setActiveTab(groupId);
30+
}
31+
32+
return (
33+
<div className="w-full">
34+
{cardGroups.map((group) => {
35+
if (!group.cards) return null;
36+
return (
37+
<button
38+
type="button"
39+
key={group.id}
40+
onClick={() => handleTabClick(group.id)}
41+
>
42+
{group.id}
43+
</button>
44+
);
45+
})}
46+
47+
{/* Tab Content */}
48+
{cardGroups.map((group) => (
49+
<div
50+
className="flex flex-wrap flex-row justify-start p-2"
51+
key={group.id}
52+
style={{ display: activeTab === group.id ? "flex" : "none" }}
53+
>
54+
{group.cards.map((card) => {
55+
let color: string = "";
56+
const opacity = Math.floor(
57+
100 - (card.forgetProbability / 0.7) * 100,
58+
);
59+
if (card.forgetProbability > 0.7 && card.correctStreak !== null)
60+
color =
61+
"border-red-300 dark:border-red-700 rounded-full border-2";
62+
if (card.forgetProbability <= 0.7)
63+
color = `bg-green-300 dark:bg-green-700 rounded-sm opacity-[.${opacity}]`; // not working for some values!!
64+
return (
65+
<div
66+
key={card.cardId}
67+
className={`flex-none w-9 h-9 m-[calc((100%-288px)/16)] flex items-center justify-center ${color}`}
68+
>
69+
<a href={`/questions/${card.groupId}-${card.cardId}`}>
70+
{card.cardId}
71+
</a>
72+
</div>
73+
);
74+
})}
75+
</div>
76+
))}
77+
</div>
78+
);
79+
}

app/hooks/useCardStore.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { persist, createJSONStorage } from "zustand/middleware";
22
import { create } from "zustand";
33
import cards from "~/cardsData/cards";
44

5-
type Card = {
5+
export type Card = {
66
question: string;
77
answerOptions: string[];
88
correctId: number;
@@ -13,16 +13,18 @@ type Card = {
1313
forgetProbability: number;
1414
};
1515

16-
type CardStore = {
17-
cards: Record<string, Card>;
18-
};
16+
export type CardStore = Record<string, Card>;
1917
type CardActions = {
2018
getCardById: (cardId: string) => Card | undefined;
2119
setCardFP: (cardId: string, newFP: number) => void;
2220
setCardStreak: (cardId: string, newStreak: number) => void;
2321
};
2422

25-
export const useCardStore = create<CardStore & CardActions>()(
23+
type CardStoreFull = {
24+
cards: CardStore;
25+
} & CardActions;
26+
27+
export const useCardStore = create<CardStoreFull>()(
2628
persist(
2729
(set, get) => ({
2830
cards: getInitialState(cards),

app/routes.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import type { RouteConfig } from "@react-router/dev/routes";
2-
import { index, route } from "@react-router/dev/routes";
2+
import { route } from "@react-router/dev/routes";
33

44
export default [
5-
index("routes/home.tsx"),
6-
// route("/questions", "routes/questions.tsx"),
7-
route("/questions/:questionId", "routes/question.tsx"),
5+
route("/", "routes/home.tsx", [
6+
route("/questions/:questionId", "routes/question.tsx"),
7+
route("/questions/", "routes/questions.tsx"),
8+
]),
89
] satisfies RouteConfig;

app/routes/home.tsx

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { useEffect } from "react";
2-
import type { Route } from "./+types/home";
3-
import { useNavigate } from "react-router";
2+
import { Outlet, useLocation, useNavigate } from "react-router";
43
import getNextCardUUID from "~/lib/getNextCard";
4+
import type { Route } from "./+types/home";
55

6-
export function meta({}: Route.MetaArgs) {
6+
export function meta() {
77
return [
88
{ title: "Тренажёр ПДД – roadrules-am" },
99
{
@@ -13,17 +13,21 @@ export function meta({}: Route.MetaArgs) {
1313
];
1414
}
1515

16-
export async function loader({ context }: Route.LoaderArgs) {
17-
const cardId = getNextCardUUID();
18-
return cardId;
19-
}
20-
21-
export default function Home({}: Route.ComponentProps) {
16+
export default function Home() {
17+
const location = useLocation();
2218
const navigate = useNavigate();
23-
const cardId = getNextCardUUID();
2419
useEffect(() => {
25-
navigate(`/questions/${cardId}`);
26-
}, [cardId, navigate]);
20+
if (location.pathname === "/") {
21+
const cardId = getNextCardUUID();
22+
navigate(`/questions/${cardId}`);
23+
}
24+
}, [navigate, location]);
2725

28-
return <p>Загрузка</p>;
26+
return (
27+
<div>
28+
<a href="/">Тренажёр</a>
29+
<a href="/questions">Вопросы</a>
30+
<Outlet />
31+
</div>
32+
);
2933
}

app/routes/questions.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import CardsGrid from "~/cardsGrid/cardsGrid";
2+
import type { Route } from "./+types/questions";
3+
import { cardStore } from "~/hooks/useCardStore";
4+
5+
export function meta() {
6+
return [
7+
{ title: "Вопросы – roadrules-am" },
8+
{
9+
name: "description",
10+
content: "Подготовься к теоретическому экзамену в Армении",
11+
},
12+
];
13+
}
14+
15+
export async function clientLoader() {
16+
const { cards } = cardStore.getState();
17+
return cards;
18+
}
19+
20+
export default function Questions({ loaderData }: Route.ComponentProps) {
21+
const cards = loaderData;
22+
return <CardsGrid cards={cards} />;
23+
}

0 commit comments

Comments
 (0)