Feature/onboarding slides (#4955)

# Description of Changes

- Added onboarding slides/upgrade banner conditions for all the
following cases
  - 'licensed'
  - 'no-login-user-under-limit-no-license'
  - 'no-login-admin-under-limit-no-license'
  - 'no-login-user-over-limit-no-license'
  - 'no-login-admin-over-limit-no-license'
  - 'login-user-under-limit-no-license'
  - 'login-admin-under-limit-no-license'
  - 'login-user-over-limit-no-license'
  - 'login-admin-over-limit-no-license';


---

## Checklist

### General

- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### Translations (if applicable)

- [ ] I ran
[`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.

---------

Co-authored-by: Anthony Stirling <[email protected]>
Co-authored-by: Connor Yoh <[email protected]>
This commit is contained in:
EthanHealy01
2025-11-25 13:45:02 +00:00
committed by GitHub
co-authored by Anthony Stirling Connor Yoh
parent 80f2980755
commit a8db2fda18
66 changed files with 5641 additions and 1248 deletions
@@ -1,4 +1,4 @@
import React, { useState, useCallback, useEffect } from 'react';
import React, { useState, useCallback, useEffect, useMemo } from 'react';
import { Divider, Loader, Alert, Group, Text, Collapse, Button, TextInput, Stack, Paper } from '@mantine/core';
import { useTranslation } from 'react-i18next';
import { usePlans } from '@app/hooks/usePlans';
@@ -9,6 +9,9 @@ import AvailablePlansSection from '@app/components/shared/config/configSections/
import StaticPlanSection from '@app/components/shared/config/configSections/plan/StaticPlanSection';
import { alert } from '@app/components/toast';
import LocalIcon from '@app/components/shared/LocalIcon';
import { ManageBillingButton } from '@app/components/shared/ManageBillingButton';
import { InfoBanner } from '@app/components/shared/InfoBanner';
import { useLicenseAlert } from '@app/hooks/useLicenseAlert';
import { isSupabaseConfigured } from '@app/services/supabaseClient';
import { getPreferredCurrency, setCachedCurrency } from '@app/utils/currencyDetection';
@@ -25,10 +28,11 @@ const AdminPlanSection: React.FC = () => {
const [licenseKeyInput, setLicenseKeyInput] = useState<string>('');
const [savingLicense, setSavingLicense] = useState(false);
const { plans, loading, error, refetch } = usePlans(currency);
const licenseAlert = useLicenseAlert();
// Check if we should use static version
useEffect(() => {
// Check if Stripe and Supabase are configured
// Check if Stripe is configured
const stripeKey = import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY;
if (!stripeKey || !isSupabaseConfigured || error) {
setUseStaticVersion(true);
@@ -146,6 +150,23 @@ const AdminPlanSection: React.FC = () => {
[openCheckout, currency, refetch, licenseInfo, t]
);
const shouldShowLicenseWarning = licenseAlert.active && licenseAlert.audience === 'admin';
const formattedUserCount = useMemo(() => {
if (licenseAlert.totalUsers == null) {
return t('plan.licenseWarning.overLimit', 'more than {{limit}}', {
limit: licenseAlert.freeTierLimit,
});
}
return licenseAlert.totalUsers.toLocaleString();
}, [licenseAlert.totalUsers, licenseAlert.freeTierLimit, t]);
const scrollToPlans = useCallback(() => {
const el = document.getElementById('available-plans-section');
if (el) {
el.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}, []);
// Show static version if Stripe is not configured or there's an error
if (useStaticVersion) {
return <StaticPlanSection currentLicenseInfo={licenseInfo ?? undefined} />;
@@ -175,6 +196,40 @@ const AdminPlanSection: React.FC = () => {
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: '2rem' }}>
{shouldShowLicenseWarning && (
<InfoBanner
icon="warning-rounded"
tone="warning"
title={t('plan.licenseWarning.title', 'Free self-hosted limit reached')}
message={t('plan.licenseWarning.body', {
total: formattedUserCount,
limit: licenseAlert.freeTierLimit,
})}
buttonText={t('plan.licenseWarning.cta', 'See plans')}
buttonIcon="upgrade-rounded"
onButtonClick={scrollToPlans}
dismissible={false}
minHeight={68}
background="#FFF4E6"
borderColor="var(--mantine-color-orange-7)"
textColor="#9A3412"
iconColor="#EA580C"
buttonVariant="filled"
buttonColor="orange.7"
/>
)}
{/* Manage Subscription Button - Only show if user has active license and Supabase is configured */}
{licenseInfo?.licenseKey && isSupabaseConfigured && (
<Paper withBorder p="md" radius="md">
<Group justify="space-between" align="center">
<Text size="sm" c="dimmed">
{t('plan.manageSubscription.description', 'Manage your subscription, billing, and payment methods')}
</Text>
<ManageBillingButton />
</Group>
</Paper>
)}
<AvailablePlansSection
plans={plans}
currentLicenseInfo={licenseInfo}