import React, { useState, useEffect, useCallback, useMemo } from 'react'; import { useNavigate, useLocation } from 'react-router-dom'; import api from '../api'; import OnboardingWizard from './OnboardingWizard'; import { useLanguage } from '../providers/language/LanguageContext'; interface OnboardingStep { id: string; label: string; description: string; completed: boolean; action?: () => void; } interface OnboardingAssistantProps { onDismiss?: () => void; } const _STORAGE_KEY = 'onboarding_hidden'; export function _isOnboardingHidden(): boolean { try { return localStorage.getItem(_STORAGE_KEY) === 'true'; } catch { return false; } } export function _showOnboarding(): void { try { localStorage.removeItem(_STORAGE_KEY); } catch { /* ignore */ } } function _hideOnboarding(): void { try { localStorage.setItem(_STORAGE_KEY, 'true'); } catch { /* ignore */ } } const OnboardingAssistant: React.FC = ({ onDismiss }) => { const { t } = useLanguage(); const callouts = useMemo(() => ({ mandate: t('Tipp: Ein Mandant ist Ihr Arbeitsbereich. Sie koennen spaeter weitere Mandanten fuer Teams oder Projekte erstellen.'), feature: t('Tipp: Im Store finden Sie AI-Workspace, CommCoach und weitere Features. Aktivieren Sie mindestens eines, um loszulegen.'), connection: t('Tipp: Verbinden Sie Ihre Datenquellen (z.B. SharePoint, Google Drive), damit der AI-Assistent auf Ihre Dokumente zugreifen kann.'), chat: t('Tipp: Starten Sie einen Chat mit dem AI-Assistenten. Er kann Ihre verbundenen Daten analysieren und Fragen beantworten.'), }), [t]); const navigate = useNavigate(); const location = useLocation(); const [hidden, setHidden] = useState(() => _isOnboardingHidden()); const [steps, setSteps] = useState([]); const [loading, setLoading] = useState(true); const [dontShowAgain, setDontShowAgain] = useState(false); const [showWizard, setShowWizard] = useState(false); const _checkOnboardingState = useCallback(async () => { setLoading(true); try { const onboardingSteps: OnboardingStep[] = []; // Check admin mandates (user-owned or where user is admin) let hasAdminMandate = false; try { const mandatesRes = await api.get('/api/store/mandates'); const mandates = mandatesRes.data?.mandates || mandatesRes.data || []; hasAdminMandate = Array.isArray(mandates) && mandates.length > 0; } catch { /* ignore */ } // Check if user has any feature access (via navigation = mandate member) let hasFeature = false; let workspaceInstancePath: string | undefined; let workspaceInstanceIds: string[] = []; try { const navRes = await api.get('/api/navigation?language=de'); const blocks = navRes.data?.blocks || []; const dynamicBlock = blocks.find((b: { type: string }) => b.type === 'dynamic'); const mandates = dynamicBlock?.mandates || []; for (const m of mandates) { for (const f of m.features || []) { for (const inst of f.instances || []) { hasFeature = true; if (f.uiComponent === 'feature.workspace' && inst.views?.length > 0) { workspaceInstanceIds.push(inst.id); if (!workspaceInstancePath) { workspaceInstancePath = inst.views[0].uiPath; } } } } } } catch { /* ignore */ } const mandateStepDone = hasAdminMandate || hasFeature; onboardingSteps.push({ id: 'mandate', label: t('Mandat einrichten'), description: hasAdminMandate ? t('Dein Mandant ist eingerichtet.') : hasFeature ? t('Du bist Mitglied eines Mandanten') : t('Erstelle deinen Arbeitsbereich'), completed: mandateStepDone, action: mandateStepDone ? undefined : () => setShowWizard(true), }); onboardingSteps.push({ id: 'feature', label: t('Aktiviere dein erstes Feature'), description: hasFeature ? t('Du hast aktive Features') : t('Aktiviere dein erstes Feature im'), completed: hasFeature, action: hasFeature ? undefined : () => navigate('/store'), }); let hasConnection = false; try { const connRes = await api.get('/api/connections/'); const items = connRes.data?.items || connRes.data?.data || connRes.data || []; hasConnection = Array.isArray(items) && items.length > 0; } catch { /* ignore */ } onboardingSteps.push({ id: 'connection', label: t('Verbinde deine erste Datenquelle'), description: hasConnection ? t('Du hast Verbindungen eingerichtet') : t('Verbinde deine erste Datenquelle'), completed: hasConnection, action: hasConnection ? undefined : () => navigate('/basedata/connections'), }); let hasChat = false; for (const instId of workspaceInstanceIds) { if (hasChat) break; try { const wfRes = await api.get(`/api/workspace/${instId}/workflows`); const wfs = wfRes.data?.workflows || wfRes.data?.data || wfRes.data?.items || []; if (Array.isArray(wfs) && wfs.length > 0) hasChat = true; } catch { /* ignore */ } } const chatAction = workspaceInstancePath ? () => navigate(workspaceInstancePath!) : undefined; onboardingSteps.push({ id: 'chat', label: t('Starte deinen ersten AI-Chat'), description: hasChat ? t('Du hast bereits Chats gestartet') : t('Starte deinen ersten Chat mit'), completed: hasChat, action: hasChat ? undefined : chatAction, }); setSteps(onboardingSteps); if (onboardingSteps.every(s => s.completed)) { setHidden(true); _hideOnboarding(); } } catch (err) { console.error('Onboarding check failed:', err); } finally { setLoading(false); } }, [navigate, t]); useEffect(() => { const state = location.state as { showOnboarding?: number } | null; if (state?.showOnboarding) { setHidden(false); window.history.replaceState({}, ''); } }, [location.state]); useEffect(() => { if (!hidden) _checkOnboardingState(); }, [hidden, _checkOnboardingState]); const _handleDismiss = () => { if (dontShowAgain) { _hideOnboarding(); } setHidden(true); onDismiss?.(); }; if (showWizard) { return ( { setShowWizard(false); _checkOnboardingState(); }} onDismiss={() => setShowWizard(false)} /> ); } if (hidden || loading) return null; const completedCount = steps.filter(s => s.completed).length; if (completedCount === steps.length) return null; return (

{t('Willkommen bei Poweron')}

{t('{completed} von {total} Schritten abgeschlossen', { completed: String(completedCount), total: String(steps.length) })}

{steps.map((step) => (
))}
{steps.map((step, idx) => { const isNextStep = !step.completed && steps.slice(0, idx).every(s => s.completed); return (
{step.completed ? '\u2713' : '\u25CB'}
{step.label}
{step.description}
{step.action && !step.completed && ( {'\u2192'} )}
{isNextStep && callouts[step.id as keyof typeof callouts] && (
{callouts[step.id as keyof typeof callouts]}
)}
); })}
); }; export default OnboardingAssistant;