feat: add license upgrade flag to server
This commit is contained in:
+6
-3
@@ -11,12 +11,15 @@ let prices: Price[] = [
|
||||
type: "booking",
|
||||
}
|
||||
];
|
||||
|
||||
const local_dev = `https://dev.voce.chat`;
|
||||
const official_dev = `https://dev.voce.chat`;
|
||||
// const local_dev = `http://07333.qicp.vip:3030`;
|
||||
const local_dev = official_dev;
|
||||
// const local_dev = `http://localhost:3333`;
|
||||
export const BASE_ORIGIN = process.env.REACT_APP_RELEASE
|
||||
? `${location.origin}`
|
||||
: local_dev;
|
||||
export const IS_OFFICIAL_DEMO = BASE_ORIGIN === official_dev;
|
||||
|
||||
const BASE_URL = `${BASE_ORIGIN}/api`;
|
||||
export const getLicensePriceList = () => {
|
||||
const ps = prices.map((p, idx) => {
|
||||
@@ -69,7 +72,7 @@ export const PAYMENT_URL_PREFIX =
|
||||
process.env.NODE_ENV === "production"
|
||||
? `https://vera.nicegoodthings.com`
|
||||
: `http://localhost:4000`;
|
||||
export const CACHE_VERSION = `0.3.33`;
|
||||
export const CACHE_VERSION = `0.3.36`;
|
||||
export const GuestRoutes = ["/", "/chat", "/chat/channel/:channel_id"];
|
||||
export const ContentTypes = {
|
||||
text: "text/plain",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createApi } from "@reduxjs/toolkit/query/react";
|
||||
import BASE_URL, { ContentTypes, PAYMENT_URL_PREFIX } from "../config";
|
||||
import BASE_URL, { ContentTypes, IS_OFFICIAL_DEMO, PAYMENT_URL_PREFIX } from "../config";
|
||||
import { updateInfo } from "../slices/server";
|
||||
import baseQuery from "./base.query";
|
||||
import { RootState } from "../store";
|
||||
@@ -214,7 +214,24 @@ export const serverApi = createApi({
|
||||
getLicense: builder.query<LicenseResponse, void>({
|
||||
query: () => ({
|
||||
url: `/license`
|
||||
})
|
||||
}),
|
||||
async onQueryStarted(data, { dispatch, queryFulfilled, getState }) {
|
||||
// vocechat官方demo 则忽略
|
||||
if (IS_OFFICIAL_DEMO) return;
|
||||
const rootStore = getState() as RootState;
|
||||
const { upgraded: prevValue } = rootStore.server;
|
||||
try {
|
||||
const { data: { user_limit } } = await queryFulfilled;
|
||||
const currValue = user_limit > 20;
|
||||
if (prevValue !== currValue) {
|
||||
dispatch(updateInfo({ upgraded: currValue }));
|
||||
}
|
||||
} catch {
|
||||
console.error("update license upgraded status failed ");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}),
|
||||
|
||||
getLicensePaymentUrl: builder.mutation<RenewLicenseResponse, RenewLicense>({
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
import { Server } from "../../types/server";
|
||||
|
||||
export interface StoredServer extends Server {
|
||||
upgraded: boolean,
|
||||
logo: string;
|
||||
inviteLink?: {
|
||||
link: string;
|
||||
@@ -9,6 +10,7 @@ export interface StoredServer extends Server {
|
||||
};
|
||||
}
|
||||
const initialState: StoredServer = {
|
||||
upgraded: false,
|
||||
name: "",
|
||||
description: "",
|
||||
logo: "",
|
||||
@@ -27,6 +29,7 @@ const serverSlice = createSlice({
|
||||
},
|
||||
fillServer(state, action: PayloadAction<StoredServer>) {
|
||||
const {
|
||||
upgraded = false,
|
||||
inviteLink = {
|
||||
link: "",
|
||||
expire: 0
|
||||
@@ -35,7 +38,7 @@ const serverSlice = createSlice({
|
||||
name = "",
|
||||
description = ""
|
||||
} = action.payload || {};
|
||||
return { name, logo, description, inviteLink };
|
||||
return { upgraded, name, logo, description, inviteLink };
|
||||
},
|
||||
updateInfo(state, action: PayloadAction<Partial<StoredServer>>) {
|
||||
const values = action.payload || {};
|
||||
|
||||
@@ -12,6 +12,7 @@ import IconInvite from "../../assets/icons/placeholder.invite.svg";
|
||||
import IconDownload from "../../assets/icons/placeholder.download.svg";
|
||||
import UsersModal from "./UsersModal";
|
||||
import { useAppSelector } from "../../app/store";
|
||||
import useLicense from "../hook/useLicense";
|
||||
|
||||
|
||||
interface Props {
|
||||
@@ -28,6 +29,7 @@ const BlankPlaceholder: FC<Props> = ({ type = "chat" }) => {
|
||||
const [inviteModalVisible, setInviteModalVisible] = useState(false);
|
||||
const [createChannelVisible, setCreateChannelVisible] = useState(false);
|
||||
const [userListVisible, setUserListVisible] = useState(false);
|
||||
const { upgraded } = useLicense();
|
||||
const toggleChannelModalVisible = () => {
|
||||
setCreateChannelVisible((prev) => !prev);
|
||||
};
|
||||
@@ -45,13 +47,11 @@ const BlankPlaceholder: FC<Props> = ({ type = "chat" }) => {
|
||||
<div className="flex flex-col gap-8 -mt-[50px] dark:bg-gray-700">
|
||||
<div className="flex flex-col gap-2 items-center group">
|
||||
<h2 className="text-center text-3xl text-slate-700 dark:text-white font-bold">{t("title", { name: server.name })}</h2>
|
||||
<p className="text-sm text-gray-400 max-w-md text-center relative break-all">
|
||||
<p className="text-sm text-gray-400 max-w-md text-center relative break-all whitespace-pre">
|
||||
<Linkify options={
|
||||
{
|
||||
render: {
|
||||
url: ({ content, attributes: { href: link } }) => {
|
||||
// console.log("attr", link);
|
||||
// if (!url) return <>{content}</>;
|
||||
return <>
|
||||
<a className="text-primary-400" target="_blank" href={link} rel="noreferrer">
|
||||
{content}
|
||||
@@ -77,14 +77,17 @@ const BlankPlaceholder: FC<Props> = ({ type = "chat" }) => {
|
||||
<IconChat className={classes.boxIcon} />
|
||||
<div className={classes.boxTip}>{chatTip}</div>
|
||||
</button>
|
||||
<a href={"https://voce.chat#download"} target={"_blank"} rel="noreferrer" className={classes.box} >
|
||||
<IconDownload className={classes.boxIcon} />
|
||||
<div className={classes.boxTip}>{t("download")}</div>
|
||||
</a>
|
||||
<a href={"https://doc.voce.chat"} target={"_blank"} rel="noreferrer" className={classes.box} >
|
||||
<IconAsk className={classes.boxIcon} />
|
||||
<div className={classes.boxTip}>{t("help")}</div>
|
||||
</a>
|
||||
{!upgraded && <>
|
||||
<a href={"https://voce.chat#download"} target={"_blank"} rel="noreferrer" className={classes.box} >
|
||||
<IconDownload className={classes.boxIcon} />
|
||||
<div className={classes.boxTip}>{t("download")}</div>
|
||||
</a>
|
||||
<a href={"https://doc.voce.chat"} target={"_blank"} rel="noreferrer" className={classes.box} >
|
||||
<IconAsk className={classes.boxIcon} />
|
||||
<div className={classes.boxTip}>{t("help")}</div>
|
||||
</a>
|
||||
</>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
{createChannelVisible && (
|
||||
|
||||
@@ -7,8 +7,8 @@ import {
|
||||
import { useAppSelector } from "../../app/store";
|
||||
|
||||
const useLicense = () => {
|
||||
const { userCount, isGuest } = useAppSelector((store) => {
|
||||
return { userCount: store.users.ids.length, isGuest: store.authData.guest };
|
||||
const { userCount, isGuest, upgraded } = useAppSelector((store) => {
|
||||
return { userCount: store.users.ids.length, isGuest: store.authData.guest, upgraded: store.server.upgraded };
|
||||
});
|
||||
const { data: license, refetch: refetchLicense } = useGetLicenseQuery(undefined, {
|
||||
refetchOnMountOrArgChange: true,
|
||||
@@ -36,6 +36,7 @@ const useLicense = () => {
|
||||
}, [upserted]);
|
||||
const lUserLimit = license?.user_limit ?? Number.MAX_SAFE_INTEGER;
|
||||
return {
|
||||
upgraded,
|
||||
reachLimit: userCount >= lUserLimit,
|
||||
license,
|
||||
checked,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import MyAccount from "./MyAccount";
|
||||
import Overview from "./Overview";
|
||||
import Logins from "./config/Logins";
|
||||
@@ -12,7 +13,6 @@ import ManageMembers from "../../common/component/ManageMembers";
|
||||
import Version from "../../common/component/Version";
|
||||
// import ConfigAgora from "./config/Agora";
|
||||
import { useAppSelector } from "../../app/store";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import ServerVersionChecker from "../../common/component/ServerVersionChecker";
|
||||
import useLicense from "../../common/hook/useLicense";
|
||||
|
||||
@@ -98,7 +98,7 @@ const navs = [
|
||||
];
|
||||
|
||||
const useNavs = () => {
|
||||
const { license: licenseInfo } = useLicense();
|
||||
const { upgraded } = useLicense();
|
||||
const { t } = useTranslation("setting");
|
||||
const loginUser = useAppSelector((store) => {
|
||||
return store.authData.user;
|
||||
@@ -107,11 +107,13 @@ const useNavs = () => {
|
||||
const { name, items, ...rest } = n;
|
||||
return {
|
||||
name,
|
||||
// @ts-ignore
|
||||
title: t(`nav.${name}`),
|
||||
items: items.map(item => {
|
||||
const { name, ...rest } = item;
|
||||
return {
|
||||
name,
|
||||
// @ts-ignore
|
||||
title: t(`nav.${name}`),
|
||||
...rest
|
||||
};
|
||||
@@ -126,7 +128,7 @@ const useNavs = () => {
|
||||
// about 特殊处理下
|
||||
if (nav.name == "about") {
|
||||
// 有付费,但是普通用户,则不显示about
|
||||
return licenseInfo?.user_limit === 20;
|
||||
return !upgraded;
|
||||
} else {
|
||||
return !nav.admin;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user