Generate me a complex React component with TypeScript that's quite long
Here's a complex React component with TypeScript:
typescript
import React, { useState, useEffect, useCallback, useMemo } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { ThunkDispatch } from 'redux-thunk';
import { AnyAction } from 'redux';
import {
fetchDataStart,
fetchDataSuccess,
fetchDataFailure,
updateFilterCriteria,
sortDataItems,
paginateResults
} from '../actions/dataActions';
import {
DataItem,
FilterCriteria,
SortDirection,
RootState,
PaginationSettings
} from '../types';
import DataTable from './DataTable';
import FilterPanel from './FilterPanel';
import Pagination from './Pagination';
import LoadingSpinner from './LoadingSpinner';
import ErrorMessage from './ErrorMessage';
import { debounce } from '../utils/helpers';
import { API_ENDPOINTS } from '../constants';
import axios, { AxiosError } from 'axios';
import { logger } from '../services/logService';
import '../styles/DataDashboard.scss';
interface DataDashboardProps {
initialFilter?: FilterCriteria;
pageSize?: number;
refreshInterval?: number;
enableRealTimeUpdates?: boolean;
onDataLoaded?: (data: DataItem[]) => void;
onError?: (error: Error) => void;
customRenderer?: (item: DataItem) => React.ReactNode;
accessLevel: 'admin' | 'user' | 'guest';
}
/**
* DataDashboard Component
*
* A comprehensive dashboard component that handles data fetching, filtering,
* sorting, pagination, and error handling.
*/
const DataDashboard: React.FC = ({
initialFilter = {},
pageSize = 10,
refreshInterval = 0,
enableRealTimeUpdates = false,
onDataLoaded,
onError,
customRenderer,
accessLevel
}) => {
// Redux hooks
const dispatch = useDispatch>();
const {
data,
loading,
error,
filteredData,
totalItems,
currentPage
} = useSelector((state: RootState) => state.data);
// Local state
const [filter, setFilter] = useState(initialFilter);
const [sortConfig, setSortConfig] = useState<{
key: keyof DataItem | null;
direction: SortDirection;
}>({ key: null, direction: 'asc' });
const [paginationSettings, setPaginationSettings] = useState({
currentPage: 1,
pageSize,
totalPages: 0
});
const [isAutoRefreshing, setIsAutoRefreshing] = useState(enableRealTimeUpdates);
const [lastUpdated, setLastUpdated] = useState(null);
const [selectedItems, setSelectedItems] = useState([]);
const [viewMode, setViewMode] = useState<'table' | 'grid' | 'list'>('table');
const [isFilterPanelOpen, setIsFilterPanelOpen] = useState(false);
// Fetch data from the API
const fetchData = useCallback(async () => {
try {
dispatch(fetchDataStart());
const response = await axios.get(`${API_ENDPOINTS.DATA}`, {
params: {
...filter,
page: paginationSettings.currentPage,
pageSize: paginationSettings.pageSize,
sortBy: sortConfig.key,
sortDirection: sortConfig.direction
}
});
const responseData = response.data;
dispatch(fetchDataSuccess({
items: responseData.items,
totalItems: responseData.totalItems,
totalPages: responseData.totalPages
}));
setLastUpdated(new Date());
if (onDataLoaded) {
onDataLoaded(responseData.items);
}
} catch (err) {
const error = err as AxiosError;
dispatch(fetchDataFailure(error.message));
logger.error('Failed to fetch data:', error);
if (onError) {
onError(error);
}
}
}, [dispatch, filter, paginationSettings.currentPage, paginationSettings.pageSize, sortConfig, onDataLoaded, onError]);
// Initial data fetch and refresh interval setup
useEffect(() => {
fetchData();
let intervalId: NodeJS.Timeout | null = null;
if (refreshInterval > 0 && isAutoRefreshing) {
intervalId = setInterval(() => {
fetchData();
}, refreshInterval);
}
return () => {
if (intervalId) {
clearInterval(intervalId);
}
};
}, [fetchData, refreshInterval, isAutoRefreshing]);
// Handle filter changes with debounce
const handleFilterChange = useMemo(() =>
debounce((newFilter: FilterCriteria) => {
setFilter(newFilter);
setPaginationSettings(prev => ({ ...prev, currentPage: 1 }));
dispatch(updateFilterCriteria(newFilter));
}, 300),
[dispatch]);
// Handle sorting
const handleSort = useCallback((key: keyof DataItem) => {
setSortConfig(prevConfig => {
const newDirection =
prevConfig.key === key && prevConfig.direction === 'asc' ? 'desc' : 'asc';
dispatch(sortDataItems(key, newDirection));
return { key, direction: newDirection };
});
}, [dispatch]);
// Handle pagination
const handlePageChange = useCallback((page: number) => {
setPaginationSettings(prev => ({ ...prev, currentPage: page }));
dispatch(paginateResults(page));
}, [dispatch]);
// Handle item selection
const handleItemSelect = useCallback((item: DataItem, isSelected: boolean) => {
setSelectedItems(prev => {
if (isSelected) {
return [...prev, item];
} else {
return prev.filter(i => i.id !== item.id);
}
});
}, []);
// Handle bulk actions
const handleBulkAction = useCallback((action: string) => {
if (selectedItems.length === 0) return;
switch (action) {
case 'delete':
// Implementation for delete action
console.log(`Deleting ${selectedItems.length} items`);
break;
case 'export':
// Implementation for export action
console.log(`Exporting ${selectedItems.length} items`);
break;
case 'tag':
// Implementation for tag action
console.log(`Tagging ${selectedItems.length} items`);
break;
default:
console.warn(`Unknown bulk action: ${action}`);
}
}, [selectedItems]);
// Render loading state
if (loading && !data.length) {
return ;
}
// Render error state
if (error && !data.length) {
return ;
}
return (
{}}
customRenderer={customRenderer}
accessLevel={accessLevel}
/>
);
};
export default DataDashboard;