mirror of
https://github.com/fosrl/pangolin.git
synced 2026-02-16 18:06:39 +00:00
use pricing matrix in existing usePaidStatus funcitons
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
import { Tier } from "@server/types/Tiers";
|
||||||
|
|
||||||
export enum TierFeature {
|
export enum TierFeature {
|
||||||
OrgOidc = "orgOidc",
|
OrgOidc = "orgOidc",
|
||||||
CustomAuthenticationDomain = "customAuthenticationDomain",
|
CustomAuthenticationDomain = "customAuthenticationDomain",
|
||||||
@@ -14,7 +16,7 @@ export enum TierFeature {
|
|||||||
PasswordExpirationPolicies = "passwordExpirationPolicies"
|
PasswordExpirationPolicies = "passwordExpirationPolicies"
|
||||||
}
|
}
|
||||||
|
|
||||||
export const tierMatrix: Record<TierFeature, string[]> = {
|
export const tierMatrix: Record<TierFeature, Tier[]> = {
|
||||||
[TierFeature.OrgOidc]: ["tier1", "tier2", "tier3", "enterprise"],
|
[TierFeature.OrgOidc]: ["tier1", "tier2", "tier3", "enterprise"],
|
||||||
[TierFeature.CustomAuthenticationDomain]: [
|
[TierFeature.CustomAuthenticationDomain]: [
|
||||||
"tier1",
|
"tier1",
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
import { Tier } from "@server/types/Tiers";
|
||||||
|
|
||||||
export async function isLicensedOrSubscribed(
|
export async function isLicensedOrSubscribed(
|
||||||
orgId: string,
|
orgId: string,
|
||||||
tiers: string[]
|
tiers: Tier[]
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
import { Tier } from "@server/types/Tiers";
|
||||||
|
|
||||||
export async function isSubscribed(
|
export async function isSubscribed(
|
||||||
orgId: string,
|
orgId: string,
|
||||||
tiers: string[]
|
tiers: Tier[]
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,10 +14,11 @@
|
|||||||
import { build } from "@server/build";
|
import { build } from "@server/build";
|
||||||
import license from "#private/license/license";
|
import license from "#private/license/license";
|
||||||
import { isSubscribed } from "#private/lib/isSubscribed";
|
import { isSubscribed } from "#private/lib/isSubscribed";
|
||||||
|
import { Tier } from "@server/types/Tiers";
|
||||||
|
|
||||||
export async function isLicensedOrSubscribed(
|
export async function isLicensedOrSubscribed(
|
||||||
orgId: string,
|
orgId: string,
|
||||||
tiers: string[]
|
tiers: Tier[]
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
if (build === "enterprise") {
|
if (build === "enterprise") {
|
||||||
return await license.isUnlocked();
|
return await license.isUnlocked();
|
||||||
|
|||||||
@@ -13,10 +13,11 @@
|
|||||||
|
|
||||||
import { build } from "@server/build";
|
import { build } from "@server/build";
|
||||||
import { getOrgTierData } from "#private/lib/billing";
|
import { getOrgTierData } from "#private/lib/billing";
|
||||||
|
import { Tier } from "@server/types/Tiers";
|
||||||
|
|
||||||
export async function isSubscribed(
|
export async function isSubscribed(
|
||||||
orgId: string,
|
orgId: string,
|
||||||
tiers: string[]
|
tiers: Tier[]
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
if (build === "saas") {
|
if (build === "saas") {
|
||||||
const { tier, active } = await getOrgTierData(orgId);
|
const { tier, active } = await getOrgTierData(orgId);
|
||||||
|
|||||||
@@ -16,8 +16,9 @@ import createHttpError from "http-errors";
|
|||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
import { build } from "@server/build";
|
import { build } from "@server/build";
|
||||||
import { getOrgTierData } from "#private/lib/billing";
|
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 (
|
return async function (
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import {
|
|||||||
import { useParams } from "next/navigation";
|
import { useParams } from "next/navigation";
|
||||||
import { FaApple, FaWindows, FaLinux } from "react-icons/fa";
|
import { FaApple, FaWindows, FaLinux } from "react-icons/fa";
|
||||||
import { SiAndroid } from "react-icons/si";
|
import { SiAndroid } from "react-icons/si";
|
||||||
|
import { tierMatrix } from "@server/lib/billing/tierMatrix";
|
||||||
|
|
||||||
function formatTimestamp(timestamp: number | null | undefined): string {
|
function formatTimestamp(timestamp: number | null | undefined): string {
|
||||||
if (!timestamp) return "-";
|
if (!timestamp) return "-";
|
||||||
@@ -156,8 +157,11 @@ export default function GeneralPage() {
|
|||||||
|
|
||||||
const showApprovalFeatures = build !== "oss" && isPaidUser;
|
const showApprovalFeatures = build !== "oss" && isPaidUser;
|
||||||
|
|
||||||
const formatPostureValue = (value: boolean | null | undefined) => {
|
const formatPostureValue = (
|
||||||
if (value === null || value === undefined) return "-";
|
value: boolean | null | undefined | "-"
|
||||||
|
) => {
|
||||||
|
if (value === null || value === undefined || value === "-")
|
||||||
|
return "-";
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{value ? (
|
{value ? (
|
||||||
@@ -594,7 +598,7 @@ export default function GeneralPage() {
|
|||||||
{t("biometricsEnabled")}
|
{t("biometricsEnabled")}
|
||||||
</InfoSectionTitle>
|
</InfoSectionTitle>
|
||||||
<InfoSectionContent>
|
<InfoSectionContent>
|
||||||
{isPaidUser
|
{isPaidUser(tierMatrix.devicePosture)
|
||||||
? formatPostureValue(
|
? formatPostureValue(
|
||||||
client.posture
|
client.posture
|
||||||
.biometricsEnabled
|
.biometricsEnabled
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ import { getUserDisplayName } from "@app/lib/getUserDisplayName";
|
|||||||
import { orgQueries, resourceQueries } from "@app/lib/queries";
|
import { orgQueries, resourceQueries } from "@app/lib/queries";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { build } from "@server/build";
|
import { build } from "@server/build";
|
||||||
|
import { tierMatrix } from "@server/lib/billing/tierMatrix";
|
||||||
import { UserType } from "@server/types/UserTypes";
|
import { UserType } from "@server/types/UserTypes";
|
||||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import SetResourcePasswordForm from "components/SetResourcePasswordForm";
|
import SetResourcePasswordForm from "components/SetResourcePasswordForm";
|
||||||
@@ -164,7 +165,7 @@ export default function ResourceAuthenticationPage() {
|
|||||||
|
|
||||||
const allIdps = useMemo(() => {
|
const allIdps = useMemo(() => {
|
||||||
if (build === "saas") {
|
if (build === "saas") {
|
||||||
if (isPaidUser) {
|
if (isPaidUser(tierMatrix.orgOidc)) {
|
||||||
return orgIdps.map((idp) => ({
|
return orgIdps.map((idp) => ({
|
||||||
id: idp.idpId,
|
id: idp.idpId,
|
||||||
text: idp.name
|
text: idp.name
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import { Separator } from "./ui/separator";
|
|||||||
import { InfoPopup } from "./ui/info-popup";
|
import { InfoPopup } from "./ui/info-popup";
|
||||||
import { ApprovalsEmptyState } from "./ApprovalsEmptyState";
|
import { ApprovalsEmptyState } from "./ApprovalsEmptyState";
|
||||||
import { usePaidStatus } from "@app/hooks/usePaidStatus";
|
import { usePaidStatus } from "@app/hooks/usePaidStatus";
|
||||||
|
import { tierMatrix } from "@server/lib/billing/tierMatrix";
|
||||||
|
|
||||||
export type ApprovalFeedProps = {
|
export type ApprovalFeedProps = {
|
||||||
orgId: string;
|
orgId: string;
|
||||||
@@ -55,7 +56,7 @@ export function ApprovalFeed({
|
|||||||
|
|
||||||
const { data, isFetching, refetch } = useQuery({
|
const { data, isFetching, refetch } = useQuery({
|
||||||
...approvalQueries.listApprovals(orgId, filters),
|
...approvalQueries.listApprovals(orgId, filters),
|
||||||
enabled: isPaidUser
|
enabled: isPaidUser(tierMatrix.deviceApprovals)
|
||||||
});
|
});
|
||||||
|
|
||||||
const approvals = data?.approvals ?? [];
|
const approvals = data?.approvals ?? [];
|
||||||
|
|||||||
@@ -47,10 +47,10 @@ export function PaidFeaturesAlert() {
|
|||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{build === "oss" && !hasEnterpriseLicense ? (
|
{build === "oss" && !hasEnterpriseLicense ? (
|
||||||
<Card className={bannerClassName}>
|
<Card className="mb-6 border-purple-500/30 bg-linear-to-br from-purple-500/10 via-background to-background overflow-hidden">
|
||||||
<CardContent className={bannerContentClassName}>
|
<CardContent className={bannerContentClassName}>
|
||||||
<div className={bannerRowClassName}>
|
<div className={bannerRowClassName}>
|
||||||
<KeyRound className="size-4 shrink-0 text-primary" />
|
<KeyRound className="size-4 shrink-0 text-purple-500" />
|
||||||
<span>
|
<span>
|
||||||
{t.rich("ossEnterpriseEditionRequired", {
|
{t.rich("ossEnterpriseEditionRequired", {
|
||||||
enterpriseEditionLink: (chunks) => (
|
enterpriseEditionLink: (chunks) => (
|
||||||
@@ -58,7 +58,7 @@ export function PaidFeaturesAlert() {
|
|||||||
href="https://docs.pangolin.net/self-host/enterprise-edition"
|
href="https://docs.pangolin.net/self-host/enterprise-edition"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
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}
|
{chunks}
|
||||||
<ExternalLink className="size-3.5 shrink-0" />
|
<ExternalLink className="size-3.5 shrink-0" />
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { GetOrgSubscriptionResponse } from "@server/routers/billing/types";
|
import { GetOrgSubscriptionResponse } from "@server/routers/billing/types";
|
||||||
|
import { Tier } from "@server/types/Tiers";
|
||||||
import { createContext } from "react";
|
import { createContext } from "react";
|
||||||
|
|
||||||
type SubscriptionStatusContextType = {
|
type SubscriptionStatusContextType = {
|
||||||
subscriptionStatus: GetOrgSubscriptionResponse | null;
|
subscriptionStatus: GetOrgSubscriptionResponse | null;
|
||||||
updateSubscriptionStatus: (updatedSite: GetOrgSubscriptionResponse) => void;
|
updateSubscriptionStatus: (updatedSite: GetOrgSubscriptionResponse) => void;
|
||||||
getTier: () => { tier: string | null; active: boolean };
|
getTier: () => { tier: Tier | null; active: boolean };
|
||||||
isSubscribed: () => boolean;
|
isSubscribed: () => boolean;
|
||||||
subscribed: boolean;
|
subscribed: boolean;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { build } from "@server/build";
|
import { build } from "@server/build";
|
||||||
import { useLicenseStatusContext } from "./useLicenseStatusContext";
|
import { useLicenseStatusContext } from "./useLicenseStatusContext";
|
||||||
import { useSubscriptionStatusContext } from "./useSubscriptionStatusContext";
|
import { useSubscriptionStatusContext } from "./useSubscriptionStatusContext";
|
||||||
import { Tier } from "@server/lib/tiers";
|
import { Tier } from "@server/types/Tiers";
|
||||||
|
|
||||||
export function usePaidStatus() {
|
export function usePaidStatus() {
|
||||||
const { isUnlocked } = useLicenseStatusContext();
|
const { isUnlocked } = useLicenseStatusContext();
|
||||||
@@ -12,7 +12,7 @@ export function usePaidStatus() {
|
|||||||
const tierData = subscription?.getTier();
|
const tierData = subscription?.getTier();
|
||||||
const hasSaasSubscription = build === "saas" && tierData?.active;
|
const hasSaasSubscription = build === "saas" && tierData?.active;
|
||||||
|
|
||||||
function isPaidUser(tiers: Tier): boolean {
|
function isPaidUser(tiers: Tier[]): boolean {
|
||||||
if (hasEnterpriseLicense) {
|
if (hasEnterpriseLicense) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user