- Brand/Theming: Marketing-Farb- und Typographievariablen in `resources/css/app.css` eingeführt, AdminLayout, Dashboardkarten und Onboarding-Komponenten entsprechend angepasst; Dokumentation (`docs/todo/tenant-admin-onboarding-fusion.md`, `docs/changes/...`) aktualisiert. - Checkout & Payments: Checkout-, PayPal-Controller und Tests für integrierte Stripe/PayPal-Flows sowie Paket-Billing-Abläufe überarbeitet; neue PayPal SDK-Factory und Admin-API-Helper (`resources/js/admin/api.ts`) schaffen Grundlage für Billing/Members/Tasks-Seiten. - DX & Tests: Neue Playwright/E2E-Struktur (docs/testing/e2e.md, `tests/e2e/tenant-onboarding-flow.test.ts`, Utilities), E2E-Tenant-Seeder und zusätzliche Übersetzungen/Factories zur Unterstützung der neuen Flows. - Marketing-Kommunikation: Automatische Kontakt-Bestätigungsmail (`ContactConfirmation` + Blade-Template) implementiert; Guest-PWA unter `/event` erreichbar. - Nebensitzung: Blogsystem gefixt und umfassenden BlogPostSeeder für Beispielinhalte angelegt.
110 lines
2.9 KiB
TypeScript
110 lines
2.9 KiB
TypeScript
import React from 'react';
|
|
|
|
export type OnboardingProgress = {
|
|
welcomeSeen: boolean;
|
|
packageSelected: boolean;
|
|
eventCreated: boolean;
|
|
lastStep?: string | null;
|
|
selectedPackage?: {
|
|
id: number;
|
|
name: string;
|
|
priceText?: string | null;
|
|
isSubscription?: boolean;
|
|
} | null;
|
|
};
|
|
|
|
type OnboardingContextValue = {
|
|
progress: OnboardingProgress;
|
|
setProgress: (updater: (prev: OnboardingProgress) => OnboardingProgress) => void;
|
|
markStep: (step: Partial<OnboardingProgress>) => void;
|
|
reset: () => void;
|
|
};
|
|
|
|
const DEFAULT_PROGRESS: OnboardingProgress = {
|
|
welcomeSeen: false,
|
|
packageSelected: false,
|
|
eventCreated: false,
|
|
lastStep: null,
|
|
selectedPackage: null,
|
|
};
|
|
|
|
const STORAGE_KEY = 'tenant-admin:onboarding-progress';
|
|
|
|
const OnboardingProgressContext = React.createContext<OnboardingContextValue | undefined>(undefined);
|
|
|
|
function readStoredProgress(): OnboardingProgress {
|
|
if (typeof window === 'undefined') {
|
|
return DEFAULT_PROGRESS;
|
|
}
|
|
try {
|
|
const raw = window.localStorage.getItem(STORAGE_KEY);
|
|
if (!raw) {
|
|
return DEFAULT_PROGRESS;
|
|
}
|
|
const parsed = JSON.parse(raw) as Partial<OnboardingProgress>;
|
|
return {
|
|
...DEFAULT_PROGRESS,
|
|
...parsed,
|
|
};
|
|
} catch (error) {
|
|
console.warn('[OnboardingProgress] Failed to parse stored value', error);
|
|
return DEFAULT_PROGRESS;
|
|
}
|
|
}
|
|
|
|
function writeStoredProgress(progress: OnboardingProgress) {
|
|
if (typeof window === 'undefined') {
|
|
return;
|
|
}
|
|
try {
|
|
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(progress));
|
|
} catch (error) {
|
|
console.warn('[OnboardingProgress] Failed to persist value', error);
|
|
}
|
|
}
|
|
|
|
export function OnboardingProgressProvider({ children }: { children: React.ReactNode }) {
|
|
const [progress, setProgressState] = React.useState<OnboardingProgress>(() => readStoredProgress());
|
|
|
|
const setProgress = React.useCallback((updater: (prev: OnboardingProgress) => OnboardingProgress) => {
|
|
setProgressState((prev) => {
|
|
const next = updater(prev);
|
|
writeStoredProgress(next);
|
|
return next;
|
|
});
|
|
}, []);
|
|
|
|
const markStep = React.useCallback((step: Partial<OnboardingProgress>) => {
|
|
setProgress((prev) => ({
|
|
...prev,
|
|
...step,
|
|
lastStep: typeof step.lastStep === 'undefined' ? prev.lastStep : step.lastStep,
|
|
}));
|
|
}, [setProgress]);
|
|
|
|
const reset = React.useCallback(() => {
|
|
setProgress(() => DEFAULT_PROGRESS);
|
|
}, [setProgress]);
|
|
|
|
const value = React.useMemo<OnboardingContextValue>(() => ({
|
|
progress,
|
|
setProgress,
|
|
markStep,
|
|
reset,
|
|
}), [progress, setProgress, markStep, reset]);
|
|
|
|
return (
|
|
<OnboardingProgressContext.Provider value={value}>
|
|
{children}
|
|
</OnboardingProgressContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function useOnboardingProgress() {
|
|
const context = React.useContext(OnboardingProgressContext);
|
|
if (!context) {
|
|
throw new Error('useOnboardingProgress must be used within OnboardingProgressProvider');
|
|
}
|
|
return context;
|
|
}
|