From 397d1c1c23e2ff612cd87113143452a0b9975e79 Mon Sep 17 00:00:00 2001 From: Tristan Yang Date: Thu, 19 Jan 2023 23:03:40 +0800 Subject: [PATCH] feat: license upgrade confirm --- public/locales/en/common.json | 6 +- public/locales/en/setting.json | 5 +- public/locales/zh/common.json | 6 +- public/locales/zh/setting.json | 5 +- src/app/config.ts | 6 ++ .../setting/License/LicensePriceListModal.tsx | 65 +++++++++++++++---- .../License/{License.tsx => index.tsx} | 2 + src/routes/setting/navs.tsx | 2 +- src/types/common.ts | 1 + 9 files changed, 80 insertions(+), 18 deletions(-) rename src/routes/setting/License/{License.tsx => index.tsx} (98%) diff --git a/public/locales/en/common.json b/public/locales/en/common.json index b49aa591..d5e3ccde 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -58,11 +58,13 @@ "price": { "pro": { "title": "VoceChat Pro", - "desc": "User Limit: 100" + "desc": "User Limit: 100", + "price": "¥12/year" }, "supreme": { "title": "VoceChat Supreme", - "desc": "User Limit: No Limit" + "desc": "User Limit: No Limit", + "price": "$499/year" } }, "server_update": { diff --git a/public/locales/en/setting.json b/public/locales/en/setting.json index 93044ee8..bb2dd7b3 100644 --- a/public/locales/en/setting.json +++ b/public/locales/en/setting.json @@ -90,7 +90,10 @@ "back_home": "Back Home", "tip_renewing": "Renewing the License, do not close the window!", "tip_renewed": "Renew the License Successfully!", - "tip_renew_error": "Invalided Stripe Session ID" + "tip_renew_error": "Invalided Stripe Session ID", + "tip_domain": "The license is bound to domain and port, please confirm or update your setting:", + "tip_port": "port 80 or 443 can be ignored", + "tip_confirm": "Start Payment" }, "bot": { "add_api_key": "Add API Key", diff --git a/public/locales/zh/common.json b/public/locales/zh/common.json index 38524c1d..c4436431 100644 --- a/public/locales/zh/common.json +++ b/public/locales/zh/common.json @@ -60,11 +60,13 @@ "price": { "pro": { "title": "VoceChat 专业版", - "desc": "用户数限制: 100人" + "desc": "用户数限制: 100人", + "price": "¥12/年" }, "supreme": { "title": "VoceChat 终极版", - "desc": "用户数限制: 无限制" + "desc": "用户数限制: 无限制", + "price": "¥3500/年" } }, "server_update": { diff --git a/public/locales/zh/setting.json b/public/locales/zh/setting.json index fb233b47..bd6aee7d 100644 --- a/public/locales/zh/setting.json +++ b/public/locales/zh/setting.json @@ -85,7 +85,10 @@ "back_home": "回到首页", "tip_renewing": "正在更新证书,请勿关闭窗口!", "tip_renewed": "证书更新成功!", - "tip_renew_error": "无效的Stripe ID" + "tip_renew_error": "无效的Stripe ID", + "tip_domain": "证书与域名以及端口相绑定,请确认或修改:", + "tip_port": "端口号80,443,可不填", + "tip_confirm": "开始支付" }, "bot": { "add_api_key": "新增API Key", diff --git a/src/app/config.ts b/src/app/config.ts index f0f05441..ea28bfa1 100644 --- a/src/app/config.ts +++ b/src/app/config.ts @@ -9,6 +9,7 @@ const BASE_URL = process.env.REACT_APP_RELEASE let prices: Price[] = [ { type: "subscription", + price: "", sub_dur: "year", // sub_type: "year", //day month year title: "Pro", @@ -18,6 +19,7 @@ let prices: Price[] = [ }, { type: "payment", + price: "", title: "supreme", limit: 99999, pid: "price_1M5VoGGGoUDRyc3j6xhQou6D", @@ -31,12 +33,14 @@ export const getLicensePriceList = () => { case 0: { p.title = i18n.t("price.pro.title"); p.desc = i18n.t("price.pro.desc"); + p.price = i18n.t("price.pro.price"); } break; // supreme case 1: { p.title = i18n.t("price.supreme.title"); p.desc = i18n.t("price.supreme.desc"); + p.price = i18n.t("price.supreme.price"); } break; @@ -51,6 +55,7 @@ export const getLicensePriceList = () => { ...ps, { type: "payment", + price: "1", title: "Test VoceChat Enterprise", limit: 99999, pid: "price_1LkQGpGGoUDRyc3jGTh3GYHw", @@ -58,6 +63,7 @@ export const getLicensePriceList = () => { }, { title: "VoceChat Pro", + price: "1", limit: 100, pid: "price_1MMNNCGGoUDRyc3jSIGIsb3C", desc: "test subscription price", diff --git a/src/routes/setting/License/LicensePriceListModal.tsx b/src/routes/setting/License/LicensePriceListModal.tsx index c29d0bb8..7245ec22 100644 --- a/src/routes/setting/License/LicensePriceListModal.tsx +++ b/src/routes/setting/License/LicensePriceListModal.tsx @@ -1,15 +1,17 @@ -import { FC, useState } from "react"; +import { ChangeEvent, FC, useState } from "react"; import toast from "react-hot-toast"; import Modal from "../../../common/component/Modal"; import StyledModal from "../../../common/component/styled/Modal"; import Button from "../../../common/component/styled/Button"; import StyledRadio from "../../../common/component/styled/Radio"; +import Input from "../../../common/component/styled/Input"; import { useGetLicensePaymentUrlMutation } from "../../../app/services/server"; import { getLicensePriceList } from "../../../app/config"; import { useTranslation } from "react-i18next"; import dayjs from "dayjs"; import { PriceSubscriptionDuration, PriceType } from "../../../types/common"; +import Tippy from "@tippyjs/react"; // import { LicenseMetadata, RenewLicense } from "../../types/server"; interface Props { @@ -41,20 +43,26 @@ const LicensePriceListModal: FC = ({ closeModal }) => { const { t } = useTranslation("setting"); const { t: ct } = useTranslation(); const [getUrl, { isLoading, isSuccess }] = useGetLicensePaymentUrlMutation(); + const [host, setHost] = useState(location.host); + const [popUpVisible, setPopUpVisible] = useState(false); const [selectPrice, setSelectPrice] = useState( `${LicensePriceList[0].pid}|${LicensePriceList[0].limit}|${LicensePriceList[0].type}|${LicensePriceList[0].sub_dur || ""}` ); const handleRenew = async () => { const [priceId, user_limit, type, sub_dur = "month"] = selectPrice.split("|") as [string, string, PriceType, PriceSubscriptionDuration]; + const metadata = { + user_limit: Number(user_limit), + expire: type == "subscription" ? getExpireDay(sub_dur) : getExpireDay("year"), + // 本地,则*通配符 + domain: host.startsWith("localhost") ? "*" : host + }; + console.log(metadata); + // return; + const resp = await getUrl({ type, priceId, - metadata: { - user_limit: Number(user_limit), - expire: type == "subscription" ? getExpireDay(sub_dur) : getExpireDay("year"), - // 本地,则*通配符 - domain: location.host.startsWith("localhost") ? "*" : location.host - }, + metadata, cancel_url: location.href, success_url: `${location.origin}/#/cb/payment_success` }); @@ -69,9 +77,16 @@ const LicensePriceListModal: FC = ({ closeModal }) => { const handlePriceSelect = (price: string) => { setSelectPrice(price); }; + const handleUpdateHost = (evt: ChangeEvent) => { + setHost(evt.target.value); + }; + const togglePopUpVisible = () => { + setPopUpVisible(prev => !prev); + }; return ( = ({ closeModal }) => { - + +
+ {t("license.tip_domain")} +
+ +
+ {t("license.tip_port")} +
+ + + +
+
+ + } + > + +
} > `${title} [${desc}]`)} + options={LicensePriceList.map(({ title, desc, price }) => `${title} [${desc}][${price}]`)} values={LicensePriceList.map(({ pid, limit, type = "payment", sub_dur = "month" }) => `${pid}|${limit}|${type}|${sub_dur}`)} value={selectPrice} onChange={(v) => { diff --git a/src/routes/setting/License/License.tsx b/src/routes/setting/License/index.tsx similarity index 98% rename from src/routes/setting/License/License.tsx rename to src/routes/setting/License/index.tsx index 1249f236..f975d5af 100644 --- a/src/routes/setting/License/License.tsx +++ b/src/routes/setting/License/index.tsx @@ -6,6 +6,7 @@ import LicensePriceListModal from "./LicensePriceListModal"; import clsx from "clsx"; import { useTranslation } from "react-i18next"; import UpdateLicenseModal from "./UpdateLicenseModal"; +import Tippy from "@tippyjs/react"; interface ItemProps extends HTMLAttributes { label: string, data?: string | number | string[], foldable?: boolean } const Item = ({ label, data, foldable = false, ...rest }: ItemProps) => { @@ -25,6 +26,7 @@ const Item = ({ label, data, foldable = false, ...rest }: ItemProps) => { }; export default function License() { const { t, i18n } = useTranslation("setting"); + const { t: ct } = useTranslation(); const { license: licenseInfo, reachLimit, upsertLicense, upserting, upserted } = useLicense(); const [modalVisible, setModalVisible] = useState(false); const [updateVisible, setUpdateVisible] = useState(false); diff --git a/src/routes/setting/navs.tsx b/src/routes/setting/navs.tsx index 747d6f85..1c491789 100644 --- a/src/routes/setting/navs.tsx +++ b/src/routes/setting/navs.tsx @@ -4,7 +4,7 @@ import Logins from "./config/Logins"; import ConfigFirebase from "./config/Firebase"; import ConfigSMTP from "./config/SMTP"; import APIConfig from "./APIConfig"; -import License from "./License/License"; +import License from "./License"; import Widget from "./Widget"; import BotConfig from "./BotConfig"; import APIDocument from "./APIDocument"; diff --git a/src/types/common.ts b/src/types/common.ts index b6f0244c..2ab97502 100644 --- a/src/types/common.ts +++ b/src/types/common.ts @@ -6,6 +6,7 @@ export type PriceType = "subscription" | "payment"; export type PriceSubscriptionDuration = "month" | "quarter" | "year"; export type Price = { title: string, + price: string, limit: number, pid: string, desc: string,