Mock data and add expression set selection page
This commit is contained in:
parent
79ba58bb36
commit
47ea97adaf
@ -17,7 +17,6 @@ const Template: ComponentStory<typeof ExpressionSetCard> = (args) => (
|
|||||||
|
|
||||||
export const Daily = Template.bind({});
|
export const Daily = Template.bind({});
|
||||||
Daily.args = {
|
Daily.args = {
|
||||||
id: 1,
|
|
||||||
name: "Daily",
|
name: "Daily",
|
||||||
description: "Words for daily practice",
|
description: "Words for daily practice",
|
||||||
word_count: 11,
|
word_count: 11,
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
export interface ExpressionSetCardProps {
|
export interface ExpressionSetCardProps {
|
||||||
id: number;
|
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
word_count: number;
|
word_count: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ExpressionSetCard({
|
export function ExpressionSetCard({
|
||||||
id,
|
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
word_count,
|
word_count,
|
||||||
|
@ -7,7 +7,7 @@ export function Navigation() {
|
|||||||
<NavigationItem
|
<NavigationItem
|
||||||
text="practice"
|
text="practice"
|
||||||
iconUrl="/icons/calendar.svg"
|
iconUrl="/icons/calendar.svg"
|
||||||
href="/practice"
|
href="/expression-sets"
|
||||||
/>
|
/>
|
||||||
<NavigationItem
|
<NavigationItem
|
||||||
text="settings"
|
text="settings"
|
||||||
|
14
src/hooks/useExpressionData.ts
Normal file
14
src/hooks/useExpressionData.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import { MockData } from "../mock";
|
||||||
|
|
||||||
|
export function useExpressionData() {
|
||||||
|
const [state] = useState(MockData);
|
||||||
|
|
||||||
|
return {
|
||||||
|
catefories: state.categories,
|
||||||
|
expressions: state.expressions,
|
||||||
|
expression_sets: state.expression_sets,
|
||||||
|
expression_to_category: state.expression_to_category,
|
||||||
|
expression_to_expression_set: state.expression_to_expression_set,
|
||||||
|
};
|
||||||
|
}
|
1
src/mock/index.ts
Normal file
1
src/mock/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from "./mock-data";
|
127
src/mock/mock-data.ts
Normal file
127
src/mock/mock-data.ts
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
import {
|
||||||
|
Category,
|
||||||
|
Expression,
|
||||||
|
ExpressionSet,
|
||||||
|
ExpressionToCategory,
|
||||||
|
ExpressionToExpressionSet,
|
||||||
|
} from "../model";
|
||||||
|
|
||||||
|
interface RawExpressionDataItem {
|
||||||
|
prompt: string;
|
||||||
|
description: string;
|
||||||
|
category: string;
|
||||||
|
expression_set: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RawExpressionSetItem {
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RawExpressionData: RawExpressionDataItem[] = [
|
||||||
|
["koira", "noun", "daily", "dog, dog paddle (swimming stroke)"],
|
||||||
|
["liite", "noun", "daily", "attachment, appendix, affix, supplement"],
|
||||||
|
["havaita", "verb", "daily", "to observe, to detect, to perceive"],
|
||||||
|
["tukea", "verb", "daily", "to support, finance, sponsor, substantiate"],
|
||||||
|
].map(([prompt, category, expression_set, description]) => ({
|
||||||
|
prompt,
|
||||||
|
description,
|
||||||
|
category,
|
||||||
|
expression_set,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const RawExpressionSetData: RawExpressionSetItem[] = [
|
||||||
|
["daily", "New expressions and poorly remembered expressions"],
|
||||||
|
["weekly", "Expressions to be reviewed at the end of the week"],
|
||||||
|
["monthly", "Expressions to be reviewed at the end of the month"],
|
||||||
|
["yearly", "Expressions to be reviewed at the end of the year"],
|
||||||
|
["ancient", "Expressions here should be memorized by now"],
|
||||||
|
].map(([name, description]) => ({ name, description }));
|
||||||
|
|
||||||
|
interface MockData {
|
||||||
|
// Tables
|
||||||
|
categories: Category[];
|
||||||
|
expressions: Expression[];
|
||||||
|
expression_sets: ExpressionSet[];
|
||||||
|
|
||||||
|
// Relationships
|
||||||
|
expression_to_category: ExpressionToCategory[];
|
||||||
|
expression_to_expression_set: ExpressionToExpressionSet[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseRawData(
|
||||||
|
raw_expression_data: RawExpressionDataItem[],
|
||||||
|
raw_expression_set_data: RawExpressionSetItem[]
|
||||||
|
): MockData {
|
||||||
|
const category_names = new Set(
|
||||||
|
raw_expression_data.map((item) => item.category)
|
||||||
|
);
|
||||||
|
const categories: Category[] = Array.from(category_names).map(
|
||||||
|
(name, index) => ({
|
||||||
|
id: index + 1,
|
||||||
|
name,
|
||||||
|
description: name,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const expressions: Expression[] = raw_expression_data.map(
|
||||||
|
({ prompt, description }, index) => ({
|
||||||
|
id: index + 1,
|
||||||
|
prompt,
|
||||||
|
description,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const expression_sets: ExpressionSet[] = raw_expression_set_data.map(
|
||||||
|
({ name, description }, index) => ({
|
||||||
|
id: index + 1,
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const expression_to_category: ExpressionToCategory[] =
|
||||||
|
raw_expression_data.map((item, index) =>
|
||||||
|
matchExpressionAndCategory(index + 1, item, categories)
|
||||||
|
);
|
||||||
|
|
||||||
|
const expression_to_expression_set: ExpressionToExpressionSet[] =
|
||||||
|
raw_expression_data.map((item, index) =>
|
||||||
|
matchExpressionAndExpressionSet(index + 1, item, expression_sets)
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
expressions,
|
||||||
|
expression_sets,
|
||||||
|
categories,
|
||||||
|
expression_to_category,
|
||||||
|
expression_to_expression_set,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchExpressionAndCategory(
|
||||||
|
expression_id: number,
|
||||||
|
{ category }: RawExpressionDataItem,
|
||||||
|
categories: Category[]
|
||||||
|
): ExpressionToCategory {
|
||||||
|
const category_id = categories.find(({ name }) => name === category)?.id || 0;
|
||||||
|
return {
|
||||||
|
category_id,
|
||||||
|
expression_id,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function matchExpressionAndExpressionSet(
|
||||||
|
expression_id: number,
|
||||||
|
{ expression_set }: RawExpressionDataItem,
|
||||||
|
expression_sets: ExpressionSet[]
|
||||||
|
): ExpressionToExpressionSet {
|
||||||
|
const expression_set_id =
|
||||||
|
expression_sets.find(({ name }) => name === expression_set)?.id || 0;
|
||||||
|
return {
|
||||||
|
expression_id,
|
||||||
|
expression_set_id,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MockData = parseRawData(RawExpressionData, RawExpressionSetData);
|
7
src/model/Category.ts
Normal file
7
src/model/Category.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export type CategoryId = number;
|
||||||
|
|
||||||
|
export type Category = {
|
||||||
|
id: CategoryId;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
};
|
7
src/model/Expression.ts
Normal file
7
src/model/Expression.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export type ExpressionId = number;
|
||||||
|
|
||||||
|
export type Expression = {
|
||||||
|
id: ExpressionId;
|
||||||
|
prompt: string;
|
||||||
|
description: string;
|
||||||
|
};
|
7
src/model/ExpressionSet.ts
Normal file
7
src/model/ExpressionSet.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export type ExpressionSetId = number;
|
||||||
|
|
||||||
|
export type ExpressionSet = {
|
||||||
|
id: ExpressionSetId;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
};
|
13
src/model/Relationships.ts
Normal file
13
src/model/Relationships.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { CategoryId } from "./Category";
|
||||||
|
import { ExpressionId } from "./Expression";
|
||||||
|
import { ExpressionSetId } from "./ExpressionSet";
|
||||||
|
|
||||||
|
export type ExpressionToCategory = {
|
||||||
|
expression_id: ExpressionId;
|
||||||
|
category_id: CategoryId;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ExpressionToExpressionSet = {
|
||||||
|
expression_id: ExpressionId;
|
||||||
|
expression_set_id: ExpressionSetId;
|
||||||
|
};
|
4
src/model/index.ts
Normal file
4
src/model/index.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export * from "./Category";
|
||||||
|
export * from "./Expression";
|
||||||
|
export * from "./ExpressionSet";
|
||||||
|
export * from "./Relationships";
|
37
src/pages/expression-sets.tsx
Normal file
37
src/pages/expression-sets.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import type { NextPage } from "next";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { ExpressionSetCard } from "../components/ExpressionSetCard";
|
||||||
|
import { Page } from "../components/Page";
|
||||||
|
import { useExpressionData } from "../hooks/useExpressionData";
|
||||||
|
|
||||||
|
const ExpressionSetsPage: NextPage = () => {
|
||||||
|
const { expression_sets, expression_to_expression_set } = useExpressionData();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Page>
|
||||||
|
<div className="content-list">
|
||||||
|
{expression_sets.map(({ id, name, description }) => (
|
||||||
|
<Link
|
||||||
|
key={id}
|
||||||
|
href={{ pathname: "/practice", query: { "set-id": id } }}
|
||||||
|
passHref
|
||||||
|
>
|
||||||
|
<a>
|
||||||
|
<ExpressionSetCard
|
||||||
|
name={name}
|
||||||
|
description={description}
|
||||||
|
word_count={
|
||||||
|
expression_to_expression_set.filter(
|
||||||
|
(item) => item.expression_set_id === id
|
||||||
|
).length
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Page>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ExpressionSetsPage;
|
@ -19,6 +19,16 @@
|
|||||||
display: block;
|
display: block;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
/* Will it conflict with overlays? Move elsewhere? */
|
||||||
|
padding: 16px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-list {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-gap: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Navigation */
|
/* Navigation */
|
||||||
|
Loading…
Reference in New Issue
Block a user