/** * Copyright (c) 2021 lingdocs.com * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * */ import { useEffect, useReducer } from "react"; import VerbInfo from "./verb-info/VerbInfo"; import VerbFormDisplay from "./VerbFormDisplay"; import ButtonSelect from "./ButtonSelect"; import Hider from "./Hider"; import { getForms } from "../lib/conjugation-forms"; import PersonSelection from "./PersonSelection"; import { personIsAllowed, randomPerson, incrementPerson, parseEc, } from "../lib/misc-helpers"; import * as T from "../types"; const VerbChoiceWarning = () => ( <>
Choose which way to use it:
> ); const stateLocalStorageName = "explorerState6"; type Difficulty = "beginner" | "advanced"; // remember to increment the stateLocalStorageName whenever changing // the State type type State = { mode: "chart" | "sentence"; subject: T.Person, object: T.Person, negative: boolean, compoundTypeSelected: "stative" | "dynamic"; transitivitySelected: "transitive" | "grammatically transitive"; compoundComplementVersionSelected: "sing" | "plur"; showingStemsAndRoots: boolean; difficulty: Difficulty; formsOpened: string[]; showingFormInfo: boolean; } type Action = { type: "choose compound type", payload: "stative" | "dynamic", } | { type: "set forms opened", payload: string, } | { type: "set difficulty", payload: Difficulty, } | { type: "set compound complement version", payload: "sing" | "plur", } | { type: "toggle showingStemsAndRoots", } | { type: "setState", payload: State, } | { type: "setMode", payload: "chart" | "sentence", } | { type: "setPerson", payload: { setting: "subject" | "object", person: T.Person }, } | { type: "randomPerson", payload: "subject" | "object", } | { type: "setShowingFormInfo", payload: boolean, } | { type: "setTransitivitySelected", payload: "transitive" | "grammatically transitive", } | { type: "setNegative", payload: boolean, }; function oppositeRole(x: "subject" | "object"): "subject" | "object" { return x === "subject" ? "object" : "subject"; } function reducer(state: State, action: Action): State { function applyFormOpen( payload: string, formsOpened: string[], ): string[] { if (formsOpened.includes(payload)) { return formsOpened.filter((f) => f !== payload); } return [...formsOpened, payload]; } function setPerson({ setting, person }: { setting: "subject" | "object", person: T.Person }): State { let newPerson = person; let otherPerson = state[oppositeRole(setting)]; let otherSetting = oppositeRole(setting); while (!personIsAllowed(newPerson, otherPerson)) { otherPerson = incrementPerson(otherPerson); } return { ...state, [setting]: newPerson, [otherSetting]: otherPerson }; } switch(action.type) { case "choose compound type": return { ...state, compoundTypeSelected: action.payload }; case "set forms opened": return { ...state, formsOpened: applyFormOpen(action.payload, state.formsOpened), }; case "set difficulty": return { ...state, difficulty: action.payload }; case "set compound complement version": return { ...state, compoundComplementVersionSelected: action.payload }; case "toggle showingStemsAndRoots": return { ...state, showingStemsAndRoots: !state.showingStemsAndRoots }; case "setState": return action.payload; case "setMode": return { ...state, mode: action.payload }; case "setPerson": return setPerson(action.payload); case "randomPerson": return { ...state, [action.payload]: randomPerson( state[action.payload === "subject" ? "object" : "subject"] ), }; case "setShowingFormInfo": return { ...state, showingFormInfo: action.payload, }; case "setTransitivitySelected": return { ...state, transitivitySelected: action.payload, }; case "setNegative": return { ...state, negative: action.payload, }; default: throw new Error(); } } const initialState: State = { subject: 0, object: 2, negative: false, compoundTypeSelected: "stative", transitivitySelected: "transitive", mode: "chart", compoundComplementVersionSelected: "plur", difficulty: "beginner", showingStemsAndRoots: false, showingFormInfo: false, formsOpened: [], }; function ConjugationViewer({ conjugation, textOptions, ec, ep }: { conjugation: T.VerbOutput, textOptions: T.TextOptions, ec?: string | undefined, ep?: string | undefined, }) { const [state, dispatch] = useReducer(reducer, initialState); useEffect(() => { const stateRaw = localStorage.getItem(stateLocalStorageName); if (stateRaw) { try { const payload = JSON.parse(stateRaw) as State; dispatch({ type: "setState", payload }); } catch (e) { console.error("error parsing saved state JSON", e); } } }, []); const verbConj1 = ("dynamic" in conjugation) ? conjugation[state.compoundTypeSelected] : ("transitive" in conjugation) ? conjugation[state.transitivitySelected === "transitive" ? "transitive" : "grammaticallyTransitive"] : conjugation; const verbConj = (verbConj1.singularForm && state.compoundComplementVersionSelected === "sing") ? verbConj1.singularForm : verbConj1; const englishConjugation: T.EnglishVerbConjugation | undefined = ec ? { ec: parseEc(ec), ep: ep, } : undefined; useEffect(() => { localStorage.setItem(stateLocalStorageName, JSON.stringify(state)); }); const filterDifficulty = (f: T.DisplayForm): boolean => ( state.difficulty === "advanced" || !f.advanced ); const forms = getForms({ conj: verbConj, filterFunc: filterDifficulty, mode: state.mode, subject: state.subject, object: state.object, negative: state.negative, englishConjugation, }); return