瀏覽代碼

Merge pull request #1666 from visuddhinanda/agile

#1636
visuddhinanda 2 年之前
父節點
當前提交
f93613ee9d

+ 32 - 0
dashboard/src/components/auth/LoginAlert.tsx

@@ -0,0 +1,32 @@
+import { useIntl } from "react-intl";
+import { Link } from "react-router-dom";
+import { Alert } from "antd";
+
+import { useAppSelector } from "../../hooks";
+import { currentUser as _currentUser } from "../../reducers/current-user";
+
+const LoginAlertWidget = () => {
+  const intl = useIntl();
+
+  const user = useAppSelector(_currentUser);
+  return user ? (
+    <></>
+  ) : (
+    <Alert
+      message={intl.formatMessage({
+        id: "message.auth.guest.alert",
+      })}
+      type="warning"
+      closable
+      action={
+        <Link to="/anonymous/users/sign-in">
+          {intl.formatMessage({
+            id: "buttons.sign-in",
+          })}
+        </Link>
+      }
+    />
+  );
+};
+
+export default LoginAlertWidget;

+ 48 - 0
dashboard/src/components/auth/LoginAlertModal.tsx

@@ -0,0 +1,48 @@
+import { useIntl } from "react-intl";
+import { Modal } from "antd";
+import { ExclamationCircleOutlined } from "@ant-design/icons";
+
+import { useAppSelector } from "../../hooks";
+import { isGuest } from "../../reducers/current-user";
+import { useEffect } from "react";
+import { useNavigate } from "react-router-dom";
+
+interface IWidget {
+  enable?: boolean;
+  mode?: string;
+}
+const LoginAlertModalWidget = ({ enable = false, mode = "read" }: IWidget) => {
+  const intl = useIntl();
+  const navigate = useNavigate();
+
+  const guest = useAppSelector(isGuest);
+  console.log("mode", mode);
+  useEffect(() => {
+    const guestMode = localStorage.getItem("guest_mode");
+    if (guestMode === "true") {
+      return;
+    }
+    if (guest && (mode !== "read" || enable === true)) {
+      Modal.confirm({
+        title: intl.formatMessage({
+          id: "labels.no.login",
+        }),
+        icon: <ExclamationCircleOutlined />,
+        content: intl.formatMessage({
+          id: "message.auth.guest.alert",
+        }),
+        okText: intl.formatMessage({
+          id: "buttons.sign-in",
+        }),
+        cancelText: intl.formatMessage({
+          id: "buttons.use.as.guest",
+        }),
+        onOk: () => navigate("/anonymous/users/sign-in"),
+        onCancel: () => localStorage.setItem("guest_mode", "true"),
+      });
+    }
+  }, [guest, mode, enable]);
+  return <></>;
+};
+
+export default LoginAlertModalWidget;

+ 0 - 4
dashboard/src/components/channel/ChannelPickerTable.tsx

@@ -20,9 +20,6 @@ import { IChannel } from "./Channel";
 import { ArticleType } from "../article/Article";
 import CopyToModal from "./CopyToModal";
 
