visuddhinanda %!s(int64=2) %!d(string=hai) anos
pai
achega
fba0e5d114

+ 49 - 0
dashboard/src/components/article/TypeAnthology.tsx

@@ -0,0 +1,49 @@
+import { ArticleMode, ArticleType } from "./Article";
+import AnthologyDetail from "./AnthologyDetail";
+import "./article.css";
+
+interface IWidget {
+  type?: ArticleType;
+  articleId?: string;
+  mode?: ArticleMode | null;
+  channelId?: string | null;
+  onArticleChange?: Function;
+  onFinal?: Function;
+  onLoad?: Function;
+  onLoading?: Function;
+  onError?: Function;
+}
+const TypeAnthologyWidget = ({
+  type,
+  channelId,
+  articleId,
+  mode = "read",
+  onArticleChange,
+  onLoading,
+  onError,
+}: IWidget) => {
+  const channels = channelId?.split("_");
+  return (
+    <AnthologyDetail
+      onArticleSelect={(anthologyId: string, keys: string[]) => {
+        if (typeof onArticleChange !== "undefined" && keys.length > 0) {
+          onArticleChange("article", keys[0], { anthologyId: anthologyId });
+        }
+      }}
+      onLoading={(loading: boolean) => {
+        if (typeof onLoading !== "undefined") {
+          onLoading(loading);
+        }
+      }}
+      onError={(code: number, message: string) => {
+        if (typeof onError !== "undefined") {
+          onError(code, message);
+        }
+      }}
+      channels={channels}
+      aid={articleId}
+    />
+  );
+};
+
+export default TypeAnthologyWidget;

+ 186 - 0
dashboard/src/components/article/TypeArticle.tsx

