Title: SupportStaffManagement Component
Overview
The SupportStaffManagement component is a React-based interface for administrators to manage support staff within an educational institution's complaint management system. It provides comprehensive functionality for adding, viewing, searching, sorting, and deleting support staff members who handle various categories of complaints.
Component Structure
The component is built using React with hooks for state management and React Query for data fetching. It implements a comprehensive management interface with form validation, search functionality, and sortable tabular data display.
Dependencies
import React, { useState, useEffect } from "react";
import { useQuery } from "@tanstack/react-query";
The component relies on:
- React and its hooks for component structure and state management
- React Query for data fetching and state synchronization
- A nested StaffComplaintsModal component for viewing staff complaint details
State Management
// State for the new support staff form
const [newStaff, setNewStaff] = useState({
name: "",
phone: "",
categories: [],
subCategories: [],
});
// State for form validation and feedback
const [formError, setFormError] = useState("");
const [successMessage, setSuccessMessage] = useState("");
// Search state
const [searchQuery, setSearchQuery] = useState("");
// Sorting state
const [sortConfig, setSortConfig] = useState({
key: "name",
direction: "ascending",
});
// Filtered and sorted staff data
const [displayedStaff, setDisplayedStaff] = useState([]);
// Selected staff for viewing complaints
const [selectedStaff, setSelectedStaff] = useState(null);
The component maintains several state variables to control its behavior:
- newStaff: Object containing form data for adding a new staff member
- formError and successMessage: Feedback messages for user actions
- searchQuery: Controls the search functionality
- sortConfig: Tracks the current sorting configuration (field and direction)
- displayedStaff: Derived state containing filtered and sorted staff data
- selectedStaff: Tracks the currently selected staff member for viewing complaints
Predefined Categories
The component includes a predefined structure of categories and subcategories:
const categoriesOptions = {
"Computer & Comm. Centre": ["Automation", "Email Services", "HPC Support", "Network", "PC & Peripherals", "Telephone", "Turnitin", "Web Services", "Other"],
"Hostel/Resident Complaints": ["Plumbing", "Room Servicing", "Electricity Issues", "Furniture Repair", "Cleaning Services", "Other"],
"Infrastructure Complaints": ["Gym", "Badminton Hall", "Table Tennis Court", "Ground", "Swimming Pool", "Food Court", "Other"],
};
This object maps each main department category to an array of specific issue subcategories, providing a structured approach to staff specialization.
Data Fetching
The component uses React Query to fetch support staff data:
const {
data: supportStaffData = [],
isLoading,
isError,
refetch,
} = useQuery({
queryKey: ["supportStaff"],
queryFn: async () => {
const response = await fetch("http://localhost:8000/api/complaints/admin/supportStaff", {
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${localStorage.getItem("accessToken")}`,
},
credentials: "include",
});
const result = await response.json();
if (!response.ok) {
throw new Error(result.message || "Failed to fetch support staff");
}
return result.supportStaff || [];
},
});
This setup: - Fetches support staff data from the API - Handles authentication via Bearer token - Provides loading and error states - Offers a refetch function to refresh data after mutations
Derived State
The component uses useEffect to derive the displayed staff list whenever the source data, sorting, or search criteria change:
useEffect(() => {
if (supportStaffData.length) {
let sortedData = [...supportStaffData];
// Apply sorting
sortedData.sort((a, b) => {
// Special case for assignedComplaints length sorting
if (sortConfig.key === "assignedComplaints") {
const aLength = a.assignedComplaints ? a.assignedComplaints.length : 0;
const bLength = b.assignedComplaints ? b.assignedComplaints.length : 0;
return sortConfig.direction === "ascending"
? aLength - bLength
: bLength - aLength;
}
// Special case for resolvedComplaints length sorting
if (sortConfig.key === "resolvedComplaints") {
const aLength = a.resolvedComplaints ? a.resolvedComplaints.length : 0;
const bLength = b.resolvedComplaints ? b.resolvedComplaints.length : 0;
return sortConfig.direction === "ascending"
? aLength - bLength
: bLength - aLength;
}
if (a[sortConfig.key] b[sortConfig.key]) {
return sortConfig.direction === "ascending" ? 1 : -1;
}
return 0;
});
// Apply search filter
if (searchQuery.trim()) {
const query = searchQuery.toLowerCase().trim();
sortedData = sortedData.filter(staff =>
staff.name.toLowerCase().includes(query) ||
staff.phone.includes(query) ||
(staff.categories && staff.categories.some(category =>
category.toLowerCase().includes(query)
)) ||
(staff.subCategories && staff.subCategories.some(subCategory =>
subCategory.toLowerCase().includes(query)
))
);
}
setDisplayedStaff(sortedData);
}
}, [supportStaffData, sortConfig, searchQuery]);
This effect: - Creates a sorted copy of the support staff data - Implements special handling for sorting by number of assigned or resolved complaints - Filters the data based on the search query across multiple fields - Updates the displayed staff list with the processed data
Data Mutations
Add Support Staff
const handleAddStaff = async (e) => {
e.preventDefault();
// Validation
if (!newStaff.name || !newStaff.phone) {
setFormError("Name and phone number are required.");
return;
}
try {
const response = await fetch("http://localhost:8000/api/complaints/admin/supportStaff", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${localStorage.getItem("accessToken")}`,
},
credentials: "include",
body: JSON.stringify(newStaff),
});
const result = await response.json();
if (!response.ok) {
throw new Error(result.message || "Failed to add support staff");
}
// Reset form and show success message
setNewStaff({
name: "",
phone: "",
categories: [],
subCategories: [],
});
setSuccessMessage("Support staff added successfully!");
setFormError("");
// Refetch the support staff list
refetch();
// Clear success message after a few seconds
setTimeout(() => {
setSuccessMessage("");
}, 3000);
} catch (error) {
setFormError(error.message || "An error occurred while adding support staff");
}
};
This function: - Validates the form data - Sends a POST request to create a new support staff member - Handles success with feedback and form reset - Triggers a refetch of the staff list - Provides error handling with user feedback
Delete Support Staff
const handleDeleteStaff = async (staffId) => {
try {
const response = await fetch("http://localhost:8000/api/complaints/admin/supportStaff", {
method: "DELETE",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${localStorage.getItem("accessToken")}`,
},
credentials: "include",
body: JSON.stringify({ supportStaffId: staffId }),
});
const result = await response.json();
if (!response.ok) {
throw new Error(result.message || "Failed to delete support staff");
}
// Show success message
setSuccessMessage("Support staff deleted successfully!");
// Refetch the support staff list
refetch();
// Clear success message after a few seconds
setTimeout(() => {
setSuccessMessage("");
}, 3000);
} catch (error) {
setFormError(error.message || "An error occurred while deleting support staff");
}
};
This function: - Sends a DELETE request to remove the staff member - Handles success with feedback - Triggers a refetch of the staff list - Provides error handling with user feedback
Form Handling
Category Selection
const handleCategoryChange = (category) => {
const updatedCategories = [...newStaff.categories];
// Toggle category selection
if (updatedCategories.includes(category)) {
const index = updatedCategories.indexOf(category);
updatedCategories.splice(index, 1);
} else {
updatedCategories.push(category);
}
setNewStaff({
...newStaff,
categories: updatedCategories,
// Clear subcategories when categories change
subCategories: []
});
};
This function: - Toggles the selection of a category - Clears subcategories when categories change to maintain data consistency
Subcategory Selection
const handleSubcategoryChange = (subcategory) => {
const updatedSubcategories = [...newStaff.subCategories];
// Toggle subcategory selection
if (updatedSubcategories.includes(subcategory)) {
const index = updatedSubcategories.indexOf(subcategory);
updatedSubcategories.splice(index, 1);
} else {
updatedSubcategories.push(subcategory);
}
setNewStaff({
...newStaff,
subCategories: updatedSubcategories
});
};
This function toggles the selection of a subcategory in the form.
Available Subcategories
const getAvailableSubcategories = () => {
let subcategories = [];
newStaff.categories.forEach(category => {
if (categoriesOptions[category]) {
subcategories = [...subcategories, ...categoriesOptions[category]];
}
});
return [...new Set(subcategories)]; // Remove duplicates
};
This helper function: - Collects all subcategories from the selected categories - Removes duplicates to create a clean list for the form
Sorting Implementation
const requestSort = (key) => {
let direction = "ascending";
if (sortConfig.key === key && sortConfig.direction === "ascending") {
direction = "descending";
}
setSortConfig({ key, direction });
};
const getSortDirectionIndicator = (key) => {
if (sortConfig.key !== key) return null;
return sortConfig.direction === "ascending" ? "↑" : "↓";
};
These functions: - Toggle sort direction when clicking the same column header - Provide visual indicators for the current sort direction - Update the sort configuration which triggers the derived state effect
Staff Complaints Modal Integration
const handleStaffRowClick = (staff) => {
// Show complaints if the staff has assigned or resolved complaints
if ((staff.assignedComplaints && staff.assignedComplaints.length > 0) ||
(staff.resolvedComplaints && staff.resolvedComplaints.length > 0)) {
setSelectedStaff(staff);
}
};
// In the render section:
{selectedStaff && (
setSelectedStaff(null)}
/>
)}
This integration: - Shows the complaints modal when clicking on a staff row with complaints - Passes the selected staff data to the modal - Provides a way to close the modal
UI Structure
The component's UI is organized into several sections:
- Header: Component title
- Feedback Messages: Success and error notifications
- Add Staff Form: Form for adding new support staff
- Staff List: Searchable and sortable table of staff members
Add Staff Form
The form includes: - Name and phone number inputs (required) - Category selection checkboxes - Dynamic subcategory selection based on chosen categories - Submit button with validation
Staff List
The staff list includes: - Search functionality across multiple fields - Column sorting with direction indicators - Staff details including name, phone, categories, and subcategories - Visual indicators for staff at capacity (5+ assigned complaints) - Delete action with appropriate disabling for staff with active complaints - Row click functionality to view staff complaints
StaffComplaintsModal Component
The component includes a nested StaffComplaintsModal component that:
- Fetches and displays complaints assigned to a specific staff member
- Provides tabs to switch between active and resolved complaints
- Shows detailed complaint information including images
- Implements loading and error states
- Provides a close button to return to the staff list
Usage
This component should be included in the administrative section of the complaint management system, accessible only to users with appropriate permissions. It provides a complete interface for managing the support staff who will be assigned to handle complaints.
The component integrates with the broader complaint system by: 1. Allowing administrators to add staff with specific specializations 2. Showing the current workload of each staff member 3. Preventing deletion of staff with active assignments 4. Providing search and sort capabilities for efficient management 5. Allowing detailed viewing of complaints assigned to each staff member