Add more functionality to TransferBox

This commit is contained in:
Matt DiMeglio 2025-06-04 02:29:10 -04:00
parent fe13b651ed
commit 892134d63b
3 changed files with 213 additions and 89 deletions

View file

@ -5,6 +5,70 @@ import DoNotDisturbIcon from '@mui/icons-material/DoNotDisturb';
import KeyboardArrowLeftIcon from '@mui/icons-material/KeyboardArrowLeft'; import KeyboardArrowLeftIcon from '@mui/icons-material/KeyboardArrowLeft';
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight'; import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
const OuterShell = styled('div')`
display: flex;
flex-direction: row;
width: 100%;
justify-content: space-around;
`;
const TransferShell = styled('div')`
display: flex;
flex-direction: column;
width: 100%;
align-items: center;
padding: 5px;
`;
const TransferButtonShell = styled('div')`
display: flex;
flex-direction: column;
width: 25%;
align-items: center;
justify-content: center;
`;
const TransferHeader = styled('div')`
padding-bottom: 10px;
`;
const TransferOuterBox = styled('div')`
display: flex;
width: 200px;
height: 250px;
border: 1px solid black;
border-radius: 5px;
background-color: #E8E8E8;
`;
const TransferInnerBox = styled('div')`
display: flex;
flex-direction: column;
padding: 5px;
`;
const TransferBoxItem = styled('div')`
display: flex;
align-items: center;
width: 188px;
padding: 2px 4px;
background-color: ${({ isSelected }) => (isSelected ? '#D3D3D3' : 'transparent')};
cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};
color: ${({ disabled }) => (disabled ? '#999' : 'inherit')};
border-radius: 4px;
overflow: hidden;
user-select: ${({ disabled }) => (disabled ? 'none' : 'auto')};
opacity: ${({ disabled }) => (disabled ? 0.5 : 1)};
`;
const TransferBoxLabel = styled('span')`
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1;
min-width: 0;
`;
const CenterButton = styled('div')` const CenterButton = styled('div')`
display: flex; display: flex;
justify-content: center; justify-content: center;
@ -26,7 +90,21 @@ const CenterButton = styled('div')`
`} `}
`; `;
export const TransferBox = ({ fields, leftGroup, rightGroup }) => { const sortByLastThenFirst = (arr) => {
return [...arr].sort((a, b) => {
const [aLast, aFirst] = a.value.split(',').map(s => s.trim());
const [bLast, bFirst] = b.value.split(',').map(s => s.trim());
if (aLast < bLast) return -1;
if (aLast > bLast) return 1;
if (aFirst < bFirst) return -1;
if (aFirst > bFirst) return 1;
return 0;
});
};
export const TransferBox = ({ fields, leftGroup, rightGroup, onSave, user={} }) => {
const { const {
id, id,
exclusionList, exclusionList,
@ -35,104 +113,141 @@ export const TransferBox = ({ fields, leftGroup, rightGroup }) => {
} = fields; } = fields;
const [itemSelected, setItemSelected] = useState({}); const [itemSelected, setItemSelected] = useState({});
const [containsSelection, setContainsSelection] = useState([]); const [leftItems, setLeftItems] = useState(sortByLastThenFirst(leftGroup || []));
const [rightItems, setRightItems] = useState(sortByLastThenFirst(rightGroup || []));
const handleItemClick = (item, side) => {
setItemSelected({ ...item, from: side });
};
const arraysEqual = (a, b) => {
if (a.length !== b.length) return false;
const aIds = a.map(i => i.id).sort();
const bIds = b.map(i => i.id).sort();
return JSON.stringify(aIds) === JSON.stringify(bIds);
};
const isLeftArrowEnabled = itemSelected?.from === 'right';
const isRightArrowEnabled = itemSelected?.from === 'left';
const hasChanges = !arraysEqual(leftItems, leftGroup) || !arraysEqual(rightItems, rightGroup);
return ( return (
<div style={{ display: 'flex', flexDirection: 'row', width: '100%', justifyContent: 'space-around' }}> <OuterShell>
<div style={{ display: 'flex', flexDirection: 'column', width: '100%', alignItems: 'center', padding: '5px' }}> <TransferShell>
<div style={{ paddingBottom: '10px' }}> <TransferHeader>
<h2>{oldListLabel}</h2> <h2>{oldListLabel}</h2>
</div> </TransferHeader>
<div style={{ display: 'flex', width: '200px', height: '250px', border: '1px solid black', borderRadius: '5px', backgroundColor: '#E8E8E8' }}> <TransferOuterBox>
<div <TransferInnerBox>
style={{ {leftItems?.filter(leftItem => !rightItems.some(rightItem => rightItem.id === leftItem.id))?.map((j) => {
display: 'flex', const isUser = user?.id === j?.id;
flexDirection: 'column', const isSelected = itemSelected?.id === j?.id && itemSelected?.from === 'left' && !isUser;
padding: '5px',
}}
>
{leftGroup?.map((j, index) => {
return ( return (
<div <TransferBoxItem
key={index} key={j?.id}
style={{ isSelected={isSelected}
whiteSpace: 'nowrap', disabled={isUser}
overflow: 'hidden', onClick={() => {
textOverflow: 'ellipsis', if (isUser) return;
width: '80%', handleItemClick(j, 'left');
padding: '2px',
}} }}
title={j?.value} title={j?.value}
> >
<span>{j?.value}</span> <TransferBoxLabel>
</div> {j?.value}
</TransferBoxLabel>
</TransferBoxItem>
) )
})} })}
</div> </TransferInnerBox>
</div> </TransferOuterBox>
</div> </TransferShell>
<div style={{ display: 'flex', flexDirection: 'column', width: '25%', alignItems: 'center', justifyContent: 'center' }}> <TransferButtonShell>
<CenterButton <CenterButton
onClick={() => { console.log('clicked Right') }} onClick={() => {
if (!itemSelected) return;
if (itemSelected.from === 'left') {
setLeftItems(prev => prev.filter(item => item.id !== itemSelected.id));
setRightItems(prev => sortByLastThenFirst([
...rightItems.filter(item => item.id !== itemSelected.id),
itemSelected
]));
}
setItemSelected({});
}}
color='#A8A8A8' color='#A8A8A8'
buttonEnabled={itemSelected?.id} buttonEnabled={isRightArrowEnabled}
> >
<KeyboardArrowRightIcon /> <KeyboardArrowRightIcon />
</CenterButton> </CenterButton>
<CenterButton <CenterButton
onClick={() => { console.log('clicked Clear') }} onClick={() => {
setLeftItems(sortByLastThenFirst(leftGroup));
setRightItems(sortByLastThenFirst(rightGroup));
setItemSelected({});
}}
color='#FF6666' color='#FF6666'
buttonEnabled={containsSelection?.length > 0} buttonEnabled={hasChanges}
> >
<DoNotDisturbIcon /> <DoNotDisturbIcon />
</CenterButton> </CenterButton>
<CenterButton <CenterButton
onClick={() => { console.log('clicked Save') }} onClick={() => {
return onSave(rightItems?.map((item) => { return item?.id }))
}}
color='#00B33C' color='#00B33C'
buttonEnabled={containsSelection?.length > 0} buttonEnabled={hasChanges}
> >
<CheckIcon /> <CheckIcon />
</CenterButton> </CenterButton>
<CenterButton <CenterButton
onClick={() => { console.log('clicked Left') }} onClick={() => {
if (!itemSelected) return;
if (itemSelected.from === 'right') {
setRightItems(prev => prev.filter(item => item.id !== itemSelected.id));
setLeftItems(prev => sortByLastThenFirst([
...leftItems.filter(item => item.id !== itemSelected.id),
itemSelected
]));
}
setItemSelected({});
}}
color='#A8A8A8' color='#A8A8A8'
buttonEnabled={itemSelected?.id} buttonEnabled={isLeftArrowEnabled}
> >
<KeyboardArrowLeftIcon /> <KeyboardArrowLeftIcon />
</CenterButton> </CenterButton>
</div> </TransferButtonShell>
<div style={{ display: 'flex', flexDirection: 'column', width: '100%', alignItems: 'center', padding: '5px' }}> <TransferShell>
<div style={{ paddingBottom: '10px' }}> <TransferHeader>
<h2>{newListLabel}</h2> <h2>{newListLabel}</h2>
</div> </TransferHeader>
<div style={{ display: 'flex', width: '200px', height: '250px', border: '1px solid black', borderRadius: '5px', backgroundColor: '#E8E8E8' }}> <TransferOuterBox>
<div <TransferInnerBox>
style={{ {rightItems?.map((j) => {
display: 'flex', const isUser = user?.id === j?.id;
flexDirection: 'column', const isSelected = itemSelected?.id === j?.id && itemSelected?.from === 'right' && !isUser;
padding: '5px',
}}
>
{rightGroup?.map((j, index) => {
return ( return (
<div <TransferBoxItem
key={index} key={j?.id}
style={{ isSelected={isSelected}
whiteSpace: 'nowrap', disabled={isUser}
overflow: 'hidden', onClick={() => {
textOverflow: 'ellipsis', if (isUser) return;
width: '80%', handleItemClick(j, 'right');
padding: '2px',
}} }}
title={j?.value} title={j?.value}
> >
<span>{j?.value}</span> <TransferBoxLabel>
</div> {j?.value}
</TransferBoxLabel>
</TransferBoxItem>
) )
})} })}
</div> </TransferInnerBox>
</div> </TransferOuterBox>
</div> </TransferShell>
</div> </OuterShell>
); );
} }

View file

@ -285,8 +285,22 @@ export const Settings = () => {
}, [pageValue?.id, windowWidth, window.innerHeight]); }, [pageValue?.id, windowWidth, window.innerHeight]);
useEffect(() => { useEffect(() => {
setPageValue(settingsFields?.filter((field) => field?.tab === tabValue?.value)[0]); const filteredFields = settingsFields?.filter((field) => {
}, [tabValue]); const hasAccess =
(field?.accessRequired === 'administrator' && isAdministrator) ||
(field?.accessRequired === 'manager' && isManager) ||
(field?.accessRequired === 'scheduler' && isScheduler) ||
(!field?.accessRequired || field?.accessRequired === 'user');
return field?.tab === tabValue?.value && hasAccess;
});
if (filteredFields.length > 0) {
setPageValue(filteredFields[0]);
} else {
setPageValue(null);
}
}, [tabValue, isAdministrator, isManager, isScheduler]);
return ( return (
<div> <div>
@ -433,9 +447,11 @@ export const Settings = () => {
} else if (field?.type === 'transfer') { } else if (field?.type === 'transfer') {
fieldType = <TransferBox fieldType = <TransferBox
style={{ display: 'flex', flexDirection: 'row' }} style={{ display: 'flex', flexDirection: 'row' }}
user={user}
fields={field} fields={field}
leftGroup={department[field?.origList]} leftGroup={department[field?.origList]}
rightGroup={department[field?.id]} rightGroup={department[field?.id]}
onSave={(t) => console.log(t)}
/> />
} }
return field?.type !== 'header' && ( return field?.type !== 'header' && (

View file

@ -85,22 +85,22 @@ export const settingsFields = [
title: 'Roles', title: 'Roles',
tab: 'department', tab: 'department',
cards: [ cards: [
{ // Need to decide if Admins should be able to Add other Admins
id: 'companyAdmins', // {
label: 'Company Administrators', // id: 'companyAdmins',
fields: [ // label: 'Company Administrators',
{ // fields: [
id: 'administrators', // {
type: 'transfer', // id: 'administrators',
exclusionList: [], // type: 'transfer',
origList: 'users', // origList: 'users',
oldListLabel: 'Users', // oldListLabel: 'Users',
newListLabel: 'Administrators' // newListLabel: 'Administrators'
}, // },
], // ],
accessRequired: 'administrator', // accessRequired: 'administrator',
removeEdit: true // removeEdit: true
}, // },
{ {
id: 'companyMgrs', id: 'companyMgrs',
label: 'Company Managers', label: 'Company Managers',
@ -108,9 +108,6 @@ export const settingsFields = [
{ {
id: 'managers', id: 'managers',
type: 'transfer', type: 'transfer',
exclusionList: [
'administrators'
],
origList: 'users', origList: 'users',
oldListLabel: 'Users', oldListLabel: 'Users',
newListLabel: 'Managers' newListLabel: 'Managers'
@ -126,10 +123,6 @@ export const settingsFields = [
{ {
id: 'schedulers', id: 'schedulers',
type: 'transfer', type: 'transfer',
exclusionList: [
'administrators',
'managers'
],
origList: 'users', origList: 'users',
oldListLabel: 'Users', oldListLabel: 'Users',
newListLabel: 'Schedulers' newListLabel: 'Schedulers'