@@ -0,0 +1,186 @@
+import { useEffect, useState } from "react";
+import { Divider, message, Space, Tag } from "antd";
+
+import { get } from "../../request";
+import { IArticleDataResponse, IArticleResponse } from "../api/Article";
+import ArticleView, { IFirstAnthology } from "./ArticleView";
+import TocTree from "./TocTree";
+import PaliText from "../template/Wbw/PaliText";
+import { ITocPathNode } from "../corpus/TocPath";
+import { ArticleMode, ArticleType } from "./Article";
+import "./article.css";
+
+interface IWidget {
+  type?: ArticleType;
+  articleId?: string;
+  mode?: ArticleMode | null;
+  channelId?: string | null;
+  anthologyId?: string | null;
+  active?: boolean;
+  onArticleChange?: Function;
+  onFinal?: Function;
+  onLoad?: Function;
+  onLoading?: Function;
+  onError?: Function;
+  onAnthologySelect?: Function;
+}
+const TypeArticleWidget = ({
+  type,
+  channelId,
+  articleId,
+  anthologyId,
+  mode = "read",
+  active = false,
+  onArticleChange,
+  onFinal,
+  onLoad,
+  onAnthologySelect,
+  onLoading,
+  onError,
+}: IWidget) => {
+  const [articleData, setArticleData] = useState<IArticleDataResponse>();
+  const [articleHtml, setArticleHtml] = useState<string[]>(["<span />"]);
+  const [extra, setExtra] = useState(<></>);
+
+  const channels = channelId?.split("_");
+
+  const srcDataMode = mode === "edit" || mode === "wbw" ? "edit" : "read";
+  useEffect(() => {
+    console.log("srcDataMode", srcDataMode);
+    if (!active) {
+      return;
+    }
+
+    if (typeof type === "undefined") {
+      return;
+    }
+
+    let url = `/v2/article/${articleId}?mode=${srcDataMode}`;
+    url += channelId ? `&channel=${channelId}` : "";
+    url += anthologyId ? `&anthology=${anthologyId}` : "";
+    console.log("url", url);
+    if (typeof onLoading !== "undefined") {
+      onLoading(true);
+    }
+
+    console.log("url", url);
+
+    get<IArticleResponse>(url)
+      .then((json) => {
+        console.log("article", json);
+        if (json.ok) {
+          setArticleData(json.data);
+          if (json.data.html) {
+            setArticleHtml([json.data.html]);
+          } else if (json.data.content) {
+            setArticleHtml([json.data.content]);
+          }
+          setExtra(
+            <TocTree
+              treeData={json.data.toc?.map((item) => {
+                const strTitle = item.title ? item.title : item.pali_title;
+                const key = item.key
+                  ? item.key
+                  : `${item.book}-${item.paragraph}`;
+                const progress = item.progress?.map((item, id) => (
+                  <Tag key={id}>{Math.round(item * 100) + "%"}</Tag>
+                ));
+                return {
+                  key: key,
+                  title: (
+                    <Space>
+                      <PaliText
+                        text={strTitle === "" ? "[unnamed]" : strTitle}
+                      />
+                      {progress}
+                    </Space>
+                  ),
+                  level: item.level,
+                };
+              })}
+              onSelect={(keys: string[]) => {
+                console.log(keys);
+                if (typeof onArticleChange !== "undefined" && keys.length > 0) {
+                  onArticleChange("article", keys[0]);
+                }
+              }}
+            />
+          );
+
+          if (typeof onLoad !== "undefined") {
+            onLoad(json.data);
+          }
+        } else {
+          if (typeof onError !== "undefined") {
+            onError(json.data, json.message);
+          }
+          message.error(json.message);
+        }
+      })
+      .finally(() => {
+        if (typeof onLoading !== "undefined") {
+          onLoading(false);
+        }
+      })
+      .catch((e) => {
+        console.error(e);
+      });
+  }, [active, type, articleId, srcDataMode, channelId, anthologyId]);
+
+  let anthology: IFirstAnthology | undefined;
+  if (articleData?.anthology_count && articleData.anthology_first) {
+    anthology = {
+      id: articleData.anthology_first.uid,
+      title: articleData.anthology_first.title,
+      count: articleData?.anthology_count,
+    };
+  }
+
+  return (
+    <div>
+      <ArticleView
+        id={articleData?.uid}
+        title={
+          articleData?.title_text ? articleData?.title_text : articleData?.title
+        }
+        subTitle={articleData?.subtitle}
+        summary={articleData?.summary}
+        content={articleData ? articleData.content : ""}
+        html={articleHtml}
+        path={articleData?.path}
+        created_at={articleData?.created_at}
+        updated_at={articleData?.updated_at}
+        channels={channels}
+        type={type}
+        articleId={articleId}
+        anthology={anthology}
+        onPathChange={(
+          node: ITocPathNode,
+          e: React.MouseEvent<HTMLSpanElement | HTMLAnchorElement, MouseEvent>
+        ) => {
+          let newType = type;
+          if (node.level === 0) {
+            newType = "anthology";
+          } else {
+            newType = "article";
+          }
+          if (typeof onArticleChange !== "undefined") {
+            const newArticleId = node.key;
+            const target = e.ctrlKey || e.metaKey ? "_blank" : "self";
+            onArticleChange(newType, newArticleId, target);
+          }
+        }}
+        onAnthologySelect={(id: string) => {
+          if (typeof onAnthologySelect !== "undefined") {
+            onAnthologySelect(id);
+          }
+        }}
+      />
+      <Divider />
+      {extra}
+      <Divider />
+    </div>
+  );
+};
+
+export default TypeArticleWidget;

+ 269 - 0
dashboard/src/components/article/TypeCourse.tsx

