From 4a148a1918d20f26b2bd48c08ceae6b0b61c7e0e Mon Sep 17 00:00:00 2001 From: EthanHealy01 Date: Sun, 23 Nov 2025 01:01:32 +0000 Subject: [PATCH] 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 --- .../public/locales/en-GB/translation.json | 3 +- .../public/locales/en-US/translation.json | 3 +- .../useInitialOnboardingState.ts | 25 ++++++++-- .../onboarding/onboardingFlowConfig.ts | 4 +- .../onboarding/slides/PlanOverviewSlide.tsx | 48 ++++++++++++++----- .../core/contexts/CookieConsentContext.tsx | 2 +- frontend/src/core/pages/HomePage.tsx | 6 ++- .../contexts/ServerExperienceContext.tsx | 9 ++++ 8 files changed, 77 insertions(+), 23 deletions(-) diff --git a/frontend/public/locales/en-GB/translation.json b/frontend/public/locales/en-GB/translation.json index ee542e2dd8..1e8ea95d48 100644 --- a/frontend/public/locales/en-GB/translation.json +++ b/frontend/public/locales/en-GB/translation.json @@ -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 {{freeTierLimit}} 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 {{freeTierLimit}} 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 {{freeTierLimit}} 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": { diff --git a/frontend/public/locales/en-US/translation.json b/frontend/public/locales/en-US/translation.json index ceb0cb2adf..c0390af772 100644 --- a/frontend/public/locales/en-US/translation.json +++ b/frontend/public/locales/en-US/translation.json @@ -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 {{freeTierLimit}} 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 {{freeTierLimit}} 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 {{freeTierLimit}} 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": { diff --git a/frontend/src/core/components/onboarding/InitialOnboardingModal/useInitialOnboardingState.ts b/frontend/src/core/components/onboarding/InitialOnboardingModal/useInitialOnboardingState.ts index c57b0990b0..a7ffb426f5 100644 --- a/frontend/src/core/components/onboarding/InitialOnboardingModal/useInitialOnboardingState.ts +++ b/frontend/src/core/components/onboarding/InitialOnboardingModal/useInitialOnboardingState.ts @@ -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(() => { diff --git a/frontend/src/core/components/onboarding/onboardingFlowConfig.ts b/frontend/src/core/components/onboarding/onboardingFlowConfig.ts index a7617a1755..30967691dc 100644 --- a/frontend/src/core/components/onboarding/onboardingFlowConfig.ts +++ b/frontend/src/core/components/onboarding/onboardingFlowConfig.ts @@ -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 = { }, 'admin-overview': { id: 'admin-overview', - createSlide: ({ licenseNotice }) => PlanOverviewSlide({ isAdmin: true, licenseNotice }), + createSlide: ({ licenseNotice, loginEnabled }) => + PlanOverviewSlide({ isAdmin: true, licenseNotice, loginEnabled }), hero: { type: 'diamond' }, buttons: [ { diff --git a/frontend/src/core/components/onboarding/slides/PlanOverviewSlide.tsx b/frontend/src/core/components/onboarding/slides/PlanOverviewSlide.tsx index 39287c8b51..e777aeff87 100644 --- a/frontend/src/core/components/onboarding/slides/PlanOverviewSlide.tsx +++ b/frontend/src/core/components/onboarding/slides/PlanOverviewSlide.tsx @@ -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 = ( - - }} - values={{ freeTierLimit }} - defaults="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." - /> - - ); + 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 ( + + {before} + {freeTierLimit} + {after} + + ); + } + return ( + + {adminBodyTemplate.replace('{{freeTierLimit}}', String(freeTierLimit))} + + ); + }; 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() : ( {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.')} diff --git a/frontend/src/core/contexts/CookieConsentContext.tsx b/frontend/src/core/contexts/CookieConsentContext.tsx index 4d46bcd013..530f99a2a3 100644 --- a/frontend/src/core/contexts/CookieConsentContext.tsx +++ b/frontend/src/core/contexts/CookieConsentContext.tsx @@ -13,7 +13,7 @@ const CookieConsentContext = createContext = ({ children }) => { const { config } = useAppConfig(); - const analyticsEnabled = config?.enableAnalytics === true; + const analyticsEnabled = config ? config.enableAnalytics !== false : false; const { showCookieConsent, showCookiePreferences, diff --git a/frontend/src/core/pages/HomePage.tsx b/frontend/src/core/pages/HomePage.tsx index c77e352963..77fc519086 100644 --- a/frontend/src/core/pages/HomePage.tsx +++ b/frontend/src/core/pages/HomePage.tsx @@ -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(null); const [activeMobileView, setActiveMobileView] = useState("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(); diff --git a/frontend/src/proprietary/contexts/ServerExperienceContext.tsx b/frontend/src/proprietary/contexts/ServerExperienceContext.tsx index 272238bce7..338dc159a4 100644 --- a/frontend/src/proprietary/contexts/ServerExperienceContext.tsx +++ b/frontend/src/proprietary/contexts/ServerExperienceContext.tsx @@ -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;