Also ensure that potential "loading" states and IndexedDB error states are marked to be handled properly
168 lines
5.6 KiB
TypeScript
168 lines
5.6 KiB
TypeScript
import { useState } from "react";
|
|
import URL from "url";
|
|
import { ExpressionCard } from "../../components";
|
|
import { ExpressionDescription } from "../../components/ExpressionDescription";
|
|
import {
|
|
getWiktionaryWordLanguage,
|
|
parseWiktionaryData,
|
|
setWiktionaryWordLanguage,
|
|
} from "../../lib/wiktionary";
|
|
import { addExpressionWithRelationships, Expression } from "../../model";
|
|
|
|
export function AddExpressionView() {
|
|
const [prompt, setPrompt] = useState("");
|
|
const [language, setLanguage] = useState(getWiktionaryWordLanguage());
|
|
const [expression, setExpression] = useState<Expression | null>(null);
|
|
const [submitStatus, setSubmitStatus] =
|
|
useState<string | undefined>(undefined);
|
|
const [error, setError] = useState<any>(undefined);
|
|
|
|
// TODO waiting fetch completion elements
|
|
|
|
return (
|
|
<form className="page-with-bottom-navigation">
|
|
<section className="padding-small scroll">
|
|
<div className="padding-small">
|
|
{error ? (
|
|
<div className="notification error" key={error.message}>
|
|
<p>{error.message}</p>
|
|
</div>
|
|
) : null}
|
|
{submitStatus ? (
|
|
<div className="notification success" key={submitStatus}>
|
|
<p>{submitStatus}</p>
|
|
</div>
|
|
) : null}
|
|
</div>
|
|
{expression ? (
|
|
<ExpressionCard
|
|
prompt={expression.prompt}
|
|
categories={[]}
|
|
description={<ExpressionDescription expression={expression} />}
|
|
show_description
|
|
/>
|
|
) : (
|
|
<div className="content-query">
|
|
<label htmlFor="word-language">Language of the word: </label>
|
|
<select
|
|
value={language}
|
|
onChange={(event) => {
|
|
setWiktionaryWordLanguage(event.target.value);
|
|
setLanguage(event.target.value);
|
|
}}
|
|
id="word-language"
|
|
name="word-language"
|
|
>
|
|
<option value="Finnish">Finnish</option>
|
|
<option value="Portuguese">Portuguese</option>
|
|
<option value="Spanish">Spanish</option>
|
|
</select>
|
|
<label htmlFor="query">Word: </label>
|
|
<input
|
|
autoComplete="off"
|
|
autoSave="off"
|
|
autoCapitalize="off"
|
|
autoCorrect="off"
|
|
type="text"
|
|
id="query"
|
|
name="query"
|
|
value={prompt}
|
|
placeholder="Type card prompt here"
|
|
onChange={(event) => setPrompt(event.target.value)}
|
|
/>
|
|
</div>
|
|
)}
|
|
</section>
|
|
<section className="navigation-bottom">
|
|
{!expression ? (
|
|
<button
|
|
className="navigation-item bottom text-navigation grow"
|
|
type="submit"
|
|
value="submit"
|
|
disabled={prompt === ""}
|
|
onClick={async (event) => {
|
|
event.preventDefault();
|
|
try {
|
|
// `https://en.wiktionary.org/w/api.php?action=parse&format=json&prop=text&page=${query}`;
|
|
const url = URL.format({
|
|
protocol: "https",
|
|
hostname: "en.wiktionary.org",
|
|
pathname: "/w/api.php",
|
|
query: {
|
|
action: "parse",
|
|
format: "json",
|
|
page: prompt,
|
|
prop: "text",
|
|
origin: "*",
|
|
},
|
|
});
|
|
const result = await fetch(url);
|
|
const data = await result.json();
|
|
const expressionData = parseWiktionaryData({
|
|
prompt,
|
|
language,
|
|
data: data.parse?.text?.["*"] || "",
|
|
});
|
|
if (!expressionData)
|
|
throw new Error(
|
|
`Unable to find ${language}-language word "${prompt}" on Wiktionary`
|
|
);
|
|
setExpression(expressionData);
|
|
setError(undefined);
|
|
} catch (error) {
|
|
setError(error);
|
|
} finally {
|
|
setSubmitStatus(undefined);
|
|
}
|
|
}}
|
|
>
|
|
Fetch Wiktionary data
|
|
</button>
|
|
) : (
|
|
<>
|
|
<button
|
|
className="navigation-item bottom text-navigation grow"
|
|
type="button"
|
|
onClick={() => {
|
|
setPrompt("");
|
|
setExpression(null);
|
|
setSubmitStatus(undefined);
|
|
setError(undefined);
|
|
}}
|
|
>
|
|
Discard card
|
|
</button>
|
|
<button
|
|
className="navigation-item bottom text-navigation grow"
|
|
type="button"
|
|
onClick={async () => {
|
|
if (!expression) {
|
|
console.error("Attempted to add expression but none exists");
|
|
return;
|
|
}
|
|
try {
|
|
await addExpressionWithRelationships({
|
|
expression,
|
|
expression_set_id: 1,
|
|
category_ids: [],
|
|
});
|
|
setSubmitStatus(`Card "${expression.prompt}" saved`);
|
|
setError(undefined);
|
|
} catch (error) {
|
|
setSubmitStatus(undefined);
|
|
setError(error);
|
|
} finally {
|
|
setPrompt("");
|
|
setExpression(null);
|
|
}
|
|
}}
|
|
>
|
|
Save card
|
|
</button>
|
|
</>
|
|
)}
|
|
</section>
|
|
</form>
|
|
);
|
|
}
|