57 lines
1.7 KiB
TypeScript
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}
|
|
/>
|
|
);
|
|
}
|