Преглед на файлове

feat: connect memo page with apis

RegMs If преди 3 години
родител
ревизия
d4fc65a359
променени са 3 файла, в които са добавени 122 реда и са изтрити 77 реда
  1. 1 1
      src/pages/MemoPage.module.css
  2. 103 72
      src/pages/MemoPage.tsx
  3. 18 4
      src/router/index.tsx

+ 1 - 1
src/pages/MemoPage.module.css

@@ -1,5 +1,5 @@
 .wrapper {
 .wrapper {
-  height: 100%;
+  height: calc(100vh - 64px);
   display: flex;
   display: flex;
 }
 }
 
 

+ 103 - 72
src/pages/MemoPage.tsx

@@ -1,30 +1,22 @@
 import React, { useState, useEffect } from 'react';
 import React, { useState, useEffect } from 'react';
+import { useParams } from 'react-router-dom';
 import _ from 'lodash';
 import _ from 'lodash';
-import { Space, Row, Col, Button, Typography, Empty } from 'antd';
+import { Space, Row, Col, Button, Typography, Empty, message } from 'antd';
 import {
 import {
   EyeOutlined,
   EyeOutlined,
   StarFilled,
   StarFilled,
   StarOutlined,
   StarOutlined,
   ArrowLeftOutlined,
   ArrowLeftOutlined,
-  PlusOutlined,
   ReloadOutlined,
   ReloadOutlined,
   ArrowRightOutlined,
   ArrowRightOutlined,
 } from '@ant-design/icons';
 } from '@ant-design/icons';
-import type { Dict } from '../types/dicts';
+import { useGetDict } from '../apis/dicts';
+import type { WordResult } from '../apis/words';
+import { useUpdateWord } from '../apis/words';
 import styles from './MemoPage.module.css';
 import styles from './MemoPage.module.css';
 
 
 const { Text } = Typography;
 const { Text } = Typography;
 
 
