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

+ 26 - 0
dashboard/src/components/auth/SoftwareEdition.tsx

@@ -0,0 +1,26 @@
+import { useIntl } from "react-intl";
+import { useAppSelector } from "../../hooks";
+import { currentUser } from "../../reducers/current-user";
+import { TSoftwareEdition } from "../api/Auth";
+
+interface IWidget {
+  style?: React.CSSProperties;
+}
+const SoftwareEdition = ({ style }: IWidget) => {
+  const intl = useIntl();
+  const user = useAppSelector(currentUser);
+  let edition: TSoftwareEdition = "pro";
+  if (user?.roles?.includes("basic")) {
+    edition = "basic";
+  }
+  console.info("edition", edition);
+  return (
+    <span style={style}>
+      {intl.formatMessage({
+        id: `labels.software.edition.${edition}`,
+      })}
+    </span>
+  );
+};
+
+export default SoftwareEdition;

+ 205 - 0
dashboard/src/components/users/SignUp.tsx

@@ -0,0 +1,205 @@
+import { useRef, useState } from "react";
+import { useIntl } from "react-intl";
+import { Alert, Button, Result, message } from "antd";
+import type { ProFormInstance } from "@ant-design/pro-components";
+import {
+  CheckCard,
+  ProForm,
+  ProFormCheckbox,
+  ProFormText,
+  StepsForm,
+} from "@ant-design/pro-components";
+
+import { post } from "../../request";
+import { IInviteRequest, IInviteResponse } from "../api/Auth";
+import { dashboardBasePath } from "../../utils";
+import { get as getUiLang } from "../../locales";
+
+interface IFormData {
+  email: string;
+  lang: string;
+}
+
+const SingUpWidget = () => {
+  const intl = useIntl();
+  const formRef = useRef<ProFormInstance>();
+  const [error, setError] = useState<string>();
+  const [agree, setAgree] = useState(false);
+  return (
+    <StepsForm<IFormData>
+      formRef={formRef}
+      onFinish={async (values: IFormData) => {}}
+      formProps={{
+        validateMessages: {
+          required: "此项为必填项",
+        },
+      }}
+      submitter={{
+        render(props, dom) {
+          if (props.step === 0) {
+            return (
+              <Button
+                type="primary"
+                disabled={!agree}
+                onClick={() => props.onSubmit?.()}
+              >
+                {"下一步"}
+              </Button>
+            );
+          } else if (props.step === 2) {
+            return <></>;
+          } else {
+            return dom;
+          }
+        },
+      }}
+    >
+      <StepsForm.StepForm<{
+        name: string;
+      }>
+        name="welcome"
+        title="注册"
+        stepProps={{
+          description: "注册wikipali教育版",
+        }}
+        onFinish={async () => {
+          return true;
+        }}
+      >
+        <Alert
+          message={"wikipali的阅读,字典,搜索功能无需注册就能使用。"}
+          style={{ marginBottom: 8 }}
+        />
+        <CheckCard.Group
+          onChange={(value) => {
+            console.log("value", value);
+          }}
+          defaultValue="A"
+          style={{ width: "100%" }}
+          size="small"
+        >
+          <CheckCard
+            title="未注册"
+            description={
+              <div>
+                <div>✅经文阅读</div>
+                <div>✅字典</div>
+                <div>✅经文搜索</div>
+                <div>❌课程</div>
+                <div>❌翻译</div>
+              </div>
+            }
+            value="B"
+            disabled
+          />
+          <CheckCard
+            title="基础版"
+            description={
+              <div>
+                <div>✅逐词解析</div>
+                <div>✅翻译</div>
+                <div>✅参加课程</div>
+                <div>❌公开发布译文和逐词解析</div>
+                <div>❌公开发布用户字典和术语</div>
+                <div>❌建立课程</div>
+                <div>❌建立群组</div>
+              </div>
+            }
+            value="A"
+          />
+
+          <CheckCard
+            title="团队版"
+            disabled
+            description={
+              <div>
+                <div>✅逐词解析</div>
+                <div>✅翻译</div>
+                <div>✅参加课程</div>
+                <div>✅公开发布译文和逐词解析</div>
+                <div>✅公开发布用户字典和术语</div>
+                <div>✅建立课程</div>
+                <div>✅建立群组</div>
+              </div>
+            }
+            value="C"
+          />
+        </CheckCard.Group>
+        <ProFormCheckbox.Group
+          name="checkbox"
+          layout="horizontal"
+          options={["我已经了解教育版的功能限制"]}
+          fieldProps={{
+            onChange(checkedValue) {
+              if (checkedValue.includes("我已经了解教育版的功能限制")) {
+                setAgree(true);
+              } else {
+                setAgree(false);
+              }
+            },
+          }}
+        />
+      </StepsForm.StepForm>
+
+      <StepsForm.StepForm<{
+        checkbox: string;
+      }>
+        name="checkbox"
+        title="邮箱验证"
+        stepProps={{
+          description: "填入您的注册邮箱",
+        }}
+        onFinish={async () => {
+          const values = formRef.current?.getFieldsValue();
+          const url = `/v2/invite`;
+          const data: IInviteRequest = {
+            email: values.email,
+            lang: getUiLang(),
+            studio: "",
+            dashboard: dashboardBasePath(),
+          };
+          console.info("api request", values);
+          try {
+            const res = await post<IInviteRequest, IInviteResponse>(url, data);
+            console.debug("api response", res);
+            if (res.ok) {
+              message.success(intl.formatMessage({ id: "flashes.success" }));
+            } else {
+              setError(intl.formatMessage({ id: `error.${res.message}` }));
+            }
+            return res.ok;
+          } catch (error) {
+            setError(error as string);
+            return false;
+          }
+        }}
+      >
+        {error ? <Alert type="error" message={error} /> : undefined}
+        <ProForm.Group>
+          <ProFormText
+            width="md"
+            name="email"
+            required
+            label={intl.formatMessage({ id: "forms.fields.email.label" })}
+            rules={[
+              {
+                required: true,
+                type: "email",
+              },
+            ]}
+          />
+        </ProForm.Group>
+      </StepsForm.StepForm>
+
+      <StepsForm.StepForm name="finish" title="完成注册">
+        <Result
+          status="success"
+          title="验证码已经成功发送"
+          subTitle="验证邮件已经发送到您的邮箱。请查收邮件,根据提示完成注册。"
+        />
+      </StepsForm.StepForm>
+    </StepsForm>
+  );
+};
+
+export default SingUpWidget;