@@ -0,0 +1,269 @@
+import { useEffect, useState } from "react";
+import { Divider, message, Result, Space, Tag } from "antd";
+
+import { get } from "../../request";
+import store from "../../store";
+import { IArticleDataResponse, IArticleResponse } from "../api/Article";
+import ArticleView from "./ArticleView";
+import { ICourseCurrUserResponse } from "../api/Course";
+import { ICourseUser, signIn } from "../../reducers/course-user";
+import { ITextbook, refresh } from "../../reducers/current-course";
+import ExerciseList from "./ExerciseList";
+import ExerciseAnswer from "../course/ExerciseAnswer";
+import "./article.css";
+import TocTree from "./TocTree";
+import PaliText from "../template/Wbw/PaliText";
+import { ITocPathNode } from "../corpus/TocPath";
+import { ArticleMode, ArticleType } from "./Article";
+
+/**
+ * 每种article type 对应的路由参数
+ * article/id?anthology=id&channel=id1,id2&mode=ArticleMode
+ * chapter/book-para?channel=id1,id2&mode=ArticleMode
+ * para/book?par=para1,para2&channel=id1,id2&mode=ArticleMode
+ * cs-para/book-para?channel=id1,id2&mode=ArticleMode
+ * sent/id?channel=id1,id2&mode=ArticleMode
+ * sim/id?channel=id1,id2&mode=ArticleMode
+ * textbook/articleId?course=id&mode=ArticleMode
+ * exercise/articleId?course=id&exercise=id&username=name&mode=ArticleMode
+ * exercise-list/articleId?course=id&exercise=id&mode=ArticleMode
+ * sent-original/id
+ */
+interface IWidget {
+  type?: ArticleType;
+  articleId?: string;
+  mode?: ArticleMode | null;
+  channelId?: string | null;
+  book?: string | null;
+  para?: string | null;
+  courseId?: string;
+  exerciseId?: string;
+  userName?: string;
+  active?: boolean;
+  onArticleChange?: Function;
+  onFinal?: Function;
+  onLoad?: Function;
+  onLoading?: Function;
+  onError?: Function;
+}
+const TypeCourseWidget = ({
+  type,
+  book,
+  para,
+  channelId,
+  articleId,
+  courseId,
+  exerciseId,
+  userName,
+  mode = "read",
+  active = false,
+  onArticleChange,
+  onFinal,
+  onLoad,
+  onLoading,
+  onError,
+}: IWidget) => {
+  const [articleData, setArticleData] = useState<IArticleDataResponse>();
+  const [articleHtml, setArticleHtml] = useState<string[]>(["<span />"]);
+  const [extra, setExtra] = useState(<></>);
+
+  const channels = channelId?.split("_");
+
+  useEffect(() => {
+    /**
+     * 由课本进入查询当前用户的权限和channel
+     */
+    if (
+      type === "textbook" ||
+      type === "exercise" ||
+      type === "exercise-list"
+    ) {
+      if (typeof articleId !== "undefined") {
+        const id = articleId.split("_");
+        get<ICourseCurrUserResponse>(`/v2/course-curr?course_id=${id[0]}`).then(
+          (response) => {
+            console.log("course user", response);
+            if (response.ok) {
+              const it: ICourseUser = {
+                channelId: response.data.channel_id,
+                role: response.data.role,
+              };
+              store.dispatch(signIn(it));
+              /**
+               * redux发布课程信息
+               */
+              const ic: ITextbook = {
+                courseId: id[0],
+                articleId: id[1],
+              };
+              store.dispatch(refresh(ic));
+            }
+          }
+        );
+      }
+    }
+  }, [articleId, type]);
+
+  const srcDataMode = mode === "edit" || mode === "wbw" ? "edit" : "read";
+  useEffect(() => {
+    console.log("srcDataMode", srcDataMode);
+    if (!active) {
+      return;
+    }
+
+    if (typeof type !== "undefined") {
+      let url = "";
+      switch (type) {
+        case "textbook":
+          if (typeof articleId !== "undefined") {
+            url = `/v2/article/${articleId}?view=textbook&course=${courseId}&mode=${srcDataMode}`;
+          }
+          break;
+        case "exercise":
+          if (typeof articleId !== "undefined") {
+            url = `/v2/article/${articleId}?mode=${srcDataMode}&course=${courseId}&exercise=${exerciseId}&user=${userName}`;
+            setExtra(
+              <ExerciseAnswer
+                courseId={courseId}
+                articleId={articleId}
+                exerciseId={exerciseId}
+              />
+            );
+          }
+          break;
+        case "exercise-list":
+          if (typeof articleId !== "undefined") {
+            url = `/v2/article/${articleId}?mode=${srcDataMode}&course=${courseId}&exercise=${exerciseId}`;
+
+            setExtra(
+              <ExerciseList
+                courseId={courseId}
+                articleId={articleId}
+                exerciseId={exerciseId}
+              />
+            );
+          }
+          break;
+      }
+
+      console.log("url", url);
+      if (typeof onLoading !== "undefined") {
+        onLoading(true);
+      }
+
+      console.log("url", url);
+
+      get<IArticleResponse>(url)
+        .then((json) => {
+          console.log("article", json);
+          if (json.ok) {
+            setArticleData(json.data);
+            if (json.data.html) {
+              setArticleHtml([json.data.html]);
+            } else if (json.data.content) {
+              setArticleHtml([json.data.content]);
+            }
+            setExtra(
+              <TocTree
+                treeData={json.data.toc?.map((item) => {
+                  const strTitle = item.title ? item.title : item.pali_title;
+                  const key = item.key
+                    ? item.key
+                    : `${item.book}-${item.paragraph}`;
+                  const progress = item.progress?.map((item, id) => (
+                    <Tag key={id}>{Math.round(item * 100) + "%"}</Tag>
+                  ));
+                  return {
+                    key: key,
+                    title: (
+                      <Space>
+                        <PaliText
+                          text={strTitle === "" ? "[unnamed]" : strTitle}
+                        />
+                        {progress}
+                      </Space>
+                    ),
+                    level: item.level,
+                  };
+                })}
+                onSelect={(keys: string[]) => {
+                  console.log(keys);
+                  if (
+                    typeof onArticleChange !== "undefined" &&
+                    keys.length > 0
+                  ) {
+                    onArticleChange(keys[0]);
+                  }
+                }}
+              />
+            );
+
+            if (typeof onLoad !== "undefined") {
+              onLoad(json.data);
+            }
+          } else {
+            if (typeof onError !== "undefined") {
+              onError(json.data, json.message);
+            }
+            message.error(json.message);
+          }
+        })
+        .finally(() => {
+          if (typeof onLoading !== "undefined") {
+            onLoading(false);
+          }
+        })
+        .catch((e) => {
+          console.error(e);
+        });
+    }
+  }, [
+    active,
+    type,
+    articleId,
+    srcDataMode,
+    channelId,
+    courseId,
+    exerciseId,
+    userName,
+  ]);
+
+  return (
+    <div>
+      <ArticleView
+        id={articleData?.uid}
+        title={
+          articleData?.title_text ? articleData?.title_text : articleData?.title
+        }
+        subTitle={articleData?.subtitle}
+        summary={articleData?.summary}
+        content={articleData ? articleData.content : ""}
+        html={articleHtml}
+        path={articleData?.path}
+        created_at={articleData?.created_at}
+        updated_at={articleData?.updated_at}
+        channels={channels}
+        type={type}
+        articleId={articleId}
+        onPathChange={(
+          node: ITocPathNode,
+          e: React.MouseEvent<HTMLSpanElement | HTMLAnchorElement, MouseEvent>
+        ) => {
+          let newType = type;
+          if (typeof onArticleChange !== "undefined") {
+            const newArticleId = node.key
+              ? node.key
+              : `${node.book}-${node.paragraph}`;
+            const target = e.ctrlKey || e.metaKey ? "_blank" : "self";
+            onArticleChange(newType, newArticleId, target);
+          }
+        }}
+      />
+      <Divider />
+      {extra}
+      <Divider />
+    </div>
+  );
+};
+
+export default TypeCourseWidget;