-import { useAppSelector } from "../../hooks";
-import { currentUser as _currentUser } from "../../reducers/current-user";
-
 const { Link, Text } = Typography;
 
 interface IParams {
@@ -75,7 +72,6 @@ const ChannelPickerTableWidget = ({
   const [copyOpen, setCopyOpen] = useState<boolean>(false);
   const [ownerChanged, setOwnerChanged] = useState<boolean>(false);
 
-  const user = useAppSelector(_currentUser);
   const ref = useRef<ActionType>();
 
   useEffect(() => {

+ 3 - 1
dashboard/src/load.ts

@@ -1,7 +1,7 @@
 //import { Empty } from "google-protobuf/google/protobuf/empty_pb";
 //import { Duration } from "google-protobuf/google/protobuf/duration_pb";
 
-import { get as getToken, IUser, signIn } from "./reducers/current-user";
+import { get as getToken, guest, IUser, signIn } from "./reducers/current-user";
 //import { DURATION } from "./reducers/current-user";
 import { ISite, refresh as refreshLayout } from "./reducers/layout";
 import { ISettingItem, refresh as refreshSetting } from "./reducers/setting";
@@ -83,10 +83,12 @@ const init = () => {
         store.dispatch(signIn([it, response.data.token]));
       } else {
         localStorage.removeItem("token");
+        store.dispatch(guest(true));
       }
     });
   } else {
     console.log("no token");
+    store.dispatch(guest(true));
   }
 
   //获取用户设置

+ 1 - 0
dashboard/src/locales/zh-Hans/buttons.ts

@@ -73,6 +73,7 @@ const items = {
   "buttons.suggestion": "修改建议",
   "buttons.accept": "接受",
   "buttons.refuse": "拒绝",
+  "buttons.use.as.guest": "以访客身份继续使用",
 };
 
 export default items;

+ 1 - 0
dashboard/src/locales/zh-Hans/label.ts

@@ -18,6 +18,7 @@ const items = {
   "labels.created-at": "创建于",
   "labels.recent-scan": "最近打开",
   "labels.icp": "ICP:",
+  "labels.no.login": "尚未登录",
 };
 
 export default items;

+ 2 - 0
dashboard/src/locales/zh-Hans/message.ts

@@ -2,6 +2,8 @@ const items = {
   "flashes.success": "操作成功",
   "message.irrevocable": "此操作不可撤销",
   "message.delete.confirm": "确定删除吗?",
+  "message.auth.guest.alert":
+    "您尚未登录,只能查看公开数据,其他功能无法使用。",
 };
 
 export default items;

+ 12 - 3
dashboard/src/pages/library/article/show.tsx

@@ -49,6 +49,7 @@ import { modeChange } from "../../../reducers/article-mode";
 import SearchButton from "../../../components/general/SearchButton";
 import ToStudio from "../../../components/auth/ToStudio";
 import { currentUser as _currentUser } from "../../../reducers/current-user";
+import LoginAlertModal from "../../../components/auth/LoginAlertModal";
 
 /**
  * type:
@@ -293,10 +294,17 @@ const Widget = () => {
                   anthologyId={searchParams.get("anthology")}
                   onSelect={(key: Key) => {
                     console.log("toc click", key);
-                    let url = `/article/${type}/${key}?`;
+                    const newType = type === "para" ? "chapter" : type;
+                    let url = `/article/${newType}/${key}?`;
                     let param: string[] = [];
-                    searchParams.forEach((value, key) => {
-                      param.push(`${key}=${value}`);
+                    searchParams.forEach((value, searchKey) => {
+                      if (type !== "para") {
+                        param.push(`${searchKey}=${value}`);
+                      } else {
+                        if (searchKey !== "book" && searchKey !== "par") {
+                          param.push(`${searchKey}=${value}`);
+                        }
+                      }
                     });
                     navigate(url + param.join("&"));
                     scrollToTop();
@@ -320,6 +328,7 @@ const Widget = () => {
             key="Article"
             style={{ marginLeft: "auto", marginRight: "auto", width: 1100 }}
           >
+            <LoginAlertModal mode={currMode} />
             <Article
               active={true}
               type={type as ArticleType}

+ 7 - 1
dashboard/src/reducers/current-user.ts

@@ -44,6 +44,7 @@ export interface IUser {
 
 interface IState {
   payload?: IUser;
+  guest?: boolean;
 }
 
 const initialState: IState = {};
@@ -60,10 +61,13 @@ export const slice = createSlice({
       state.payload = undefined;
       remove();
     },
+    guest: (state, action: PayloadAction<boolean>) => {
+      state.guest = action.payload;
+    },
   },
 });
 
-export const { signIn, signOut } = slice.actions;
+export const { signIn, signOut, guest } = slice.actions;
 
 export const isRoot = (state: RootState): boolean =>
   state.currentUser.payload?.roles.includes(ROLE_ROOT) || false;
@@ -71,5 +75,7 @@ export const isAdministrator = (state: RootState): boolean =>
   state.currentUser.payload?.roles.includes(ROLE_ADMINISTRATOR) || false;
 export const currentUser = (state: RootState): IUser | undefined =>
   state.currentUser.payload;
+export const isGuest = (state: RootState): boolean | undefined =>
+  state.currentUser.guest;
 
 export default slice.reducer;