Skip to content

Commit 4460644

Browse files
authored
Merge pull request #16 from dgmstuart/multiple-word-lists-path
Load different word lists based on URL
2 parents 9fb02f7 + 5890a60 commit 4460644

File tree

9 files changed

+205
-14
lines changed

9 files changed

+205
-14
lines changed

src/App.tsx

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,55 @@
11
import React from "react";
22
import { createBrowserRouter, RouterProvider } from "react-router-dom";
33
import ContentLayout from "./layouts/ContentLayout";
4-
import Card from "./components/Card";
5-
import WordList from "./components/WordList";
6-
import wordList from "./data/teamLindyWordList.json";
4+
import Card from "./components/DynamicCard";
5+
import WordList from "./components/DynamicWordList";
76
import QRCode from "./components/QRCode";
8-
import flattenWordList from "./lib/flattenWordList";
7+
import {
8+
defaultWordListLoader,
9+
wordListLoader,
10+
} from "./loaders/wordListLoaders";
911

1012
const App: React.FC = () => {
11-
const flattenedWordList = flattenWordList(wordList);
13+
const rootPath = "/bingo-frontend";
1214

1315
const router = createBrowserRouter([
1416
{
15-
path: "/bingo-frontend",
16-
element: <Card wordList={flattenedWordList} />,
17+
path: rootPath,
18+
loader: defaultWordListLoader,
19+
element: <Card />,
1720
},
1821
{
19-
path: "/",
22+
path: rootPath,
2023
element: <ContentLayout />,
2124
children: [
2225
{
23-
path: "/bingo-frontend/word_list",
24-
element: <WordList wordList={wordList} />,
26+
path: "word_list",
27+
element: <WordList />,
28+
loader: defaultWordListLoader,
2529
},
2630
{
27-
path: "/bingo-frontend/qr_code",
31+
path: "qr_code",
32+
element: <QRCode />,
33+
},
34+
],
35+
},
36+
{
37+
path: `${rootPath}/:wordListName`,
38+
loader: wordListLoader,
39+
element: <Card />,
40+
},
41+
{
42+
path: `${rootPath}/:wordListName`,
43+
loader: wordListLoader,
44+
element: <ContentLayout />,
45+
children: [
46+
{
47+
path: "word_list",
48+
element: <WordList />,
49+
loader: wordListLoader,
50+
},
51+
{
52+
path: "qr_code",
2853
element: <QRCode />,
2954
},
3055
],

src/components/CardActions.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const CardActions: React.FC<{
2020
onClick={shareClick}
2121
activeDuration={1500}
2222
/>
23-
<Link className="QRCodeButton" to="/bingo-frontend/qr_code">
23+
<Link className="QRCodeButton" to="qr_code">
2424
<img src={qrCodeIcon} alt="QR code Icon" />
2525
</Link>
2626
</div>

src/components/DynamicCard.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import React from "react";
2+
import { useLoaderData } from "react-router-dom";
3+
import Card from "./Card";
4+
import flattenWordList from "../lib/flattenWordList";
5+
import type { WordListData } from "../data/wordList";
6+
7+
const DynamicCard: React.FC = () => {
8+
const wordList = useLoaderData() as WordListData;
9+
10+
if (wordList.length > 0) {
11+
// Card saves the word list to the session, so don't render a card if the
12+
// word list hasn't loaded yet
13+
const words = flattenWordList(wordList);
14+
return <Card wordList={words} />;
15+
}
16+
};
17+
18+
export default DynamicCard;

src/components/DynamicWordList.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import React from "react";
2+
import { useLoaderData } from "react-router-dom";
3+
import WordList from "./WordList";
4+
import type { WordListData } from "../data/wordList";
5+
6+
const DynamicWordList: React.FC = () => {
7+
const wordList = useLoaderData() as WordListData;
8+
9+
if (wordList.length > 0) {
10+
return <WordList wordList={wordList} />;
11+
}
12+
};
13+
14+
export default DynamicWordList;

src/components/Footer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const Footer: React.FC<{ className?: string }> = ({ className }) => {
88
<footer className={classNames("Footer", className)}>
99
<ul>
1010
<li>
11-
<Link to="/bingo-frontend/word_list">Full word list</Link>
11+
<Link to="word_list">Full word list</Link>
1212
</li>
1313
<li>
1414
<a

src/data/loader.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import defaultWordList from "./teamLindyWordList.json";
2+
import type { WordListData } from "./wordList";
3+
4+
export default async (listName: string): Promise<WordListData> => {
5+
let data = defaultWordList;
6+
7+
try {
8+
data = (await import(`./${listName}.json`)).default;
9+
} catch (error) {
10+
console.error("Failed to load the word list", error);
11+
}
12+
13+
return data;
14+
};

src/data/numbers.json

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
[
2+
{
3+
"title": "Numbers",
4+
"words": [
5+
{ "word": "1", "description": "Kelly's eye" },
6+
{ "word": "2", "description": "One little duck" },
7+
{ "word": "3", "description": "Cup of tea" },
8+
{ "word": "4", "description": "Knock at the door" },
9+
{ "word": "5", "description": "Man alive" },
10+
{ "word": "6", "description": "Half a dozen" },
11+
{ "word": "7", "description": "Lucky" },
12+
{ "word": "8", "description": "Garden gate" },
13+
{ "word": "9", "description": "Brighton line" },
14+
{ "word": "10", "description": "(Current Prime Minister of the United Kingdom) Rishi's den" },
15+
{ "word": "11", "description": "Legs eleven" },
16+
{ "word": "12", "description": "One dozen" },
17+
{ "word": "13", "description": "Unlucky for some" },
18+
{ "word": "14", "description": "Valentine's Day" },
19+
{ "word": "15", "description": "Young and keen" },
20+
{ "word": "16", "description": "Never been kissed" },
21+
{ "word": "17", "description": "Dancing Queen" },
22+
{ "word": "18", "description": "Coming of age" },
23+
{ "word": "19", "description": "Goodbye, teens" },
24+
{ "word": "20", "description": "score" },
25+
{ "word": "21", "description": "Key of the door" },
26+
{ "word": "22", "description": "Two little ducks" },
27+
{ "word": "23", "description": "The Lord is My Shepherd" },
28+
{ "word": "24", "description": "Two dozen" },
29+
{ "word": "25", "description": "Duck and dive" },
30+
{ "word": "26", "description": "Half a crown" },
31+
{ "word": "27", "description": "Duck and a crutch" },
32+
{ "word": "28", "description": "In a state" },
33+
{ "word": "29", "description": "Rise and shine" },
34+
{ "word": "30", "description": "Dirty Gertie" },
35+
{ "word": "31", "description": "Get up and run" },
36+
{ "word": "32", "description": "Buckle my shoe" },
37+
{ "word": "33", "description": "Dirty knee" },
38+
{ "word": "34", "description": "Ask for more" },
39+
{ "word": "35", "description": "Jump and jive" },
40+
{ "word": "36", "description": "Three dozen" },
41+
{ "word": "37", "description": "More than 11" },
42+
{ "word": "38", "description": "Christmas cake" },
43+
{ "word": "39", "description": "Steps" },
44+
{ "word": "40", "description": "Life begins" },
45+
{ "word": "41", "description": "Time for fun" },
46+
{ "word": "42", "description": "Winnie the Pooh" },
47+
{ "word": "43", "description": "Down on your knees" },
48+
{ "word": "44", "description": "Droopy drawers" },
49+
{ "word": "45", "description": "Halfway there" },
50+
{ "word": "46", "description": "Up to tricks" },
51+
{ "word": "47", "description": "Four and seven" },
52+
{ "word": "48", "description": "Four dozen" },
53+
{ "word": "49", "description": "PC" },
54+
{ "word": "50", "description": "It's a bullseye!" },
55+
{ "word": "51", "description": "Tweak of the thumb" },
56+
{ "word": "52", "description": "Deck of cards" },
57+
{ "word": "53", "description": "Here comes Herbie!" },
58+
{ "word": "54", "description": "Man at the door" },
59+
{ "word": "55", "description": "All the fives" },
60+
{ "word": "56", "description": "Shotts bus" },
61+
{ "word": "57", "description": "Heinz varieties" },
62+
{ "word": "58", "description": "Make them wait" },
63+
{ "word": "59", "description": "Brighton line" },
64+
{ "word": "60", "description": "Grandma's getting frisky" },
65+
{ "word": "61", "description": "Baker's bun" },
66+
{ "word": "62", "description": "Tickety-boo" },
67+
{ "word": "63", "description": "Tickle me" },
68+
{ "word": "64", "description": "Almost retired" },
69+
{ "word": "65", "description": "Retirement age: stop work" },
70+
{ "word": "66", "description": "Clickety click" },
71+
{ "word": "67", "description": "Stairway to Heaven" },
72+
{ "word": "68", "description": "Pick a mate" },
73+
{ "word": "69", "description": "Anyway up" },
74+
{ "word": "70", "description": "Three score and 10" },
75+
{ "word": "71", "description": "Bang on the drum" },
76+
{ "word": "72", "description": "Danny La Rue" },
77+
{ "word": "73", "description": "Queen bee" },
78+
{ "word": "74", "description": "Hit the floor" },
79+
{ "word": "75", "description": "Strive and strive" },
80+
{ "word": "76", "description": "Trombones" },
81+
{ "word": "77", "description": "Two little crutches" },
82+
{ "word": "78", "description": "39 more steps" },
83+
{ "word": "79", "description": "One more time" },
84+
{ "word": "80", "description": "Gandhi's breakfast" },
85+
{ "word": "81", "description": "Fat lady with a walking stick" },
86+
{ "word": "82", "description": "Straight on through" },
87+
{ "word": "83", "description": "Time for tea" },
88+
{ "word": "84", "description": "Give me more" },
89+
{ "word": "85", "description": "Staying alive" },
90+
{ "word": "86", "description": "Between the sticks" },
91+
{ "word": "87", "description": "Torquay in Devon" },
92+
{ "word": "88", "description": "Two fat ladies" },
93+
{ "word": "89", "description": "Nearly there" },
94+
{ "word": "90", "description": "Top of the shop" }
95+
]
96+
}
97+
]

src/layouts/ContentLayout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const ContentLayout: React.FC = () => {
77
const headerContent = (
88
<>
99
<div className="Content-actions">
10-
<Link to="/bingo-frontend">Back</Link>
10+
<Link to=".">Back</Link>
1111
</div>
1212
</>
1313
);

src/loaders/wordListLoaders.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import defaultWordList from "../data/teamLindyWordList.json";
2+
import loader from "../data/loader";
3+
import type { Params } from "react-router-dom";
4+
import type { WordListData } from "../data/wordList";
5+
6+
export const defaultWordListLoader = (): WordListData => {
7+
return defaultWordList;
8+
};
9+
10+
export const wordListLoader = async ({
11+
params,
12+
}: {
13+
params: Params<string>;
14+
}): Promise<WordListData> => {
15+
if (params.wordListName) {
16+
return await loader(params.wordListName);
17+
} else {
18+
console.error(
19+
"expected a param of 'wordListName' but didn't find one or it had a falsey value",
20+
);
21+
return [];
22+
}
23+
};

0 commit comments

Comments
 (0)