feat: update license manually
This commit is contained in:
+6
-6
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vocechat-web",
|
||||
"version": "0.3.21",
|
||||
"version": "0.3.23",
|
||||
"private": true,
|
||||
"homepage": "https://voce.chat",
|
||||
"dependencies": {
|
||||
@@ -36,7 +36,7 @@
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"i18next": "^22.0.6",
|
||||
"i18next-browser-languagedetector": "^7.0.1",
|
||||
"i18next-http-backend": "^2.0.1",
|
||||
"i18next-http-backend": "^2.0.2",
|
||||
"linkify-it": "3.0.3",
|
||||
"linkify-plugin-mention": "^3.0.4",
|
||||
"linkifyjs": "^3.0.5",
|
||||
@@ -64,9 +64,9 @@
|
||||
"react-textarea-autosize": "^8.4.0",
|
||||
"resolve": "^1.22.1",
|
||||
"rooks": "^7.4.2",
|
||||
"slate": "^0.85.0",
|
||||
"slate-history": "^0.85.0",
|
||||
"slate-react": "^0.83.2",
|
||||
"slate": "^0.86.0",
|
||||
"slate-history": "^0.86.0",
|
||||
"slate-react": "^0.86.0",
|
||||
"source-map-loader": "^4.0.1",
|
||||
"style-loader": "^3.3.1",
|
||||
"styled-components": "^5.3.6",
|
||||
@@ -142,7 +142,7 @@
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"gh-pages": "^4.0.0",
|
||||
"husky": "^8.0.2",
|
||||
"lint-staged": "^13.0.3",
|
||||
"lint-staged": "^13.0.4",
|
||||
"md5-file": "^5.0.0",
|
||||
"patch-package": "^6.5.0",
|
||||
"postcss": "^8.4.19",
|
||||
|
||||
@@ -66,6 +66,8 @@
|
||||
"create": "Created At",
|
||||
"value": "License Value",
|
||||
"renew": "Renew License",
|
||||
"update": "Update Manually",
|
||||
"update_placeholder": "Please Input the new license value",
|
||||
"renew_select": "Please select the price",
|
||||
"tip": {
|
||||
"title": "A chance to get a free license upgrade!",
|
||||
@@ -120,7 +122,12 @@
|
||||
"config": "Configuration Description",
|
||||
"param_key": "Parameter Key",
|
||||
"default_value": "Default Value",
|
||||
"remark": "Remarks"
|
||||
"remark": "Remarks",
|
||||
"param_host": "Assign the user chatting with visitor(User ID)",
|
||||
"param_close_width": "The width while widget closed",
|
||||
"param_close_height": "The height while widget closed",
|
||||
"param_open_width": "The width while widget opened",
|
||||
"param_open_height": "The height while widget opened"
|
||||
},
|
||||
"faq": {
|
||||
"client_version": "Client Version",
|
||||
|
||||
@@ -67,6 +67,9 @@
|
||||
"create": "创建时间",
|
||||
"value": "证书内容",
|
||||
"renew": "升级证书",
|
||||
"update": "手动更新",
|
||||
"update_placeholder": "请输入新的证书内容",
|
||||
|
||||
"renew_select": "请选择价格套餐",
|
||||
"tip": {
|
||||
"title": "一个获取免费升级的机会!",
|
||||
@@ -121,7 +124,12 @@
|
||||
"config": "配置说明",
|
||||
"param_key": "参数",
|
||||
"default_value": "默认值",
|
||||
"remark": "备注"
|
||||
"remark": "备注",
|
||||
"param_host": "指定和谁聊天(用户ID)",
|
||||
"param_close_width": "挂件关闭态的宽度",
|
||||
"param_close_height": "挂件关闭态的高度",
|
||||
"param_open_width": "挂件打开态的宽度",
|
||||
"param_open_height": "挂件打开态的高度"
|
||||
},
|
||||
"faq": {
|
||||
"client_version": "客户端版本",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// import { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import {
|
||||
useCheckLicenseMutation,
|
||||
useGetLicenseQuery,
|
||||
@@ -10,12 +10,12 @@ const useLicense = () => {
|
||||
const { userCount, isGuest } = useAppSelector((store) => {
|
||||
return { userCount: store.users.ids.length, isGuest: store.authData.guest };
|
||||
});
|
||||
const { data: license } = useGetLicenseQuery(undefined, {
|
||||
const { data: license, refetch: refetchLicense } = useGetLicenseQuery(undefined, {
|
||||
refetchOnMountOrArgChange: true,
|
||||
skip: isGuest
|
||||
});
|
||||
const [check, { isLoading: isChecking, isSuccess: checked }] = useCheckLicenseMutation();
|
||||
const [upsert, { isSuccess: upserted, isLoading: upserting }] = useUpsertLicenseMutation();
|
||||
const [upsert, { isSuccess: upserted, isLoading: upserting, reset: resetUpsert }] = useUpsertLicenseMutation();
|
||||
const checkLicense = (l: string) => {
|
||||
check(l);
|
||||
};
|
||||
@@ -28,7 +28,12 @@ const useLicense = () => {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
console.log("uuu", userCount, license);
|
||||
useEffect(() => {
|
||||
if (upserted) {
|
||||
refetchLicense();
|
||||
resetUpsert();
|
||||
}
|
||||
}, [upserted]);
|
||||
const lUserLimit = license?.user_limit ?? Number.MAX_SAFE_INTEGER;
|
||||
return {
|
||||
reachLimit: userCount >= lUserLimit,
|
||||
|
||||
@@ -5,6 +5,7 @@ import useLicense from "../../../common/hook/useLicense";
|
||||
import LicensePriceListModal from "./LicensePriceListModal";
|
||||
import clsx from "clsx";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import UpdateLicenseModal from "./UpdateLicenseModal";
|
||||
|
||||
interface ItemProps extends HTMLAttributes<HTMLSpanElement> { label: string, data?: string | number | string[], foldable?: boolean }
|
||||
const Item = ({ label, data, foldable = false, ...rest }: ItemProps) => {
|
||||
@@ -24,18 +25,20 @@ const Item = ({ label, data, foldable = false, ...rest }: ItemProps) => {
|
||||
};
|
||||
export default function License() {
|
||||
const { t } = useTranslation("setting");
|
||||
const { license: licenseInfo, reachLimit } = useLicense();
|
||||
const { license: licenseInfo, reachLimit, upsertLicense, upserting, upserted } = useLicense();
|
||||
const [modalVisible, setModalVisible] = useState(false);
|
||||
const [updateVisible, setUpdateVisible] = useState(false);
|
||||
const [base58Fold, setBase58Fold] = useState(true);
|
||||
const handleRenewLicense = () => {
|
||||
toggleModalVisible();
|
||||
};
|
||||
const toggleModalVisible = () => {
|
||||
setModalVisible((prev) => !prev);
|
||||
};
|
||||
const toggleUpdateModalVisible = () => {
|
||||
setUpdateVisible((prev) => !prev);
|
||||
};
|
||||
const handleLicenseValueToggle = () => {
|
||||
setBase58Fold(pre => !pre);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="max-w-3xl flex flex-col justify-start items-start gap-4">
|
||||
@@ -48,7 +51,10 @@ export default function License() {
|
||||
<Item label={t("license.value")} data={licenseInfo?.base58} foldable={base58Fold} title={base58Fold ? "Click to see full text" : "Click to fold text"}
|
||||
onClick={handleLicenseValueToggle} />
|
||||
</div>
|
||||
<Button onClick={handleRenewLicense}>{t("license.renew")}</Button>
|
||||
<div className="flex gap-2">
|
||||
<Button onClick={toggleModalVisible}>{t("license.renew")}</Button>
|
||||
<Button onClick={toggleUpdateModalVisible} className="ghost">{t("license.update")}</Button>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4 bg-primary-500 text-white rounded drop-shadow-xl p-5">
|
||||
<h2 className="text-2xl font-bold">{t("license.tip.title")} 🎁</h2>
|
||||
<p className="text-base flex flex-col"><span>
|
||||
@@ -58,7 +64,7 @@ export default function License() {
|
||||
{t("license.tip.booking")} <a className="underline text-lg text-green-200" href="https://calendly.com/hansu/han-meeting" target="_blank" rel="noopener noreferrer">https://calendly.com/hansu/han-meeting</a>
|
||||
</span>
|
||||
<span>
|
||||
{t("license.tip.wechat")}<em className="text-lg text-green-200">yanggc_2013</em>
|
||||
{t("license.tip.wechat")}<em className="text-lg text-green-200">Privoce</em>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
@@ -68,6 +74,14 @@ export default function License() {
|
||||
closeModal={toggleModalVisible}
|
||||
/>
|
||||
)}
|
||||
{updateVisible && (
|
||||
<UpdateLicenseModal
|
||||
updated={upserted}
|
||||
updating={upserting}
|
||||
updateLicense={upsertLicense}
|
||||
closeModal={toggleUpdateModalVisible}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@ interface Props {
|
||||
}
|
||||
|
||||
const LicensePriceListModal: FC<Props> = ({ closeModal }) => {
|
||||
const { t } = useTranslation(["setting", "common"]);
|
||||
const { t } = useTranslation("setting");
|
||||
const { t: ct } = useTranslation();
|
||||
const [getUrl, { isLoading, isSuccess }] = useGetLicensePaymentUrlMutation();
|
||||
const [selectPrice, setSelectPrice] = useState(
|
||||
`${LicensePriceList[0].pid}|${LicensePriceList[0].limit}`
|
||||
@@ -53,9 +54,9 @@ const LicensePriceListModal: FC<Props> = ({ closeModal }) => {
|
||||
buttons={
|
||||
<>
|
||||
<Button onClick={closeModal} className="ghost">
|
||||
{t("action.cancel", { ns: "common" })}
|
||||
{ct("action.cancel")}
|
||||
</Button>
|
||||
<Button disabled={isLoading || isSuccess} onClick={handleRenew} className="danger">
|
||||
<Button disabled={isLoading || isSuccess} onClick={handleRenew} >
|
||||
{isLoading ? "Initialize Payment Url" : isSuccess ? "Redirecting" : t("license.renew")}
|
||||
</Button>
|
||||
</>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import { ChangeEvent, FC, useState, useEffect } 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 Textarea from "../../../common/component/styled/Textarea";
|
||||
|
||||
import { useTranslation } from "react-i18next";
|
||||
interface Props {
|
||||
closeModal: () => void;
|
||||
updateLicense: (param: string) => void;
|
||||
updated: boolean;
|
||||
updating: boolean
|
||||
// domain: string;
|
||||
}
|
||||
|
||||
const UpdateLicenseModal: FC<Props> = ({ closeModal, updateLicense, updating, updated }) => {
|
||||
const [value, setValue] = useState("");
|
||||
const { t } = useTranslation("setting");
|
||||
const { t: ct } = useTranslation();
|
||||
|
||||
const handleRenew = () => {
|
||||
updateLicense(value);
|
||||
|
||||
};
|
||||
const handleLicenseUpdate = (evt: ChangeEvent<HTMLTextAreaElement>) => {
|
||||
setValue(evt.target.value);
|
||||
};
|
||||
useEffect(() => {
|
||||
if (updated) {
|
||||
toast.success("Update Successfully!");
|
||||
closeModal();
|
||||
}
|
||||
}, [updated]);
|
||||
|
||||
return (
|
||||
<Modal id="modal-modal">
|
||||
<StyledModal
|
||||
buttons={
|
||||
<>
|
||||
<Button onClick={closeModal} className="ghost">
|
||||
{ct("action.cancel")}
|
||||
</Button>
|
||||
<Button disabled={updating || updated || !value} onClick={handleRenew} >
|
||||
{updating ? "Updating" : updated ? "Update Successfully" : t("license.update")}
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<Textarea rows={18} placeholder={t("license.update_placeholder")} value={value} onChange={handleLicenseUpdate} />
|
||||
</StyledModal>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default UpdateLicenseModal;
|
||||
@@ -29,7 +29,7 @@ export default function Widget() {
|
||||
{t('code')}:
|
||||
</label>
|
||||
<SyntaxHighlighter id="code" language="html" style={vscDarkPlus} className="rounded">
|
||||
{`<!-- ${t('code_comment')} -->\n<script \n data-host-id="4" \n data-close-width="48" \n data-close-height="48" \n data-open-width="380" \n data-open-height="680" \n src="${location.origin}/widget.js" \n async \n/>`}
|
||||
{`<!-- ${t('code_comment')} -->\n<script \n data-host-id="1" \n data-close-width="48" \n data-close-height="48" \n data-open-width="380" \n data-open-height="680" \n src="${location.origin}/widget.js" \n async \n/>`}
|
||||
</SyntaxHighlighter>
|
||||
<div className="text-gray-500 text-sm mt-5 mb-2">
|
||||
{t('config')}:
|
||||
@@ -47,23 +47,23 @@ export default function Widget() {
|
||||
{[{
|
||||
paramKey: "host-id",
|
||||
paramDefault: 1,
|
||||
remarks: "Assign the user chatting with visitor"
|
||||
remarks: t("param_host")
|
||||
}, {
|
||||
paramKey: "close-width",
|
||||
paramDefault: `48(px)`,
|
||||
remarks: "The width while widget closed"
|
||||
remarks: t("param_open_width")
|
||||
}, {
|
||||
paramKey: "close-height",
|
||||
paramDefault: `48(px)`,
|
||||
remarks: "The height while widget closed"
|
||||
remarks: t("param_close_height")
|
||||
}, {
|
||||
paramKey: "open-width",
|
||||
paramDefault: `380(px)`,
|
||||
remarks: "The width while widget opened"
|
||||
remarks: t("param_open_width")
|
||||
}, {
|
||||
paramKey: "open-height",
|
||||
paramDefault: `680(px)`,
|
||||
remarks: "The height while widget opened"
|
||||
remarks: t("param_open_height")
|
||||
}
|
||||
].map(row => <Row key={row.paramKey} {...row} />)}
|
||||
</tbody>
|
||||
|
||||
@@ -78,7 +78,7 @@ const navs = [
|
||||
},
|
||||
{
|
||||
name: "feedback",
|
||||
component: "Email: han@privoce.com\nWechat: yanggc_2013"
|
||||
component: "Email: han@privoce.com Wechat: Privoce"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -7036,10 +7036,10 @@ i18next-browser-languagedetector@^7.0.1:
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.19.4"
|
||||
|
||||
i18next-http-backend@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://mirrors.cloud.tencent.com/npm/i18next-http-backend/-/i18next-http-backend-2.0.1.tgz#ef744dd76f36399b9bc169c4e4221db9bbaf6fe5"
|
||||
integrity sha512-kzvSkOT3yhVijumDlp8/TgD1v07lYdFXsf5YYbB7Yu+K2S6PO0lKgZ4c/fyFcAKWiAiTjt9uVecBAbnJjKzhOw==
|
||||
i18next-http-backend@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://mirrors.cloud.tencent.com/npm/i18next-http-backend/-/i18next-http-backend-2.0.2.tgz#83fa92c12b0b6e90f1969d904b81855d57b1db1c"
|
||||
integrity sha512-TFiIqitZEc8+jyca31EW5ef5PjUYtUGGfL8c8FJwiiHguq5OQTqoR3mxpKqaCPiikg+cxSgXtNA2gZPCu0aryQ==
|
||||
dependencies:
|
||||
cross-fetch "3.1.5"
|
||||
|
||||
@@ -8265,7 +8265,7 @@ linkifyjs@^3.0.5:
|
||||
resolved "https://mirrors.cloud.tencent.com/npm/linkifyjs/-/linkifyjs-3.0.5.tgz#99e51a3a0c0e232fcb63ebb89eea3ff923378f34"
|
||||
integrity sha512-1Y9XQH65eQKA9p2xtk+zxvnTeQBG7rdAXSkUG97DmuI/Xhji9uaUzaWxRj6rf9YC0v8KKHkxav7tnLX82Sz5Fg==
|
||||
|
||||
lint-staged@^13.0.3:
|
||||
lint-staged@^13.0.4:
|
||||
version "13.0.4"
|
||||
resolved "https://mirrors.cloud.tencent.com/npm/lint-staged/-/lint-staged-13.0.4.tgz#c4b4391280c35165b805ad43304ba01f733067a0"
|
||||
integrity sha512-HxlHCXoYRsq9QCby5wFozmZW00hMs/9e3l+/dz6Qr8Kle4UH0kJTdABAbqhzG+3pcG6QjL9kz7NgGBfph+a5dw==
|
||||
@@ -11090,17 +11090,17 @@ slash@^4.0.0:
|
||||
resolved "https://mirrors.cloud.tencent.com/npm/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7"
|
||||
integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==
|
||||
|
||||
slate-history@^0.85.0:
|
||||
version "0.85.0"
|
||||
resolved "https://mirrors.cloud.tencent.com/npm/slate-history/-/slate-history-0.85.0.tgz#fdbaa8f91b0513bbc269a08523cade7e9732ac62"
|
||||
integrity sha512-4rPx+Y7ubROlc85mYzK9iXRMgjmor6v87AMx5Oh6eOuW4elCz+uAiBWT6ates7JjCNiDXBHxtMvBEa37UG5dWg==
|
||||
slate-history@^0.86.0:
|
||||
version "0.86.0"
|
||||
resolved "https://mirrors.cloud.tencent.com/npm/slate-history/-/slate-history-0.86.0.tgz#5554612271d2fc1018a7918be3961bb66e620c58"
|
||||
integrity sha512-OxObL9tbhgwvSlnKSCpGIh7wnuaqvOj5jRExGjEyCU2Ke8ctf22HjT+jw7GEi9ttLzNTUmTEU3YIzqKGeqN+og==
|
||||
dependencies:
|
||||
is-plain-object "^5.0.0"
|
||||
|
||||
slate-react@^0.83.2:
|
||||
version "0.83.2"
|
||||
resolved "https://mirrors.cloud.tencent.com/npm/slate-react/-/slate-react-0.83.2.tgz#7099db1607b79c95cc2a41e2df1e04982b7e26a5"
|
||||
integrity sha512-V5qtPsCOiDVCMU3ovj/CWndxx9/as5/wGJxnbJDRVzuazSh+NVw/YuGTlus1fCt+Nlt6UHOhFvM7C9pXYaftPA==
|
||||
slate-react@^0.86.0:
|
||||
version "0.86.0"
|
||||
resolved "https://mirrors.cloud.tencent.com/npm/slate-react/-/slate-react-0.86.0.tgz#e1e0bfaf9a21f8e18d86b616538d11e81c0f8920"
|
||||
integrity sha512-FlzG0CL1MtpZk7DRH6a101FdqdhTi+vZ23SbY5hQudIdgLo7QnUBv97BRe30VctqsL9L+Z2OsFHSCmWpIIxJAw==
|
||||
dependencies:
|
||||
"@types/is-hotkey" "^0.1.1"
|
||||
"@types/lodash" "^4.14.149"
|
||||
@@ -11111,10 +11111,10 @@ slate-react@^0.83.2:
|
||||
scroll-into-view-if-needed "^2.2.20"
|
||||
tiny-invariant "1.0.6"
|
||||
|
||||
slate@^0.85.0:
|
||||
version "0.85.0"
|
||||
resolved "https://mirrors.cloud.tencent.com/npm/slate/-/slate-0.85.0.tgz#1e922dce13a7b37816670312f5caac70aa2a8d1c"
|
||||
integrity sha512-SHlgOI7fDG50sL+lfAI+nXF9FQpoqf7KNRofggyyE4ngsj1nINOEpFSYKGPkZgVUUkPflWK6PuBJMR6nEuUiKg==
|
||||
slate@^0.86.0:
|
||||
version "0.86.0"
|
||||
resolved "https://mirrors.cloud.tencent.com/npm/slate/-/slate-0.86.0.tgz#9704a195a2fe56bcff497b278f0489f3a94b23fc"
|
||||
integrity sha512-aexL720Tpqx6St5oz0jo0/wZWCT7z8lChKkVJo2eiFkSNmoSnCGR62d2itAvmse7dEXkl4DbfAxRQPj8JDuGTg==
|
||||
dependencies:
|
||||
immer "^9.0.6"
|
||||
is-plain-object "^5.0.0"
|
||||
|
||||
Reference in New Issue
Block a user