2
0

SentCellEditable.tsx 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. import { useEffect, useState } from "react";
  2. import { useIntl } from "react-intl";
  3. import { Button, message, Typography } from "antd";
  4. import { SaveOutlined } from "@ant-design/icons";
  5. import { post, put } from "../../../request";
  6. import {
  7. ISentencePrRequest,
  8. ISentencePrResponse,
  9. ISentenceRequest,
  10. ISentenceResponse,
  11. } from "../../api/Corpus";
  12. import { ISentence } from "../SentEdit";
  13. import TermTextArea from "../../general/TermTextArea";
  14. import { useAppSelector } from "../../../hooks";
  15. import { wordList } from "../../../reducers/sent-word";
  16. import Builder from "../Builder/Builder";
  17. const { Text } = Typography;
  18. export const sentSave = (
  19. data: ISentence,
  20. ok: (res: ISentence) => void,
  21. finish: () => void
  22. ) => {
  23. let url = `/v2/sentence/${data.book}_${data.para}_${data.wordStart}_${data.wordEnd}_${data.channel.id}`;
  24. url += "?mode=edit&html=true";
  25. const body = {
  26. book: data.book,
  27. para: data.para,
  28. wordStart: data.wordStart,
  29. wordEnd: data.wordEnd,
  30. channel: data.channel.id,
  31. content: data.content,
  32. channels: data.translationChannels?.join(),
  33. };
  34. console.log("save url", url, body);
  35. put<ISentenceRequest, ISentenceResponse>(url, body)
  36. .then((json) => {
  37. if (json.ok) {
  38. console.debug("sent save ok", json.data);
  39. const newData: ISentence = {
  40. id: json.data.id,
  41. content: json.data.content,
  42. html: json.data.html,
  43. book: json.data.book,
  44. para: json.data.paragraph,
  45. wordStart: json.data.word_start,
  46. wordEnd: json.data.word_end,
  47. editor: json.data.editor,
  48. studio: json.data.studio,
  49. channel: json.data.channel,
  50. forkAt: json.data.fork_at,
  51. updateAt: json.data.updated_at,
  52. };
  53. ok(newData);
  54. } else {
  55. message.error(json.message);
  56. }
  57. })
  58. .finally(() => {
  59. finish();
  60. })
  61. .catch((e) => {
  62. console.error("catch", e);
  63. message.error(e.message);
  64. });
  65. };
  66. interface IWidget {
  67. data: ISentence;
  68. isPr?: boolean;
  69. isCreatePr?: boolean;
  70. onSave?: Function;
  71. onClose?: Function;
  72. onCreate?: Function;
  73. }
  74. const SentCellEditableWidget = ({
  75. data,
  76. onSave,
  77. onClose,
  78. onCreate,
  79. isPr = false,
  80. isCreatePr = false,
  81. }: IWidget) => {
  82. const intl = useIntl();
  83. const [value, setValue] = useState(data.content);
  84. const [saving, setSaving] = useState<boolean>(false);
  85. const [termList, setTermList] = useState<string[]>();
  86. const sentWords = useAppSelector(wordList);
  87. useEffect(() => {
  88. const sentId = `${data.book}-${data.para}-${data.wordStart}-${data.wordEnd}`;
  89. setTermList(sentWords.find((value) => value.sentId === sentId)?.words);
  90. }, [data.book, data.para, data.wordEnd, data.wordStart, sentWords]);
  91. const savePr = () => {
  92. setSaving(true);
  93. if (!value) {
  94. return;
  95. }
  96. if (isCreatePr) {
  97. post<ISentencePrRequest, ISentencePrResponse>(`/v2/sentpr`, {
  98. book: data.book,
  99. para: data.para,
  100. begin: data.wordStart,
  101. end: data.wordEnd,
  102. channel: data.channel.id,
  103. text: value,
  104. })
  105. .then((json) => {
  106. setSaving(false);
  107. if (json.ok) {
  108. message.success(intl.formatMessage({ id: "flashes.success" }));
  109. if (typeof onCreate !== "undefined") {
  110. onCreate();
  111. }
  112. } else {
  113. message.error(json.message);
  114. }
  115. })
  116. .catch((e) => {
  117. setSaving(false);
  118. console.error("catch", e);
  119. message.error(e.message);
  120. });
  121. } else {
  122. const url = `/v2/sentpr/${data.id}`;
  123. console.log("url", url);
  124. put<ISentencePrRequest, ISentencePrResponse>(url, {
  125. text: value,
  126. })
  127. .then((json) => {
  128. if (json.ok) {
  129. message.success(intl.formatMessage({ id: "flashes.success" }));
  130. if (typeof onSave !== "undefined") {
  131. onSave();
  132. }
  133. } else {
  134. message.error(json.message);
  135. }
  136. })
  137. .finally(() => {
  138. setSaving(false);
  139. })
  140. .catch((e) => {
  141. console.error("catch", e);
  142. message.error(e.message);
  143. });
  144. }
  145. };
  146. const save = () => {
  147. setSaving(true);
  148. let url = `/v2/sentence/${data.book}_${data.para}_${data.wordStart}_${data.wordEnd}_${data.channel.id}`;
  149. url += "?mode=edit&html=true";
  150. const body = {
  151. book: data.book,
  152. para: data.para,
  153. wordStart: data.wordStart,
  154. wordEnd: data.wordEnd,
  155. channel: data.channel.id,
  156. content: value,
  157. channels: data.translationChannels?.join(),
  158. };
  159. console.debug("save url", url, body);
  160. put<ISentenceRequest, ISentenceResponse>(url, body)
  161. .then((json) => {
  162. if (json.ok) {
  163. message.success(intl.formatMessage({ id: "flashes.success" }));
  164. if (typeof onSave !== "undefined") {
  165. const newData: ISentence = {
  166. id: json.data.id,
  167. content: json.data.content,
  168. html: json.data.html,
  169. book: json.data.book,
  170. para: json.data.paragraph,
  171. wordStart: json.data.word_start,
  172. wordEnd: json.data.word_end,
  173. editor: json.data.editor,
  174. studio: json.data.studio,
  175. channel: json.data.channel,
  176. forkAt: json.data.fork_at,
  177. updateAt: json.data.updated_at,
  178. };
  179. onSave(newData);
  180. }
  181. } else {
  182. message.error(json.message);
  183. }
  184. })
  185. .finally(() => {
  186. setSaving(false);
  187. })
  188. .catch((e) => {
  189. console.error("catch", e);
  190. message.error(e.message);
  191. });
  192. };
  193. return (
  194. <Typography.Paragraph style={{ width: "100%" }}>
  195. <TermTextArea
  196. value={value ? value : ""}
  197. menuOptions={termList}
  198. onChange={(value: string) => {
  199. setValue(value);
  200. }}
  201. placeholder={intl.formatMessage({
  202. id: "labels.input",
  203. })}
  204. onClose={() => {
  205. if (typeof onClose !== "undefined") {
  206. onClose();
  207. }
  208. }}
  209. onSave={(value: string) => {
  210. setValue(value);
  211. isPr ? savePr() : save();
  212. }}
  213. />
  214. <div style={{ display: "flex", justifyContent: "space-between" }}>
  215. <div>
  216. <span>
  217. <Text keyboard>esc</Text>=
  218. <Button
  219. size="small"
  220. type="link"
  221. onClick={(e) => {
  222. if (typeof onClose !== "undefined") {
  223. onClose();
  224. }
  225. }}
  226. >
  227. {intl.formatMessage({ id: "buttons.cancel" })}
  228. </Button>
  229. </span>
  230. <span>
  231. <Text keyboard>enter</Text>=
  232. <Button size="small" type="link">
  233. new line
  234. </Button>
  235. </span>
  236. <Text keyboard style={{ cursor: "pointer" }}>
  237. <Builder trigger={"<t>"} />
  238. </Text>
  239. </div>
  240. <div>
  241. <Text keyboard>Ctrl/⌘</Text>➕<Text keyboard>enter</Text>=
  242. <Button
  243. size="small"
  244. type="primary"
  245. icon={<SaveOutlined />}
  246. loading={saving}
  247. onClick={() => (isPr ? savePr() : save())}
  248. >
  249. {intl.formatMessage({ id: "buttons.save" })}
  250. </Button>
  251. </div>
  252. </div>
  253. </Typography.Paragraph>
  254. );
  255. };
  256. export default SentCellEditableWidget;