Visual update
Browse files
frontend/src/App.tsx
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
import { Container, CssBaseline, ThemeProvider, createTheme, Button, Box, Typography, Alert, CircularProgress } from '@mui/material';
|
2 |
import Header from './components/Header';
|
3 |
import DocumentInput from './components/DocumentInput';
|
4 |
import QuizGenerator from './components/QuizGenerator';
|
@@ -98,8 +98,14 @@ function App() {
|
|
98 |
<Container maxWidth="md" sx={{ py: 4 }}>
|
99 |
<Header />
|
100 |
<DocumentInput />
|
101 |
-
<
|
102 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
|
104 |
{error && (
|
105 |
<Alert severity="error" sx={{ mt: 2, mb: 2 }}>
|
|
|
1 |
+
import { Container, CssBaseline, ThemeProvider, createTheme, Button, Box, Typography, Alert, CircularProgress, Grid } from '@mui/material';
|
2 |
import Header from './components/Header';
|
3 |
import DocumentInput from './components/DocumentInput';
|
4 |
import QuizGenerator from './components/QuizGenerator';
|
|
|
98 |
<Container maxWidth="md" sx={{ py: 4 }}>
|
99 |
<Header />
|
100 |
<DocumentInput />
|
101 |
+
<Grid container spacing={2} sx={{ mb: 2 }}>
|
102 |
+
<Grid item xs={12} md={4}>
|
103 |
+
<Topics onTopicChange={handleTopicChange} />
|
104 |
+
</Grid>
|
105 |
+
<Grid item xs={12} md={8}>
|
106 |
+
<QuizGenerator onProblemsGenerated={handleProblemsGenerated} />
|
107 |
+
</Grid>
|
108 |
+
</Grid>
|
109 |
|
110 |
{error && (
|
111 |
<Alert severity="error" sx={{ mt: 2, mb: 2 }}>
|
frontend/src/components/Header.tsx
CHANGED
@@ -4,7 +4,7 @@ function Header() {
|
|
4 |
return (
|
5 |
<Box sx={{ mb: 4 }}>
|
6 |
<Typography variant="h2" component="h1" align="center">
|
7 |
-
|
8 |
</Typography>
|
9 |
</Box>
|
10 |
);
|
|
|
4 |
return (
|
5 |
<Box sx={{ mb: 4 }}>
|
6 |
<Typography variant="h2" component="h1" align="center">
|
7 |
+
Simplifi
|
8 |
</Typography>
|
9 |
</Box>
|
10 |
);
|
frontend/src/components/Topics.tsx
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
import { FormControl, InputLabel, Select, MenuItem, SelectChangeEvent } from '@mui/material';
|
2 |
import { useEffect, useState } from 'react';
|
3 |
|
4 |
interface TopicsProps {
|
@@ -13,17 +13,18 @@ export default function Topics({ onTopicChange }: TopicsProps) {
|
|
13 |
const [topics, setTopics] = useState<string[]>([]);
|
14 |
const [selectedTopic, setSelectedTopic] = useState('');
|
15 |
const [error, setError] = useState<string | null>(null);
|
|
|
16 |
|
17 |
useEffect(() => {
|
18 |
const fetchTopics = async () => {
|
19 |
try {
|
|
|
20 |
const response = await fetch('/api/topics');
|
21 |
if (!response.ok) {
|
22 |
throw new Error('Failed to fetch topics');
|
23 |
}
|
24 |
const data: TopicsResponse = await response.json();
|
25 |
|
26 |
-
// Validate that we received an array of sources
|
27 |
if (!data.sources || !Array.isArray(data.sources)) {
|
28 |
throw new Error('Invalid topics data received');
|
29 |
}
|
@@ -32,7 +33,9 @@ export default function Topics({ onTopicChange }: TopicsProps) {
|
|
32 |
} catch (error) {
|
33 |
console.error('Error fetching topics:', error);
|
34 |
setError('Failed to load topics');
|
35 |
-
setTopics([]);
|
|
|
|
|
36 |
}
|
37 |
};
|
38 |
|
@@ -47,18 +50,28 @@ export default function Topics({ onTopicChange }: TopicsProps) {
|
|
47 |
|
48 |
return (
|
49 |
<FormControl fullWidth sx={{ mb: 2 }}>
|
50 |
-
<InputLabel>
|
51 |
<Select
|
52 |
value={selectedTopic}
|
53 |
-
label="
|
54 |
onChange={handleChange}
|
55 |
error={!!error}
|
|
|
56 |
>
|
57 |
-
{
|
58 |
-
<MenuItem
|
59 |
-
{
|
|
|
|
|
|
|
60 |
</MenuItem>
|
61 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
</Select>
|
63 |
</FormControl>
|
64 |
);
|
|
|
1 |
+
import { FormControl, InputLabel, Select, MenuItem, SelectChangeEvent, CircularProgress, Box } from '@mui/material';
|
2 |
import { useEffect, useState } from 'react';
|
3 |
|
4 |
interface TopicsProps {
|
|
|
13 |
const [topics, setTopics] = useState<string[]>([]);
|
14 |
const [selectedTopic, setSelectedTopic] = useState('');
|
15 |
const [error, setError] = useState<string | null>(null);
|
16 |
+
const [isLoading, setIsLoading] = useState(true);
|
17 |
|
18 |
useEffect(() => {
|
19 |
const fetchTopics = async () => {
|
20 |
try {
|
21 |
+
setIsLoading(true);
|
22 |
const response = await fetch('/api/topics');
|
23 |
if (!response.ok) {
|
24 |
throw new Error('Failed to fetch topics');
|
25 |
}
|
26 |
const data: TopicsResponse = await response.json();
|
27 |
|
|
|
28 |
if (!data.sources || !Array.isArray(data.sources)) {
|
29 |
throw new Error('Invalid topics data received');
|
30 |
}
|
|
|
33 |
} catch (error) {
|
34 |
console.error('Error fetching topics:', error);
|
35 |
setError('Failed to load topics');
|
36 |
+
setTopics([]);
|
37 |
+
} finally {
|
38 |
+
setIsLoading(false);
|
39 |
}
|
40 |
};
|
41 |
|
|
|
50 |
|
51 |
return (
|
52 |
<FormControl fullWidth sx={{ mb: 2 }}>
|
53 |
+
<InputLabel>Topic</InputLabel>
|
54 |
<Select
|
55 |
value={selectedTopic}
|
56 |
+
label="Topic"
|
57 |
onChange={handleChange}
|
58 |
error={!!error}
|
59 |
+
disabled={isLoading}
|
60 |
>
|
61 |
+
{isLoading ? (
|
62 |
+
<MenuItem value="" disabled>
|
63 |
+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
64 |
+
<CircularProgress size={20} />
|
65 |
+
Loading topics...
|
66 |
+
</Box>
|
67 |
</MenuItem>
|
68 |
+
) : (
|
69 |
+
Array.isArray(topics) && topics.map((topic) => (
|
70 |
+
<MenuItem key={topic} value={topic}>
|
71 |
+
{topic}
|
72 |
+
</MenuItem>
|
73 |
+
))
|
74 |
+
)}
|
75 |
</Select>
|
76 |
</FormControl>
|
77 |
);
|