+ 5 - 0
dashboard/src/locales/en-US/error.ts

@@ -0,0 +1,5 @@
+const items = {
+  "error.email.exists": "该邮箱已经存在",
+};
+
+export default items;

+ 5 - 0
dashboard/src/locales/zh-Hans/error.ts

@@ -0,0 +1,5 @@
+const items = {
+  "error.email.exists": "该邮箱已经存在",
+};
+
+export default items;

+ 25 - 0
dashboard/src/pages/users/index.tsx

@@ -0,0 +1,25 @@
+import { Outlet } from "react-router-dom";
+import UiLangSelect from "../../components/general/UiLangSelect";
+import { Footer } from "antd/lib/layout/layout";
+
+const Widget = () => {
+  return (
+    <div style={{ minHeight: "100vh" }}>
+      <div style={{ textAlign: "right", backgroundColor: "#3e3e3e" }}>
+        <UiLangSelect />
+      </div>
+      <div
+        style={{
+          minHeight: "100vh",
+          paddingTop: "1em",
+          backgroundColor: "#3e3e3e",
+        }}
+      >
+        <Outlet />
+      </div>
+      <Footer />
+    </div>
+  );
+};
+
+export default Widget;

+ 22 - 0
dashboard/src/pages/users/sign-up.tsx

@@ -0,0 +1,22 @@
+import { Card } from "antd";
+
+import SignUp from "../../components/users/SignUp";
+
+const Widget = () => {
+  return (
+    <div
+      style={{
+        width: 1000,
+        maxWidth: "100%",
+        marginLeft: "auto",
+        marginRight: "auto",
+      }}
+    >
+      <Card title="注册">
+        <SignUp />
+      </Card>
+    </div>
+  );
+};
+
+export default Widget;