import React, {useState, useEffect} from "react"; import { useDispatch, useSelector } from "react-redux"; import { useNavigate, useParams } from "react-router-dom"; import { customerSlice } from "./../../store"; import { AuthService, CustomerService, EventsService, LabelService } from "../../services"; import { CUSTOMER_TYPE, ManageTable } from "../../shared"; import { Spinner, Breadcrumb, BreadcrumbItem, Tabs, Tab, Dropdown, Modal } from "react-bootstrap"; import { Columns, Download, Filter, PencilSquare, PersonSquare, Plus } from "react-bootstrap-icons"; const DashboardCustomersList = ({ additionalButtons, showBreadcrumb = false, title = null }) => { const navigate = useNavigate(); const dispatch = useDispatch(); const site = EventsService.site; const [customers, setCustomers] = useState([]); const [keyword, setKeyword] = useState(''); const [showInactive, setShowInactive] = useState(false); const [transferMap, setTransferMap] = useState({}); const [showSpinner, setShowSpinner] = useState(false); const [sorting, setSorting] = useState({key: '', order: ''}); const [selectedItems, setSelectedItems] = useState([]); const [filteredCustomers, setFilteredCustomers] = useState(customers); const [showFilterDropdown, setShowFilterDropdown] = useState(false); const [showManageTableDropdown, setShowManageTableDropdown] = useState(false); const [showExportDropdown, setShowExportDropdown] = useState(false); const [tagsFilter, setTagsFilter] = useState([]); const [availableLabels, setAvailableLabels] = useState([]); const [showAvatarModal, setShowAvatarModal] = useState(false); const [avatarData, setAvatarData] = useState(null); const [avatarCustomerName, setAvatarCustomerName] = useState(''); const [avatarLoading, setAvatarLoading] = useState(false); const [customerAvatars, setCustomerAvatars] = useState({}); const isAllCustomersPage = title === 'All Customers'; const [columns, setColumns] = useState([ { key: 'name', label:'Name', show: true }, { key: 'chinese_name', label: 'Preferred Name', show: true }, { key: 'email', label: 'Email', show: true }, { key: 'type', label: 'Type', show: true }, { key: 'pickup_status', label: 'Pickup Status', show: true }, { key: 'birth_date', label: 'Date of Birth', show: true }, { key: 'gender', label: 'Gender', show: true }, { key: 'language', label: 'Language', show: true }, { key: 'medicare_number', label: 'Medicare Number', show: true }, { key: 'medicaid_number', label: 'Medicaid Number', show: true }, { key: 'address', label: 'Address', show: true }, { key: 'phone', label: 'Phone', show: true }, { key: 'emergency_contact', label: 'Fasting', show: true }, { key: 'tags', label: 'Tags', show: true } ]); useEffect(() => { if (!AuthService.canViewCustomers()) { window.alert('You haven\'t login yet OR this user does not have access to this page. Please change an admin account to login.') AuthService.logout(); navigate(`/login`); } CustomerService.getAllCustomers().then((data) => { setCustomers(data.data.map((item) =>{ item.phone = item?.phone || item?.home_phone || item?.mobile_phone; item.address = item?.address1 || item?.address2 || item?.address3 || item?.address4|| item?.address5; return item; }).sort((a, b) => a.lastname > b.lastname ? 1: -1)); }) LabelService.getAll().then((data) => { setAvailableLabels(data.data); }) }, []); // Load avatars for customers - same approach as ViewCustomer useEffect(() => { if (customers.length === 0) return; customers.forEach((customer) => { if (customerAvatars[customer.id] !== undefined) return; // Already loaded or attempted // Mark as loading to prevent duplicate requests setCustomerAvatars(prev => ({ ...prev, [customer.id]: false })); CustomerService.getAvatar(customer.id) .then(result => { if (result?.data) { // Store raw data exactly like ViewCustomer does setCustomerAvatars(prev => ({ ...prev, [customer.id]: result.data })); } else { setCustomerAvatars(prev => ({ ...prev, [customer.id]: null })); } }) .catch(() => { setCustomerAvatars(prev => ({ ...prev, [customer.id]: null })); }); }); }, [customers]); useEffect(() => { let filtered = customers; // Basic keyword filter if (keyword) { filtered = filtered.filter((item) => item?.name.toLowerCase().includes(keyword.toLowerCase())); } // Active/Inactive filter if (showInactive) { // Discharged Customers tab: show customers with type discharged, transferred, or deceased filtered = filtered.filter(item => item.type === CUSTOMER_TYPE.TRANSFERRED || item.type === CUSTOMER_TYPE.DECEASED || item.type === CUSTOMER_TYPE.DISCHARGED); } else { // Active Customers tab: show customers who are active AND not discharged/transferred/deceased filtered = filtered.filter(item => item.status === 'active' && item.type !== CUSTOMER_TYPE.TRANSFERRED && item.type !== CUSTOMER_TYPE.DECEASED && item.type !== CUSTOMER_TYPE.DISCHARGED); } // Tags filter if (tagsFilter.length > 0) { filtered = filtered.filter(item => { if (!item?.tags || item.tags.length === 0) return false; return tagsFilter.some(tag => item.tags.includes(tag)); }); } setFilteredCustomers(filtered); }, [keyword, customers, showInactive, tagsFilter]) useEffect(() => { const newCustomers = [...customers]; const sortedCustomers = sorting.key === '' ? newCustomers : newCustomers.sort((a, b) => { return a[sorting.key]?.localeCompare(b[sorting.key]); }); setCustomers( sorting.order === 'asc' ? sortedCustomers : sortedCustomers.reverse() ) }, [sorting]); const getSortingImg = (key) => { return sorting.key === key ? (sorting.order === 'asc' ? 'up_arrow' : 'down_arrow') : 'default'; } const sortTableWithField = (key) => { if (sorting.key === key) { setSorting({key: key, order: sorting.order === 'asc' ? 'desc' : 'asc'}); } else { setSorting({key: key, order: 'asc'}); } } const toggleSelectedAllItems = () => { if (selectedItems.length === filteredCustomers.length) { setSelectedItems([]); } else { setSelectedItems(filteredCustomers.map(item => item.id)); } } const toggleItem = (id) => { if (selectedItems.includes(id)) { setSelectedItems(selectedItems.filter(item => item !== id)); } else { setSelectedItems([...selectedItems, id]); } } const showArchive = (value) => { setShowInactive(value === 'archivedCustomers'); } const checkSelectAll = () => { return selectedItems.length === filteredCustomers.length && filteredCustomers.length > 0; } const cleanFilterAndClose = () => { setTagsFilter([]); setShowFilterDropdown(false); } const FilterAndClose = () => { setShowFilterDropdown(false); } const toggleTagFilter = (tagName) => { if (tagsFilter.includes(tagName)) { setTagsFilter(tagsFilter.filter(tag => tag !== tagName)); } else { setTagsFilter([...tagsFilter, tagName]); } } const handleColumnsChange = (newColumns) => { setColumns(newColumns); } const goToEdit = (id) => { navigate(`/customers/edit/${id}`); } const goToCreateNew = () => { navigate(`/customers`); } const setTransferValue = (customerId, site) => { setTransferMap(prev => ({ ...prev, [customerId]: site })); } const goToView = (id) => { navigate(`/customers/${id}`); } const showProfilePicture = (customer) => { setAvatarCustomerName(customer?.name || ''); setAvatarData(null); setAvatarLoading(true); setShowAvatarModal(true); CustomerService.getAvatar(customer?.id).then((data) => { setAvatarData(data.data); setAvatarLoading(false); }).catch(() => { setAvatarLoading(false); }); } const closeAvatarModal = () => { setShowAvatarModal(false); setAvatarData(null); setAvatarCustomerName(''); } const table =
{ columns.filter(col => col.show).map((column, index) => ) } { filteredCustomers.map((customer, index) => {columns.find(col => col.key === 'name')?.show && } {columns.find(col => col.key === 'chinese_name')?.show && } {columns.find(col => col.key === 'email')?.show && } {columns.find(col => col.key === 'type')?.show && } {columns.find(col => col.key === 'pickup_status')?.show && } {columns.find(col => col.key === 'birth_date')?.show && } {columns.find(col => col.key === 'gender')?.show && } {columns.find(col => col.key === 'language')?.show && } {columns.find(col => col.key === 'medicare_number')?.show && } {columns.find(col => col.key === 'medicaid_number')?.show && } {columns.find(col => col.key === 'address')?.show && } {columns.find(col => col.key === 'phone')?.show && } {columns.find(col => col.key === 'emergency_contact')?.show && } {columns.find(col => col.key === 'tags')?.show && } ) }
No. {column.label} sortTableWithField(column.key)}>
{index + 1}
{AuthService.canViewCustomers() && ( customerAvatars[customer.id] && customerAvatars[customer.id] !== false ? ( {customer?.name} showProfilePicture(customer)} style={{ width: '64px', height: '64px', borderRadius: '8px', objectFit: 'cover', cursor: 'pointer', flexShrink: 0 }} /> ) : ( showProfilePicture(customer)} size={64} className="clickable" style={{ flexShrink: 0, color: '#ccc' }} /> ) )} {AuthService.canAddOrEditCustomers() && isAllCustomersPage ? goToEdit(customer?.id) : goToView(customer?.id)} style={{ flexShrink: 0 }}>} goToView(customer?.id)}>{customer?.name}
{customer?.name_cn}{customer?.email}{customer?.type}{customer?.pickup_status}{customer?.birth_date}{customer?.gender}{customer?.language}{customer?.medicare_number}{customer?.medicaid_number}{customer?.address1 || customer?.address2 || customer?.address3 || customer?.address4 || customer?.address5}{customer?.phone || customer?.home_phone || customer?.mobile_phone}{customer?.emergency_contact}{customer?.tags?.join(', ')}
; const customFilterMenu = React.forwardRef( ({ children, style, className, 'aria-labelledby': labeledBy }, ref) => { return (
Filter By
Tags
{availableLabels.map((label) => (
toggleTagFilter(label.label_name)} />
))}
); }, ); return ( <> {showSpinner &&
Loading...
} {showBreadcrumb && (
General Customer Information

{title || 'All Customers'}

)}
showArchive(k)}> {table} {table}
setKeyword(e.currentTarget.value)} /> { if (isOpen) { setShowManageTableDropdown(false); setShowExportDropdown(false); } setShowFilterDropdown(isOpen); }} autoClose={false} > Filter { if (isOpen) { setShowFilterDropdown(false); setShowExportDropdown(false); } setShowManageTableDropdown(isOpen); }} /> {typeof additionalButtons === 'function' ? additionalButtons({ showExportDropdown, onExportToggle: (isOpen) => { if (isOpen) { setShowFilterDropdown(false); setShowManageTableDropdown(false); } setShowExportDropdown(isOpen); } }) : additionalButtons }
{avatarCustomerName} {avatarLoading && } {!avatarLoading && avatarData && ( {avatarCustomerName} )} {!avatarLoading && !avatarData && (
No profile picture available
)}
) }; export default DashboardCustomersList;