|
|
@@ -1,30 +1,22 @@
|
|
|
import React, { useState, useEffect } from 'react';
|
|
|
+import { useParams } from 'react-router-dom';
|
|
|
import _ from 'lodash';
|
|
|
-import { Space, Row, Col, Button, Typography, Empty } from 'antd';
|
|
|
+import { Space, Row, Col, Button, Typography, Empty, message } from 'antd';
|
|
|
import {
|
|
|
EyeOutlined,
|
|
|
StarFilled,
|
|
|
StarOutlined,
|
|
|
ArrowLeftOutlined,
|
|
|
- PlusOutlined,
|
|
|
ReloadOutlined,
|
|
|
ArrowRightOutlined,
|
|
|
} 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';
|
|
|
|
|
|
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 {
|
|
|
ValueToMeaning,
|
|
|
MeaningToValue,
|
|
|
@@ -32,21 +24,42 @@ enum Mode {
|
|
|
|
|
|
const MemoPage: React.FC = () => {
|
|
|
const [mode, setMode] = useState<Mode>(Mode.ValueToMeaning);
|
|
|
- const [words, setWords] = useState<Dict['words']>([]);
|
|
|
+ const [shuffledWords, setShuffledWords] = useState<WordResult[]>();
|
|
|
const [index, setIndex] = useState(0);
|
|
|
const [showValueOrMeaning, setShowValueOrMeaning] = useState(false);
|
|
|
const [showExtra, setShowExtra] = useState(false);
|
|
|
|
|
|
+ const { dictID = '' } = useParams();
|
|
|
+
|
|
|
+ const { data: { dict, words } = {} } = useGetDict({
|
|
|
+ id: parseInt(dictID),
|
|
|
+ });
|
|
|
+ const updateWord = useUpdateWord();
|
|
|
+
|
|
|
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);
|
|
|
setShowValueOrMeaning(false);
|
|
|
setShowExtra(false);
|
|
|
};
|
|
|
|
|
|
+ if (!dict || !shuffledWords) {
|
|
|
+ return <></>;
|
|
|
+ }
|
|
|
+
|
|
|
return (
|
|
|
<div className={styles.wrapper}>
|
|
|
<Space className={styles.space} size="large" direction="vertical">
|
|
|
@@ -56,7 +69,7 @@ const MemoPage: React.FC = () => {
|
|
|
type={mode === Mode.ValueToMeaning ? 'primary' : 'default'}
|
|
|
onClick={() => setMode(Mode.ValueToMeaning)}
|
|
|
>
|
|
|
- {dict.valueTitle} → {dict.meaningTitle}
|
|
|
+ {dict.value} → {dict.meaning}
|
|
|
</Button>
|
|
|
</Col>
|
|
|
<Col>
|
|
|
@@ -64,18 +77,18 @@ const MemoPage: React.FC = () => {
|
|
|
type={mode === Mode.MeaningToValue ? 'primary' : 'default'}
|
|
|
onClick={() => setMode(Mode.MeaningToValue)}
|
|
|
>
|
|
|
- {dict.meaningTitle} → {dict.valueTitle}
|
|
|
+ {dict.meaning} → {dict.value}
|
|
|
</Button>
|
|
|
</Col>
|
|
|
</Row>
|
|
|
- {words.length ? (
|
|
|
+ {shuffledWords.length ? (
|
|
|
<>
|
|
|
<Row justify="center">
|
|
|
<Col className={styles.primaryText}>
|
|
|
<Text strong>
|
|
|
{mode === Mode.ValueToMeaning
|
|
|
- ? words[index].value
|
|
|
- : words[index].meaning}
|
|
|
+ ? shuffledWords[index].value
|
|
|
+ : shuffledWords[index].meaning}
|
|
|
</Text>
|
|
|
</Col>
|
|
|
</Row>
|
|
|
@@ -84,8 +97,8 @@ const MemoPage: React.FC = () => {
|
|
|
{showValueOrMeaning ? (
|
|
|
<Text>
|
|
|
{mode === Mode.MeaningToValue
|
|
|
- ? words[index].value
|
|
|
- : words[index].meaning}
|
|
|
+ ? shuffledWords[index].value
|
|
|
+ : shuffledWords[index].meaning}
|
|
|
</Text>
|
|
|
) : (
|
|
|
<Button
|
|
|
@@ -94,15 +107,13 @@ const MemoPage: React.FC = () => {
|
|
|
icon={<EyeOutlined />}
|
|
|
onClick={() => setShowValueOrMeaning(true)}
|
|
|
>
|
|
|
- {mode === Mode.MeaningToValue
|
|
|
- ? dict.valueTitle
|
|
|
- : dict.meaningTitle}
|
|
|
+ {mode === Mode.MeaningToValue ? dict.value : dict.meaning}
|
|
|
</Button>
|
|
|
)}
|
|
|
</Col>
|
|
|
<Col className={styles.secondaryText} flex="1">
|
|
|
{showExtra ? (
|
|
|
- <Text>{words[index].extra}</Text>
|
|
|
+ <Text>{shuffledWords[index].extra}</Text>
|
|
|
) : (
|
|
|
<Button
|
|
|
type="text"
|
|
|
@@ -110,61 +121,81 @@ const MemoPage: React.FC = () => {
|
|
|
icon={<EyeOutlined />}
|
|
|
onClick={() => setShowExtra(true)}
|
|
|
>
|
|
|
- {dict.extraTitle}
|
|
|
+ {dict.extra}
|
|
|
</Button>
|
|
|
)}
|
|
|
</Col>
|
|
|
</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 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>
|
|
|
- )}
|
|
|
+ </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>
|
|
|
</>
|
|
|
) : (
|
|
|
<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>
|
|
|
</div>
|
|
|
);
|