153 lines
4.7 KiB
TypeScript
153 lines
4.7 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect, useState } from 'react';
|
|
import { useRouter, useParams } from 'next/navigation';
|
|
import Header from '../../components/Header';
|
|
import Sidebar from '../../components/Sidebar';
|
|
import AudioPlayer from '../../components/AudioPlayer';
|
|
import TranscriptViewer from '../../components/TranscriptViewer';
|
|
import SummaryDisplay from '../../components/SummaryDisplay';
|
|
import type { User, Recording } from '@/types';
|
|
|
|
export default function RecordingDetailPage() {
|
|
const [user, setUser] = useState<User | null>(null);
|
|
const [recording, setRecording] = useState<Recording | null>(null);
|
|
const [isPlaying, setIsPlaying] = useState(false);
|
|
const [currentTime, setCurrentTime] = useState(0);
|
|
const [isTranscribing, setIsTranscribing] = useState(false);
|
|
const router = useRouter();
|
|
const params = useParams();
|
|
const id = params?.id as string;
|
|
|
|
useEffect(() => {
|
|
// Fetch current user
|
|
fetch('/api/auth/me')
|
|
.then(res => {
|
|
if (!res.ok) {
|
|
router.push('/login');
|
|
return null;
|
|
}
|
|
return res.json();
|
|
})
|
|
.then(data => {
|
|
if (data) setUser(data);
|
|
})
|
|
.catch(() => router.push('/login'));
|
|
|
|
// Fetch recording
|
|
if (id) {
|
|
fetch(`/api/recordings/${id}`)
|
|
.then(res => {
|
|
if (!res.ok) throw new Error('Recording not found');
|
|
return res.json();
|
|
})
|
|
.then(data => {
|
|
setRecording(data);
|
|
setIsTranscribing(data.isTranscribing);
|
|
})
|
|
.catch(() => router.push('/recordings'));
|
|
}
|
|
}, [id, router]);
|
|
|
|
const handleTranscribe = async () => {
|
|
if (!id) return;
|
|
|
|
try {
|
|
const response = await fetch(`/api/recordings/${id}/transcribe`, {
|
|
method: 'POST',
|
|
});
|
|
|
|
if (response.ok) {
|
|
setIsTranscribing(true);
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to start transcription:', error);
|
|
}
|
|
};
|
|
|
|
const handleSummarize = async () => {
|
|
if (!id) return;
|
|
|
|
try {
|
|
const response = await fetch(`/api/recordings/${id}/summarize`, {
|
|
method: 'POST',
|
|
});
|
|
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
setRecording(prev => prev ? { ...prev, summary: data.summary } : null);
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to generate summary:', error);
|
|
}
|
|
};
|
|
|
|
if (!recording) {
|
|
return (
|
|
<div className="flex min-h-screen items-center justify-center">
|
|
<div className="w-8 h-8 border-4 border-blue-500 border-t-transparent rounded-full animate-spin" />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="flex min-h-screen bg-gray-50">
|
|
<Sidebar activePath="/recordings" />
|
|
<div className="flex-1">
|
|
<Header user={user} />
|
|
<main className="p-6">
|
|
<div className="max-w-4xl mx-auto">
|
|
<div className="mb-6">
|
|
<h1 className="text-3xl font-bold text-gray-900 mb-2">
|
|
{recording.title}
|
|
</h1>
|
|
<p className="text-gray-600">
|
|
{recording.createdAt && new Date(recording.createdAt).toLocaleString()}
|
|
</p>
|
|
</div>
|
|
|
|
<div className="space-y-6">
|
|
<AudioPlayer
|
|
audioUrl={recording.audioFilePath}
|
|
duration={recording.duration}
|
|
onPlayPause={(playing) => setIsPlaying(playing)}
|
|
onSeek={(time) => setCurrentTime(time)}
|
|
/>
|
|
|
|
<div className="flex gap-4">
|
|
<button
|
|
onClick={handleTranscribe}
|
|
disabled={isTranscribing || !!recording.transcript}
|
|
className="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
>
|
|
{isTranscribing ? 'Transcribing...' : recording.transcript ? 'Transcribed' : 'Transcribe'}
|
|
</button>
|
|
<button
|
|
onClick={handleSummarize}
|
|
disabled={!recording.transcript || !!recording.summary}
|
|
className="px-4 py-2 bg-green-500 text-white rounded-md hover:bg-green-600 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
>
|
|
{recording.summary ? 'Summary Generated' : 'Generate Summary'}
|
|
</button>
|
|
</div>
|
|
|
|
{recording.transcript && (
|
|
<TranscriptViewer
|
|
transcript={recording.transcript}
|
|
isLive={isTranscribing}
|
|
/>
|
|
)}
|
|
|
|
{recording.summary && (
|
|
<SummaryDisplay
|
|
summary={recording.summary}
|
|
/>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|