Criteria Management Enhancement
Criteria Management Enhancement
import {
Typography,
InputBase,
Button,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Paper,
IconButton,
CircularProgress,
Box,
} from "@mui/material";
import {
Search as SearchIcon,
Delete as DeleteIcon,
Add as AddIcon,
KeyboardArrowDown as KeyboardArrowDownIcon,
EditNoteRounded,
InfoOutlined,
} from "@mui/icons-material";
import PlayArrowRoundedIcon from '@mui/icons-material/PlayArrowRounded';
import CustomButton from "../UI/CustomeButton.tsx";
// TypeScript interfaces
interface CriteriaItem {
id: number;
name: string;
companies: number;
shortlist: number;
expressions: number;
dateCreated: string;
createdBy: string;
}
interface SearchBarProps {
searchTerm: string;
onSearchChange: (value: string) => void;
onNewSearch: () => void;
}
interface ActionButtonsProps {
onRun: () => void;
onEdit: () => void;
onDelete: () => void;
}
interface PaginationProps {
currentPage: number;
totalPages: number;
onPageChange: (page: number) => void;
}
// Styles
const styles = {
typography: {
header: {
fontSize: "14px",
fontWeight: "600",
lineHeight: "22px",
letterSpacing: "0",
verticalAlign: "middle",
},
enterprise: {
fontWeight: "600",
color: "black",
textDecoration: "underline",
lineHeight: "22px",
fontSize: "14px",
letterSpacing: "0",
verticalAlign: "middle",
cursor: "pointer",
},
regular: {
fontWeight: "600",
color: "black",
lineHeight: "22px",
fontSize: "14px",
letterSpacing: "0",
},
creator: {
color: "black",
fontSize: "14px",
}
},
table: {
container: {
boxShadow: "none",
borderRadius: "10px",
border: "1px solid lightgray",
},
row: (isEven: boolean) => ({
backgroundColor: isEven ? "white" : "#f9f9f9",
}),
},
searchBar: {
container: {
p: "2px 4px",
boxShadow: "none",
borderRadius: "12px",
},
},
pagination: {
button: (isActive: boolean) => ({
minWidth: "32px",
height: "32px",
padding: 0,
borderRadius: "8px",
backgroundColor: isActive ? "#0a2559" : "white",
color: isActive ? "#fff" : "#666",
"&:hover": {
backgroundColor: isActive ? "#061a54" : "#f0f0f0",
},
}),
navButton: (disabled: boolean) => ({
color: disabled ? "#ccc" : "black",
backgroundColor: "white",
}),
},
actions: {
run: {
color: "rgba(16, 171, 78, 1)",
padding: "12px",
fontSize: "10px",
},
edit: {
color: "rgba(20, 45, 93, 1)",
fontWeight: "bold",
},
delete: {
color: "red",
fontWeight: "bold",
},
},
};
// Reusable components
const SearchBar: FC<SearchBarProps> = ({ searchTerm, onSearchChange, onNewSearch })
=> (
<div className="flex mb-6 gap-4">
<Paper
component="form"
className="flex items-center w-full border"
sx={styles.searchBar.container}
elevation={0}
>
<IconButton className="p-2.5" aria-label="search">
<SearchIcon />
</IconButton>
<InputBase
className="ml-1 flex-1"
placeholder="Search"
value={searchTerm}
onChange={(e) => onSearchChange(e.target.value)}
/>
</Paper>
<CustomButton
className="font-bold rounded px-4 normal-case shadow-none whitespace-
nowrap"
onClick={onNewSearch}
>
<AddIcon />
NEW SEARCH
</CustomButton>
</div>
);
<IconButton
size="large"
sx={styles.actions.edit}
onClick={onEdit}
>
<EditNoteRounded />
</IconButton>
<IconButton
size="large"
className="text-red-500"
sx={styles.actions.delete}
onClick={onDelete}
>
<DeleteIcon />
</IconButton>
</div>
);
return pages;
}, [totalPages]);
return (
<div className="flex justify-end mt-4">
<div className="flex items-center gap-2">
<Button
disabled={currentPage === 1}
onClick={() => onPageChange(currentPage - 1)}
sx={styles.pagination.navButton(currentPage === 1)}
>
Prev
</Button>
return (
<Button
key={pageNum}
onClick={() => onPageChange(pageNum)}
sx={styles.pagination.button(currentPage === pageNum)}
>
{pageNum}
</Button>
);
})}
<Button
disabled={currentPage === totalPages}
onClick={() => onPageChange(currentPage + 1)}
sx={styles.pagination.navButton(currentPage === totalPages)}
>
Next
</Button>
</div>
</div>
);
};
// Main component
export default function CriteriaManagement() {
const [page, setPage] = useState(1);
const [searchTerm, setSearchTerm] = useState("");
const [loading, setLoading] = useState(false);
const [criteriaData, setCriteriaData] = useState<CriteriaItem[]>([]);
// In a real app, this would be calculated based on total items and items per
page
const totalPages = 10;
fetchData();
}, []);
// Handle actions
const handleNewSearch = () => {
console.log("Creating new search criteria");
// In a real app, this would navigate to a new page or open a modal
};
return (
<div className="p-6 max-w-full bg-gray-50 min-h-screen">
<h2 className="text-[30px] font-bold text-[#0a2559] leading-[40px]
tracking-normal mb-8">
Criteria Management
</h2>
<SearchBar
searchTerm={searchTerm}
onSearchChange={setSearchTerm}
onNewSearch={handleNewSearch}
/>
{loading ? (
<Box sx={{ display: 'flex', justifyContent: 'center', my: 4 }}>
<CircularProgress />
</Box>
) : filteredData.length === 0 ? (
<Box sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
my: 4,
p: 4,
border: '1px solid #e0e0e0',
borderRadius: '10px',
backgroundColor: 'white'
}}>
<InfoOutlined sx={{ fontSize: 48, color: '#0a2559', mb: 2 }} />
<Typography variant="h6" sx={{ mb: 1 }}>No criteria
found</Typography>
<Typography variant="body2" color="textSecondary">
{searchTerm ? 'Try adjusting your search term' : 'Create a
new search to get started'}
</Typography>
</Box>
) : (
<TableContainer component={Paper} sx={styles.table.container}>
<Table className="min-w-[650px]">
<TableHead className="bg-gray-100">
<TableRow>
<TableCell className="py-3">
<div className="flex items-center">
<Typography className="text-black"
sx={styles.typography.header}>
Criteria Name
</Typography>
<KeyboardArrowDownIcon fontSize="small"
className="ml-1 text-gray-500"/>
</div>
</TableCell>
<TableCell align="center" className="py-3">
<Typography className="text-black"
sx={styles.typography.header}>
Companies
</Typography>
</TableCell>
<TableCell align="center" className="py-3">
<Typography className="text-black"
sx={styles.typography.header}>
Shortlist
</Typography>
</TableCell>
<TableCell align="center" className="py-3">
<Typography className="text-black"
sx={styles.typography.header}>
Expressions of interest
</Typography>
</TableCell>
<TableCell className="py-3">
<div className="flex items-center">
<Typography className="text-black"
sx={styles.typography.header}>
Date created
</Typography>
<KeyboardArrowDownIcon fontSize="small"
className="ml-1 text-gray-500"/>
</div>
</TableCell>
<TableCell className="py-3">
<Typography className="text-black"
sx={styles.typography.header}>
Created By
</Typography>
</TableCell>
<TableCell align="center" className="py-3">
<Typography className="text-black"
sx={styles.typography.header}>
Actions
</Typography>
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{filteredData.map((row, index) => (
<TableRow
key={row.id}
sx={styles.table.row(index % 2 === 0)}
className="last:border-0"
>
<TableCell component="th" scope="row"
className="py-4">
<Typography className="text-blue-700"
sx={styles.typography.regular}>
{row.name}
</Typography>
</TableCell>
<TableCell align="center" className="py-4">
<Typography
sx={styles.typography.enterprise}>
{row.companies}
</Typography>
</TableCell>
<TableCell align="center" className="py-4">
<Typography
sx={styles.typography.enterprise}>
{row.shortlist}
</Typography>
</TableCell>
<TableCell align="center" className="py-4">
<Typography
sx={styles.typography.enterprise}>
{row.expressions}
</Typography>
</TableCell>
<TableCell className="py-4">
<Typography sx={styles.typography.regular}>
{row.dateCreated}
</Typography>
</TableCell>
<TableCell className="py-4">
<Typography sx={styles.typography.creator}>
{row.createdBy}
</Typography>
</TableCell>
<TableCell className="py-4">
<ActionButtons
onRun={() => handleRunCriteria(row.id)}
onEdit={() =>
handleEditCriteria(row.id)}
onDelete={() =>
handleDeleteCriteria(row.id)}
/>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
)}