SentCellEditable.tsx 6.6 KB

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