import React, { useState, useEffect } from 'react'; import { Formik, Form, Field, ErrorMessage } from 'formik'; import * as Yup from 'yup'; import axios from 'axios'; import { Container, Row, Col, Card, Button, Spinner, Alert, Form as BootstrapForm } from 'react-bootstrap'; import DatePicker from 'react-datepicker'; import "react-datepicker/dist/react-datepicker.css"; import { useNavigate, useParams } from 'react-router-dom'; const ServiceRequestForm = () => { const navigate = useNavigate(); const { propertyId, equipmentId } = useParams(); const [properties, setProperties] = useState([]); const [equipment, setEquipment] = useState([]); const [loading, setLoading] = useState(true); const [submitting, setSubmitting] = useState(false); const [error, setError] = useState(null); const [success, setSuccess] = useState(false); const [selectedPropertyId, setSelectedPropertyId] = useState(propertyId || ''); // Initial values for the form const initialValues = { property_id: propertyId || '', equipment_id: equipmentId || '', service_type: 'repair', // Default service type priority: 'medium', // Default priority description: '', preferred_date: null, preferred_time_start: '', preferred_time_end: '' }; // Validation schema using Yup const validationSchema = Yup.object({ property_id: Yup.number() .required('Property is required'), equipment_id: Yup.number() .nullable(), service_type: Yup.string() .required('Service type is required') .oneOf(['installation', 'repair', 'maintenance', 'inspection']), priority: Yup.string() .required('Priority is required') .oneOf(['low', 'medium', 'high', 'emergency']), description: Yup.string() .required('Description is required') .min(10, 'Description must be at least 10 characters') .max(1000, 'Description must be less than 1000 characters'), preferred_date: Yup.date() .nullable() .min(new Date(), 'Preferred date must be today or later'), preferred_time_start: Yup.string() .nullable() .matches(/^([01]?[0-9]|2[0-3]):[0-5][0-9]$/, 'Invalid time format'), preferred_time_end: Yup.string() .nullable() .matches(/^([01]?[0-9]|2[0-3]):[0-5][0-9]$/, 'Invalid time format') .test('is-greater', 'End time must be after start time', function(value) { const { preferred_time_start } = this.parent; if (!preferred_time_start || !value) return true; return value > preferred_time_start; }) }); // Load properties on component mount useEffect(() => { const fetchUserProperties = async () => { try { const response = await axios.get('/api/v1/properties'); setProperties(response.data.data); setLoading(false); // If only one property exists, select it by default if (response.data.data.length === 1 && !propertyId) { setSelectedPropertyId(response.data.data[0].id.toString()); } } catch (err) { setError('Failed to load properties. Please try again later.'); setLoading(false); } }; fetchUserProperties(); }, [propertyId]); // Load equipment when property is selected useEffect(() => { const fetchPropertyEquipment = async () => { if (!selectedPropertyId) { setEquipment([]); return; } try { const response = await axios.get(`/api/v1/properties/${selectedPropertyId}/equipment`); setEquipment(response.data.data); } catch (err) { setError('Failed to load equipment. Please try again later.'); } }; fetchPropertyEquipment(); }, [selectedPropertyId]); // Handle property selection change const handlePropertyChange = (e, setFieldValue) => { const newPropertyId = e.target.value; setSelectedPropertyId(newPropertyId); setFieldValue('property_id', newPropertyId); setFieldValue('equipment_id', ''); // Reset equipment selection }; // Handle form submission const handleSubmit = async (values, { resetForm }) => { setSubmitting(true); setError(null); try { // Format time values for API const formattedValues = { ...values, preferred_date: values.preferred_date ? formatDate(values.preferred_date) : null }; await axios.post('/api/v1/service-requests', formattedValues); setSuccess(true); resetForm(); // Redirect after a short delay setTimeout(() => { navigate('/service-requests'); }, 2000); } catch (err) { setError(err.response?.data?.message || 'Failed to create service request. Please try again.'); } finally { setSubmitting(false); } }; // Helper function to format date for API const formatDate = (date) => { return date.toISOString().split('T')[0]; }; // Helper function to format time for display const formatTimeForDisplay = (timeString) => { if (!timeString) return ''; const [hours, minutes] = timeString.split(':'); const date = new Date(); date.setHours(parseInt(hours, 10)); date.setMinutes(parseInt(minutes, 10)); return date; }; if (loading) { return ( Loading... Loading your properties... ); } if (properties.length === 0) { return ( No Properties Found You need to add a property before you can request service. navigate('/properties/new')} > Add a Property ); } return ( Request Service {error && ( setError(null)}> {error} )} {success && ( Service request created successfully! Redirecting to your service requests... )} {({ setFieldValue, values, errors, touched }) => ( Property * handlePropertyChange(e, setFieldValue)} > Select a property {properties.map((property) => ( {property.propertyName} ))} Equipment (Optional) Select equipment (optional) {equipment.map((item) => ( {item.nickname || item.model.name} ({item.model.manufacturerName}) ))} {values.property_id && equipment.length === 0 && ( No equipment found for this property. You can still request general service. )} Service Type * Repair Maintenance Installation Inspection Priority * Low - No rush Medium - Standard service High - Needs attention soon Emergency - Urgent service needed Description * Include as much detail as possible to help the technician prepare for your service. Preferred Date (Optional) setFieldValue('preferred_date', date)} dateFormat="yyyy-MM-dd" minDate={new Date()} className={`form-control ${ errors.preferred_date && touched.preferred_date ? 'is-invalid' : '' }`} placeholderText="Click to select a date" /> Preferred Start Time Preferred End Time navigate(-1)} disabled={submitting} > Cancel {submitting ? ( <> Submitting... > ) : ( 'Submit Service Request' )} )} ); }; export default ServiceRequestForm;
Loading your properties...
You need to add a property before you can request service.