fix: remove free tier

This commit is contained in:
Carl-Gerhard Lindesvärd
2025-03-24 10:57:20 +01:00
parent 76239314dd
commit 7ab869ff45
12 changed files with 141 additions and 76 deletions

View File

@@ -21,6 +21,7 @@ import type { LucideIcon } from 'lucide-react';
import { usePathname } from 'next/navigation';
import { ProjectLink } from '@/components/links';
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
import { useNumber } from '@/hooks/useNumerFormatter';
import type { IServiceDashboards, IServiceOrganization } from '@openpanel/db';
import { differenceInDays, format } from 'date-fns';
@@ -72,10 +73,29 @@ export default function LayoutMenu({
subscriptionEndsAt,
subscriptionPeriodEventsCount,
subscriptionPeriodEventsLimit,
subscriptionProductId,
} = organization;
return (
<>
<div className="col border rounded mb-2 divide-y">
{(subscriptionProductId === '036efa2a-b3b4-4c75-b24a-9cac6bb8893b' ||
subscriptionProductId === 'a18b4bee-d3db-4404-be6f-fba2f042d9ed') && (
<ProjectLink
href={'/settings/organization?tab=billing'}
className={cn(
'rounded p-2 row items-center gap-2 hover:bg-def-200 text-destructive',
)}
>
<BanknoteIcon size={20} />
<div className="flex-1 col gap-1">
<div className="font-medium">Free plan is removed</div>
<div className="text-sm opacity-80">
We've removed the free plan. You can upgrade to a paid plan to
continue using OpenPanel.
</div>
</div>
</ProjectLink>
)}
{process.env.SELF_HOSTED && (
<ProjectLink
href={'/settings/organization?tab=billing'}

View File

@@ -10,9 +10,13 @@ import { Widget, WidgetBody, WidgetHead } from '@/components/widget';
const questions = [
{
question: "What's the free tier?",
question: 'Does OpenPanel have a free tier?',
answer: [
'You get 5000 events per month for free. This is mostly for you to try out OpenPanel but also for solo developers or people who want to try out OpenPanel without committing to a paid plan.',
'For our Cloud plan we offer a 14 days free trial, this is mostly for you to be able to try out OpenPanel before committing to a paid plan.',
'OpenPanel is also open-source and you can self-host it for free!',
'',
'Why does OpenPanel not have a free tier?',
'We want to make sure that OpenPanel is used by people who are serious about using it. We also need to invest time and resources to maintain the platform and provide support to our users.',
],
},
{

View File

@@ -47,9 +47,9 @@ export default function Billing({ organization }: Props) {
);
const products = useMemo(() => {
return (productsQuery.data || []).filter(
(product) => product.recurringInterval === recurringInterval,
);
return (productsQuery.data || [])
.filter((product) => product.recurringInterval === recurringInterval)
.filter((product) => product.prices.some((p) => p.amountType !== 'free'));
}, [productsQuery.data, recurringInterval]);
useEffect(() => {
@@ -77,19 +77,22 @@ export default function Billing({ organization }: Props) {
}
return (
<WidgetTable
className="w-full max-w-full [&_td]:text-left"
className="w-full max-w-full [&_.cell:first-child]:pl-4 [&_.cell:last-child]:pr-4"
columnClassName="!h-auto"
data={products}
keyExtractor={(item) => item.id}
columns={[
{
name: 'Tier',
className: 'text-left',
width: 'auto',
render(item) {
return <div className="font-medium">{item.name}</div>;
},
},
{
name: 'Price',
width: 'auto',
render(item) {
const price = item.prices[0];
if (!price) {
@@ -97,20 +100,21 @@ export default function Billing({ organization }: Props) {
}
if (price.amountType === 'free') {
return (
<div className="row gap-2 whitespace-nowrap">
<div className="items-center text-right justify-end gap-4 flex-1 row">
<span>Free</span>
<CheckoutButton
disabled={item.disabled}
key={price.id}
price={price}
organization={organization}
projectId={projectId}
/>
</div>
</div>
);
return null;
// return (
// <div className="row gap-2 whitespace-nowrap">
// <div className="items-center text-right justify-end gap-4 flex-1 row">
// <span>Free</span>
// <CheckoutButton
// disabled={item.disabled}
// key={price.id}
// price={price}
// organization={organization}
// projectId={projectId}
// />
// </div>
// </div>
// );
}
if (price.amountType !== 'fixed') {

View File

@@ -107,6 +107,15 @@ export default function CurrentSubscription({ organization }: Props) {
return (
<>
<div className="gap-4 col">
{price.amountType === 'free' && (
<Alert variant="warning">
<AlertTitle>Free plan is removed</AlertTitle>
<AlertDescription>
We've removed the free plan. You can upgrade to a paid plan to
continue using OpenPanel.
</AlertDescription>
</Alert>
)}
<div className="row justify-between">
<div>Name</div>
<div className="text-right font-medium">{product.name}</div>

View File

@@ -114,10 +114,9 @@ export default function Usage({ organization }: Props) {
subscriptionPeriodEventsLimit === 0
? '👀'
: number.formatWithUnit(
(1 -
1 -
subscriptionPeriodEventsCount /
subscriptionPeriodEventsLimit) *
100,
subscriptionPeriodEventsLimit,
'%',
)
}