NissayaCard.tsx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import { useEffect, useState } from "react";
  2. import { Button, message, Modal, Popover, Skeleton, Typography } from "antd";
  3. import { EditOutlined, ReloadOutlined } from "@ant-design/icons";
  4. import { get } from "../../request";
  5. import { get as getLang } from "../../locales";
  6. import NissayaCardTable, { type INissayaRelation } from "./NissayaCardTable";
  7. import type { ITerm } from "../term/TermEdit";
  8. import { Link } from "react-router";
  9. import TermModal from "../term/TermModal";
  10. import type { ITermDataResponse } from "../../api/Term";
  11. import { useIntl } from "react-intl";
  12. import MdView from "../template/MdView";
  13. const { Paragraph, Title } = Typography;
  14. interface INissayaCardModal {
  15. text?: string;
  16. trigger?: JSX.Element | string;
  17. }
  18. export const NissayaCardPop = ({ text, trigger }: INissayaCardModal) => {
  19. return (
  20. <Popover
  21. style={{ width: 700 }}
  22. content={<NissayaCardWidget text={text} cache={true} hideEditButton />}
  23. placement="bottom"
  24. >
  25. <Typography.Link>{trigger}</Typography.Link>
  26. </Popover>
  27. );
  28. };
  29. export const NissayaCardModal = ({ text, trigger }: INissayaCardModal) => {
  30. const [isModalOpen, setIsModalOpen] = useState(false);
  31. const showModal = () => {
  32. setIsModalOpen(true);
  33. };
  34. const handleOk = () => {
  35. setIsModalOpen(false);
  36. };
  37. const handleCancel = () => {
  38. setIsModalOpen(false);
  39. };
  40. return (
  41. <>
  42. <span onClick={showModal}>{trigger}</span>
  43. <Modal
  44. width={800}
  45. title="缅文语尾"
  46. open={isModalOpen}
  47. onOk={handleOk}
  48. onCancel={handleCancel}
  49. destroyOnClose
  50. >
  51. <NissayaCardWidget text={text} />
  52. </Modal>
  53. </>
  54. );
  55. };
  56. interface INissayaCardData {
  57. row: INissayaRelation[];
  58. ending: ITerm;
  59. }
  60. interface INissayaCardResponse {
  61. ok: boolean;
  62. message: string;
  63. data: INissayaCardData;
  64. }
  65. interface IWidget {
  66. text?: string;
  67. cache?: boolean;
  68. hideEditButton?: boolean;
  69. }
  70. const NissayaCardWidget = ({
  71. text,
  72. cache = false,
  73. hideEditButton = false,
  74. }: IWidget) => {
  75. const intl = useIntl();
  76. const [cardData, setCardData] = useState<INissayaRelation[]>();
  77. const [term, setTerm] = useState<ITerm>();
  78. const [loading, setLoading] = useState(false);
  79. useEffect(() => load(), [cache, text]);
  80. const load = () => {
  81. const uiLang = getLang();
  82. const key = `nissaya-ending/${uiLang}/${text}`;
  83. if (cache) {
  84. const value = sessionStorage.getItem(key);
  85. if (value !== null) {
  86. const valueJson: INissayaCardData = JSON.parse(value);
  87. setCardData(valueJson.row);
  88. setTerm(valueJson.ending);
  89. setLoading(false);
  90. return;
  91. }
  92. }
  93. const url = `/v2/nissaya-card/${text}?lang=${uiLang}&content_type=json`;
  94. console.debug("api request", url);
  95. setLoading(true);
  96. get<INissayaCardResponse>(url)
  97. .then((json) => {
  98. console.debug("api response", json);
  99. if (json.ok) {
  100. setCardData(json.data.row);
  101. setTerm(json.data.ending);
  102. if (cache) {
  103. sessionStorage.setItem(
  104. `nissaya-ending/${uiLang}/${text}`,
  105. JSON.stringify(json.data)
  106. );
  107. }
  108. } else {
  109. message.error(json.message);
  110. }
  111. })
  112. .finally(() => setLoading(false))
  113. .catch((e: INissayaCardResponse) => message.error(e.message));
  114. };
  115. const reload = () => {
  116. const uiLang = getLang();
  117. const key = `nissaya-ending/${uiLang}/${text}`;
  118. sessionStorage.removeItem(key);
  119. load();
  120. };
  121. return loading ? (
  122. <Skeleton title={{ width: 200 }} paragraph={{ rows: 4 }} active />
  123. ) : (
  124. <div style={{ maxWidth: 750 }}>
  125. <div style={{ display: "flex", justifyContent: "space-between" }}>
  126. <Title level={4}>
  127. {term?.word}
  128. {hideEditButton ? (
  129. <></>
  130. ) : (
  131. <TermModal
  132. id={term?.id}
  133. onUpdate={(_value: ITermDataResponse) => {
  134. //onModalClose();
  135. }}
  136. onClose={() => {
  137. //onModalClose();
  138. }}
  139. trigger={<Button type="link" icon={<EditOutlined />} />}
  140. />
  141. )}
  142. </Title>
  143. <div>
  144. <Link to={`/nissaya/ending/${term?.word}`} target="_blank">
  145. {intl.formatMessage(
  146. {
  147. id: "buttons.open.in.new.tab",
  148. },
  149. { item: "" }
  150. )}
  151. </Link>
  152. <Button
  153. type="link"
  154. icon={<ReloadOutlined />}
  155. onClick={() => reload()}
  156. />
  157. </div>
  158. </div>
  159. <Paragraph>{term?.meaning}</Paragraph>
  160. <MdView html={term?.html} />
  161. {cardData && <NissayaCardTable data={cardData} />}
  162. </div>
  163. );
  164. };
  165. export default NissayaCardWidget;