From b6a3d1e34d3253d48beb83b93967f3dcb065e43e Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Thu, 11 Dec 2025 18:07:22 +0000 Subject: [PATCH] refactor entitlements --- client/src/components/common/HeaderCreate.tsx | 23 +++++----------- client/src/hooks/UsePlanEntitlements.ts | 27 +++++++++++++++++++ .../pages/infrastructure/InfraMonitors.tsx | 3 ++- .../src/pages/pagespeed/PageSpeedMonitors.tsx | 3 ++- client/src/pages/uptime/UptimeMonitors.tsx | 5 ++-- 5 files changed, 40 insertions(+), 21 deletions(-) create mode 100644 client/src/hooks/UsePlanEntitlements.ts diff --git a/client/src/components/common/HeaderCreate.tsx b/client/src/components/common/HeaderCreate.tsx index 40f6f7182..5af4e8629 100644 --- a/client/src/components/common/HeaderCreate.tsx +++ b/client/src/components/common/HeaderCreate.tsx @@ -4,15 +4,10 @@ import { useTheme } from "@mui/material/styles"; import { useTranslation } from "react-i18next"; import { useNavigate } from "react-router"; import Tooltip from "@mui/material/Tooltip"; -import { useSelector } from "react-redux"; -import type { RootState } from "@/store"; -import { useMemo } from "react"; -type EntitlementsKey = - | "monitorsMax" - | "notificationChannelsMax" - | "statusPagesMax" - | "checksIntervalMsMin" - | "teamsMax"; +import { + useLimitReached, + type PlanEntitlementKey, +} from "@/hooks/UsePlanEntitlements"; export const HeaderCreate = ({ label, isLoading, @@ -23,19 +18,13 @@ export const HeaderCreate = ({ label?: string; isLoading: boolean; path: string; - entitlement: EntitlementsKey | null; + entitlement: PlanEntitlementKey | null; entitlementCount: number; }) => { const theme = useTheme(); const { t } = useTranslation(); const navigate = useNavigate(); - const ent = useSelector((s: RootState) => s.auth.user?.entitlements); - - const limitReached = useMemo(() => { - if (!entitlement) return false; - if (!ent || typeof ent[entitlement] !== "number") return false; - return entitlementCount < ent[entitlement] ? false : true; - }, [ent, entitlement, entitlementCount]); + const limitReached = useLimitReached(entitlement, entitlementCount); return ( s.auth?.user?.entitlements); + + return useMemo(() => { + if (config.DEPLOYMENT_MODE === "self_hosted") return false; + if (!entitlement) return false; + const value = entitlements?.[entitlement]; + if (typeof value !== "number") return false; + return currentCount >= value; + }, [entitlement, currentCount, entitlements]); +} + +export default useLimitReached; diff --git a/client/src/pages/infrastructure/InfraMonitors.tsx b/client/src/pages/infrastructure/InfraMonitors.tsx index 08b6b2b7c..661160147 100644 --- a/client/src/pages/infrastructure/InfraMonitors.tsx +++ b/client/src/pages/infrastructure/InfraMonitors.tsx @@ -21,6 +21,7 @@ import { useDelete } from "@/hooks/UseApi"; import { InitializingStatusBox } from "@/components/design-elements/StatusBox"; import { useAppSelector } from "@/hooks/AppHooks"; import { config } from "@/config/index"; +import { useLimitReached } from "@/hooks/UsePlanEntitlements"; const GLOBAL_REFRESH = config.GLOBAL_REFRESH; @@ -67,7 +68,7 @@ const PageSpeedMonitorsPage = () => { const downCount = response?.data?.downCount || 0; const pausedCount = response?.data?.pausedCount || 0; - const monitorLimitReached = count >= (user?.entitlements?.monitorsMax || 0); + const monitorLimitReached = useLimitReached("monitorsMax", count); const handleConfirm = async () => { await deleteFn(`/monitors/${selectedMonitor?._id}`); diff --git a/client/src/pages/pagespeed/PageSpeedMonitors.tsx b/client/src/pages/pagespeed/PageSpeedMonitors.tsx index f526f9374..28f16e7a4 100644 --- a/client/src/pages/pagespeed/PageSpeedMonitors.tsx +++ b/client/src/pages/pagespeed/PageSpeedMonitors.tsx @@ -21,6 +21,7 @@ import { useDelete } from "@/hooks/UseApi"; import { InitializingStatusBox } from "@/components/design-elements/StatusBox"; import { useAppSelector } from "@/hooks/AppHooks"; import { config } from "@/config/index"; +import { useLimitReached } from "@/hooks/UsePlanEntitlements"; const GLOBAL_REFRESH = config.GLOBAL_REFRESH; @@ -68,7 +69,7 @@ const PageSpeedMonitorsPage = () => { const downCount = response?.data?.downCount || 0; const pausedCount = response?.data?.pausedCount || 0; - const monitorLimitReached = count >= (user?.entitlements?.monitorsMax || 0); + const monitorLimitReached = useLimitReached("monitorsMax", count); const handleConfirm = async () => { await deleteFn(`/monitors/${selectedMonitor?._id}`); diff --git a/client/src/pages/uptime/UptimeMonitors.tsx b/client/src/pages/uptime/UptimeMonitors.tsx index 884015a69..73271622e 100644 --- a/client/src/pages/uptime/UptimeMonitors.tsx +++ b/client/src/pages/uptime/UptimeMonitors.tsx @@ -29,6 +29,7 @@ import { useState } from "react"; import { useDelete } from "@/hooks/UseApi"; import { useAppSelector } from "@/hooks/AppHooks"; import { config } from "@/config/index"; +import { useLimitReached } from "@/hooks/UsePlanEntitlements"; const GLOBAL_REFRESH = config.GLOBAL_REFRESH; @@ -94,7 +95,7 @@ const UptimeMonitors = () => { const downCount = response?.data?.downCount || 0; const pausedCount = response?.data?.pausedCount || 0; - const monitorLimitReached = count >= (user?.entitlements?.monitorsMax || 0); + const monitorLimitReached = useLimitReached("monitorsMax", count); const handleConfirm = async () => { await deleteFn(`/monitors/${selectedMonitor?._id}`); @@ -163,7 +164,7 @@ const UptimeMonitors = () => { setSortField={setSortField} sortOrder={sortOrder} setSortOrder={setSortOrder} - count={monitors?.length || 0} + count={count || 0} page={page} setPage={setPage} rowsPerPage={rowsPerPage}