import React, { useState, useEffect } from 'react'; import { Container, Row, Col, Card, Badge, Button, Spinner, Alert, Form, Tabs, Tab, Modal } from 'react-bootstrap'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faWrench, faSearch, faFilter, faPlus, faCalendarAlt, faHome, faInfoCircle, faExclamationTriangle } from '@fortawesome/free-solid-svg-icons'; import axios from 'axios'; import { Link, useNavigate, useLocation } from 'react-router-dom'; import qs from 'query-string'; const ServiceRequestList = () => { const navigate = useNavigate(); const location = useLocation(); const queryParams = qs.parse(location.search); // State const [serviceRequests, setServiceRequests] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [filters, setFilters] = useState({ status: queryParams.status || 'all', property_id: queryParams.property_id || '', service_type: queryParams.service_type || 'all', priority: queryParams.priority || 'all' }); const [statusCounts, setStatusCounts] = useState({}); const [filterOptions, setFilterOptions] = useState({ status: [], service_type: [], priority: [] }); const [properties, setProperties] = useState([]); const [showFilterModal, setShowFilterModal] = useState(false); const [cancelRequestId, setCancelRequestId] = useState(null); const [showCancelModal, setShowCancelModal] = useState(false); const [cancelReason, setCancelReason] = useState(''); const [cancelling, setCancelling] = useState(false); // Load service requests useEffect(() => { fetchServiceRequests(); // Load user properties for filtering fetchUserProperties(); }, []); // Update URL when filters change useEffect(() => { const queryString = qs.stringify({ ...filters, status: filters.status !== 'all' ? filters.status : undefined, property_id: filters.property_id || undefined, service_type: filters.service_type !== 'all' ? filters.service_type : undefined, priority: filters.priority !== 'all' ? filters.priority : undefined }); navigate({ pathname: location.pathname, search: queryString ? `?${queryString}` : '' }, { replace: true }); // Reload data when filters change fetchServiceRequests(); }, [filters]); const fetchServiceRequests = async () => { setLoading(true); setError(null); try { // Build query params const queryParams = { ...filters, status: filters.status !== 'all' ? filters.status : undefined, property_id: filters.property_id || undefined, service_type: filters.service_type !== 'all' ? filters.service_type : undefined, priority: filters.priority !== 'all' ? filters.priority : undefined }; const response = await axios.get('/api/v1/service-requests', { params: queryParams }); setServiceRequests(response.data.data); setStatusCounts(response.data.counts || {}); setFilterOptions(response.data.filter_options || { status: [], service_type: [], priority: [] }); } catch (err) { setError('Failed to load service requests. Please try again.'); console.error('Error fetching service requests:', err); } finally { setLoading(false); } }; const fetchUserProperties = async () => { try { const response = await axios.get('/api/v1/properties'); setProperties(response.data.data || []); } catch (err) { console.error('Error fetching properties:', err); } }; const handleTabChange = (status) => { setFilters(prev => ({ ...prev, status })); }; const handleFilterChange = (field, value) => { setFilters(prev => ({ ...prev, [field]: value })); }; const resetFilters = () => { setFilters({ status: 'all', property_id: '', service_type: 'all', priority: 'all' }); setShowFilterModal(false); }; const handleCancelRequest = (requestId) => { setCancelRequestId(requestId); setShowCancelModal(true); }; const confirmCancelRequest = async () => { if (!cancelRequestId) return; setCancelling(true); try { await axios.put(`/api/v1/service-requests/${cancelRequestId}`, { status: 'cancelled', technician_notes: cancelReason || 'Cancelled by homeowner' }); // Close modal and reset state setShowCancelModal(false); setCancelRequestId(null); setCancelReason(''); // Refresh data fetchServiceRequests(); } catch (err) { setError('Failed to cancel service request. Please try again.'); console.error('Error cancelling service request:', err); } finally { setCancelling(false); } }; // Render status badge const renderStatusBadge = (status) => { const statusMap = { 'pending': { bg: 'secondary', text: 'Pending' }, 'assigned': { bg: 'info', text: 'Assigned' }, 'scheduled': { bg: 'primary', text: 'Scheduled' }, 'in_progress': { bg: 'warning', text: 'In Progress' }, 'completed': { bg: 'success', text: 'Completed' }, 'cancelled': { bg: 'danger', text: 'Cancelled' } }; const { bg, text } = statusMap[status] || { bg: 'secondary', text: status }; return {text}; }; // Render priority badge const renderPriorityBadge = (priority) => { const priorityMap = { 'low': { variant: 'success', text: 'Low' }, 'medium': { variant: 'info', text: 'Medium' }, 'high': { variant: 'warning', text: 'High' }, 'emergency': { variant: 'danger', text: 'Emergency' } }; const { variant, text } = priorityMap[priority] || { variant: 'secondary', text: priority }; return {text}; }; // Render service type badge const renderServiceTypeBadge = (serviceType) => { const serviceTypeMap = { 'repair': { variant: 'danger', text: 'Repair' }, 'maintenance': { variant: 'primary', text: 'Maintenance' }, 'installation': { variant: 'success', text: 'Installation' }, 'inspection': { variant: 'info', text: 'Inspection' } }; const { variant, text } = serviceTypeMap[serviceType] || { variant: 'secondary', text: serviceType }; return {text}; }; if (loading && serviceRequests.length === 0) { return (
Loading...

Loading your service requests...

); } return (

My Service Requests

{error && ( setError(null)}> {error} )} {serviceRequests.length === 0 ? (

No Service Requests Found

{filters.status === 'all' ? "You haven't created any service requests yet." : `You don't have any ${filters.status} service requests.`}

) : (
{serviceRequests.map(request => (
{renderServiceTypeBadge(request.service_type)} {request.equipment ? request.equipment.name : 'General Service'}

{request.description.substring(0, 150)}...

{request.property.name}
{request.preferred_date && (
{request.preferred_date} {request.preferred_time_window && `(${request.preferred_time_window})`}
)}
{renderStatusBadge(request.status)} {renderPriorityBadge(request.priority)}
Created: {new Date(request.created_at).toLocaleDateString()}
{request.meta.can_cancel && ( )}
))}
)}
{/* Filter Modal */} setShowFilterModal(false)}> Filter Service Requests
Property handleFilterChange('property_id', e.target.value)} > {properties.map(property => ( ))} Service Type handleFilterChange('service_type', e.target.value)} > {filterOptions.service_type.map(option => ( ))} Priority handleFilterChange('priority', e.target.value)} > {filterOptions.priority.map(option => ( ))}
{/* Cancel Confirmation Modal */} setShowCancelModal(false)}> Confirm Cancellation

Are you sure you want to cancel this service request?

Reason for cancellation (optional) setCancelReason(e.target.value)} placeholder="Please provide a reason for cancellation..." />
); }; export default ServiceRequestList;