mirror of
https://github.com/HamzaSha1/zod-backend.git
synced 2025-08-25 13:49:40 +00:00
267 lines
8.0 KiB
TypeScript
267 lines
8.0 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import {
|
|
Box,
|
|
TextField,
|
|
Button,
|
|
Typography,
|
|
Paper,
|
|
FormControl,
|
|
InputLabel,
|
|
Select,
|
|
MenuItem,
|
|
Grid,
|
|
Alert,
|
|
SelectChangeEvent,
|
|
Divider
|
|
} from '@mui/material';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { juniorsApi } from '../../api/client';
|
|
import { CreateJuniorRequest } from '../../types/junior';
|
|
import { DocumentUpload } from '../document/DocumentUpload';
|
|
import { DocumentType } from '../../types/document';
|
|
import { ApiError } from '../../types/api';
|
|
import { AxiosError } from 'axios';
|
|
|
|
export const AddJuniorForm = () => {
|
|
const navigate = useNavigate();
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState('');
|
|
const [formData, setFormData] = useState<CreateJuniorRequest>({
|
|
countryCode: '+962',
|
|
phoneNumber: '',
|
|
firstName: '',
|
|
lastName: '',
|
|
dateOfBirth: '',
|
|
email: '',
|
|
relationship: 'PARENT',
|
|
civilIdFrontId: '',
|
|
civilIdBackId: ''
|
|
});
|
|
|
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
console.log('Form data:', formData);
|
|
|
|
setError('');
|
|
setLoading(true);
|
|
|
|
try {
|
|
if (!formData.civilIdFrontId || !formData.civilIdBackId) {
|
|
console.log('Missing documents - Front:', formData.civilIdFrontId, 'Back:', formData.civilIdBackId);
|
|
throw new Error('Please upload both front and back civil ID documents');
|
|
}
|
|
|
|
console.log('Submitting data:', formData);
|
|
const dataToSubmit = {
|
|
...formData,
|
|
civilIdFrontId: formData.civilIdFrontId.trim(),
|
|
civilIdBackId: formData.civilIdBackId.trim()
|
|
};
|
|
await juniorsApi.createJunior(dataToSubmit);
|
|
navigate('/juniors');
|
|
} catch (err) {
|
|
console.error('Create junior error:', err);
|
|
if (err instanceof AxiosError && err.response?.data) {
|
|
const apiError = err.response.data as ApiError;
|
|
const messages = Array.isArray(apiError.message)
|
|
? apiError.message.map(m => `${m.field}: ${m.message}`).join('\n')
|
|
: apiError.message;
|
|
setError(messages);
|
|
} else {
|
|
setError(err instanceof Error ? err.message : 'Failed to create junior');
|
|
}
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
const { name, value } = e.target;
|
|
setFormData(prev => ({
|
|
...prev,
|
|
[name]: value
|
|
}));
|
|
};
|
|
|
|
const handleSelectChange = (e: SelectChangeEvent) => {
|
|
const { name, value } = e.target;
|
|
setFormData(prev => ({
|
|
...prev,
|
|
[name as string]: value
|
|
}));
|
|
};
|
|
|
|
useEffect(() => {
|
|
console.log('Form data updated:', formData);
|
|
}, [formData]);
|
|
|
|
const handleCivilIdFrontUpload = (documentId: string) => {
|
|
console.log('Front ID uploaded:', documentId);
|
|
setFormData(prev => ({
|
|
...prev,
|
|
civilIdFrontId: documentId
|
|
}));
|
|
};
|
|
|
|
const handleCivilIdBackUpload = (documentId: string) => {
|
|
console.log('Back ID uploaded:', documentId);
|
|
setFormData(prev => ({
|
|
...prev,
|
|
civilIdBackId: documentId
|
|
}));
|
|
};
|
|
|
|
return (
|
|
<Box p={3}>
|
|
<Typography variant="h4" gutterBottom>
|
|
Add New Junior
|
|
</Typography>
|
|
|
|
<Paper sx={{ p: 3, maxWidth: 600, mx: 'auto' }}>
|
|
{error && (
|
|
<Alert severity="error" sx={{ mb: 3, whiteSpace: 'pre-line' }}>
|
|
{error}
|
|
</Alert>
|
|
)}
|
|
|
|
<Box component="form" onSubmit={handleSubmit}>
|
|
<Grid container spacing={3}>
|
|
<Grid item xs={12} sm={6}>
|
|
<FormControl fullWidth>
|
|
<InputLabel>Country Code</InputLabel>
|
|
<Select
|
|
name="countryCode"
|
|
value={formData.countryCode}
|
|
label="Country Code"
|
|
onChange={handleSelectChange}
|
|
>
|
|
<MenuItem value="+962">Jordan (+962)</MenuItem>
|
|
</Select>
|
|
</FormControl>
|
|
</Grid>
|
|
<Grid item xs={12} sm={6}>
|
|
<TextField
|
|
fullWidth
|
|
label="Phone Number"
|
|
name="phoneNumber"
|
|
value={formData.phoneNumber}
|
|
onChange={handleInputChange}
|
|
placeholder="7XXXXXXXX"
|
|
required
|
|
/>
|
|
</Grid>
|
|
<Grid item xs={12} sm={6}>
|
|
<TextField
|
|
fullWidth
|
|
label="First Name"
|
|
name="firstName"
|
|
value={formData.firstName}
|
|
onChange={handleInputChange}
|
|
required
|
|
/>
|
|
</Grid>
|
|
<Grid item xs={12} sm={6}>
|
|
<TextField
|
|
fullWidth
|
|
label="Last Name"
|
|
name="lastName"
|
|
value={formData.lastName}
|
|
onChange={handleInputChange}
|
|
required
|
|
/>
|
|
</Grid>
|
|
<Grid item xs={12} sm={6}>
|
|
<TextField
|
|
fullWidth
|
|
label="Email"
|
|
name="email"
|
|
type="email"
|
|
value={formData.email}
|
|
onChange={handleInputChange}
|
|
required
|
|
/>
|
|
</Grid>
|
|
<Grid item xs={12} sm={6}>
|
|
<TextField
|
|
fullWidth
|
|
label="Date of Birth"
|
|
name="dateOfBirth"
|
|
type="date"
|
|
value={formData.dateOfBirth}
|
|
onChange={handleInputChange}
|
|
required
|
|
InputLabelProps={{
|
|
shrink: true,
|
|
}}
|
|
/>
|
|
</Grid>
|
|
<Grid item xs={12}>
|
|
<FormControl fullWidth>
|
|
<InputLabel>Relationship</InputLabel>
|
|
<Select
|
|
name="relationship"
|
|
value={formData.relationship}
|
|
label="Relationship"
|
|
onChange={handleSelectChange}
|
|
>
|
|
<MenuItem value="PARENT">Parent</MenuItem>
|
|
<MenuItem value="GUARDIAN">Guardian</MenuItem>
|
|
</Select>
|
|
</FormControl>
|
|
</Grid>
|
|
|
|
<Grid item xs={12}>
|
|
<Divider sx={{ my: 2 }}>
|
|
<Typography variant="body2" color="textSecondary">
|
|
Civil ID Documents
|
|
</Typography>
|
|
</Divider>
|
|
</Grid>
|
|
|
|
<Grid item xs={12} sm={6}>
|
|
<DocumentUpload
|
|
documentType={DocumentType.PASSPORT}
|
|
label="Upload Civil ID Front"
|
|
onUploadSuccess={handleCivilIdFrontUpload}
|
|
/>
|
|
{formData.civilIdFrontId && (
|
|
<Typography variant="caption" color="success.main" sx={{ mt: 1, display: 'block' }}>
|
|
Civil ID Front uploaded (ID: {formData.civilIdFrontId})
|
|
</Typography>
|
|
)}
|
|
</Grid>
|
|
<Grid item xs={12} sm={6}>
|
|
<DocumentUpload
|
|
documentType={DocumentType.PASSPORT}
|
|
label="Upload Civil ID Back"
|
|
onUploadSuccess={handleCivilIdBackUpload}
|
|
/>
|
|
{formData.civilIdBackId && (
|
|
<Typography variant="caption" color="success.main" sx={{ mt: 1, display: 'block' }}>
|
|
Civil ID Back uploaded (ID: {formData.civilIdBackId})
|
|
</Typography>
|
|
)}
|
|
</Grid>
|
|
</Grid>
|
|
|
|
<Box sx={{ mt: 3, display: 'flex', gap: 2, justifyContent: 'flex-end' }}>
|
|
<Button
|
|
variant="outlined"
|
|
onClick={() => navigate('/juniors')}
|
|
>
|
|
Cancel
|
|
</Button>
|
|
<Button
|
|
type="submit"
|
|
variant="contained"
|
|
disabled={loading}
|
|
>
|
|
{loading ? 'Adding...' : 'Add Junior'}
|
|
</Button>
|
|
</Box>
|
|
</Box>
|
|
</Paper>
|
|
</Box>
|
|
);
|
|
};
|