connection base prisma + postgres + login ok
This commit is contained in:
15
src/app/project/[id]/ideas/page.tsx
Normal file
15
src/app/project/[id]/ideas/page.tsx
Normal 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 })}
|
||||
/>
|
||||
);
|
||||
}
|
||||
141
src/app/project/[id]/layout.tsx
Normal file
141
src/app/project/[id]/layout.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
28
src/app/project/[id]/page.tsx
Normal file
28
src/app/project/[id]/page.tsx
Normal 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;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
25
src/app/project/[id]/settings/page.tsx
Normal file
25
src/app/project/[id]/settings/page.tsx
Normal 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');
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
19
src/app/project/[id]/workflow/page.tsx
Normal file
19
src/app/project/[id]/workflow/page.tsx
Normal 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`)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
26
src/app/project/[id]/world/page.tsx
Normal file
26
src/app/project/[id]/world/page.tsx
Normal 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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user