-const dict: Dict = {
-  valueTitle: '日文',
-  meaningTitle: '中文',
-  extraTitle: '假名',
-  words: [
-    { value: 'test', meaning: '测试', extra: '附加?', star: true },
-    { value: 'good', meaning: '好', extra: 'no!', star: false },
-  ],
-};
-
 enum Mode {
 enum Mode {
   ValueToMeaning,
   ValueToMeaning,
   MeaningToValue,
   MeaningToValue,
@@ -32,21 +24,42 @@ enum Mode {
 
 
 const MemoPage: React.FC = () => {
 const MemoPage: React.FC = () => {
   const [mode, setMode] = useState<Mode>(Mode.ValueToMeaning);
   const [mode, setMode] = useState<Mode>(Mode.ValueToMeaning);
-  const [words, setWords] = useState<Dict['words']>([]);
+  const [shuffledWords, setShuffledWords] = useState<WordResult[]>();
   const [index, setIndex] = useState(0);
   const [index, setIndex] = useState(0);
   const [showValueOrMeaning, setShowValueOrMeaning] = useState(false);
   const [showValueOrMeaning, setShowValueOrMeaning] = useState(false);
   const [showExtra, setShowExtra] = useState(false);
   const [showExtra, setShowExtra] = useState(false);
 
 
+  const { dictID = '' } = useParams();
+
+  const { data: { dict, words } = {} } = useGetDict({
+    id: parseInt(dictID),
+  });
+  const updateWord = useUpdateWord();
+
   useEffect(() => {
   useEffect(() => {
-    setWords(_.shuffle(dict.words));
-  }, []);
+    if (!shuffledWords && words?.list) {
+      setShuffledWords(_.shuffle(words.list));
+    }
+  }, [shuffledWords, words?.list]);
 
 
-  const updateIndex = (index: number) => {
+  const mutateWordsList = (word: WordResult, index: number) =>
+    shuffledWords &&
+    setShuffledWords([
+      ...shuffledWords.slice(0, index),
+      word,
+      ...shuffledWords.slice(index + 1),
+    ]);
+
+  const mutateIndex = (index: number) => {
     setIndex(index);
     setIndex(index);
     setShowValueOrMeaning(false);
     setShowValueOrMeaning(false);
     setShowExtra(false);
     setShowExtra(false);
   };
   };
 
 
+  if (!dict || !shuffledWords) {
+    return <></>;
+  }
+
   return (
   return (
     <div className={styles.wrapper}>
     <div className={styles.wrapper}>
       <Space className={styles.space} size="large" direction="vertical">
       <Space className={styles.space} size="large" direction="vertical">
@@ -56,7 +69,7 @@ const MemoPage: React.FC = () => {
               type={mode === Mode.ValueToMeaning ? 'primary' : 'default'}
               type={mode === Mode.ValueToMeaning ? 'primary' : 'default'}
               onClick={() => setMode(Mode.ValueToMeaning)}
               onClick={() => setMode(Mode.ValueToMeaning)}
             >
             >
-              {dict.valueTitle} → {dict.meaningTitle}
+              {dict.value} → {dict.meaning}
             </Button>
             </Button>
           </Col>
           </Col>
           <Col>
           <Col>
@@ -64,18 +77,18 @@ const MemoPage: React.FC = () => {
               type={mode === Mode.MeaningToValue ? 'primary' : 'default'}
               type={mode === Mode.MeaningToValue ? 'primary' : 'default'}
               onClick={() => setMode(Mode.MeaningToValue)}
               onClick={() => setMode(Mode.MeaningToValue)}
             >
             >
-              {dict.meaningTitle} → {dict.valueTitle}
+              {dict.meaning} → {dict.value}
             </Button>
             </Button>
           </Col>
           </Col>
         </Row>
         </Row>
-        {words.length ? (
+        {shuffledWords.length ? (
           <>
           <>
             <Row justify="center">
             <Row justify="center">
               <Col className={styles.primaryText}>
               <Col className={styles.primaryText}>
                 <Text strong>
                 <Text strong>
                   {mode === Mode.ValueToMeaning
                   {mode === Mode.ValueToMeaning
-                    ? words[index].value
-                    : words[index].meaning}
+                    ? shuffledWords[index].value
+                    : shuffledWords[index].meaning}
                 </Text>
                 </Text>
               </Col>
               </Col>
             </Row>
             </Row>
@@ -84,8 +97,8 @@ const MemoPage: React.FC = () => {
                 {showValueOrMeaning ? (
                 {showValueOrMeaning ? (
                   <Text>
                   <Text>
                     {mode === Mode.MeaningToValue
                     {mode === Mode.MeaningToValue
-                      ? words[index].value
-                      : words[index].meaning}
+                      ? shuffledWords[index].value
+                      : shuffledWords[index].meaning}
                   </Text>
                   </Text>
                 ) : (
                 ) : (
                   <Button
                   <Button
@@ -94,15 +107,13 @@ const MemoPage: React.FC = () => {
                     icon={<EyeOutlined />}
                     icon={<EyeOutlined />}
                     onClick={() => setShowValueOrMeaning(true)}
                     onClick={() => setShowValueOrMeaning(true)}
                   >
                   >
-                    {mode === Mode.MeaningToValue
-                      ? dict.valueTitle
-                      : dict.meaningTitle}
+                    {mode === Mode.MeaningToValue ? dict.value : dict.meaning}
                   </Button>
                   </Button>
                 )}
                 )}
               </Col>
               </Col>
               <Col className={styles.secondaryText} flex="1">
               <Col className={styles.secondaryText} flex="1">
                 {showExtra ? (
                 {showExtra ? (
-                  <Text>{words[index].extra}</Text>
+                  <Text>{shuffledWords[index].extra}</Text>
                 ) : (
                 ) : (
                   <Button
                   <Button
                     type="text"
                     type="text"
@@ -110,61 +121,81 @@ const MemoPage: React.FC = () => {
                     icon={<EyeOutlined />}
                     icon={<EyeOutlined />}
                     onClick={() => setShowExtra(true)}
                     onClick={() => setShowExtra(true)}
                   >
                   >
-                    {dict.extraTitle}
+                    {dict.extra}
                   </Button>
                   </Button>
                 )}
                 )}
               </Col>
               </Col>
             </Row>
             </Row>
-            <Row justify="center">
-              {words[index].star ? (
-                <Button type="primary" danger icon={<StarFilled />}>
-                  取消易错词
+            <Row>
+              <Col flex="1">
+                <Button
+                  type="link"
+                  block
+                  disabled={index <= 0}
+                  onClick={() => mutateIndex(index - 1)}
+                >
+                  <ArrowLeftOutlined /> 上一个
                 </Button>
                 </Button>
-              ) : (
-                <Button danger icon={<StarOutlined />}>
-                  标记易错词
+              </Col>
+              <Col>
+                <Button
+                  type={shuffledWords[index].star ? 'primary' : 'default'}
+                  danger
+                  icon={
+                    shuffledWords[index].star ? (
+                      <StarFilled />
+                    ) : (
+                      <StarOutlined />
+                    )
+                  }
+                  onClick={() =>
+                    void (async () => {
+                      try {
+                        const newWord = {
+                          ...shuffledWords[index],
+                          star: !shuffledWords[index].star,
+                        };
+                        mutateWordsList(newWord, index);
+                        await updateWord(newWord);
+                        void message.success('更新成功');
+                      } catch (err) {
+                        if (err instanceof Error) {
+                          void message.error(err.message);
+                        }
+                      }
+                    })()
+                  }
+                >
+                  {shuffledWords[index].star ? '取消易错词' : '标记易错词'}
                 </Button>
                 </Button>
-              )}
+              </Col>
+              <Col flex="1">
+                {index >= shuffledWords.length - 1 ? (
+                  <Button
+                    type="link"
+                    block
+                    onClick={() => {
+                      setShuffledWords(_.shuffle(shuffledWords));
+                      mutateIndex(0);
+                    }}
+                  >
+                    再来一次 <ReloadOutlined />
+                  </Button>
+                ) : (
+                  <Button
+                    type="link"
+                    block
+                    onClick={() => mutateIndex(index + 1)}
+                  >
+                    下一个 <ArrowRightOutlined />
+                  </Button>
+                )}
+              </Col>
             </Row>
             </Row>
           </>
           </>
         ) : (
         ) : (
           <Empty />
           <Empty />
         )}
         )}
-        <Row>
-          <Col flex="1">
-            <Button
-              type="link"
-              block
-              disabled={index <= 0}
-              onClick={() => updateIndex(index - 1)}
-            >
-              <ArrowLeftOutlined /> 上一个
-            </Button>
-          </Col>
-          <Col>
-            <Button type="dashed" icon={<PlusOutlined />}>
-              输入新单词
-            </Button>
-          </Col>
-          <Col flex="1">
-            {index >= words.length - 1 ? (
-              <Button
-                type="link"
-                block
-                onClick={() => {
-                  setWords(_.shuffle(dict.words));
-                  updateIndex(0);
-                }}
-              >
-                再来一次 <ReloadOutlined />
-              </Button>
-            ) : (
-              <Button type="link" block onClick={() => updateIndex(index + 1)}>
-                下一个 <ArrowRightOutlined />
-              </Button>
-            )}
-          </Col>
-        </Row>
       </Space>
       </Space>
     </div>
     </div>
   );
   );

+ 18 - 4
src/router/index.tsx

@@ -1,21 +1,35 @@
 import React from 'react';
 import React from 'react';
-import { createBrowserRouter } from 'react-router-dom';
+import { Link, createBrowserRouter } from 'react-router-dom';
+import { Result, Button } from 'antd';
 import PageLayout from '../layout/PageLayout';
 import PageLayout from '../layout/PageLayout';
+import DictsPage from '../pages/DictsPage';
+import DictPage from '../pages/DictPage';
 import MemoPage from '../pages/MemoPage';
 import MemoPage from '../pages/MemoPage';
 
 
 export default createBrowserRouter([
 export default createBrowserRouter([
   {
   {
     path: '/',
     path: '/',
     element: <PageLayout />,
     element: <PageLayout />,
+    errorElement: (
+      <Result
+        status="404"
+        subTitle="页面不存在"
+        extra={
+          <Link to="/dicts">
+            <Button type="primary">返回首页</Button>
+          </Link>
+        }
+      />
+    ),
     children: [
     children: [
       {
       {
         path: 'dicts',
         path: 'dicts',
         children: [
         children: [
-          { index: true, element: '233' },
+          { index: true, element: <DictsPage /> },
           {
           {
-            path: ':dictId',
+            path: ':dictID',
             children: [
             children: [
-              { index: true, element: '666' },
+              { index: true, element: <DictPage /> },
               { path: 'memo', element: <MemoPage /> },
               { path: 'memo', element: <MemoPage /> },
             ],
             ],
           },
           },