generated from fahricansecer/boilerplate-fe
Initial commit
This commit is contained in:
241
src/components/skriptai/ProjectDetail.tsx
Normal file
241
src/components/skriptai/ProjectDetail.tsx
Normal file
@@ -0,0 +1,241 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Container,
|
||||
Flex,
|
||||
Heading,
|
||||
HStack,
|
||||
IconButton,
|
||||
Spinner,
|
||||
Tabs,
|
||||
Text,
|
||||
VStack,
|
||||
Badge,
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
LuArrowLeft,
|
||||
LuPlay,
|
||||
LuFileText,
|
||||
LuSearch,
|
||||
LuUsers,
|
||||
LuBrain,
|
||||
LuChartBar,
|
||||
LuDownload,
|
||||
} from 'react-icons/lu';
|
||||
import {
|
||||
useGetProject,
|
||||
useGenerateScript,
|
||||
useDeepResearch,
|
||||
useNeuroAnalysis,
|
||||
useYoutubeAudit,
|
||||
projectsService,
|
||||
} from '@/lib/api/skriptai';
|
||||
|
||||
// Tab Components
|
||||
import ResearchTab from './tabs/ResearchTab';
|
||||
import { BriefTab, CharactersTab, ScriptTab, AnalysisTab } from './tabs';
|
||||
|
||||
|
||||
interface ProjectDetailProps {
|
||||
projectId: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Project Detail Component
|
||||
*
|
||||
* Full project view with tabbed interface for research, brief, characters, script, and analysis.
|
||||
*/
|
||||
export default function ProjectDetail({ projectId }: ProjectDetailProps) {
|
||||
const t = useTranslations('projectDashboard');
|
||||
const router = useRouter();
|
||||
const [activeTab, setActiveTab] = useState('research');
|
||||
|
||||
// Queries
|
||||
const { data: project, isLoading, error } = useGetProject(projectId);
|
||||
const generateScript = useGenerateScript(projectId);
|
||||
const deepResearch = useDeepResearch(projectId);
|
||||
const neuroAnalysis = useNeuroAnalysis(projectId);
|
||||
const youtubeAudit = useYoutubeAudit(projectId);
|
||||
|
||||
// Export to JSON
|
||||
const handleExport = async () => {
|
||||
try {
|
||||
const response = await projectsService.exportToJson(projectId);
|
||||
const data = response.data;
|
||||
const blob = new Blob([JSON.stringify(data, null, 2)], {
|
||||
type: 'application/json',
|
||||
});
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `${project?.topic || 'project'}.json`;
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
} catch (err) {
|
||||
console.error('Export failed:', err);
|
||||
}
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<Flex justify='center' align='center' minH='400px'>
|
||||
<Spinner size='xl' color='blue.500' />
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
if (error || !project) {
|
||||
return (
|
||||
<Container maxW='4xl' py={10}>
|
||||
<VStack gap={4}>
|
||||
<Text color='red.500'>{t('projectNotFound')}</Text>
|
||||
<Button onClick={() => router.push('/skriptai')}>
|
||||
{t('backToDashboard')}
|
||||
</Button>
|
||||
</VStack>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Container maxW='8xl' py={6}>
|
||||
{/* Header */}
|
||||
<Flex justify='space-between' align='start' mb={6} flexWrap='wrap' gap={4}>
|
||||
<VStack align='start' gap={2}>
|
||||
<HStack>
|
||||
<IconButton
|
||||
aria-label={t('back')}
|
||||
variant='ghost'
|
||||
onClick={() => router.push('/skriptai')}
|
||||
>
|
||||
<LuArrowLeft />
|
||||
</IconButton>
|
||||
<Heading size='lg'>{project.topic}</Heading>
|
||||
</HStack>
|
||||
|
||||
<HStack gap={2} flexWrap='wrap'>
|
||||
<Badge colorPalette='blue'>{project.contentType}</Badge>
|
||||
<Badge colorPalette='green'>
|
||||
{project.speechStyle?.join(', ')}
|
||||
</Badge>
|
||||
<Badge colorPalette='purple'>{project.targetDuration}</Badge>
|
||||
<Badge colorPalette='gray'>
|
||||
{project.language?.toUpperCase()}
|
||||
</Badge>
|
||||
</HStack>
|
||||
|
||||
{project.logline && (
|
||||
<Text color='gray.500' fontStyle='italic' maxW='600px'>
|
||||
{project.logline}
|
||||
</Text>
|
||||
)}
|
||||
</VStack>
|
||||
|
||||
<HStack gap={2}>
|
||||
<Button
|
||||
variant='outline'
|
||||
onClick={handleExport}
|
||||
>
|
||||
<LuDownload />
|
||||
{t('export')}
|
||||
</Button>
|
||||
<Button
|
||||
colorPalette='blue'
|
||||
onClick={() => generateScript.mutate()}
|
||||
loading={generateScript.isPending}
|
||||
disabled={!project.sources || project.sources.length === 0}
|
||||
>
|
||||
<LuPlay />
|
||||
{t('generateScript')}
|
||||
</Button>
|
||||
</HStack>
|
||||
</Flex>
|
||||
|
||||
{/* Tabs */}
|
||||
<Tabs.Root
|
||||
value={activeTab}
|
||||
onValueChange={(e) => setActiveTab(e.value)}
|
||||
>
|
||||
<Tabs.List mb={6}>
|
||||
<Tabs.Trigger value='research'>
|
||||
<LuSearch />
|
||||
{t('research')}
|
||||
{project.sources && (
|
||||
<Badge ml={2} size='sm'>
|
||||
{project.sources.length}
|
||||
</Badge>
|
||||
)}
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value='brief'>
|
||||
<LuFileText />
|
||||
{t('brief')}
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value='characters'>
|
||||
<LuUsers />
|
||||
{t('characters')}
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value='script'>
|
||||
<LuFileText />
|
||||
{t('script')}
|
||||
{project.segments && (
|
||||
<Badge ml={2} size='sm'>
|
||||
{project.segments.length}
|
||||
</Badge>
|
||||
)}
|
||||
</Tabs.Trigger>
|
||||
<Tabs.Trigger value='analysis'>
|
||||
<LuChartBar />
|
||||
{t('analysis')}
|
||||
</Tabs.Trigger>
|
||||
</Tabs.List>
|
||||
|
||||
<Box minH='500px'>
|
||||
<Tabs.Content value='research'>
|
||||
<ResearchTab
|
||||
project={project}
|
||||
onResearch={() => deepResearch.mutate(undefined)}
|
||||
isResearching={deepResearch.isPending}
|
||||
onNext={() => setActiveTab('brief')}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value='brief'>
|
||||
<BriefTab
|
||||
project={project}
|
||||
onNext={() => setActiveTab('characters')}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value='characters'>
|
||||
<CharactersTab
|
||||
project={project}
|
||||
onNext={() => setActiveTab('script')}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value='script'>
|
||||
<ScriptTab
|
||||
project={project}
|
||||
onGenerate={() => generateScript.mutate(undefined)}
|
||||
isGenerating={generateScript.isPending}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value='analysis'>
|
||||
<AnalysisTab
|
||||
project={project}
|
||||
onNeuroAnalysis={() => neuroAnalysis.mutate()}
|
||||
onYoutubeAudit={() => youtubeAudit.mutate()}
|
||||
isAnalyzing={neuroAnalysis.isPending || youtubeAudit.isPending}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
</Box>
|
||||
</Tabs.Root>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user