import React, { useState, useContext } from "react"; import { Dialog, DialogTitle, DialogContent, Box, TextField, Button, Typography, List, ListItem, ListItemText, Checkbox, InputAdornment, } from "@mui/material"; import { Search as SearchIcon } from "@mui/icons-material"; import { Context } from "../context/ContextApi.jsx"; import { getTheme } from "../theme.jsx"; /** * A reusable dialog for selecting/distributing sub-organizations. * * Props: * open {boolean} - controls dialog visibility * onClose {function} - called on Cancel or backdrop click (no args) * title {string} - dialog title text * extraInfo {string} - secondary line below the title (e.g. "Selected Key: xxx") * orgs {Array} - ordered array of { id, name, image? } objects to display * selectedOrgIds {string[]} - currently selected org IDs (controlled) * onSelectionChange {function} - called with a updater fn (prev => next) when selection changes * onSave {function} - called with the final selectedOrgIds array when Save is clicked * disabled {boolean} - disables checkboxes and Save button (default: false) */ const SubOrgDistributionDialog = ({ open, onClose, title, extraInfo = null, orgs = [], selectedOrgIds = [], onSelectionChange, onSave, disabled = false, }) => { const [searchQuery, setSearchQuery] = useState(""); const { themeMode, brandColor } = useContext(Context); const theme = getTheme(themeMode, brandColor); const safeOrgs = orgs || []; const filteredOrgs = safeOrgs.filter( o => o && o.name.toLowerCase().includes(searchQuery.toLowerCase()) ); const handleSelectAll = () => { if (searchQuery) { const filteredIds = filteredOrgs.map(o => o.id); onSelectionChange(prev => [...new Set([...prev, ...filteredIds])]); } else { const allIds = safeOrgs.map(o => o.id); onSelectionChange(prev => [...new Set([...prev, ...allIds])]); } }; const handleDeselectAll = () => { if (searchQuery) { const filteredIds = filteredOrgs.map(o => o.id); onSelectionChange(prev => prev.filter(id => !filteredIds.includes(id))); } else { onSelectionChange([]); } }; const handleToggle = (id) => { if (disabled) return; onSelectionChange(prev => prev.includes(id) ? prev.filter(i => i !== id) : [...prev, id] ); }; const handleClose = () => { setSearchQuery(""); onClose(); }; const filteredSelected = filteredOrgs.filter(o => selectedOrgIds.includes(o.id)).length; const countText = searchQuery ? `${filteredSelected} of ${filteredOrgs.length} filtered selected` : `${selectedOrgIds.length} of ${safeOrgs.length} selected`; const imageSize = 22; const imageStyle = { width: imageSize, height: imageSize, pointerEvents: "none", marginRight: 10 }; return ( {title} {extraInfo && ( {extraInfo} )} setSearchQuery(e.target.value)} InputProps={{ startAdornment: ( ), style: { color: theme.palette.textFieldStyle?.color }, }} style={{ backgroundColor: theme.palette.textFieldStyle?.backgroundColor, flexShrink: 0 }} />
{countText}
{filteredOrgs.map((org, index) => { const isSelected = selectedOrgIds.includes(org.id); const hasImage = org.image !== undefined; return ( handleToggle(org.id)} sx={{ cursor: disabled ? "default" : "pointer", backgroundColor: index % 2 === 0 ? "transparent" : themeMode === "dark" ? "rgba(255,255,255,0.02)" : "rgba(0,0,0,0.02)", "&:hover": { backgroundColor: themeMode === "dark" ? "rgba(255,255,255,0.05)" : "rgba(0,0,0,0.05)", }, }} > {hasImage && ( org.image === "" ? ( {org.name} ) : ( {org.name} ) )} ); })} {filteredOrgs.length === 0 && ( )}
); }; export default SubOrgDistributionDialog;