From aacc6b9c1291ac77c2d5b21ef6bb3ddd9d1b19ef Mon Sep 17 00:00:00 2001 From: Zhang Minghan Date: Wed, 17 Jan 2024 10:59:22 +0800 Subject: [PATCH] feat: update subscription data context --- app/src/api/connection.ts | 42 +++++-- app/src/api/v1.ts | 3 +- app/src/components/app/AppProvider.tsx | 13 +-- app/src/components/app/MenuBar.tsx | 4 +- app/src/components/home/ModelFinder.tsx | 16 ++- app/src/components/home/ModelMarket.tsx | 9 +- .../home/subscription/BuyDialog.tsx | 26 ++++- app/src/conf/index.ts | 6 +- app/src/{utils => conf}/storage.ts | 21 +++- app/src/conf/subscription.tsx | 29 +++-- app/src/dialogs/QuotaDialog.tsx | 3 +- app/src/dialogs/SubscriptionDialog.tsx | 106 ++++++++++++------ app/src/resources/i18n/cn.json | 1 + app/src/resources/i18n/en.json | 5 +- app/src/resources/i18n/ja.json | 5 +- app/src/resources/i18n/ru.json | 5 +- app/src/store/chat.ts | 2 +- app/src/store/globals.ts | 36 ++++++ app/src/store/index.ts | 2 + app/src/store/subscription.ts | 4 +- 20 files changed, 235 insertions(+), 103 deletions(-) rename app/src/{utils => conf}/storage.ts (77%) create mode 100644 app/src/store/globals.ts diff --git a/app/src/api/connection.ts b/app/src/api/connection.ts index fd28c2e8..2d10e4c8 100644 --- a/app/src/api/connection.ts +++ b/app/src/api/connection.ts @@ -1,7 +1,9 @@ import { tokenField, websocketEndpoint } from "@/conf"; import { getMemory } from "@/utils/memory.ts"; +import { getErrorMessage } from "@/utils/base.ts"; export const endpoint = `${websocketEndpoint}/chat`; +export const maxRetry = 5; export type StreamMessage = { conversation?: number; @@ -72,20 +74,38 @@ export class Connection { return true; } - public sendWithRetry(t: any, data: ChatProps): void { + public sendWithRetry(t: any, data: ChatProps, times?: number): void { try { - if (!this.send(data)) { - setTimeout(() => { - this.sendWithRetry(t, data); - }, 500); + if (!times || times < maxRetry) { + if (!this.send(data)) { + setTimeout(() => { + this.sendWithRetry(t, data, (times ?? 0) + 1); + }, 500); + } + + return; } - } catch { - if (t !== undefined) - this.triggerCallback({ - message: t("request-failed"), - end: true, - }); + } catch (e) { + console.warn( + `[connection] failed to send message: ${getErrorMessage(e)}`, + ); } + + const trace = { + message: data.message, + endpoint: endpoint, + }; + + t && + this.triggerCallback({ + message: ` +${t("request-failed")} +\`\`\`json +${JSON.stringify(trace, null, 2)} +\`\`\` + `, + end: true, + }); } public close(): void { diff --git a/app/src/api/v1.ts b/app/src/api/v1.ts index 4a71f742..c6db12b1 100644 --- a/app/src/api/v1.ts +++ b/app/src/api/v1.ts @@ -15,7 +15,8 @@ export async function getApiModels(): Promise { export async function getApiPlans(): Promise { try { const res = await axios.get("/v1/plans"); - return res.data as Plan[]; + const plans = res.data as Plan[]; + return plans.filter((plan: Plan) => plan.level !== 0); } catch (e) { console.warn(e); return []; diff --git a/app/src/components/app/AppProvider.tsx b/app/src/components/app/AppProvider.tsx index a01139a0..d38123bb 100644 --- a/app/src/components/app/AppProvider.tsx +++ b/app/src/components/app/AppProvider.tsx @@ -3,7 +3,7 @@ import { ThemeProvider } from "@/components/ThemeProvider.tsx"; import DialogManager from "@/dialogs"; import Broadcast from "@/components/Broadcast.tsx"; import { useEffectAsync } from "@/utils/hook.ts"; -import { allModels, subscriptionData, supportModels } from "@/conf"; +import { allModels, supportModels } from "@/conf"; import { channelModels } from "@/admin/channel.ts"; import { getApiCharge, @@ -11,12 +11,13 @@ import { getApiModels, getApiPlans, } from "@/api/v1.ts"; -import { loadPreferenceModels } from "@/utils/storage.ts"; +import { loadPreferenceModels } from "@/conf/storage.ts"; import { resetJsArray } from "@/utils/base.ts"; import { useDispatch } from "react-redux"; import { initChatModels } from "@/store/chat.ts"; -import { Model, Plan } from "@/api/types.ts"; +import { Model } from "@/api/types.ts"; import { ChargeProps, nonBilling } from "@/admin/charge.ts"; +import { dispatchSubscriptionData } from "@/store/globals.ts"; function AppProvider() { const dispatch = useDispatch(); @@ -46,11 +47,7 @@ function AppProvider() { if (!channelModels.includes(model)) channelModels.push(model); }); - const plans = await getApiPlans(); - resetJsArray( - subscriptionData, - plans.filter((plan: Plan) => plan.level !== 0), - ); + dispatchSubscriptionData(dispatch, await getApiPlans()); }, [allModels]); return ( diff --git a/app/src/components/app/MenuBar.tsx b/app/src/components/app/MenuBar.tsx index aa784c3c..c1099767 100644 --- a/app/src/components/app/MenuBar.tsx +++ b/app/src/components/app/MenuBar.tsx @@ -29,7 +29,7 @@ import { openDialog as openApiDialog } from "@/store/api.ts"; import router from "@/router.tsx"; import { useDeeptrain } from "@/conf/env.ts"; import React from "react"; -import { subscriptionData } from "@/conf"; +import { subscriptionDataSelector } from "@/store/globals.ts"; type MenuBarProps = { children: React.ReactNode; @@ -43,6 +43,8 @@ function MenuBar({ children, className }: MenuBarProps) { const quota = useSelector(quotaSelector); const admin = useSelector(selectAdmin); + const subscriptionData = useSelector(subscriptionDataSelector); + return ( {children} diff --git a/app/src/components/home/ModelFinder.tsx b/app/src/components/home/ModelFinder.tsx index e1640bb8..84e5b008 100644 --- a/app/src/components/home/ModelFinder.tsx +++ b/app/src/components/home/ModelFinder.tsx @@ -1,5 +1,5 @@ import SelectGroup, { SelectItemProps } from "@/components/SelectGroup.tsx"; -import { subscriptionData, supportModels } from "@/conf"; +import { supportModels } from "@/conf"; import { openMarket, selectModel, @@ -10,7 +10,7 @@ import { useTranslation } from "react-i18next"; import { useDispatch, useSelector } from "react-redux"; import { selectAuthenticated } from "@/store/auth.ts"; import { useToast } from "@/components/ui/use-toast.ts"; -import { Model } from "@/api/types.ts"; +import { Model, Plans } from "@/api/types.ts"; import { modelEvent } from "@/events/model.ts"; import { levelSelector } from "@/store/subscription.ts"; import { teenagerSelector } from "@/store/package.ts"; @@ -19,6 +19,7 @@ import { useEffect, useMemo, useState } from "react"; import { Sparkles } from "lucide-react"; import { goAuth } from "@/utils/app.ts"; import { includingModelFromPlan } from "@/conf/subscription.tsx"; +import { subscriptionDataSelector } from "@/store/globals.ts"; function GetModel(name: string): Model { return supportModels.find((model) => model.id === name) as Model; @@ -28,8 +29,8 @@ type ModelSelectorProps = { side?: "left" | "right" | "top" | "bottom"; }; -function filterModel(model: Model, level: number) { - if (includingModelFromPlan(level, model.id)) { +function filterModel(data: Plans, model: Model, level: number) { + if (includingModelFromPlan(data, level, model.id)) { return { name: model.id, value: model.name, @@ -55,6 +56,8 @@ function ModelFinder(props: ModelSelectorProps) { const student = useSelector(teenagerSelector); const list = useSelector(selectModelList); + const subscriptionData = useSelector(subscriptionDataSelector); + const [sync, setSync] = useState(false); modelEvent.bind((target: string) => { @@ -77,7 +80,10 @@ function ModelFinder(props: ModelSelectorProps) { } as Model); return [ - ...raw.map((model: Model): SelectItemProps => filterModel(model, level)), + ...raw.map( + (model: Model): SelectItemProps => + filterModel(subscriptionData, model, level), + ), { icon: , name: "market", diff --git a/app/src/components/home/ModelMarket.tsx b/app/src/components/home/ModelMarket.tsx index b080a1a1..46de7fa7 100644 --- a/app/src/components/home/ModelMarket.tsx +++ b/app/src/components/home/ModelMarket.tsx @@ -11,7 +11,7 @@ import { X, } from "lucide-react"; import React, { useMemo, useState } from "react"; -import { subscriptionData, supportModels } from "@/conf"; +import { supportModels } from "@/conf"; import { isUrl, splitList } from "@/utils/base.ts"; import { Model } from "@/api/types.ts"; import { useDispatch, useSelector } from "react-redux"; @@ -37,7 +37,7 @@ import { Draggable, DropResult, } from "react-beautiful-dnd"; -import { savePreferenceModels } from "@/utils/storage.ts"; +import { savePreferenceModels } from "@/conf/storage.ts"; import { cn } from "@/components/ui/lib/utils.ts"; import { Badge } from "@/components/ui/badge.tsx"; import { @@ -49,6 +49,7 @@ import { import { useMobile } from "@/utils/device.ts"; import Tips from "@/components/Tips.tsx"; import { includingModelFromPlan } from "@/conf/subscription.tsx"; +import { subscriptionDataSelector } from "@/store/globals.ts"; type SearchBarProps = { value: string; @@ -115,6 +116,8 @@ function ModelItem({ const student = useSelector(teenagerSelector); const auth = useSelector(selectAuthenticated); + const subscriptionData = useSelector(subscriptionDataSelector); + const state = useMemo(() => { if (current === model.id) return 0; if (list.includes(model.id)) return 1; @@ -122,7 +125,7 @@ function ModelItem({ }, [model, current, list]); const pro = useMemo(() => { - return includingModelFromPlan(level, model.id); + return includingModelFromPlan(subscriptionData, level, model.id); }, [subscriptionData, model, level, student]); const avatar = useMemo(() => { diff --git a/app/src/components/home/subscription/BuyDialog.tsx b/app/src/components/home/subscription/BuyDialog.tsx index ab21f09c..83409081 100644 --- a/app/src/components/home/subscription/BuyDialog.tsx +++ b/app/src/components/home/subscription/BuyDialog.tsx @@ -28,9 +28,11 @@ import { deeptrainEndpoint, useDeeptrain } from "@/conf/env.ts"; import { AppDispatch } from "@/store"; import { openDialog } from "@/store/quota.ts"; import { getPlanPrice } from "@/conf/subscription.tsx"; +import { Plans } from "@/api/types.ts"; +import { subscriptionDataSelector } from "@/store/globals.ts"; -function countPrice(base: number, month: number): number { - const price = getPlanPrice(base) * month; +function countPrice(data: Plans, base: number, month: number): number { + const price = getPlanPrice(data, base) * month; if (month >= 36) { return price * 0.7; } else if (month >= 12) { @@ -43,11 +45,12 @@ function countPrice(base: number, month: number): number { } function countUpgradePrice( + data: Plans, level: number, target: number, days: number, ): number { - const bias = getPlanPrice(target) - getPlanPrice(level); + const bias = getPlanPrice(data, target) - getPlanPrice(data, level); const v = (bias / 30) * days; return v > 0 ? v + 1 : 0; // time count offset } @@ -127,6 +130,8 @@ export function Upgrade({ level, current }: UpgradeProps) { const dispatch = useDispatch(); const { toast } = useToast(); + const subscriptionData = useSelector(subscriptionDataSelector); + const isCurrent = useMemo(() => current === level, [current, level]); const isUpgrade = useMemo(() => current < level, [current, level]); @@ -170,13 +175,17 @@ export function Upgrade({ level, current }: UpgradeProps) {

- {t("sub.price", { price: countPrice(level, month).toFixed(2) })} + {t("sub.price", { + price: countPrice(subscriptionData, level, month).toFixed(2), + })} {useDeeptrain && (   ( {t("sub.price-tax", { - price: (countPrice(level, month) * 0.25).toFixed(1), + price: ( + countPrice(subscriptionData, level, month) * 0.25 + ).toFixed(1), })} ) @@ -223,7 +232,12 @@ export function Upgrade({ level, current }: UpgradeProps) { {isUpgrade && (

{t("sub.upgrade-price", { - price: countUpgradePrice(current, level, expired).toFixed(2), + price: countUpgradePrice( + subscriptionData, + current, + level, + expired, + ).toFixed(2), })}

)} diff --git a/app/src/conf/index.ts b/app/src/conf/index.ts index c7c156ac..2fc333e1 100644 --- a/app/src/conf/index.ts +++ b/app/src/conf/index.ts @@ -1,4 +1,4 @@ -import { Model, Plans } from "@/api/types.ts"; +import { Model } from "@/api/types.ts"; import { getDev, getRestApi, @@ -6,7 +6,7 @@ import { getWebsocketApi, } from "@/conf/env.ts"; import { syncSiteInfo } from "@/admin/api/info.ts"; -import { getOfflineModels, loadPreferenceModels } from "@/utils/storage.ts"; +import { getOfflineModels, loadPreferenceModels } from "@/conf/storage.ts"; import { setAxiosConfig } from "@/conf/api.ts"; export const version = "3.8.6"; // version of the current build @@ -20,8 +20,6 @@ export let websocketEndpoint: string = getWebsocketApi(deploy); // api endpoint export let supportModels: Model[] = loadPreferenceModels(getOfflineModels()); // support models in model market of the current site export let allModels: string[] = supportModels.map((model) => model.id); // all support model id list of the current site -export let subscriptionData: Plans = []; // subscription data of the current site - setAxiosConfig({ endpoint: apiEndpoint, token: tokenField, diff --git a/app/src/utils/storage.ts b/app/src/conf/storage.ts similarity index 77% rename from app/src/utils/storage.ts rename to app/src/conf/storage.ts index fdf300f8..03f66f15 100644 --- a/app/src/utils/storage.ts +++ b/app/src/conf/storage.ts @@ -1,5 +1,5 @@ import { getMemory, setMemory } from "@/utils/memory.ts"; -import { Model } from "@/api/types.ts"; +import { Model, Plan } from "@/api/types.ts"; export function savePreferenceModels(models: Model[]): void { setMemory("model_preference", models.map((item) => item.id).join(",")); @@ -68,3 +68,22 @@ export function getOfflineModels(): Model[] { const memory = getMemory("model_offline"); return memory && memory.length ? parseOfflineModels(memory) : []; } + +export function setOfflinePlans(plans: Plan[]): void { + setMemory("plan_offline", JSON.stringify(plans)); +} + +export function parseOfflinePlans(plans: string): Plan[] { + try { + const parsed = JSON.parse(plans); + if (!Array.isArray(parsed)) return []; + return parsed.filter((item) => typeof item === "object"); + } catch { + return []; + } +} + +export function getOfflinePlans(): Plan[] { + const memory = getMemory("plan_offline"); + return memory && memory.length ? parseOfflinePlans(memory) : []; +} diff --git a/app/src/conf/subscription.tsx b/app/src/conf/subscription.tsx index a422c09b..2ceb72b6 100644 --- a/app/src/conf/subscription.tsx +++ b/app/src/conf/subscription.tsx @@ -7,8 +7,7 @@ import { AudioLines, } from "lucide-react"; import React, { useMemo } from "react"; -import { subscriptionData } from "@/conf/index.ts"; -import { Plan } from "@/api/types.ts"; +import { Plan, Plans } from "@/api/types.ts"; import Icon from "@/components/utils/Icon.tsx"; export const subscriptionIcons: Record = { @@ -39,25 +38,25 @@ export function SubscriptionIcon({ type, className }: SubscriptionIconProps) { return ; } -export function getPlan(level: number): Plan { - const raw = subscriptionData.filter((item) => item.level === level); - return raw.length > 0 - ? raw[0] - : subscriptionData.length - ? subscriptionData[0] - : { level: 0, price: 0, items: [] }; +export function getPlan(data: Plans, level: number): Plan { + const raw = data.filter((item) => item.level === level); + return raw.length > 0 ? raw[0] : { level: 0, price: 0, items: [] }; } -export function getPlanModels(level: number): string[] { - return getPlan(level).items.flatMap((item) => item.models); +export function getPlanModels(data: Plans, level: number): string[] { + return getPlan(data, level).items.flatMap((item) => item.models); } -export function includingModelFromPlan(level: number, model: string): boolean { - return getPlanModels(level).includes(model); +export function includingModelFromPlan( + data: Plans, + level: number, + model: string, +): boolean { + return getPlanModels(data, level).includes(model); } -export function getPlanPrice(level: number): number { - return getPlan(level).price; +export function getPlanPrice(data: Plans, level: number): number { + return getPlan(data, level).price; } export function getPlanName(level: number): string { diff --git a/app/src/dialogs/QuotaDialog.tsx b/app/src/dialogs/QuotaDialog.tsx index ef786353..64a41a55 100644 --- a/app/src/dialogs/QuotaDialog.tsx +++ b/app/src/dialogs/QuotaDialog.tsx @@ -42,7 +42,7 @@ import { ToastAction } from "@/components/ui/toast.tsx"; import { deeptrainEndpoint, docsEndpoint, useDeeptrain } from "@/conf/env.ts"; import { useRedeem } from "@/api/redeem.ts"; import { cn } from "@/components/ui/lib/utils.ts"; -import { subscriptionData } from "@/conf"; +import { subscriptionDataSelector } from "@/store/globals.ts"; type AmountComponentProps = { amount: number; @@ -84,6 +84,7 @@ function QuotaDialog() { const auth = useSelector(selectAuthenticated); const sub = useSelector(subDialogSelector); + const subscriptionData = useSelector(subscriptionDataSelector); const [redeem, setRedeem] = useState(""); diff --git a/app/src/dialogs/SubscriptionDialog.tsx b/app/src/dialogs/SubscriptionDialog.tsx index 62c77416..7d427c56 100644 --- a/app/src/dialogs/SubscriptionDialog.tsx +++ b/app/src/dialogs/SubscriptionDialog.tsx @@ -36,8 +36,8 @@ import { SubscriptionIcon, } from "@/conf/subscription.tsx"; import { cn } from "@/components/ui/lib/utils.ts"; -import { subscriptionData } from "@/conf"; import { Badge } from "@/components/ui/badge.tsx"; +import { subscriptionDataSelector } from "@/store/globals.ts"; type PlanItemProps = { level: number; @@ -46,8 +46,13 @@ type PlanItemProps = { function PlanItem({ level }: PlanItemProps) { const { t } = useTranslation(); const current = useSelector(levelSelector); - const plan = useMemo(() => getPlan(level), [subscriptionData, level]); - const name = useMemo(() => getPlanName(level), [subscriptionData, level]); + const subscriptionData = useSelector(subscriptionDataSelector); + + const plan = useMemo( + () => getPlan(subscriptionData, level), + [subscriptionData, level], + ); + const name = useMemo(() => getPlanName(level), [level]); return (
@@ -95,7 +100,12 @@ function SubscriptionDialog() { const auth = useSelector(selectAuthenticated); const quota = useSelector(quotaDialogSelector); - const plan = useMemo(() => getPlan(level), [level]); + const subscriptionData = useSelector(subscriptionDataSelector); + + const plan = useMemo( + () => getPlan(subscriptionData, level), + [subscriptionData, level], + ); const dispatch = useDispatch(); useEffectAsync(async () => { @@ -115,42 +125,64 @@ function SubscriptionDialog() { {t("sub.dialog-title")} -
-

- quota ? dispatch(closeDialog()) : dispatch(openQuotaDialog()) - } - > - {t("sub.quota-link")} -

- {subscription && ( -
- } - name={t("sub.expired")} - usage={expired} - /> + {subscriptionData.length > 0 ? ( +
+

+ quota + ? dispatch(closeDialog()) + : dispatch(openQuotaDialog()) + } + > + {t("sub.quota-link")} +

+ {subscription && ( +
+ } + name={t("sub.expired")} + usage={expired} + /> - {plan.items.map( - (item, index) => - usage?.[item.id] && ( - - ), - )} + {plan.items.map( + (item, index) => + usage?.[item.id] && ( + + ), + )} +
+ )} +
+ {subscriptionData.map((item, index) => ( + + ))} +
+
+ ) : ( +
+

+ quota + ? dispatch(closeDialog()) + : dispatch(openQuotaDialog()) + } + > + {t("sub.quota-link")} +

+
+
+

{t("sub.disable")}

+
- )} -
- {subscriptionData.map((item, index) => ( - - ))}
-
+ )} diff --git a/app/src/resources/i18n/cn.json b/app/src/resources/i18n/cn.json index 7d7fee6d..8fc3b3f3 100644 --- a/app/src/resources/i18n/cn.json +++ b/app/src/resources/i18n/cn.json @@ -172,6 +172,7 @@ }, "sub": { "title": "订阅", + "disable": "本站订阅功能已被关闭", "quota-link": "寻求弹性计费?购买点数", "subscription-link": "寻求固定计费?订阅计划", "dialog-title": "订阅计划", diff --git a/app/src/resources/i18n/en.json b/app/src/resources/i18n/en.json index d2a4b816..5daf4506 100644 --- a/app/src/resources/i18n/en.json +++ b/app/src/resources/i18n/en.json @@ -179,7 +179,8 @@ "migrate-failed": "Migrate failed", "migrate-failed-prompt": "Your subscription migration failed.", "plan-usage": "{{name}} uses {{times}} times per month", - "plan-tip": "Callable Model" + "plan-tip": "Callable Model", + "disable": "This site's subscription feature has been turned off" }, "cancel": "Cancel", "confirm": "Confirm", @@ -519,4 +520,4 @@ "reset": "Reset", "request-error": "Request failed for {{reason}}", "update": "Updated" -} +} \ No newline at end of file diff --git a/app/src/resources/i18n/ja.json b/app/src/resources/i18n/ja.json index e8a379cb..f621e2ce 100644 --- a/app/src/resources/i18n/ja.json +++ b/app/src/resources/i18n/ja.json @@ -179,7 +179,8 @@ "migrate-failed": "変更できませんでした", "migrate-failed-prompt": "サブスクリプションの変更に失敗しました。", "plan-usage": "{{name}}は月に{{times}}回使用", - "plan-tip": "呼び出し可能なモデル" + "plan-tip": "呼び出し可能なモデル", + "disable": "このサイトのサブスクリプション機能はオフになっています" }, "cancel": "キャンセル", "confirm": "確認", @@ -519,4 +520,4 @@ "reset": "リセット", "request-error": "{{reason}}のためにリクエストできませんでした", "update": "更新" -} +} \ No newline at end of file diff --git a/app/src/resources/i18n/ru.json b/app/src/resources/i18n/ru.json index feaece3e..9067adeb 100644 --- a/app/src/resources/i18n/ru.json +++ b/app/src/resources/i18n/ru.json @@ -179,7 +179,8 @@ "migrate-failed": "Перенос подписки не удался", "migrate-failed-prompt": "Ваша подписка не удалась.", "plan-usage": "{{name}} использует {{times}} раз в месяц", - "plan-tip": "Вызываемая модель" + "plan-tip": "Вызываемая модель", + "disable": "Функция подписки на этом сайте отключена" }, "cancel": "Отмена", "confirm": "Подтвердить", @@ -519,4 +520,4 @@ "reset": "сброс", "request-error": "Запрос не выполнен по {{reason}}", "update": "Обновить" -} +} \ No newline at end of file diff --git a/app/src/store/chat.ts b/app/src/store/chat.ts index c451afe8..f3606475 100644 --- a/app/src/store/chat.ts +++ b/app/src/store/chat.ts @@ -11,7 +11,7 @@ import { setArrayMemory, setMemory, } from "@/utils/memory.ts"; -import { setOfflineModels } from "@/utils/storage.ts"; +import { setOfflineModels } from "@/conf/storage.ts"; type initialStateType = { history: ConversationInstance[]; diff --git a/app/src/store/globals.ts b/app/src/store/globals.ts new file mode 100644 index 00000000..c0993c84 --- /dev/null +++ b/app/src/store/globals.ts @@ -0,0 +1,36 @@ +import { createSlice } from "@reduxjs/toolkit"; +import { Plans } from "@/api/types.ts"; +import { AppDispatch, RootState } from "@/store/index.ts"; +import { getOfflinePlans, setOfflinePlans } from "@/conf/storage.ts"; + +type GlobalState = { + subscription: Plans; +}; + +export const globalSlice = createSlice({ + name: "global", + initialState: { + subscription: getOfflinePlans(), + } as GlobalState, + reducers: { + setSubscription: (state, action) => { + const plans = action.payload as Plans; + state.subscription = plans; + setOfflinePlans(plans); + }, + }, +}); + +export const { setSubscription } = globalSlice.actions; + +export default globalSlice.reducer; + +export const subscriptionDataSelector = (state: RootState): Plans => + state.global.subscription; + +export const dispatchSubscriptionData = ( + dispatch: AppDispatch, + subscription: Plans, +) => { + dispatch(setSubscription(subscription)); +}; diff --git a/app/src/store/index.ts b/app/src/store/index.ts index 0e0a4228..9e95ca1b 100644 --- a/app/src/store/index.ts +++ b/app/src/store/index.ts @@ -1,4 +1,5 @@ import { configureStore } from "@reduxjs/toolkit"; +import globalReducer from "./globals"; import menuReducer from "./menu"; import authReducer from "./auth"; import chatReducer from "./chat"; @@ -12,6 +13,7 @@ import settingsReducer from "./settings"; const store = configureStore({ reducer: { + global: globalReducer, menu: menuReducer, auth: authReducer, chat: chatReducer, diff --git a/app/src/store/subscription.ts b/app/src/store/subscription.ts index 7cbee895..48a73b0f 100644 --- a/app/src/store/subscription.ts +++ b/app/src/store/subscription.ts @@ -1,7 +1,6 @@ import { createSlice } from "@reduxjs/toolkit"; import { getSubscription } from "@/api/addition.ts"; import { AppDispatch } from "./index.ts"; -import { subscriptionData } from "@/conf"; export const subscriptionSlice = createSlice({ name: "subscription", @@ -17,14 +16,13 @@ export const subscriptionSlice = createSlice({ }, reducers: { toggleDialog: (state) => { - if (!state.dialog && !subscriptionData.length) return; + if (!state.dialog) return; state.dialog = !state.dialog; }, setDialog: (state, action) => { state.dialog = action.payload as boolean; }, openDialog: (state) => { - if (!subscriptionData.length) return; state.dialog = true; }, closeDialog: (state) => {