import React, { useState, useEffect } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import axios from 'axios'; import { Form, Button, Card, Row, Col, Alert, Spinner, Table, InputGroup } from 'react-bootstrap'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faSave, faPlus, faMinus, faCamera, faClock, faTools } from '@fortawesome/free-solid-svg-icons'; import PartSelector from './PartSelector'; import ImageUploader from './ImageUploader'; const ServiceRecordForm = () => { const { appointmentId } = useParams(); const navigate = useNavigate(); const [appointment, setAppointment] = useState(null); const [equipment, setEquipment] = useState(null); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); const [success, setSuccess] = useState(false); const [formData, setFormData] = useState({ diagnosis: '', workPerformed: '', recommendations: '', followUpRequired: false, parts: [], images: [] }); // Timer for service duration const [timer, setTimer] = useState({ startTime: null, endTime: null, isRunning: false, duration: 0 }); useEffect(() => { const fetchAppointmentDetails = async () => { try { setLoading(true); const response = await axios.get(`/api/v1/appointments/${appointmentId}`); setAppointment(response.data.data); // Fetch equipment details const equipmentResponse = await axios.get( `/api/v1/properties/${response.data.data.propertyId}/equipment/${response.data.data.equipmentId}` ); setEquipment(equipmentResponse.data.data); setError(null); } catch (err) { setError(err.response?.data?.message || 'Failed to load appointment details'); } finally { setLoading(false); } }; fetchAppointmentDetails(); }, [appointmentId]); // Handle timer useEffect(() => { let interval = null; if (timer.isRunning) { interval = setInterval(() => { const now = new Date(); const diff = Math.floor((now - timer.startTime) / 1000); setTimer(prev => ({ ...prev, duration: diff })); }, 1000); } return () => { if (interval) { clearInterval(interval); } }; }, [timer.isRunning, timer.startTime]); const startTimer = () => { const now = new Date(); setTimer({ startTime: now, endTime: null, isRunning: true, duration: 0 }); }; const stopTimer = () => { const now = new Date(); setTimer(prev => ({ ...prev, endTime: now, isRunning: false })); }; const formatDuration = (seconds) => { const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); const secs = seconds % 60; return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; }; const handleInputChange = (e) => { const { name, value, type, checked } = e.target; setFormData(prev => ({ ...prev, [name]: type === 'checkbox' ? checked : value })); }; const handleAddPart = (part) => { setFormData(prev => ({ ...prev, parts: [...prev.parts, part] })); }; const handleRemovePart = (index) => { setFormData(prev => ({ ...prev, parts: prev.parts.filter((_, i) => i !== index) })); }; const handleImageUpload = (images) => { setFormData(prev => ({ ...prev, images: [...prev.images, ...images] })); }; const handleRemoveImage = (index) => { setFormData(prev => ({ ...prev, images: prev.images.filter((_, i) => i !== index) })); }; const handleSubmit = async (e) => { e.preventDefault(); try { setSaving(true); // Prepare service record data const serviceRecordData = { appointmentId, equipmentId: equipment.id, diagnosis: formData.diagnosis, workPerformed: formData.workPerformed, recommendations: formData.recommendations, followUpRequired: formData.followUpRequired, startTime: timer.startTime, endTime: timer.endTime || new Date(), parts: formData.parts.map(part => ({ partId: part.id, quantity: part.quantity, unitPrice: part.unitPrice })) }; // Create service record const response = await axios.post('/api/v1/service-records', serviceRecordData); // Upload images if any if (formData.images.length > 0) { const formPayload = new FormData(); formData.images.forEach(image => { formPayload.append('images[]', image.file); }); await axios.post(`/api/v1/service-records/${response.data.data.recordId}/images`, formPayload, { headers: { 'Content-Type': 'multipart/form-data' } }); } // Update appointment status await axios.patch(`/api/v1/appointments/${appointmentId}`, { status: 'completed' }); setSuccess(true); // Redirect after a short delay setTimeout(() => { navigate(`/technician/service-records/${response.data.data.recordId}`); }, 1500); } catch (err) { setError(err.response?.data?.message || 'Failed to save service record'); setSaving(false); } }; if (loading) { return (
Loading...
); } if (!appointment || !equipment) { return ( Appointment or equipment details not found ); } return (

Create Service Record

{error && ( setError(null)}> {error} )} {success && ( Service record saved successfully! )}

Equipment Information

Manufacturer {equipment.model.manufacturerName}
Model {equipment.model.name} ({equipment.model.modelNumber})
Serial Number {equipment.serialNumber || 'N/A'}
Property {appointment.propertyName}
Address {appointment.propertyAddress}
Customer {appointment.customerName}
Service Timer

{formatDuration(timer.duration)}

{!timer.isRunning ? ( ) : ( )}

Service Details

Diagnosis Work Performed Recommendations

Parts Used

{formData.parts.length > 0 && ( {formData.parts.map((part, index) => ( ))}
Part Number Description Quantity Price Total Action
{part.partNumber} {part.name} {part.quantity} ${part.unitPrice.toFixed(2)} ${(part.quantity * part.unitPrice).toFixed(2)}
Total: ${formData.parts.reduce((total, part) => total + (part.quantity * part.unitPrice), 0).toFixed(2)}
)}

Service Images

{formData.images.length > 0 && ( {formData.images.map((image, index) => (
{`Service
))}
)}
); }; export default ServiceRecordForm;