change wording for when enableLogin is false, if isNewServer, assume person is an admin, and add the enable analytics to the end of the onboarding flow

This commit is contained in:
EthanHealy01
2025-11-23 01:01:32 +00:00
parent 6fb44181ce
commit 4a148a1918
8 changed files with 77 additions and 23 deletions

View File

@@ -5104,7 +5104,8 @@
"planOverview": {
"adminTitle": "Admin Overview",
"userTitle": "Plan Overview",
"adminBody": "As an admin, you can manage users, configure settings, and monitor server health. The first <strong>{{freeTierLimit}}</strong> people on your server get to use Stirling free of charge.",
"adminBodyLoginEnabled": "As an admin, you can manage users, configure settings, and monitor server health. The first <strong>{{freeTierLimit}}</strong> people on your server get to use Stirling free of charge.",
"adminBodyLoginDisabled": "Once you enable login mode, you can manage users, configure settings, and monitor server health. The first <strong>{{freeTierLimit}}</strong> people on your server get to use Stirling free of charge.",
"userBody": "Invite teammates, assign roles, and keep your documents organized in one secure workspace. Enable login mode whenever you're ready to grow beyond solo use."
},
"securityCheck": {

View File

@@ -4914,7 +4914,8 @@
"planOverview": {
"adminTitle": "Admin Overview",
"userTitle": "Plan Overview",
"adminBody": "As an admin, you can manage users, configure settings, and monitor server health. The first <strong>{{freeTierLimit}}</strong> people on your server get to use Stirling free of charge.",
"adminBodyLoginEnabled": "As an admin, you can manage users, configure settings, and monitor server health. The first <strong>{{freeTierLimit}}</strong> people on your server get to use Stirling free of charge.",
"adminBodyLoginDisabled": "Once you enable login mode, you can manage users, configure settings, and monitor server health. The first <strong>{{freeTierLimit}}</strong> people on your server get to use Stirling free of charge.",
"userBody": "Invite teammates, assign roles, and keep your documents organized in one secure workspace. Enable login mode whenever you're ready to grow beyond solo use."
},
"securityCheck": {

View File

@@ -42,6 +42,7 @@ export function useInitialOnboardingState({
hasPaidLicense,
scenarioKey,
setSelfReportedAdmin,
isNewServer,
} = useServerExperience();
const osType = useOs();
const navigate = useNavigate();
@@ -93,6 +94,13 @@ export function useInitialOnboardingState({
const effectiveEnableLogin = enableLogin;
const effectiveIsAdmin = isAdmin;
const shouldAssumeAdminForNewServer = Boolean(isNewServer) && !effectiveEnableLogin;
useEffect(() => {
if (shouldAssumeAdminForNewServer && !state.selfReportedAdmin) {
handleRoleSelect('admin');
}
}, [handleRoleSelect, shouldAssumeAdminForNewServer, state.selfReportedAdmin]);
const shouldUseServerCount =
(effectiveEnableLogin && effectiveIsAdmin) || !effectiveEnableLogin;
@@ -127,11 +135,19 @@ export function useInitialOnboardingState({
return options.filter(opt => opt.url);
}, []);
const { ids: flowSlideIds, type: flowType } = resolveFlow(
effectiveEnableLogin,
effectiveIsAdmin,
state.selfReportedAdmin,
const resolvedFlow = useMemo(
() => resolveFlow(effectiveEnableLogin, effectiveIsAdmin, state.selfReportedAdmin),
[effectiveEnableLogin, effectiveIsAdmin, state.selfReportedAdmin],
);
const shouldSkipSecurityCheck = shouldAssumeAdminForNewServer;
const flowSlideIds = useMemo(
() =>
shouldSkipSecurityCheck
? resolvedFlow.ids.filter((id) => id !== 'security-check')
: resolvedFlow.ids,
[resolvedFlow.ids, shouldSkipSecurityCheck],
);
const flowType = resolvedFlow.type;
const totalSteps = flowSlideIds.length;
const maxIndex = Math.max(totalSteps - 1, 0);
@@ -212,6 +228,7 @@ export function useInitialOnboardingState({
selectedRole: state.selectedRole,
onRoleSelect: handleRoleSelect,
licenseNotice,
loginEnabled: effectiveEnableLogin,
});
const goNext = useCallback(() => {

View File

@@ -45,6 +45,7 @@ export interface SlideFactoryParams {
selectedRole: 'admin' | 'user' | null;
onRoleSelect: (role: 'admin' | 'user' | null) => void;
licenseNotice?: LicenseNotice;
loginEnabled?: boolean;
}
export interface HeroDefinition {
@@ -142,7 +143,8 @@ export const SLIDE_DEFINITIONS: Record<SlideId, SlideDefinition> = {
},
'admin-overview': {
id: 'admin-overview',
createSlide: ({ licenseNotice }) => PlanOverviewSlide({ isAdmin: true, licenseNotice }),
createSlide: ({ licenseNotice, loginEnabled }) =>
PlanOverviewSlide({ isAdmin: true, licenseNotice, loginEnabled }),
hero: { type: 'diamond' },
buttons: [
{

View File

@@ -1,36 +1,58 @@
import React from 'react';
import { useTranslation, Trans } from 'react-i18next';
import { useTranslation } from 'react-i18next';
import { SlideConfig, LicenseNotice } from '../../../types/types';
import { UNIFIED_CIRCLE_CONFIG } from './unifiedBackgroundConfig';
interface PlanOverviewSlideProps {
isAdmin: boolean;
licenseNotice?: LicenseNotice;
loginEnabled?: boolean;
}
const DEFAULT_FREE_TIER_LIMIT = 5;
export default function PlanOverviewSlide({ isAdmin, licenseNotice }: PlanOverviewSlideProps): SlideConfig {
export default function PlanOverviewSlide({
isAdmin,
licenseNotice,
loginEnabled = false,
}: PlanOverviewSlideProps): SlideConfig {
const { t } = useTranslation();
const freeTierLimit = licenseNotice?.freeTierLimit ?? DEFAULT_FREE_TIER_LIMIT;
const adminBody = (
<span>
<Trans
i18nKey="onboarding.planOverview.adminBody"
components={{ strong: <strong /> }}
values={{ freeTierLimit }}
defaults="As an admin, you can manage users, configure settings, and monitor server health. The first <strong>{{freeTierLimit}}</strong> people on your server get to use Stirling free of charge."
/>
</span>
);
const adminBodyKey = loginEnabled
? 'onboarding.planOverview.adminBodyLoginEnabled'
: 'onboarding.planOverview.adminBodyLoginDisabled';
const adminBodyTemplate = t(adminBodyKey, {
freeTierLimit: '{{freeTierLimit}}',
defaultValue: loginEnabled
? 'As an admin, you can manage users, configure settings, and monitor server health. The first {{freeTierLimit}} people on your server get to use Stirling free of charge.'
: 'Once you enable login mode, you can manage users, configure settings, and monitor server health. The first {{freeTierLimit}} people on your server get to use Stirling free of charge.',
});
const renderAdminBody = () => {
const [before, after] = adminBodyTemplate.split('{{freeTierLimit}}');
if (after !== undefined) {
return (
<span>
{before}
<strong>{freeTierLimit}</strong>
{after}
</span>
);
}
return (
<span>
{adminBodyTemplate.replace('{{freeTierLimit}}', String(freeTierLimit))}
</span>
);
};
return {
key: isAdmin ? 'admin-overview' : 'plan-overview',
title: isAdmin
? t('onboarding.planOverview.adminTitle', 'Admin Overview')
: t('onboarding.planOverview.userTitle', 'Plan Overview'),
body: isAdmin ? adminBody : (
body: isAdmin ? renderAdminBody() : (
<span>
{t('onboarding.planOverview.userBody', 'Invite teammates, assign roles, and keep your documents organized in one secure workspace. Enable login mode whenever you\'re ready to grow beyond solo use.')}
</span>

View File

@@ -13,7 +13,7 @@ const CookieConsentContext = createContext<CookieConsentContextValue | undefined
export const CookieConsentProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const { config } = useAppConfig();
const analyticsEnabled = config?.enableAnalytics === true;
const analyticsEnabled = config ? config.enableAnalytics !== false : false;
const {
showCookieConsent,
showCookiePreferences,

View File

@@ -9,6 +9,7 @@ import { useBaseUrl } from "@app/hooks/useBaseUrl";
import { useIsMobile } from "@app/hooks/useIsMobile";
import { useAppConfig } from "@app/contexts/AppConfigContext";
import { useLogoPath } from "@app/hooks/useLogoPath";
import { useCookieConsentContext } from "@app/contexts/CookieConsentContext";
import AppsIcon from '@mui/icons-material/AppsRounded';
import ToolPanel from "@app/components/tools/ToolPanel";
@@ -45,6 +46,7 @@ export default function HomePage() {
const { openFilesModal } = useFilesModalContext();
const { colorScheme } = useMantineColorScheme();
const { config } = useAppConfig();
const { hasResponded: cookieConsentResponded } = useCookieConsentContext();
const isMobile = useIsMobile();
const sliderRef = useRef<HTMLDivElement | null>(null);
const [activeMobileView, setActiveMobileView] = useState<MobileView>("tools");
@@ -54,10 +56,10 @@ export default function HomePage() {
// Show admin analytics choice modal if analytics settings not configured
useEffect(() => {
if (config && config.enableAnalytics === null) {
if (config && config.enableAnalytics === null && cookieConsentResponded) {
setShowAnalyticsModal(true);
}
}, [config]);
}, [config, cookieConsentResponded]);
const brandAltText = t("home.mobile.brandAlt", "Stirling PDF logo");
const brandIconSrc = useLogoPath();

View File

@@ -158,6 +158,15 @@ export function ServerExperienceProvider({ children }: { children: ReactNode })
return () => window.removeEventListener('storage', handleStorage);
}, []);
useEffect(() => {
if (!config) {
return;
}
if (config.isNewServer && !loginEnabled && !selfReportedAdmin) {
setSelfReportedAdmin(true);
}
}, [config, loginEnabled, selfReportedAdmin, setSelfReportedAdmin]);
const fetchUserCounts = useCallback(async () => {
if (!config) {
return;