app/src/views/ExpressionPracticeView/ExpressionPracticeView.tsx

57 lines
1.7 KiB
TypeScript

import { useMemo } from "react";
import {
useCategoriesByExpressionId,
useQueryExpressionIdFilters,
useQueryExpressionSetId,
useExpressionsByExpressionSetId,
} from "../../hooks";
import { IndexedExpression } from "../../model";
import { sample } from "../../util";
import { ErrorView } from "../ErrorView";
import { LoadingView } from "../LoadingView/LoadingView";
import { ExpressionPracticeCardView } from "./ExpressionPracticeCardView";
export function ExpressionPracticeView() {
const expression_set_id = useQueryExpressionSetId();
const filter_ids = useQueryExpressionIdFilters();
const expressions = useExpressionsByExpressionSetId(expression_set_id);
// TODO handle errors
if (!expressions) return <LoadingView />;
const filtered_expressions = expressions.filter(
(expression) => !filter_ids.includes(expression.id!)
);
if (!filtered_expressions.length) {
return <ErrorView message="No expressions left in this set" />;
}
return (
<ExpressionPracticeViewImpl
select_from_expressions={filtered_expressions}
/>
);
}
interface ExpressionPracticeViewImplProps {
select_from_expressions: IndexedExpression[];
}
function ExpressionPracticeViewImpl({
select_from_expressions: expressions,
}: ExpressionPracticeViewImplProps) {
const expression = useMemo(() => sample(expressions), [expressions]);
const categories = useCategoriesByExpressionId(expression.id!);
if (!categories) return null; // Loading
// Delegate internal interaction state to next component so it resets
// on an expression switch
return (
<ExpressionPracticeCardView
key={expression.id}
expression={expression}
categories={categories}
/>
);
}