connection base prisma + postgres + login ok

This commit is contained in:
2026-02-26 21:58:16 +01:00
parent 78dc8813f1
commit 56b5615abf
1462 changed files with 429582 additions and 2546 deletions

View File

@@ -0,0 +1,15 @@
'use client';
import IdeaBoard from '@/components/IdeaBoard';
import { useProjectContext } from '@/providers/ProjectProvider';
export default function IdeasPage() {
const { project, updateProject } = useProjectContext();
return (
<IdeaBoard
ideas={project.ideas || []}
onUpdate={(ideas) => updateProject({ ideas })}
/>
);
}

View File

@@ -0,0 +1,141 @@
'use client';
import React, { useState, useEffect } from 'react';
import { useParams, useRouter, usePathname } from 'next/navigation';
import { useAuthContext } from '@/providers/AuthProvider';
import { ProjectProvider } from '@/providers/ProjectProvider';
import { useProjects } from '@/hooks/useProjects';
import { useChat } from '@/hooks/useChat';
import { ViewMode } from '@/lib/types';
import EditorShell from '@/components/layout/EditorShell';
import ExportModal from '@/components/ExportModal';
import HelpModal from '@/components/HelpModal';
import { Loader2, BookOpen } from 'lucide-react';
function getViewModeFromPath(pathname: string): ViewMode {
if (pathname.endsWith('/world')) return 'world_building';
if (pathname.endsWith('/ideas')) return 'ideas';
if (pathname.endsWith('/workflow')) return 'workflow';
if (pathname.endsWith('/settings')) return 'settings';
return 'write';
}
export default function ProjectLayout({ children }: { children: React.ReactNode }) {
const params = useParams();
const router = useRouter();
const pathname = usePathname();
const projectId = params.id as string;
const { user, logout, incrementUsage, loading: authLoading } = useAuthContext();
const {
projects, setCurrentProjectId,
updateProject, updateChapter, addChapter,
} = useProjects(user);
const { chatHistory, isGenerating, sendMessage } = useChat();
const [currentChapterId, setCurrentChapterId] = useState('');
const [isExportModalOpen, setIsExportModalOpen] = useState(false);
const [isHelpModalOpen, setIsHelpModalOpen] = useState(false);
const viewMode = getViewModeFromPath(pathname);
useEffect(() => {
if (projectId) setCurrentProjectId(projectId);
}, [projectId, setCurrentProjectId]);
useEffect(() => {
if (!authLoading && !user) router.replace('/login');
}, [user, authLoading, router]);
const project = projects.find(p => p.id === projectId);
useEffect(() => {
if (project && (!currentChapterId || !project.chapters.some(c => c.id === currentChapterId))) {
setCurrentChapterId(project.chapters[0]?.id || '');
}
}, [project, currentChapterId]);
if (authLoading || !user) {
return (
<div className="h-screen w-full flex flex-col items-center justify-center bg-slate-900 text-white">
<Loader2 className="animate-spin text-blue-500 mb-4" size={48} />
<div className="flex items-center gap-2">
<BookOpen className="text-blue-500" size={20} />
<span className="text-lg font-bold">PlumeIA</span>
</div>
</div>
);
}
if (!project) {
return (
<div className="h-screen w-full flex flex-col items-center justify-center bg-slate-900 text-white">
<Loader2 className="animate-spin text-blue-500 mb-4" size={48} />
<p className="text-slate-400">Chargement du projet...</p>
</div>
);
}
const handleViewModeChange = (mode: ViewMode) => {
const base = `/project/${projectId}`;
switch (mode) {
case 'write': router.push(base); break;
case 'world_building': router.push(`${base}/world`); break;
case 'ideas': router.push(`${base}/ideas`); break;
case 'workflow': router.push(`${base}/workflow`); break;
case 'settings': router.push(`${base}/settings`); break;
case 'dashboard': router.push('/dashboard'); break;
default: router.push(base);
}
};
return (
<ProjectProvider value={{
project,
user,
projectId,
currentChapterId,
setCurrentChapterId,
updateProject: (updates) => updateProject(projectId, updates),
updateChapter: (chapterId, data) => updateChapter(projectId, chapterId, data),
incrementUsage,
}}>
<EditorShell
project={project}
user={user}
viewMode={viewMode}
currentChapterId={currentChapterId}
chatHistory={chatHistory}
isGenerating={isGenerating}
onViewModeChange={handleViewModeChange}
onChapterSelect={(id) => { setCurrentChapterId(id); router.push(`/project/${projectId}`); }}
onUpdateProject={(updates) => updateProject(projectId, updates)}
onAddChapter={async () => {
const id = await addChapter(projectId, {});
if (id) {
setCurrentChapterId(id);
router.push(`/project/${projectId}`);
}
}}
onDeleteChapter={(id) => {
if (project.chapters.length > 1) {
const newChapters = project.chapters.filter(c => c.id !== id);
updateProject(projectId, { chapters: newChapters });
if (currentChapterId === id) setCurrentChapterId(newChapters[0].id);
}
}}
onLogout={() => { logout(); router.push('/'); }}
onSendMessage={(msg) => {
if (project && user) sendMessage(project, 'global', msg, user, incrementUsage);
}}
onInsertText={() => { }}
onOpenExport={() => setIsExportModalOpen(true)}
onOpenHelp={() => setIsHelpModalOpen(true)}
>
<ExportModal isOpen={isExportModalOpen} onClose={() => setIsExportModalOpen(false)} project={project} onPrint={() => { }} />
<HelpModal isOpen={isHelpModalOpen} onClose={() => setIsHelpModalOpen(false)} viewMode={viewMode} />
{children}
</EditorShell>
</ProjectProvider>
);
}