+ 265 - 0
dashboard/src/components/article/TypePali.tsx

@@ -0,0 +1,265 @@
+import { useEffect, useState } from "react";
+import { Divider, message, Result, Space, Tag } from "antd";
+
+import { get, post } from "../../request";
+import { IArticleDataResponse, IArticleResponse } from "../api/Article";
+import ArticleView from "./ArticleView";
+import TocTree from "./TocTree";
+import PaliText from "../template/Wbw/PaliText";
+import { IViewRequest, IViewStoreResponse } from "../api/view";
+import { ITocPathNode } from "../corpus/TocPath";
+import { ArticleMode, ArticleType } from "./Article";
+import "./article.css";
+
+interface IWidget {
+  type?: ArticleType;
+  articleId?: string;
+  mode?: ArticleMode | null;
+  channelId?: string | null;
+  book?: string | null;
+  para?: string | null;
+  active?: boolean;
+  onArticleChange?: Function;
+  onFinal?: Function;
+  onLoad?: Function;
+  onLoading?: Function;
+  onError?: Function;
+}
+const TypePaliWidget = ({
+  type,
+  book,
+  para,
+  channelId,
+  articleId,
+  mode = "read",
+  active = false,
+  onArticleChange,
+  onFinal,
+  onLoad,
+  onLoading,
+  onError,
+}: IWidget) => {
+  const [articleData, setArticleData] = useState<IArticleDataResponse>();
+  const [articleHtml, setArticleHtml] = useState<string[]>(["<span />"]);
+  const [extra, setExtra] = useState(<></>);
+
+  const [remains, setRemains] = useState(false);
+
+  const channels = channelId?.split("_");
+
+  const srcDataMode = mode === "edit" || mode === "wbw" ? "edit" : "read";
+  useEffect(() => {
+    console.log("srcDataMode", srcDataMode);
+    if (!active) {
+      return;
+    }
+    if (typeof type === "undefined") {
+      return;
+    }
+
+    let url = "";
+    switch (type) {
+      case "chapter":
+        if (typeof articleId !== "undefined") {
+          url = `/v2/corpus-chapter/${articleId}?mode=${srcDataMode}`;
+          url += channelId ? `&channels=${channelId}` : "";
+        }
+        break;
+      case "para":
+        const _book = book ? book : articleId;
+        url = `/v2/corpus?view=para&book=${_book}&par=${para}&mode=${srcDataMode}`;
+        url += channelId ? `&channels=${channelId}` : "";
+        break;
+      default:
+        if (typeof articleId !== "undefined") {
+          url = `/v2/corpus/${type}/${articleId}/${srcDataMode}?mode=${srcDataMode}`;
+          url += channelId ? `&channel=${channelId}` : "";
+        }
+        break;
+    }
+
+    console.log("url", url);
+    if (typeof onLoading !== "undefined") {
+      onLoading(true);
+    }
+
+    console.log("url", url);
+
+    get<IArticleResponse>(url)
+      .then((json) => {
+        console.log("article", json);
+        if (json.ok) {
+          setArticleData(json.data);
+          if (json.data.html) {
+            setArticleHtml([json.data.html]);
+          } else if (json.data.content) {
+            setArticleHtml([json.data.content]);
+          }
+          if (json.data.from) {
+            setRemains(true);
+          }
+          setExtra(
+            <TocTree
+              treeData={json.data.toc?.map((item) => {
+                const strTitle = item.title ? item.title : item.pali_title;
+                const key = item.key
+                  ? item.key
+                  : `${item.book}-${item.paragraph}`;
+                const progress = item.progress?.map((item, id) => (
+                  <Tag key={id}>{Math.round(item * 100) + "%"}</Tag>
+                ));
+                return {
+                  key: key,
+                  title: (
+                    <Space>
+                      <PaliText
+                        text={strTitle === "" ? "[unnamed]" : strTitle}
+                      />
+                      {progress}
+                    </Space>
+                  ),
+                  level: item.level,
+                };
+              })}
+              onSelect={(keys: string[]) => {
+                console.log(keys);
+                if (typeof onArticleChange !== "undefined" && keys.length > 0) {
+                  onArticleChange(keys[0]);
+                }
+              }}
+            />
+          );
+
+          switch (type) {
+            case "chapter":
+              if (typeof articleId === "string" && channelId) {
+                const [book, para] = articleId?.split("-");
+                post<IViewRequest, IViewStoreResponse>("/v2/view", {
+                  target_type: type,
+                  book: parseInt(book),
+                  para: parseInt(para),
+                  channel: channelId,
+                  mode: srcDataMode,
+                }).then((json) => {
+                  console.log("view", json.data);
+                });
+              }
+              break;
+            default:
+              break;
+          }
+
+          if (typeof onLoad !== "undefined") {
+            onLoad(json.data);
+          }
+        } else {
+          if (typeof onError !== "undefined") {
+            onError(json.data, json.message);
+          }
+          message.error(json.message);
+        }
+      })
+      .finally(() => {
+        if (typeof onLoading !== "undefined") {
+          onLoading(false);
+        }
+      })
+      .catch((e) => {
+        console.error(e);
+      });
+  }, [active, type, articleId, srcDataMode, book, para, channelId]);
+
+  const getNextPara = (next: IArticleDataResponse): void => {
+    if (
+      typeof next.paraId === "undefined" ||
+      typeof next.mode === "undefined" ||
+      typeof next.from === "undefined" ||
+      typeof next.to === "undefined"
+    ) {
+      setRemains(false);
+      return;
+    }
+    let url = `/v2/corpus-chapter/${next.paraId}?mode=${next.mode}`;
+    url += `&from=${next.from}`;
+    url += `&to=${next.to}`;
+    url += channels ? `&channels=${channels}` : "";
+    console.log("lazy load", url);
+    get<IArticleResponse>(url).then((json) => {
+      if (json.ok) {
+        if (typeof json.data.content === "string") {
+          const content: string = json.data.content;
+          setArticleData((origin) => {
+            if (origin) {
+              origin.from = json.data.from;
+            }
+            return origin;
+          });
+          setArticleHtml((origin) => {
+            return [...origin, content];
+          });
+        }
+
+        //getNextPara(json.data);
+      }
+    });
+    return;
+  };
+
+  return (
+    <div>
+      <ArticleView
+        id={articleData?.uid}
+        title={
+          articleData?.title_text ? articleData?.title_text : articleData?.title
+        }
+        subTitle={articleData?.subtitle}
+        summary={articleData?.summary}
+        content={articleData ? articleData.content : ""}
+        html={articleHtml}
+        path={articleData?.path}
+        created_at={articleData?.created_at}
+        updated_at={articleData?.updated_at}
+        channels={channels}
+        type={type}
+        articleId={articleId}
+        remains={remains}
+        onEnd={() => {
+          if (type === "chapter" && articleData) {
+            getNextPara(articleData);
+          }
+        }}
+        onPathChange={(
+          node: ITocPathNode,
+          e: React.MouseEvent<HTMLSpanElement | HTMLAnchorElement, MouseEvent>
+        ) => {
+          let newType = type;
+          if (node.level === 0) {
+            switch (type) {
+              case "article":
+                newType = "anthology";
+                break;
+              case "chapter":
+                newType = "series";
+                break;
+              default:
+                break;
+            }
+          }
+
+          if (typeof onArticleChange !== "undefined") {
+            const newArticle = node.key
+              ? node.key
+              : `${node.book}-${node.paragraph}`;
+            const target = e.ctrlKey || e.metaKey ? "_blank" : "self";
+            onArticleChange(newType, newArticle, target);
+          }
+        }}
+      />
+      <Divider />
+      {extra}
+      <Divider />
+    </div>
+  );
+};
+
+export default TypePaliWidget;

