Initial commit
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import { useState } from 'react';
|
||||
import { Button, Box, Typography, Alert } from '@mui/material';
|
||||
import { logger } from '../../../debugConfig';
|
||||
import { SchoolNeoDBService } from '../../../services/graph/schoolNeoDBService';
|
||||
|
||||
export const SchoolUploadSection = () => {
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [success, setSuccess] = useState<string | null>(null);
|
||||
const [isCreating, setIsCreating] = useState(false);
|
||||
|
||||
const handleSchoolUpload = async () => {
|
||||
try {
|
||||
setIsCreating(true);
|
||||
setError(null);
|
||||
setSuccess(null);
|
||||
|
||||
const result = await SchoolNeoDBService.createSchools();
|
||||
setSuccess(result.message);
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Failed to upload school';
|
||||
logger.error('admin-page', '❌ School upload failed:', error);
|
||||
setError(errorMessage);
|
||||
} finally {
|
||||
setIsCreating(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box sx={{ mt: 4 }}>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Create Schools
|
||||
</Typography>
|
||||
|
||||
{error && (
|
||||
<Alert severity="error" sx={{ mb: 2 }}>
|
||||
{error}
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
{success && (
|
||||
<Alert severity="success" sx={{ mb: 2 }}>
|
||||
{success}
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={handleSchoolUpload}
|
||||
disabled={isCreating}
|
||||
>
|
||||
{isCreating ? 'Creating...' : 'Create Schools'}
|
||||
</Button>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,78 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Button, Box, Typography, Alert } from '@mui/material';
|
||||
import { useNeoUser } from '../../../contexts/NeoUserContext';
|
||||
import { TimetableNeoDBService } from '../../../services/graph/timetableNeoDBService';
|
||||
import { CCTeacherNodeProps } from '../../../utils/tldraw/cc-base/cc-graph/cc-graph-types';
|
||||
|
||||
export const TimetableUploadSection = () => {
|
||||
const { userNode, workerNode } = useNeoUser();
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [success, setSuccess] = useState<string | null>(null);
|
||||
const [isUploading, setIsUploading] = useState(false);
|
||||
|
||||
const handleTimetableUpload = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
try {
|
||||
setIsUploading(true);
|
||||
setError(null);
|
||||
setSuccess(null);
|
||||
|
||||
const result = await TimetableNeoDBService.handleTimetableUpload(
|
||||
event.target.files?.[0],
|
||||
userNode || undefined,
|
||||
workerNode?.nodeData as CCTeacherNodeProps | undefined
|
||||
);
|
||||
|
||||
if (result.success) {
|
||||
setSuccess(result.message);
|
||||
} else {
|
||||
setError(result.message);
|
||||
}
|
||||
} finally {
|
||||
setIsUploading(false);
|
||||
if (event.target) {
|
||||
event.target.value = '';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box sx={{ mt: 4 }}>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Upload Teacher Timetable
|
||||
</Typography>
|
||||
|
||||
{error && (
|
||||
<Alert severity="error" sx={{ mb: 2 }}>
|
||||
{error}
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
{success && (
|
||||
<Alert severity="success" sx={{ mb: 2 }}>
|
||||
{success}
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
component="label"
|
||||
disabled={isUploading || !workerNode}
|
||||
>
|
||||
{isUploading ? 'Uploading...' : 'Upload Timetable'}
|
||||
<input
|
||||
type="file"
|
||||
hidden
|
||||
accept=".xlsx"
|
||||
onChange={handleTimetableUpload}
|
||||
disabled={isUploading}
|
||||
/>
|
||||
</Button>
|
||||
|
||||
{!workerNode && (
|
||||
<Typography color="error" sx={{ mt: 1 }}>
|
||||
No teacher node found. Please ensure you have the correct permissions.
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Button, TextField } from '@mui/material';
|
||||
import { EmailCredentials } from '../../../services/auth/authService';
|
||||
import { logger } from '../../../debugConfig';
|
||||
|
||||
interface LoginFormProps {
|
||||
role: 'email_teacher' | 'email_student';
|
||||
onSubmit: (credentials: EmailCredentials) => Promise<void>;
|
||||
}
|
||||
|
||||
export const LoginForm: React.FC<LoginFormProps> = ({ role, onSubmit }) => {
|
||||
const [email, setEmail] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
logger.debug('login-form', '🔄 Submitting login form', { role });
|
||||
await onSubmit({ email, password, role });
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit} className="login-form">
|
||||
<TextField
|
||||
label="Email"
|
||||
variant="outlined"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
fullWidth
|
||||
autoComplete="new-username"
|
||||
/>
|
||||
<TextField
|
||||
label="Password"
|
||||
type="password"
|
||||
variant="outlined"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
fullWidth
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
<Button type="submit" variant="contained" fullWidth>
|
||||
Login
|
||||
</Button>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Button } from '@mui/material';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { logger } from '../../../debugConfig';
|
||||
|
||||
export const SuperAdminSection = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleAdminClick = () => {
|
||||
logger.info('super-admin-section', '🔑 Navigating to admin page');
|
||||
navigate('/admin');
|
||||
};
|
||||
|
||||
return (
|
||||
<Button
|
||||
onClick={handleAdminClick}
|
||||
variant="contained"
|
||||
color="warning"
|
||||
sx={{ mb: 2 }}
|
||||
>
|
||||
Admin Dashboard
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
import { CircularProgress, Box } from '@mui/material';
|
||||
|
||||
export const LoadingSpinner = () => (
|
||||
<Box
|
||||
display="flex"
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
minHeight="100vh"
|
||||
>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
);
|
||||
Reference in New Issue
Block a user