generated from fahricansecer/boilerplate-fe
242 lines
8.1 KiB
TypeScript
242 lines
8.1 KiB
TypeScript
'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>
|
|
);
|
|
}
|