diff --git a/server/lib/billing/tierMatrix.ts b/server/lib/billing/tierMatrix.ts index 3e5eb0f6..ad1f33c4 100644 --- a/server/lib/billing/tierMatrix.ts +++ b/server/lib/billing/tierMatrix.ts @@ -1,3 +1,5 @@ +import { Tier } from "@server/types/Tiers"; + export enum TierFeature { OrgOidc = "orgOidc", CustomAuthenticationDomain = "customAuthenticationDomain", @@ -14,7 +16,7 @@ export enum TierFeature { PasswordExpirationPolicies = "passwordExpirationPolicies" } -export const tierMatrix: Record = { +export const tierMatrix: Record = { [TierFeature.OrgOidc]: ["tier1", "tier2", "tier3", "enterprise"], [TierFeature.CustomAuthenticationDomain]: [ "tier1", diff --git a/server/lib/isLicencedOrSubscribed.ts b/server/lib/isLicencedOrSubscribed.ts index a04d44aa..9ebe1922 100644 --- a/server/lib/isLicencedOrSubscribed.ts +++ b/server/lib/isLicencedOrSubscribed.ts @@ -1,6 +1,8 @@ +import { Tier } from "@server/types/Tiers"; + export async function isLicensedOrSubscribed( orgId: string, - tiers: string[] + tiers: Tier[] ): Promise { return false; } diff --git a/server/lib/isSubscribed.ts b/server/lib/isSubscribed.ts index 306ab871..533eec91 100644 --- a/server/lib/isSubscribed.ts +++ b/server/lib/isSubscribed.ts @@ -1,6 +1,8 @@ +import { Tier } from "@server/types/Tiers"; + export async function isSubscribed( orgId: string, - tiers: string[] + tiers: Tier[] ): Promise { return false; } diff --git a/server/private/lib/isLicencedOrSubscribed.ts b/server/private/lib/isLicencedOrSubscribed.ts index 3f8d2a6d..d6063c6c 100644 --- a/server/private/lib/isLicencedOrSubscribed.ts +++ b/server/private/lib/isLicencedOrSubscribed.ts @@ -14,10 +14,11 @@ import { build } from "@server/build"; import license from "#private/license/license"; import { isSubscribed } from "#private/lib/isSubscribed"; +import { Tier } from "@server/types/Tiers"; export async function isLicensedOrSubscribed( orgId: string, - tiers: string[] + tiers: Tier[] ): Promise { if (build === "enterprise") { return await license.isUnlocked(); diff --git a/server/private/lib/isSubscribed.ts b/server/private/lib/isSubscribed.ts index 23ffc698..e6e4c877 100644 --- a/server/private/lib/isSubscribed.ts +++ b/server/private/lib/isSubscribed.ts @@ -13,10 +13,11 @@ import { build } from "@server/build"; import { getOrgTierData } from "#private/lib/billing"; +import { Tier } from "@server/types/Tiers"; export async function isSubscribed( orgId: string, - tiers: string[] + tiers: Tier[] ): Promise { if (build === "saas") { const { tier, active } = await getOrgTierData(orgId); diff --git a/server/private/middlewares/verifySubscription.ts b/server/private/middlewares/verifySubscription.ts index 0c28f7aa..9673f8f5 100644 --- a/server/private/middlewares/verifySubscription.ts +++ b/server/private/middlewares/verifySubscription.ts @@ -16,8 +16,9 @@ import createHttpError from "http-errors"; import HttpCode from "@server/types/HttpCode"; import { build } from "@server/build"; import { getOrgTierData } from "#private/lib/billing"; +import { Tier } from "@server/types/Tiers"; -export function verifyValidSubscription(tiers: string[]) { +export function verifyValidSubscription(tiers: Tier[]) { return async function ( req: Request, res: Response, diff --git a/src/app/[orgId]/settings/clients/user/[niceId]/general/page.tsx b/src/app/[orgId]/settings/clients/user/[niceId]/general/page.tsx index 013bdd47..e5b9de66 100644 --- a/src/app/[orgId]/settings/clients/user/[niceId]/general/page.tsx +++ b/src/app/[orgId]/settings/clients/user/[niceId]/general/page.tsx @@ -40,6 +40,7 @@ import { import { useParams } from "next/navigation"; import { FaApple, FaWindows, FaLinux } from "react-icons/fa"; import { SiAndroid } from "react-icons/si"; +import { tierMatrix } from "@server/lib/billing/tierMatrix"; function formatTimestamp(timestamp: number | null | undefined): string { if (!timestamp) return "-"; @@ -156,8 +157,11 @@ export default function GeneralPage() { const showApprovalFeatures = build !== "oss" && isPaidUser; - const formatPostureValue = (value: boolean | null | undefined) => { - if (value === null || value === undefined) return "-"; + const formatPostureValue = ( + value: boolean | null | undefined | "-" + ) => { + if (value === null || value === undefined || value === "-") + return "-"; return (
{value ? ( @@ -594,7 +598,7 @@ export default function GeneralPage() { {t("biometricsEnabled")} - {isPaidUser + {isPaidUser(tierMatrix.devicePosture) ? formatPostureValue( client.posture .biometricsEnabled diff --git a/src/app/[orgId]/settings/resources/proxy/[niceId]/authentication/page.tsx b/src/app/[orgId]/settings/resources/proxy/[niceId]/authentication/page.tsx index 3dedea05..121e7196 100644 --- a/src/app/[orgId]/settings/resources/proxy/[niceId]/authentication/page.tsx +++ b/src/app/[orgId]/settings/resources/proxy/[niceId]/authentication/page.tsx @@ -44,6 +44,7 @@ import { getUserDisplayName } from "@app/lib/getUserDisplayName"; import { orgQueries, resourceQueries } from "@app/lib/queries"; import { zodResolver } from "@hookform/resolvers/zod"; import { build } from "@server/build"; +import { tierMatrix } from "@server/lib/billing/tierMatrix"; import { UserType } from "@server/types/UserTypes"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import SetResourcePasswordForm from "components/SetResourcePasswordForm"; @@ -164,7 +165,7 @@ export default function ResourceAuthenticationPage() { const allIdps = useMemo(() => { if (build === "saas") { - if (isPaidUser) { + if (isPaidUser(tierMatrix.orgOidc)) { return orgIdps.map((idp) => ({ id: idp.idpId, text: idp.name diff --git a/src/components/ApprovalFeed.tsx b/src/components/ApprovalFeed.tsx index e587354b..87a9d11a 100644 --- a/src/components/ApprovalFeed.tsx +++ b/src/components/ApprovalFeed.tsx @@ -31,6 +31,7 @@ import { Separator } from "./ui/separator"; import { InfoPopup } from "./ui/info-popup"; import { ApprovalsEmptyState } from "./ApprovalsEmptyState"; import { usePaidStatus } from "@app/hooks/usePaidStatus"; +import { tierMatrix } from "@server/lib/billing/tierMatrix"; export type ApprovalFeedProps = { orgId: string; @@ -55,7 +56,7 @@ export function ApprovalFeed({ const { data, isFetching, refetch } = useQuery({ ...approvalQueries.listApprovals(orgId, filters), - enabled: isPaidUser + enabled: isPaidUser(tierMatrix.deviceApprovals) }); const approvals = data?.approvals ?? []; diff --git a/src/components/PaidFeaturesAlert.tsx b/src/components/PaidFeaturesAlert.tsx index b2c96ab8..11b88fbb 100644 --- a/src/components/PaidFeaturesAlert.tsx +++ b/src/components/PaidFeaturesAlert.tsx @@ -47,10 +47,10 @@ export function PaidFeaturesAlert() { ) : null} {build === "oss" && !hasEnterpriseLicense ? ( - +
- + {t.rich("ossEnterpriseEditionRequired", { enterpriseEditionLink: (chunks) => ( @@ -58,7 +58,7 @@ export function PaidFeaturesAlert() { href="https://docs.pangolin.net/self-host/enterprise-edition" target="_blank" rel="noopener noreferrer" - className="inline-flex items-center gap-1 font-medium text-foreground underline" + className="inline-flex items-center gap-1 font-medium text-purple-600 underline" > {chunks} diff --git a/src/contexts/subscriptionStatusContext.ts b/src/contexts/subscriptionStatusContext.ts index a3efc67f..95946350 100644 --- a/src/contexts/subscriptionStatusContext.ts +++ b/src/contexts/subscriptionStatusContext.ts @@ -1,10 +1,11 @@ import { GetOrgSubscriptionResponse } from "@server/routers/billing/types"; +import { Tier } from "@server/types/Tiers"; import { createContext } from "react"; type SubscriptionStatusContextType = { subscriptionStatus: GetOrgSubscriptionResponse | null; updateSubscriptionStatus: (updatedSite: GetOrgSubscriptionResponse) => void; - getTier: () => { tier: string | null; active: boolean }; + getTier: () => { tier: Tier | null; active: boolean }; isSubscribed: () => boolean; subscribed: boolean; }; diff --git a/src/hooks/usePaidStatus.ts b/src/hooks/usePaidStatus.ts index db36519a..41244a07 100644 --- a/src/hooks/usePaidStatus.ts +++ b/src/hooks/usePaidStatus.ts @@ -1,7 +1,7 @@ import { build } from "@server/build"; import { useLicenseStatusContext } from "./useLicenseStatusContext"; import { useSubscriptionStatusContext } from "./useSubscriptionStatusContext"; -import { Tier } from "@server/lib/tiers"; +import { Tier } from "@server/types/Tiers"; export function usePaidStatus() { const { isUnlocked } = useLicenseStatusContext(); @@ -12,7 +12,7 @@ export function usePaidStatus() { const tierData = subscription?.getTier(); const hasSaasSubscription = build === "saas" && tierData?.active; - function isPaidUser(tiers: Tier): boolean { + function isPaidUser(tiers: Tier[]): boolean { if (hasEnterpriseLicense) { return true; }