refactor and add tiers

This commit is contained in:
miloschwartz
2026-02-10 10:27:10 -08:00
parent 69c2212ea0
commit d27482e812
20 changed files with 201 additions and 78 deletions

View File

@@ -35,6 +35,7 @@ import { usePaidStatus } from "@app/hooks/usePaidStatus";
import { build } from "@server/build";
import { PaidFeaturesAlert } from "./PaidFeaturesAlert";
import { Alert, AlertDescription, AlertTitle } from "./ui/alert";
import { tierMatrix } from "@server/lib/billing/tierMatrix";
export type AuthPageCustomizationProps = {
orgId: string;
@@ -139,7 +140,7 @@ export default function AuthPageBrandingForm({
`Choose your preferred authentication method for {{resourceName}}`,
primaryColor: branding?.primaryColor ?? `#f36117` // default pangolin primary color
},
disabled: !isPaidUser
disabled: !isPaidUser(tierMatrix.loginPageBranding)
});
async function updateBranding() {
@@ -221,7 +222,9 @@ export default function AuthPageBrandingForm({
<SettingsSectionBody>
<SettingsSectionForm>
<PaidFeaturesAlert />
<PaidFeaturesAlert
tiers={tierMatrix.loginPageBranding}
/>
<Form {...form}>
<form

View File

@@ -285,7 +285,7 @@ function AuthPageSettings({
</SettingsSectionHeader>
<SettingsSectionBody>
<SettingsSectionForm>
<PaidFeaturesAlert />
<PaidFeaturesAlert tiers={tierMatrix.loginPageDomain} />
<Form {...form}>
<form

View File

@@ -20,6 +20,8 @@ import {
import { Input } from "@app/components/ui/input";
import { useTranslations } from "next-intl";
import { Control, FieldValues, Path } from "react-hook-form";
import { usePaidStatus } from "@app/hooks/usePaidStatus";
import { tierMatrix } from "@server/lib/billing/tierMatrix";
type Role = {
roleId: number;
@@ -49,6 +51,8 @@ export default function AutoProvisionConfigWidget<T extends FieldValues>({
}: AutoProvisionConfigWidgetProps<T>) {
const t = useTranslations();
const { isPaidUser } = usePaidStatus();
return (
<div className="space-y-4">
<div className="mb-4">
@@ -57,6 +61,7 @@ export default function AutoProvisionConfigWidget<T extends FieldValues>({
label={t("idpAutoProvisionUsers")}
defaultChecked={autoProvision}
onCheckedChange={onAutoProvisionChange}
disabled={!isPaidUser(tierMatrix.autoProvisioning)}
/>
<span className="text-sm text-muted-foreground">
{t("idpAutoProvisionUsersDescription")}

View File

@@ -36,6 +36,7 @@ import { useForm } from "react-hook-form";
import { z } from "zod";
import { PaidFeaturesAlert } from "./PaidFeaturesAlert";
import { CheckboxWithLabel } from "./ui/checkbox";
import { tierMatrix } from "@server/lib/billing/tierMatrix";
type CreateRoleFormProps = {
open: boolean;
@@ -164,7 +165,9 @@ export default function CreateRoleForm({
{!env.flags.disableEnterpriseFeatures && (
<>
<PaidFeaturesAlert />
<PaidFeaturesAlert
tiers={tierMatrix.deviceApprovals}
/>
<FormField
control={form.control}
@@ -175,7 +178,9 @@ export default function CreateRoleForm({
<CheckboxWithLabel
{...field}
disabled={
!isPaidUser
!isPaidUser(
tierMatrix.deviceApprovals
)
}
value="on"
checked={form.watch(

View File

@@ -42,6 +42,7 @@ import { useForm } from "react-hook-form";
import { z } from "zod";
import { PaidFeaturesAlert } from "./PaidFeaturesAlert";
import { CheckboxWithLabel } from "./ui/checkbox";
import { tierMatrix } from "@server/lib/billing/tierMatrix";
type CreateRoleFormProps = {
role: Role;
@@ -172,7 +173,9 @@ export default function EditRoleForm({
{!env.flags.disableEnterpriseFeatures && (
<>
<PaidFeaturesAlert />
<PaidFeaturesAlert
tiers={tierMatrix.deviceApprovals}
/>
<FormField
control={form.control}
@@ -183,7 +186,9 @@ export default function EditRoleForm({
<CheckboxWithLabel
{...field}
disabled={
!isPaidUser
!isPaidUser(
tierMatrix.deviceApprovals
)
}
value="on"
checked={form.watch(

View File

@@ -120,6 +120,7 @@ type DataTableProps<TData, TValue> = {
// Row expansion props
expandable?: boolean;
renderExpandedRow?: (row: TData) => React.ReactNode;
isExportDisabled?: boolean;
};
export function LogDataTable<TData, TValue>({
@@ -145,7 +146,8 @@ export function LogDataTable<TData, TValue>({
isLoading = false,
expandable = false,
disabled = false,
renderExpandedRow
renderExpandedRow,
isExportDisabled
}: DataTableProps<TData, TValue>) {
const t = useTranslations();
@@ -403,7 +405,7 @@ export function LogDataTable<TData, TValue>({
onClick={() =>
!disabled && onExport()
}
disabled={isExporting || disabled}
disabled={isExporting || disabled || isExportDisabled}
>
{isExporting ? (
<Loader className="mr-2 size-4 animate-spin" />

View File

@@ -1,4 +1,5 @@
"use client";
import { Card, CardContent } from "@app/components/ui/card";
import { build } from "@server/build";
import { usePaidStatus } from "@app/hooks/usePaidStatus";
@@ -6,6 +7,7 @@ import { ExternalLink, KeyRound, Sparkles } from "lucide-react";
import { useTranslations } from "next-intl";
import Link from "next/link";
import { useEnvContext } from "@app/hooks/useEnvContext";
import { Tier } from "@server/types/Tiers";
const bannerClassName =
"mb-6 border-primary/30 bg-linear-to-br from-primary/10 via-background to-background overflow-hidden";
@@ -13,7 +15,11 @@ const bannerContentClassName = "py-3 px-4";
const bannerRowClassName =
"flex items-center gap-2.5 text-sm text-muted-foreground";
export function PaidFeaturesAlert() {
type Props = {
tiers: Tier[];
};
export function PaidFeaturesAlert({ tiers }: Props) {
const t = useTranslations();
const { hasSaasSubscription, hasEnterpriseLicense } = usePaidStatus();
const { env } = useEnvContext();
@@ -24,7 +30,7 @@ export function PaidFeaturesAlert() {
return (
<>
{build === "saas" && !hasSaasSubscription ? (
{build === "saas" && !hasSaasSubscription(tiers) ? (
<Card className={bannerClassName}>
<CardContent className={bannerContentClassName}>
<div className={bannerRowClassName}>

View File

@@ -5,16 +5,12 @@ import DeleteRoleForm from "@app/components/DeleteRoleForm";
import { RolesDataTable } from "@app/components/RolesDataTable";
import { Button } from "@app/components/ui/button";
import { ExtendedColumnDef } from "@app/components/ui/data-table";
import { useEnvContext } from "@app/hooks/useEnvContext";
import { useOrgContext } from "@app/hooks/useOrgContext";
import { toast } from "@app/hooks/useToast";
import { createApiClient } from "@app/lib/api";
import { Role } from "@server/db";
import { ArrowRight, ArrowUpDown, Link, MoreHorizontal } from "lucide-react";
import { ArrowUpDown, MoreHorizontal } from "lucide-react";
import { useTranslations } from "next-intl";
import { useRouter } from "next/navigation";
import { useState, useTransition } from "react";
import { usePaidStatus } from "@app/hooks/usePaidStatus";
import {
DropdownMenu,
DropdownMenuTrigger,
@@ -38,11 +34,6 @@ export default function UsersTable({ roles }: RolesTableProps) {
const [roleToRemove, setRoleToRemove] = useState<RoleRow | null>(null);
const api = createApiClient(useEnvContext());
const { org } = useOrgContext();
const { isPaidUser } = usePaidStatus();
const t = useTranslations();
const [isRefreshing, startTransition] = useTransition();