mirror of
https://github.com/HamzaSha1/zod-backend.git
synced 2025-08-26 06:09:41 +00:00
api client for testing
This commit is contained in:
266
client/src/components/juniors/AddJuniorForm.tsx
Normal file
266
client/src/components/juniors/AddJuniorForm.tsx
Normal file
@ -0,0 +1,266 @@
|
||||
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>
|
||||
);
|
||||
};
|
Reference in New Issue
Block a user