Files
audio_splitter/web/frontend/src/App.tsx
T

128 lines
3.9 KiB
TypeScript

import React from 'react'
import { ThemeProvider, createTheme, CssBaseline } from '@mui/material'
import { Box, Grid, Button, CircularProgress, Typography } from '@mui/material'
import { PlayArrow } from '@mui/icons-material'
import { Layout } from './components/Layout'
import { UploadZone } from './components/UploadZone'
import { TracklistEditor } from './components/TracklistEditor'
import { OptionsPanel } from './components/OptionsPanel'
import { ProgressDisplay } from './components/ProgressDisplay'
import { DownloadSection } from './components/DownloadSection'
import { useUploadStore } from './stores/uploadStore'
import { useTracklistStore } from './stores/tracklistStore'
import { useOptionsStore } from './stores/optionsStore'
import { useTaskStore } from './stores/taskStore'
import { useUIStore } from './stores/uiStore'
import { useValidationStore } from './stores/validationStore'
import { useWebSocket } from './hooks/useWebSocket'
import { startSplit } from './api/client'
const App: React.FC = () => {
const { theme } = useUIStore()
const { taskId } = useUploadStore()
const { entries, isValid } = useTracklistStore()
const { options } = useOptionsStore()
const {
isProcessing,
setTaskId,
setError,
setIsProcessing,
addLog,
reset,
} = useTaskStore()
const { formatError } = useValidationStore()
useWebSocket(taskId && isProcessing ? taskId : null)
const handleSplit = async () => {
if (!taskId) {
alert('Please upload a file first')
return
}
if (!isValid) {
alert('Tracklist has errors. Please fix them before splitting.')
return
}
if (entries.length === 0) {
alert('Tracklist is empty')
return
}
try {
setTaskId(taskId)
setIsProcessing(true)
addLog('🚀 Starting split...')
const response = await startSplit(taskId, entries, options)
addLog(`✅ Split task started (ID: ${response.task_id})`)
} catch (error: any) {
setError(error.response?.data?.detail || error.message || 'Failed to start split')
addLog(`❌ Error: ${error.response?.data?.detail || error.message || 'Failed to start split'}`)
setIsProcessing(false)
}
}
const handleReset = () => {
reset()
}
const isSplitDisabled = !taskId || !isValid || entries.length === 0 || isProcessing || !!formatError
return (
<ThemeProvider
theme={createTheme({
palette: {
mode: theme,
},
})}
>
<CssBaseline />
<Layout>
<Grid container spacing={3}>
<Grid item xs={12} md={6}>
<UploadZone />
</Grid>
<Grid item xs={12} md={6}>
<TracklistEditor />
</Grid>
<Grid item xs={12} md={4}>
<OptionsPanel />
</Grid>
<Grid item xs={12} md={8}>
<Box sx={{ display: 'flex', gap: 2, mb: 3 }}>
<Button
variant="contained"
color="success"
startIcon={isProcessing ? <CircularProgress size={20} color="inherit" /> : <PlayArrow />}
onClick={handleSplit}
disabled={isSplitDisabled}
sx={{ flex: 1 }}
>
{isProcessing ? 'Processing...' : 'Split'}
</Button>
<Button variant="outlined" color="secondary" onClick={handleReset} disabled={isProcessing}>
Reset
</Button>
</Box>
{formatError && (
<Box sx={{ mb: 2, p: 2, bgcolor: 'warning.light', borderRadius: 1 }}>
<Typography color="warning.dark" variant="body2">
⚠️ {formatError}
</Typography>
</Box>
)}
<ProgressDisplay />
<DownloadSection />
</Grid>
</Grid>
</Layout>
</ThemeProvider>
)
}
export default App