From 5b1d3d8f0e38dbef49b7d23e2d67d99cc5ff311b Mon Sep 17 00:00:00 2001 From: Usman Baig Date: Fri, 20 Feb 2026 16:50:43 +0100 Subject: [PATCH] refactor: update PricingSection styles for improved layout and accessibility; enhance OrganizationSettings to handle plan changes and display past due notices --- components/PricingSection.tsx | 26 +++-- components/settings/OrganizationSettings.tsx | 116 ++++++++++++++++--- 2 files changed, 116 insertions(+), 26 deletions(-) diff --git a/components/PricingSection.tsx b/components/PricingSection.tsx index 04d8b1f..37f5c40 100644 --- a/components/PricingSection.tsx +++ b/components/PricingSection.tsx @@ -219,10 +219,10 @@ export default function PricingSection() { transition={{ duration: 0.5 }} className="text-center mb-12" > -

+

Transparent Pricing

-

+

Scale with your traffic. No hidden fees.

@@ -232,11 +232,11 @@ export default function PricingSection() { initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.5, delay: 0.1 }} - className="max-w-6xl mx-auto border border-neutral-200 dark:border-neutral-800 rounded-3xl bg-white/50 dark:bg-neutral-900/50 backdrop-blur-xl shadow-sm overflow-hidden mb-20" + className="max-w-6xl mx-auto border border-neutral-200 dark:border-neutral-800 rounded-2xl bg-white/50 dark:bg-neutral-900/50 backdrop-blur-xl shadow-sm overflow-hidden mb-20" > {/* Top Toolbar */} -
+
10k @@ -252,7 +252,9 @@ export default function PricingSection() { step="1" value={sliderIndex} onChange={(e) => setSliderIndex(parseInt(e.target.value))} - className="w-full h-2 bg-neutral-200 rounded-lg appearance-none cursor-pointer dark:bg-neutral-700 accent-brand-orange" + aria-label="Monthly pageview limit" + aria-valuetext={`${currentTraffic.label} pageviews per month`} + className="w-full h-2 bg-neutral-200 rounded-lg appearance-none cursor-pointer dark:bg-neutral-700 accent-brand-orange focus:outline-none focus:ring-2 focus:ring-brand-orange focus:ring-offset-2" />
@@ -260,10 +262,12 @@ export default function PricingSection() { Get 1 month free with yearly -
+
+
+ )} + {/* Cancel-at-period-end notice */} {subscription.cancel_at_period_end && (
@@ -886,9 +916,11 @@ export default function OrganizationSettings() { ? 'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-300' : subscription.subscription_status === 'trialing' ? 'bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-300' + : subscription.subscription_status === 'past_due' + ? 'bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-300' : 'bg-neutral-100 text-neutral-700 dark:bg-neutral-800 dark:text-neutral-300' }`}> - {subscription.subscription_status === 'trialing' ? 'Trial' : (subscription.subscription_status || 'Free')} + {subscription.subscription_status === 'trialing' ? 'Trial' : subscription.subscription_status === 'past_due' ? 'Past Due' : (subscription.subscription_status || 'Free')} {subscription.billing_interval && ( @@ -918,7 +950,7 @@ export default function OrganizationSettings() { )} {/* Usage stats */} -
+
Sites
@@ -937,6 +969,22 @@ export default function OrganizationSettings() { ? `${subscription.pageview_usage.toLocaleString()} / ${subscription.pageview_limit.toLocaleString()}` : '—'}
+ {subscription.pageview_limit > 0 && typeof subscription.pageview_usage === 'number' && ( +
+
= 1 + ? 'bg-red-500' + : subscription.pageview_usage / subscription.pageview_limit >= 0.9 + ? 'bg-red-400' + : subscription.pageview_usage / subscription.pageview_limit >= 0.8 + ? 'bg-amber-400' + : 'bg-green-500' + }`} + style={{ width: `${Math.min(100, (subscription.pageview_usage / subscription.pageview_limit) * 100)}%` }} + /> +
+ )}
@@ -975,7 +1023,7 @@ export default function OrganizationSettings() { type="button" onClick={handleManageSubscription} disabled={isRedirectingToPortal} - className="inline-flex items-center gap-1.5 text-sm text-neutral-600 dark:text-neutral-400 hover:text-neutral-900 dark:hover:text-white transition-colors disabled:opacity-50" + className="inline-flex items-center gap-1.5 text-sm text-neutral-600 dark:text-neutral-400 hover:text-neutral-900 dark:hover:text-white transition-colors disabled:opacity-50 focus:outline-none focus:ring-2 focus:ring-brand-orange focus:rounded" > Payment method & invoices @@ -985,7 +1033,7 @@ export default function OrganizationSettings() { @@ -994,7 +1042,7 @@ export default function OrganizationSettings() { {/* Invoice History */}
-

Recent invoices

+

Recent invoices

{isLoadingInvoices ? (
@@ -1028,14 +1076,14 @@ export default function OrganizationSettings() { {invoice.invoice_pdf && ( + className="inline-flex items-center gap-1.5 px-2.5 py-1.5 text-xs font-medium text-neutral-600 dark:text-neutral-400 hover:text-neutral-900 dark:hover:text-white hover:bg-neutral-100 dark:hover:bg-neutral-800 rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange" title="Download PDF"> Download PDF )} {invoice.hosted_invoice_url && ( + className="inline-flex items-center gap-1.5 px-2.5 py-1.5 text-xs font-medium text-neutral-600 dark:text-neutral-400 hover:text-neutral-900 dark:hover:text-white hover:bg-neutral-100 dark:hover:bg-neutral-800 rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange" title="View invoice"> View invoice @@ -1411,8 +1459,9 @@ export default function OrganizationSettings() { @@ -1421,6 +1470,41 @@ export default function OrganizationSettings() { Choose your pageview limit and billing interval. {hasActiveSubscription ? 'Your next invoice will reflect prorations.' : 'You’ll start a new subscription.'}

+
+ +
+ {([ + { id: PLAN_ID_SOLO, name: 'Solo', sites: '1 site' }, + { id: PLAN_ID_TEAM, name: 'Team', sites: 'Up to 5 sites' }, + { id: PLAN_ID_BUSINESS, name: 'Business', sites: 'Up to 10 sites' }, + ] as const).map((plan) => { + const isCurrentPlan = subscription?.plan_id === plan.id + const isSelected = changePlanId === plan.id + return ( + + ) + })} +
+