View File

@@ -0,0 +1,28 @@
'use client';
import React, { useRef } from 'react';
import RichTextEditor, { RichTextEditorHandle } from '@/components/RichTextEditor';
import { useProjectContext } from '@/providers/ProjectProvider';
import api from '@/lib/api';
export default function WritePage() {
const editorRef = useRef<RichTextEditorHandle>(null);
const { project, user, currentChapterId, updateChapter, incrementUsage } = useProjectContext();
if (!currentChapterId) return null;
const currentChapter = project.chapters?.find(c => c.id === currentChapterId);
return (
<RichTextEditor
ref={editorRef}
initialContent={currentChapter?.content || ''}
onSave={(html) => updateChapter(currentChapterId, { content: html })}
onAiTransform={async (text, mode) => {
const result = await api.ai.transform(text, mode, currentChapter?.content || '', user);
incrementUsage();
return result;
}}
/>
);
}

View File

@@ -0,0 +1,25 @@
'use client';
import BookSettingsComponent from '@/components/BookSettings';
import { useProjectContext } from '@/providers/ProjectProvider';
import { useAuthContext } from '@/providers/AuthProvider';
import { useProjects } from '@/hooks/useProjects';
import { useRouter } from 'next/navigation';
export default function SettingsPage() {
const { project, projectId, updateProject } = useProjectContext();
const { user } = useAuthContext();
const { deleteProject } = useProjects(user);
const router = useRouter();
return (
<BookSettingsComponent
project={project}
onUpdate={(updates) => updateProject(updates)}
onDeleteProject={async () => {
await deleteProject(projectId);
router.push('/dashboard');
}}
/>
);
}

View File

@@ -0,0 +1,19 @@
'use client';
import StoryWorkflow from '@/components/StoryWorkflow';
import { useProjectContext } from '@/providers/ProjectProvider';
import { useRouter } from 'next/navigation';
export default function WorkflowPage() {
const { project, projectId, updateProject } = useProjectContext();
const router = useRouter();
return (
<StoryWorkflow
data={project.workflow || { nodes: [], connections: [] }}
onUpdate={(workflow) => updateProject({ workflow })}
entities={project.entities || []}
onNavigateToEntity={() => router.push(`/project/${projectId}/world`)}
/>
);
}

View File

@@ -0,0 +1,26 @@
'use client';
import WorldBuilder from '@/components/WorldBuilder';
import { useProjectContext } from '@/providers/ProjectProvider';
import { useProjects } from '@/hooks/useProjects';
import { useAuthContext } from '@/providers/AuthProvider';
export default function WorldPage() {
const { project, projectId, updateProject } = useProjectContext();
const { user } = useAuthContext();
const { createEntity, updateEntity, deleteEntity } = useProjects(user);
return (
<WorldBuilder
entities={project.entities || []}
onCreate={async (entityData) => {
return await createEntity(projectId, entityData.type, entityData);
}}
onUpdate={(entityId, updates) => updateEntity(projectId, entityId, updates)}
onDelete={(entityId) => deleteEntity(projectId, entityId)}
templates={project.templates || []}
onUpdateTemplates={(t) => updateProject({ templates: t })}
initialSelectedId={null}
/>
);
}