Draft functionality for fetching card data from Wiktionary
This commit is contained in:
parent
ec836a8465
commit
f19f2d5601
@ -12,7 +12,7 @@ export function Navigation() {
|
|||||||
<NavigationItem
|
<NavigationItem
|
||||||
text="settings"
|
text="settings"
|
||||||
iconUrl="/icons/check.svg"
|
iconUrl="/icons/check.svg"
|
||||||
href="/check"
|
href="/settings"
|
||||||
/>
|
/>
|
||||||
</nav>
|
</nav>
|
||||||
);
|
);
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -154,6 +154,15 @@ export async function addExpressionWithRelationships({
|
|||||||
expression_set_id,
|
expression_set_id,
|
||||||
category_ids,
|
category_ids,
|
||||||
}: addExpressionWithRelationshipsParams) {
|
}: addExpressionWithRelationshipsParams) {
|
||||||
|
const existing = await database.expressions
|
||||||
|
.where("prompt")
|
||||||
|
.equals(expression.prompt)
|
||||||
|
.first();
|
||||||
|
if (existing) {
|
||||||
|
const error_message = `Expression ${expression.prompt} already exists in database`;
|
||||||
|
console.error(error_message);
|
||||||
|
throw new Error(error_message);
|
||||||
|
}
|
||||||
return await database.transaction(
|
return await database.transaction(
|
||||||
"rw",
|
"rw",
|
||||||
database.expressions,
|
database.expressions,
|
||||||
@ -165,9 +174,11 @@ export async function addExpressionWithRelationships({
|
|||||||
expression_id,
|
expression_id,
|
||||||
expression_set_id,
|
expression_set_id,
|
||||||
});
|
});
|
||||||
database.expression_to_category.bulkAdd(
|
if (category_ids.length) {
|
||||||
category_ids.map((category_id) => ({ expression_id, category_id }))
|
database.expression_to_category.bulkAdd(
|
||||||
);
|
category_ids.map((category_id) => ({ expression_id, category_id }))
|
||||||
|
);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -8,8 +8,8 @@ export function parseWiktionaryData(
|
|||||||
if (typeof window === "undefined") return null;
|
if (typeof window === "undefined") return null;
|
||||||
|
|
||||||
const parser = new DOMParser();
|
const parser = new DOMParser();
|
||||||
const description = JSON.parse(data).parse.text["*"];
|
console.log("Parsing", data);
|
||||||
const document = parser.parseFromString(description, "text/html");
|
const document = parser.parseFromString(data, "text/html");
|
||||||
|
|
||||||
// TODO settings-based language selection
|
// TODO settings-based language selection
|
||||||
const header = document.getElementById("Finnish")?.parentElement;
|
const header = document.getElementById("Finnish")?.parentElement;
|
||||||
|
18
src/pages/settings/add-expression.tsx
Normal file
18
src/pages/settings/add-expression.tsx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import type { NextPage } from "next";
|
||||||
|
import dynamic from "next/dynamic";
|
||||||
|
import { Page } from "../../components";
|
||||||
|
import { AddExpressionView } from "../../views/AddExpressionView";
|
||||||
|
|
||||||
|
const PageTitle = "Settings - Add expression";
|
||||||
|
|
||||||
|
const AddExpressionPage: NextPage = () => {
|
||||||
|
return (
|
||||||
|
<Page title={PageTitle}>
|
||||||
|
<AddExpressionView />
|
||||||
|
</Page>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default dynamic(() => Promise.resolve(AddExpressionPage), {
|
||||||
|
ssr: false,
|
||||||
|
});
|
3
src/pages/settings/index.tsx
Normal file
3
src/pages/settings/index.tsx
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import AddExpressionPage from "./add-expression";
|
||||||
|
|
||||||
|
export default AddExpressionPage;
|
@ -40,6 +40,13 @@
|
|||||||
line-height: 1.3rem;
|
line-height: 1.3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-error {
|
||||||
|
color: brown;
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 11px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
/* Page */
|
/* Page */
|
||||||
|
|
||||||
.page {
|
.page {
|
||||||
@ -106,6 +113,10 @@
|
|||||||
background-color: bisque;
|
background-color: bisque;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.navigation-item:disabled {
|
||||||
|
background-color: slategray;
|
||||||
|
}
|
||||||
|
|
||||||
.icon-button {
|
.icon-button {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -146,6 +157,17 @@
|
|||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content-query {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin: auto;
|
||||||
|
padding: 30px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-query > label {
|
||||||
|
margin: 10px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Margins and paddings */
|
/* Margins and paddings */
|
||||||
|
|
||||||
.padding-small {
|
.padding-small {
|
||||||
|
127
src/views/AddExpressionView/AddExpressionView.tsx
Normal file
127
src/views/AddExpressionView/AddExpressionView.tsx
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import URL from "url";
|
||||||
|
import { ExpressionCard } from "../../components";
|
||||||
|
import { ExpressionDescription } from "../../components/ExpressionDescription";
|
||||||
|
import {
|
||||||
|
addExpression,
|
||||||
|
addExpressionWithRelationships,
|
||||||
|
Expression,
|
||||||
|
} from "../../model";
|
||||||
|
import { parseWiktionaryData } from "../../model/parseWiktionaryData";
|
||||||
|
|
||||||
|
export function AddExpressionView() {
|
||||||
|
const [prompt, setPrompt] = useState("");
|
||||||
|
const [expression, setExpression] = useState<Expression | null>(null);
|
||||||
|
const [submitStatus, setSubmitStatus] = useState<string | undefined>(
|
||||||
|
undefined
|
||||||
|
);
|
||||||
|
const [error, setError] = useState<any>(undefined);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="page-with-bottom-navigation">
|
||||||
|
<section className="padding-small scroll">
|
||||||
|
<div className="padding-small">
|
||||||
|
{error ? <p className="text-error">{error.message}</p> : null}
|
||||||
|
{submitStatus ? <p className="text-meta">{submitStatus}</p> : null}
|
||||||
|
</div>
|
||||||
|
{expression ? (
|
||||||
|
<ExpressionCard
|
||||||
|
prompt={expression.prompt}
|
||||||
|
categories={[]}
|
||||||
|
description={<ExpressionDescription expression={expression} />}
|
||||||
|
show_description
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div className="content-query">
|
||||||
|
<label htmlFor="query">Word: </label>
|
||||||
|
<input
|
||||||
|
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"
|
||||||
|
disabled={prompt === ""}
|
||||||
|
onClick={async () => {
|
||||||
|
try {
|
||||||
|
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();
|
||||||
|
setExpression(
|
||||||
|
parseWiktionaryData(prompt, data.parse?.text?.["*"] || "")
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
setError(error);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Fetch Wiktionary data
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
className="navigation-item bottom text-navigation grow"
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
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: [],
|
||||||
|
});
|
||||||
|
setExpression(null);
|
||||||
|
setSubmitStatus(`Card "${expression.prompt}" saved`);
|
||||||
|
setError(undefined);
|
||||||
|
} catch (error) {
|
||||||
|
setSubmitStatus(undefined);
|
||||||
|
setError(error);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Save card
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildUrl(query: string) {
|
||||||
|
return `https://en.wiktionary.org/w/api.php?action=parse&format=json&prop=text&page=${query}`;
|
||||||
|
}
|
1
src/views/AddExpressionView/index.ts
Normal file
1
src/views/AddExpressionView/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from "./AddExpressionView";
|
@ -35,6 +35,7 @@ export function ExpressionPracticeCardView({
|
|||||||
) : (
|
) : (
|
||||||
<button
|
<button
|
||||||
className="navigation-item bottom text-navigation grow"
|
className="navigation-item bottom text-navigation grow"
|
||||||
|
type="button"
|
||||||
onClick={() => setRevealed(true)}
|
onClick={() => setRevealed(true)}
|
||||||
>
|
>
|
||||||
Reveal
|
Reveal
|
||||||
|
Loading…
Reference in New Issue
Block a user