diff --git a/src/app/services/server.ts b/src/app/services/server.ts index bdea4d05..65300e33 100644 --- a/src/app/services/server.ts +++ b/src/app/services/server.ts @@ -13,7 +13,8 @@ import { CreateAdminDTO, SMTPConfig, AgoraConfig, - GithubAuthConfig + GithubAuthConfig, + LicenseResponse } from "../../types/server"; const defaultExpireDuration = 7 * 24 * 60 * 60; @@ -192,6 +193,21 @@ export const serverApi = createApi({ query: () => ({ url: `/admin/system/initialized` }) + }), + + checkLicense: builder.mutation({ + query: (license) => ({ + url: "/license/check", + method: "POST", + body: { license } + }) + }), + upsertLicense: builder.mutation({ + query: (license) => ({ + url: "/license/save", + method: "POST", + body: { license } + }) }) }) }); @@ -223,5 +239,7 @@ export const { useGetThirdPartySecretQuery, useUpdateThirdPartySecretMutation, useCreateAdminMutation, - useGetInitializedQuery + useGetInitializedQuery, + useUpsertLicenseMutation, + useCheckLicenseMutation } = serverApi; diff --git a/src/common/hook/useLicense.ts b/src/common/hook/useLicense.ts new file mode 100644 index 00000000..1b03ea1b --- /dev/null +++ b/src/common/hook/useLicense.ts @@ -0,0 +1,36 @@ +import { useEffect } from "react"; +import { useCheckLicenseMutation, useUpsertLicenseMutation } from "../../app/services/server"; + +const useLicense = (license?: string) => { + const [check, { data, isLoading: isChecking, isSuccess: checked }] = useCheckLicenseMutation(); + const [upsert, { isSuccess: upserted, isLoading: upserting }] = useUpsertLicenseMutation(); + const checkLicense = (l: string) => { + check(l); + }; + const upsertLicense = async (l: string) => { + // check first + const resp = await check(l); + if ("data" in resp && resp.data.sign) { + return await upsert(l); + } else { + return false; + } + }; + useEffect(() => { + if (license) { + checkLicense(license); + } + }, [license]); + + return { + validInfo: data, + checked, + checking: isChecking, + upserting, + upserted, + checkLicense, + upsertLicense + }; +}; + +export default useLicense; diff --git a/src/routes/setting/License.tsx b/src/routes/setting/License.tsx new file mode 100644 index 00000000..d3e30bc5 --- /dev/null +++ b/src/routes/setting/License.tsx @@ -0,0 +1,96 @@ +import { ChangeEvent, useState } from "react"; +import styled from "styled-components"; +import Tippy from "@tippyjs/react"; +import toast from "react-hot-toast"; +import { hideAll } from "tippy.js"; +import Textarea from "../../common/component/styled/Textarea"; +import Button from "../../common/component/styled/Button"; +import useLicense from "../../common/hook/useLicense"; + +const StyledConfirm = styled.div` + padding: 12px; + border-radius: 10px; + border: 1px solid orange; + background-color: #fff; + display: flex; + flex-direction: column; + gap: 10px; + width: 250px; + .tip { + color: orange; + font-size: 12px; + line-height: 1.5; + } + .btns { + display: flex; + width: 100%; + justify-content: flex-end; + gap: 14px; + } +`; +const Styled = styled.div` + max-width: 500px; + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + gap: 15px; + > .input { + width: 100%; + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 8px; + } +`; + +export default function License() { + const { checking, upserting, upsertLicense } = useLicense(); + const [license, setLicense] = useState(""); + const handleUpsert = async () => { + if (!license) { + toast.error("License Empty"); + hideAll(); + return; + } + const success = await upsertLicense(license); + if (!success) { + toast.error("Invalid License"); + hideAll(); + } else { + toast.success("License Updated!"); + } + }; + const handleLicenseInput = (evt: ChangeEvent) => { + setLicense(evt.target.value); + }; + + const disableBtn = checking || upserting || !license; + return ( + +
+