Manara / src /App.tsx
Kebe77's picture
Create src/App.tsx
3cea435 verified
Raw
History Blame Contribute Delete
7.26 kB
import React, { useState, useEffect } from 'react';
import { Layout } from './components/Layout';
import { Home } from './components/Home';
import { ProjectWorkspace } from './components/ProjectWorkspace';
import { ResearchSpace } from './components/ResearchSpace';
import { Library } from './components/Library';
import { SmartResearcher } from './components/SmartResearcher';
import { Project, Source, ProjectOutput, Language, ChatMessage, Note } from './types';
import { INITIAL_SOURCES } from './constants';
import { translations } from './translations';
const App: React.FC = () => {
const [lang, setLang] = useState<Language>('ar');
const [view, setView] = useState<'home' | 'smart-researcher' | 'library' | 'research' | 'workspace'>('home');
const [projects, setProjects] = useState<Project[]>([]);
const [activeProject, setActiveProject] = useState<Project | null>(null);
const [allSources, setAllSources] = useState<Source[]>(INITIAL_SOURCES);
const t = translations[lang];
// التحميل من الذاكرة المحلية عند بدء التشغيل
useEffect(() => {
const savedProjects = localStorage.getItem('mouride_projects');
const savedSources = localStorage.getItem('mouride_sources');
const savedLang = localStorage.getItem('mouride_lang') as Language;
if (savedProjects) setProjects(JSON.parse(savedProjects));
if (savedSources) setAllSources(JSON.parse(savedSources));
if (savedLang) setLang(savedLang);
}, []);
const saveProjects = (newProjects: Project[]) => {
setProjects(newProjects);
localStorage.setItem('mouride_projects', JSON.stringify(newProjects));
};
const saveSources = (newSources: Source[]) => {
setAllSources(newSources);
localStorage.setItem('mouride_sources', JSON.stringify(newSources));
};
const handleLanguageChange = (newLang: Language) => {
setLang(newLang);
localStorage.setItem('mouride_lang', newLang);
};
const createProject = (name: string, description: string) => {
const newProject: Project = {
id: `proj-${Date.now()}`,
name,
description,
createdAt: Date.now(),
sources: [],
notes: [],
outputs: []
};
const updatedProjects = [...projects, newProject];
saveProjects(updatedProjects);
handleOpenProject(newProject);
};
const updateProject = (id: string, name: string, description: string) => {
const updatedProjects = projects.map(p =>
p.id === id ? { ...p, name, description } : p
);
saveProjects(updatedProjects);
if (activeProject?.id === id) {
setActiveProject({ ...activeProject, name, description });
}
};
const handlePromoteToProject = (chatHistory: ChatMessage[]) => {
const firstUserMsg = chatHistory.find(m => m.role === 'user')?.content || 'موضوع بحثي جديد';
const citedSourceIds = new Set<string>();
chatHistory.forEach(msg => {
if (msg.citations) msg.citations.forEach(cit => citedSourceIds.add(cit.sourceId));
if (msg.sources) msg.sources.forEach(sid => citedSourceIds.add(sid));
});
const newProject: Project = {
id: `proj-${Date.now()}`,
name: firstUserMsg.substring(0, 50) + (firstUserMsg.length > 50 ? '...' : ''),
description: 'مشروع بحثي متكامل تم استخلاصه من الحوار.',
createdAt: Date.now(),
sources: Array.from(citedSourceIds),
notes: chatHistory.filter(m => m.role === 'assistant').map((m, idx) => ({
id: `note-${Date.now()}-${idx}`,
title: 'استنتاج علمي مرجعي',
content: m.content,
timestamp: Date.now()
})),
outputs: []
};
saveProjects([...projects, newProject]);
setActiveProject(newProject);
setView('workspace');
};
const handleOpenProject = (project: Project) => {
setActiveProject(project);
setView('workspace');
};
const handleAddSourceToProject = (sourceId: string, projectId?: string) => {
const targetId = projectId || activeProject?.id;
if (!targetId) return;
const updatedProjects = projects.map(p => {
if (p.id === targetId && !p.sources.includes(sourceId)) {
const updated = { ...p, sources: [...p.sources, sourceId] };
if (activeProject?.id === targetId) setActiveProject(updated);
return updated;
}
return p;
});
saveProjects(updatedProjects);
};
const handleRemoveSourceFromProject = (sourceId: string) => {
if (!activeProject) return;
const updatedProject = {
...activeProject,
sources: activeProject.sources.filter(id => id !== sourceId)
};
setActiveProject(updatedProject);
saveProjects(projects.map(p => p.id === updatedProject.id ? updatedProject : p));
};
const handleUpdateNotes = (notes: Note[]) => {
if (!activeProject) return;
const updatedProject = { ...activeProject, notes };
setActiveProject(updatedProject);
saveProjects(projects.map(p => p.id === updatedProject.id ? updatedProject : p));
};
const handleSaveOutput = (output: ProjectOutput) => {
if (!activeProject) return;
const updatedProject = {
...activeProject,
outputs: [output, ...activeProject.outputs]
};
setActiveProject(updatedProject);
saveProjects(projects.map(p => p.id === updatedProject.id ? updatedProject : p));
};
const handleAddGlobalSource = (source: Source) => {
const newSources = [...allSources, source];
saveSources(newSources);
};
const handleAddCustomSource = (source: Source) => {
const newSources = [...allSources, source];
saveSources(newSources);
if (activeProject) handleAddSourceToProject(source.id);
};
return (
<Layout
currentView={view}
setView={setView}
activeProject={activeProject}
lang={lang}
onLangChange={handleLanguageChange}
t={t}
>
{view === 'home' && (
<Home
onStartResearch={() => setView('smart-researcher')}
onExploreLibrary={() => setView('library')}
t={t}
/>
)}
{view === 'smart-researcher' && (
<SmartResearcher
allSources={allSources}
onPromoteToProject={handlePromoteToProject}
t={t}
/>
)}
{view === 'library' && (
<Library
sources={allSources}
onAddToProject={handleAddSourceToProject}
onAddGlobalSource={handleAddGlobalSource}
activeProjectId={activeProject?.id}
projects={projects}
t={t}
/>
)}
{view === 'research' && (
<ResearchSpace
projects={projects}
onCreateProject={createProject}
onUpdateProject={updateProject}
onOpenProject={handleOpenProject}
t={t}
/>
)}
{view === 'workspace' && activeProject && (
<ProjectWorkspace
project={activeProject}
allSources={allSources}
onRemoveSource={handleRemoveSourceFromProject}
onUpdateNotes={handleUpdateNotes}
onAddCustomSource={handleAddCustomSource}
onSaveOutput={handleSaveOutput}
t={t}
/>
)}
</Layout>
);
};
export default App;