+ 113 - 0
dashboard/src/components/article/TypeTerm.tsx

@@ -0,0 +1,113 @@
+import { useEffect, useState } from "react";
+
+import { get } from "../../request";
+import { IArticleDataResponse } from "../api/Article";
+import ArticleView from "./ArticleView";
+import { ITermResponse } from "../api/Term";
+import { ArticleMode, ArticleType } from "./Article";
+import "./article.css";
+import { message } from "antd";
+
+interface IWidget {
+  type?: ArticleType;
+  articleId?: string;
+  mode?: ArticleMode | null;
+  channelId?: string | null;
+  active?: boolean;
+  onArticleChange?: Function;
+  onFinal?: Function;
+  onLoad?: Function;
+  onLoading?: Function;
+  onError?: Function;
+}
+const TypeTermWidget = ({
+  type,
+  channelId,
+  articleId,
+  mode = "read",
+  active = false,
+  onArticleChange,
+  onLoading,
+  onError,
+}: IWidget) => {
+  const [articleData, setArticleData] = useState<IArticleDataResponse>();
+  const [articleHtml, setArticleHtml] = useState<string[]>(["<span />"]);
+
+  const channels = channelId?.split("_");
+
+  useEffect(() => {
+    if (!active) {
+      return;
+    }
+    if (typeof articleId === "undefined") {
+      return;
+    }
+    const queryMode = mode === "edit" || mode === "wbw" ? "edit" : "read";
+    let url = "";
+    url = `/v2/terms/${articleId}?mode=${queryMode}`;
+    url += channelId ? `&channel=${channelId}` : "";
+
+    console.log("article url", url);
+
+    if (typeof onLoading !== "undefined") {
+      onLoading(true);
+    }
+    console.log("url", url);
+    get<ITermResponse>(url)
+      .then((json) => {
+        if (json.ok) {
+          setArticleData({
+            uid: json.data.guid,
+            title: json.data.meaning,
+            subtitle: json.data.word,
+            summary: json.data.note,
+            content: json.data.note ? json.data.note : "",
+            content_type: "markdown",
+            html: json.data.html,
+            path: [],
+            status: 30,
+            lang: json.data.language,
+            created_at: json.data.created_at,
+            updated_at: json.data.updated_at,
+          });
+          if (json.data.html) {
+            setArticleHtml([json.data.html]);
+          } else if (json.data.note) {
+            setArticleHtml([json.data.note]);
+          }
+        } else {
+          if (typeof onError !== "undefined") {
+            onError(json.data, json.message);
+          }
+          message.error(json.message);
+        }
+      })
+      .finally(() => {
+        if (typeof onLoading !== "undefined") {
+          onLoading(false);
+        }
+      })
+      .catch((error) => {
+        console.error(error);
+      });
+  }, [active, type, articleId, channelId, mode]);
+
+  return (
+    <ArticleView
+      id={articleData?.uid}
+      title={articleData?.title}
+      subTitle={articleData?.subtitle}
+      summary={articleData?.summary}
+      content={articleData ? articleData.content : ""}
+      html={articleHtml}
+      path={articleData?.path}
+      created_at={articleData?.created_at}
+      updated_at={articleData?.updated_at}
+      channels={channels}
+      type={type}
+      articleId={articleId}
+    />
+  );
+};
+
+export default TypeTermWidget;