Files
plume/components/AppRouter.tsx

163 lines
8.3 KiB
TypeScript

import React, { useState, useRef } from 'react';
import { ViewMode, BookProject, UserProfile, Chapter, Entity } from '../types';
import LandingPage from './LandingPage';
import FeaturesPage from './FeaturesPage';
import Pricing from './Pricing';
import Checkout from './Checkout';
import AuthPage from './AuthPage';
import LoginPage from './LoginPage';
import Dashboard from './Dashboard';
import UserProfileSettings from './UserProfileSettings';
import ExportModal from './ExportModal';
import HelpModal from './HelpModal';
import EditorShell from './layout/EditorShell';
import RichTextEditor, { RichTextEditorHandle } from './RichTextEditor';
import WorldBuilder from './WorldBuilder';
import StoryWorkflow from './StoryWorkflow';
import IdeaBoard from './IdeaBoard';
import BookSettingsComponent from './BookSettings';
import { transformText } from '../services/geminiService';
interface AppRouterProps {
user: UserProfile | null;
projects: BookProject[];
currentProjectId: string | null;
viewMode: ViewMode;
chatHistory: any[];
isGenerating: boolean;
onLogin: (data: any) => Promise<any>;
onSignup: (data: any) => Promise<any>;
onLogout: () => void;
onViewModeChange: (mode: ViewMode) => void;
onSelectProject: (id: string) => void;
onCreateProject: () => void;
onUpdateProject: (updates: Partial<BookProject>) => void;
onUpdateChapter: (chapterId: string, updates: Partial<Chapter>) => void;
onAddChapter: () => Promise<string | null>;
onCreateEntity: (entity: Omit<Entity, 'id'>) => Promise<string | null>;
onUpdateEntity: (entityId: string, updates: Partial<Entity>) => void;
onDeleteEntity: (entityId: string) => void;
onUpdateProfile: (updates: Partial<UserProfile>) => void;
onUpgradePlan: (plan: any) => void;
onSendMessage: (msg: string) => void;
onIncrementUsage: () => void;
}
const AppRouter: React.FC<AppRouterProps> = (props) => {
const [currentChapterId, setCurrentChapterId] = useState<string>('');
const [isExportModalOpen, setIsExportModalOpen] = useState(false);
const [isHelpModalOpen, setIsHelpModalOpen] = useState(false);
const [targetEntityId, setTargetEntityId] = useState<string | null>(null);
const editorRef = useRef<RichTextEditorHandle>(null);
const { user, viewMode, currentProjectId, projects } = props;
const project = projects.find(p => p.id === currentProjectId);
console.log('props', props);
// DEBUG: Check all props
console.log("[AppRouter DEBUG] PROPS RECEIVED:", {
user,
userId: user?.id,
viewMode,
currentProjectId,
projectsCount: projects?.length,
fullProps: props
});
React.useEffect(() => {
if (project && (!currentChapterId || !project.chapters.some(c => c.id === currentChapterId))) {
setCurrentChapterId(project.chapters[0]?.id || '');
}
}, [currentProjectId, project]);
if (viewMode === 'landing') return <LandingPage onLogin={() => props.onViewModeChange('auth')} onFeatures={() => props.onViewModeChange('features')} onPricing={() => props.onViewModeChange('pricing')} />;
// Use new LoginPage for 'auth' view (Login)
if (viewMode === 'auth') return <LoginPage onSuccess={() => props.onViewModeChange('dashboard')} onRegister={() => props.onViewModeChange('signup')} />;
// Use existing AuthPage for 'signup' view (Register) - defaulted to signup mode inside AuthPage if possible,
// but AuthPage manages its own state. We can pass a prop if AuthPage supports it, or just let user toggle.
// Since AuthPage has internal state for mode, we might just render it.
// Ideally AuthPage should accept an initialMode prop. Let's check AuthPage again or just render it.
if (viewMode === 'signup') return <AuthPage onBack={() => props.onViewModeChange('landing')} onSuccess={() => props.onViewModeChange('dashboard')} initialMode='signup' />;
if (viewMode === 'features') return <FeaturesPage onBack={() => props.onViewModeChange(user ? 'dashboard' : 'landing')} />;
if (viewMode === 'pricing') return <Pricing currentPlan={user?.subscription.plan || 'free'} onBack={() => props.onViewModeChange(user ? 'dashboard' : 'landing')} onSelectPlan={() => user ? props.onViewModeChange('checkout') : props.onViewModeChange('auth')} />;
if (viewMode === 'checkout') return <Checkout onComplete={() => props.onUpgradePlan('pro')} onCancel={() => props.onViewModeChange('pricing')} />;
if (viewMode === 'dashboard' && user) return <Dashboard user={user} projects={projects} onSelect={props.onSelectProject} onCreate={props.onCreateProject} onLogout={props.onLogout} onPricing={() => props.onViewModeChange('pricing')} onProfile={() => props.onViewModeChange('profile')} />;
if (viewMode === 'profile' && user) return <UserProfileSettings user={user} onUpdate={props.onUpdateProfile} onBack={() => props.onViewModeChange('dashboard')} />;
console.log("[AppRouter] Render State:", { viewMode, hasUser: !!user, hasProject: !!project, currentProjectId, currentChapterId });
if (!project || !user) {
// If we are here, we are in a protected route ('write', 'world_building', etc.)
// BUT we don't have a project or user. This is an invalid state.
console.warn("[AppRouter] Fallthrough to NULL - displaying fallback");
return (
<div className="flex flex-col items-center justify-center h-screen bg-slate-100 text-slate-800">
<h2 className="text-xl font-bold mb-2">État Indéfini</h2>
<p>Mode: {viewMode}</p>
<p>Utilisateur: {user ? 'Connecté' : 'Non connecté'}</p>
<p>Projet sélectionné: {currentProjectId || 'Aucun'}</p>
<button className="mt-4 px-4 py-2 bg-blue-600 text-white rounded" onClick={() => props.onViewModeChange('landing')}>
Retour à l'accueil
</button>
</div>
);
}
const currentChapter = project.chapters.find(c => c.id === currentChapterId);
return (
<EditorShell
project={project}
user={user}
viewMode={viewMode}
currentChapterId={currentChapterId}
chatHistory={props.chatHistory}
isGenerating={props.isGenerating}
onViewModeChange={props.onViewModeChange}
onChapterSelect={(id) => { setCurrentChapterId(id); props.onViewModeChange('write'); }}
onUpdateProject={props.onUpdateProject}
onAddChapter={async () => {
const id = await props.onAddChapter();
if (id) setCurrentChapterId(id);
}}
onDeleteChapter={(id) => {
if (project.chapters.length > 1) {
const newChapters = project.chapters.filter(c => c.id !== id);
props.onUpdateProject({ chapters: newChapters });
if (currentChapterId === id) setCurrentChapterId(newChapters[0].id);
}
}}
onLogout={props.onLogout}
onSendMessage={props.onSendMessage}
onInsertText={(text) => editorRef.current?.insertHtml(text)}
onOpenExport={() => setIsExportModalOpen(true)}
onOpenHelp={() => setIsHelpModalOpen(true)}
>
<ExportModal isOpen={isExportModalOpen} onClose={() => setIsExportModalOpen(false)} project={project} onPrint={() => { }} />
<HelpModal isOpen={isHelpModalOpen} onClose={() => setIsHelpModalOpen(false)} viewMode={viewMode} />
{viewMode === 'write' && <RichTextEditor
ref={editorRef}
initialContent={currentChapter?.content || ""}
onSave={(html) => props.onUpdateChapter(currentChapterId, { content: html })}
onAiTransform={(text, mode) => transformText(text, mode, currentChapter?.content || "", user, props.onIncrementUsage)}
/>}
{viewMode === 'world_building' && <WorldBuilder
entities={project.entities}
onCreate={props.onCreateEntity}
onUpdate={props.onUpdateEntity}
onDelete={props.onDeleteEntity}
templates={project.templates || []}
onUpdateTemplates={(t) => props.onUpdateProject({ templates: t })}
initialSelectedId={targetEntityId}
/>}
{viewMode === 'ideas' && <IdeaBoard ideas={project.ideas || []} onUpdate={(i) => props.onUpdateProject({ ideas: i })} />}
{viewMode === 'workflow' && <StoryWorkflow data={project.workflow || { nodes: [], connections: [] }} onUpdate={(w) => props.onUpdateProject({ workflow: w })} entities={project.entities} onNavigateToEntity={(id) => { setTargetEntityId(id); props.onViewModeChange('world_building'); }} />}
{viewMode === 'settings' && <BookSettingsComponent project={project} onUpdate={props.onUpdateProject} />}
</EditorShell>
);
};
export default AppRouter;