From 84935724240f3da772df54a131c56d22a155424d Mon Sep 17 00:00:00 2001 From: Orkhan Ashrafov <70017511+webofpies@users.noreply.github.com> Date: Fri, 7 Feb 2025 01:33:03 +0400 Subject: [PATCH] refactor: language and new book forms --- .../components/NewBookForm/NewBookForm.jsx | 86 ++----------------- .../components/ImportURLInfoPopup.jsx | 28 ++++++ .../src/features/book/hooks/useNewBookForm.js | 31 +++++++ .../components/LanguageForm/LanguageForm.jsx | 75 +++------------- .../language/hooks/useLanguageForm.js | 38 ++++++++ .../language/hooks/useSelectedLanguage.js | 36 ++++++++ frontend/src/pages/LanguagesPage.jsx | 17 ++++ frontend/src/pages/NewBookPage.jsx | 41 ++++++++- 8 files changed, 204 insertions(+), 148 deletions(-) create mode 100644 frontend/src/features/book/components/NewBookForm/components/ImportURLInfoPopup.jsx create mode 100644 frontend/src/features/book/hooks/useNewBookForm.js create mode 100644 frontend/src/features/language/hooks/useLanguageForm.js create mode 100644 frontend/src/features/language/hooks/useSelectedLanguage.js diff --git a/frontend/src/features/book/components/NewBookForm/NewBookForm.jsx b/frontend/src/features/book/components/NewBookForm/NewBookForm.jsx index b81361dd..35521a09 100644 --- a/frontend/src/features/book/components/NewBookForm/NewBookForm.jsx +++ b/frontend/src/features/book/components/NewBookForm/NewBookForm.jsx @@ -1,21 +1,15 @@ import { useNavigate, useSearchParams } from "react-router-dom"; import { useMutation, useQuery } from "@tanstack/react-query"; -import { useForm } from "@mantine/form"; import { notifications } from "@mantine/notifications"; import { - ActionIcon, Button, Fieldset, FileInput, Group, NumberInput, - Paper, - Popover, - rem, Select, Stack, TagsInput, - Text, Textarea, TextInput, } from "@mantine/core"; @@ -26,21 +20,19 @@ import { IconHeading, IconHeadphones, IconLink, - IconQuestionMark, - IconSquareRoundedPlusFilled, IconTags, IconWorldWww, } from "@tabler/icons-react"; -import LanguageCards from "@language/components/LanguageCards/LanguageCards"; import FormButtons from "@common/FormButtons/FormButtons"; import { userLanguageQuery } from "@language/api/query"; import { initialQuery } from "@settings/api/settings"; import { errorMessage } from "@resources/notifications"; import { createBook, getBookDataFromUrl } from "../../api/api"; -import { getFormDataFromObj } from "@actions/utils"; +import useNewBookForm from "@book/hooks/useNewBookForm"; +import ImportURLInfoPopup from "./components/ImportURLInfoPopup"; import classes from "./NewBookForm.module.css"; -function NewBookForm({ openDrawer }) { +function NewBookForm() { const navigate = useNavigate(); const [params] = useSearchParams(); const langId = params.get("langId"); @@ -49,43 +41,7 @@ function NewBookForm({ openDrawer }) { const { data: initial } = useQuery(initialQuery); const dir = language?.right_to_left ? "rtl" : "ltr"; - const form = useForm({ - initialValues: { - language_id: "", - title: "", - text: "", - importurl: "", - text_file: undefined, - audio_file: undefined, - threshold_page_tokens: 250, - split_by: "paragraphs", - source_uri: "", - book_tags: [], - }, - transformValues: (values) => { - const data = { - ...values, - language_id: Number(langId), - }; - - return getFormDataFromObj(data); - }, - }); - - const cardsRadioLabel = ( - - - Language - - - - - - ); + const form = useNewBookForm(langId); const createBookMutation = useMutation({ mutationFn: createBook, @@ -108,14 +64,6 @@ function NewBookForm({ openDrawer }) {
- {initial.haveLanguages ? ( - - ) : ( - cardsRadioLabel - )} } - rightSection={} + rightSection={} key={form.key("importurl")} {...form.getInputProps("importurl")} /> @@ -254,28 +202,4 @@ function NewBookForm({ openDrawer }) { ); } -function ImportURLInfo() { - return ( - - - - - - - - -

- This import is very primitive -- it grabs all the headings - and text from an HTML page. -

-

- This will likely include stuff you don't want. You are able to - edit the resulting text -

-
-
-
- ); -} - export default NewBookForm; diff --git a/frontend/src/features/book/components/NewBookForm/components/ImportURLInfoPopup.jsx b/frontend/src/features/book/components/NewBookForm/components/ImportURLInfoPopup.jsx new file mode 100644 index 00000000..cb9d5720 --- /dev/null +++ b/frontend/src/features/book/components/NewBookForm/components/ImportURLInfoPopup.jsx @@ -0,0 +1,28 @@ +import { ActionIcon, Paper, Popover, rem } from "@mantine/core"; +import { IconQuestionMark } from "@tabler/icons-react"; + +function ImportURLInfoPopup() { + return ( + + + + + + + + +

+ This import is very primitive -- it grabs all the headings + and text from an HTML page. +

+

+ This will likely include stuff you don't want. You are able to + edit the resulting text +

+
+
+
+ ); +} + +export default ImportURLInfoPopup; diff --git a/frontend/src/features/book/hooks/useNewBookForm.js b/frontend/src/features/book/hooks/useNewBookForm.js new file mode 100644 index 00000000..b695539c --- /dev/null +++ b/frontend/src/features/book/hooks/useNewBookForm.js @@ -0,0 +1,31 @@ +import { useForm } from "@mantine/form"; +import { getFormDataFromObj } from "@actions/utils"; + +function useNewBookForm(langId) { + const form = useForm({ + initialValues: { + language_id: "", + title: "", + text: "", + importurl: "", + text_file: undefined, + audio_file: undefined, + threshold_page_tokens: 250, + split_by: "paragraphs", + source_uri: "", + book_tags: [], + }, + transformValues: (values) => { + const data = { + ...values, + language_id: Number(langId), + }; + + return getFormDataFromObj(data); + }, + }); + + return form; +} + +export default useNewBookForm; diff --git a/frontend/src/features/language/components/LanguageForm/LanguageForm.jsx b/frontend/src/features/language/components/LanguageForm/LanguageForm.jsx index 71b95f79..eb16a27c 100644 --- a/frontend/src/features/language/components/LanguageForm/LanguageForm.jsx +++ b/frontend/src/features/language/components/LanguageForm/LanguageForm.jsx @@ -1,7 +1,6 @@ import { useEffect } from "react"; import { useQuery } from "@tanstack/react-query"; -import { useLocation, useSearchParams } from "react-router-dom"; -import { useForm } from "@mantine/form"; +import { useSearchParams } from "react-router-dom"; import { randomId } from "@mantine/hooks"; import { Box, @@ -21,76 +20,28 @@ import { } from "@tabler/icons-react"; import FormButtons from "@common/FormButtons/FormButtons"; import LanguageSelect from "./LanguageSelect"; -import LanguageCards from "../LanguageCards/LanguageCards"; import DictionaryBars from "./components/DictionaryBars"; -import LanguageRadioLabel from "./components/LanguageRadioLabel"; import InsertDictionaryButton from "./components/InsertDictionaryButton"; -import { - parsersQuery, - userLanguageQuery, - predefinedLanguageQuery, -} from "../../api/query"; -import { initialQuery } from "@settings/api/settings"; +import useSelectedLanguage from "@language/hooks/useSelectedLanguage"; +import useLanguageForm from "@language/hooks/useLanguageForm"; +import { parsersQuery } from "../../api/query"; import classes from "./LanguageForm.module.css"; function LanguageForm() { - const { pathname } = useLocation(); const [params] = useSearchParams(); - const openedFromLanguages = pathname === "/languages"; const langId = params.get("langId"); - const predefinedSelected = langId === "0"; - const predefSettingsQuery = useQuery( - predefinedLanguageQuery(params.get("name", null)) - ); - const defSettingsQuery = useQuery(userLanguageQuery(langId)); const { data: parsers } = useQuery(parsersQuery); - const { data: initial } = useQuery(initialQuery); - - const form = useForm({ - mode: "uncontrolled", - initialValues: { - character_substitutions: "´='|`='|’='|‘='|...=…|..=‥", - split_sentences: ".!?", - split_sentence_exceptions: "Mr.|Mrs.|Dr.|[A-Z].|Vd.|Vds.", - word_chars: "a-zA-ZÀ-ÖØ-öø-ȳáéíóúÁÉÍÓÚñÑ", - right_to_left: false, - show_romanization: false, - parser_type: "spacedel", - // minimum dictionaries should be defined on backend with other settings - dictionaries: [ - { - for: "terms", - type: "embedded", - url: "", - active: true, - key: randomId(), - }, - { - for: "sentences", - type: "popup", - url: "", - active: true, - key: randomId(), - }, - ], - }, - }); + const { language, isSuccess } = useSelectedLanguage(); - useEffect(() => { - if (predefSettingsQuery.isSuccess && params.get("name", null)) { - const { dictionaries, ...rest } = predefSettingsQuery.data; - setFormValues(rest, dictionaries); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [predefSettingsQuery.data, predefSettingsQuery.isSuccess]); + const form = useLanguageForm(); useEffect(() => { - if (defSettingsQuery.isSuccess && openedFromLanguages) { - const { dictionaries, ...rest } = defSettingsQuery.data; + if (isSuccess && language) { + const { dictionaries, ...rest } = language; setFormValues(rest, dictionaries); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [defSettingsQuery.data, defSettingsQuery.isSuccess]); + }, [language, isSuccess]); useEffect(() => { if (!langId) { @@ -101,19 +52,13 @@ function LanguageForm() { return ( - {openedFromLanguages && initial.haveLanguages && ( - } - description="Edit existing language" - /> - )} diff --git a/frontend/src/features/language/hooks/useLanguageForm.js b/frontend/src/features/language/hooks/useLanguageForm.js new file mode 100644 index 00000000..de044880 --- /dev/null +++ b/frontend/src/features/language/hooks/useLanguageForm.js @@ -0,0 +1,38 @@ +import { useForm } from "@mantine/form"; +import { randomId } from "@mantine/hooks"; + +function useLanguageForm() { + const form = useForm({ + mode: "uncontrolled", + initialValues: { + character_substitutions: "´='|`='|’='|‘='|...=…|..=‥", + split_sentences: ".!?", + split_sentence_exceptions: "Mr.|Mrs.|Dr.|[A-Z].|Vd.|Vds.", + word_chars: "a-zA-ZÀ-ÖØ-öø-ȳáéíóúÁÉÍÓÚñÑ", + right_to_left: false, + show_romanization: false, + parser_type: "spacedel", + // minimum dictionaries should be defined on backend with other settings + dictionaries: [ + { + for: "terms", + type: "embedded", + url: "", + active: true, + key: randomId(), + }, + { + for: "sentences", + type: "popup", + url: "", + active: true, + key: randomId(), + }, + ], + }, + }); + + return form; +} + +export default useLanguageForm; diff --git a/frontend/src/features/language/hooks/useSelectedLanguage.js b/frontend/src/features/language/hooks/useSelectedLanguage.js new file mode 100644 index 00000000..aca63ee7 --- /dev/null +++ b/frontend/src/features/language/hooks/useSelectedLanguage.js @@ -0,0 +1,36 @@ +import { useQuery } from "@tanstack/react-query"; +import { useSearchParams } from "react-router-dom"; +import { + predefinedLanguageQuery, + userLanguageQuery, +} from "@language/api/query"; + +function useSelectedLanguage() { + const [params] = useSearchParams(); + const langId = params.get("langId"); + const predefinedSelected = langId === "0"; + const userSelected = langId && langId !== "0"; + + const { data: predefinedLang, isSuccess: predefSuccess } = useQuery( + predefinedLanguageQuery(params.get("name", null)) + ); + const { data: userLang, isSuccess: userSuccess } = useQuery( + userLanguageQuery(langId) + ); + + const language = predefinedSelected + ? predefinedLang + : userSelected + ? userLang + : null; + + const isSuccess = predefinedSelected + ? predefSuccess + : userSelected + ? userSuccess + : false; + + return { language, isSuccess }; +} + +export default useSelectedLanguage; diff --git a/frontend/src/pages/LanguagesPage.jsx b/frontend/src/pages/LanguagesPage.jsx index b497e5b8..33313ca8 100644 --- a/frontend/src/pages/LanguagesPage.jsx +++ b/frontend/src/pages/LanguagesPage.jsx @@ -1,11 +1,28 @@ +import { useQuery } from "@tanstack/react-query"; +import { useSearchParams } from "react-router-dom"; import LanguageForm from "@language/components/LanguageForm/LanguageForm"; import PageContainer from "@common/PageContainer/PageContainer"; import PageTitle from "@common/PageTitle/PageTitle"; +import LanguageCards from "@language/components/LanguageCards/LanguageCards"; +import LanguageRadioLabel from "@language/components/LanguageForm/components/LanguageRadioLabel"; +import { initialQuery } from "@settings/api/settings"; function LanguagesPage() { + const { data: initial } = useQuery(initialQuery); + const [params] = useSearchParams(); + const langId = params.get("langId"); + return ( Create or edit a language + + {initial.haveLanguages && ( + } + description="Edit existing language" + /> + )} + ); diff --git a/frontend/src/pages/NewBookPage.jsx b/frontend/src/pages/NewBookPage.jsx index ba4a4cf9..80800596 100644 --- a/frontend/src/pages/NewBookPage.jsx +++ b/frontend/src/pages/NewBookPage.jsx @@ -1,12 +1,39 @@ -import { Drawer, ScrollAreaAutosize } from "@mantine/core"; +import { useQuery } from "@tanstack/react-query"; +import { + ActionIcon, + Drawer, + Group, + ScrollAreaAutosize, + Text, +} from "@mantine/core"; import { useDisclosure } from "@mantine/hooks"; +import { IconSquareRoundedPlusFilled } from "@tabler/icons-react"; import NewBookForm from "@book/components/NewBookForm/NewBookForm"; import LanguageForm from "@language/components/LanguageForm/LanguageForm"; +import LanguageCards from "@language/components/LanguageCards/LanguageCards"; import PageContainer from "@common/PageContainer/PageContainer"; import PageTitle from "@common/PageTitle/PageTitle"; +import { initialQuery } from "@settings/api/settings"; function NewBookPage() { const [opened, { open, close }] = useDisclosure(false); + const { data: initial } = useQuery(initialQuery); + + const cardsRadioLabel = ( + + + Language + + + + + + ); + return ( <> Create a new book - + + {initial.haveLanguages ? ( + + ) : ( + cardsRadioLabel + )} + + );