app/src/views/AddExpressionView/AddExpressionView.tsx
Thiago Chaves a8f3bbac49 Refactor hook names and make their usage more uniform
Also ensure that potential "loading" states and IndexedDB
error states are marked to be handled properly
2022-08-29 21:43:52 +03:00

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>
);
}