Set Up bases of Roles Page
This commit is contained in:
parent
ea06cc04e6
commit
fe13b651ed
6 changed files with 558 additions and 237 deletions
138
components/common/TransferBox/TransferBox.jsx
Normal file
138
components/common/TransferBox/TransferBox.jsx
Normal file
|
|
@ -0,0 +1,138 @@
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import CheckIcon from '@mui/icons-material/Check';
|
||||||
|
import DoNotDisturbIcon from '@mui/icons-material/DoNotDisturb';
|
||||||
|
import KeyboardArrowLeftIcon from '@mui/icons-material/KeyboardArrowLeft';
|
||||||
|
import KeyboardArrowRightIcon from '@mui/icons-material/KeyboardArrowRight';
|
||||||
|
|
||||||
|
const CenterButton = styled('div')`
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
border: 1px solid black;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin: 5px;
|
||||||
|
cursor: ${({ buttonEnabled }) => (buttonEnabled ? 'pointer' : 'not-allowed')};
|
||||||
|
transition: background-color 0.3s ease, color 0.3s ease;
|
||||||
|
opacity: ${({ buttonEnabled }) => (buttonEnabled ? 1 : 0.5)};
|
||||||
|
|
||||||
|
${({ color, buttonEnabled }) => buttonEnabled && color && `
|
||||||
|
&:hover {
|
||||||
|
background-color: ${color};
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const TransferBox = ({ fields, leftGroup, rightGroup }) => {
|
||||||
|
const {
|
||||||
|
id,
|
||||||
|
exclusionList,
|
||||||
|
oldListLabel,
|
||||||
|
newListLabel
|
||||||
|
} = fields;
|
||||||
|
|
||||||
|
const [itemSelected, setItemSelected] = useState({});
|
||||||
|
const [containsSelection, setContainsSelection] = useState([]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'row', width: '100%', justifyContent: 'space-around' }}>
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column', width: '100%', alignItems: 'center', padding: '5px' }}>
|
||||||
|
<div style={{ paddingBottom: '10px' }}>
|
||||||
|
<h2>{oldListLabel}</h2>
|
||||||
|
</div>
|
||||||
|
<div style={{ display: 'flex', width: '200px', height: '250px', border: '1px solid black', borderRadius: '5px', backgroundColor: '#E8E8E8' }}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
padding: '5px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{leftGroup?.map((j, index) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
style={{
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
width: '80%',
|
||||||
|
padding: '2px',
|
||||||
|
}}
|
||||||
|
title={j?.value}
|
||||||
|
>
|
||||||
|
<span>{j?.value}</span>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column', width: '25%', alignItems: 'center', justifyContent: 'center' }}>
|
||||||
|
<CenterButton
|
||||||
|
onClick={() => { console.log('clicked Right') }}
|
||||||
|
color='#A8A8A8'
|
||||||
|
buttonEnabled={itemSelected?.id}
|
||||||
|
>
|
||||||
|
<KeyboardArrowRightIcon />
|
||||||
|
</CenterButton>
|
||||||
|
<CenterButton
|
||||||
|
onClick={() => { console.log('clicked Clear') }}
|
||||||
|
color='#FF6666'
|
||||||
|
buttonEnabled={containsSelection?.length > 0}
|
||||||
|
>
|
||||||
|
<DoNotDisturbIcon />
|
||||||
|
</CenterButton>
|
||||||
|
<CenterButton
|
||||||
|
onClick={() => { console.log('clicked Save') }}
|
||||||
|
color='#00B33C'
|
||||||
|
buttonEnabled={containsSelection?.length > 0}
|
||||||
|
>
|
||||||
|
<CheckIcon />
|
||||||
|
</CenterButton>
|
||||||
|
<CenterButton
|
||||||
|
onClick={() => { console.log('clicked Left') }}
|
||||||
|
color='#A8A8A8'
|
||||||
|
buttonEnabled={itemSelected?.id}
|
||||||
|
>
|
||||||
|
<KeyboardArrowLeftIcon />
|
||||||
|
</CenterButton>
|
||||||
|
</div>
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column', width: '100%', alignItems: 'center', padding: '5px' }}>
|
||||||
|
<div style={{ paddingBottom: '10px' }}>
|
||||||
|
<h2>{newListLabel}</h2>
|
||||||
|
</div>
|
||||||
|
<div style={{ display: 'flex', width: '200px', height: '250px', border: '1px solid black', borderRadius: '5px', backgroundColor: '#E8E8E8' }}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
padding: '5px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{rightGroup?.map((j, index) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
style={{
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
width: '80%',
|
||||||
|
padding: '2px',
|
||||||
|
}}
|
||||||
|
title={j?.value}
|
||||||
|
>
|
||||||
|
<span>{j?.value}</span>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
1
components/common/TransferBox/index.js
Normal file
1
components/common/TransferBox/index.js
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export { TransferBox } from './TransferBox';
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
export { ToggleTabs } from './ToggleTabs';
|
export { ToggleTabs } from './ToggleTabs';
|
||||||
|
export { TransferBox } from './TransferBox';
|
||||||
|
|
@ -3,7 +3,10 @@ import styled from '@emotion/styled';
|
||||||
import { Stack } from '@mui/material';
|
import { Stack } from '@mui/material';
|
||||||
import EditIcon from '@mui/icons-material/Edit';
|
import EditIcon from '@mui/icons-material/Edit';
|
||||||
import EditOffIcon from '@mui/icons-material/EditOff';
|
import EditOffIcon from '@mui/icons-material/EditOff';
|
||||||
import { ToggleTabs, useLocalStore } from '@components';
|
import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank';
|
||||||
|
import CheckBoxIcon from '@mui/icons-material/CheckBox';
|
||||||
|
import { ToggleTabs, TransferBox, useLocalStore } from '@components';
|
||||||
|
import { settingsFields } from './helpers';
|
||||||
|
|
||||||
const OuterContainer = styled(Stack)`
|
const OuterContainer = styled(Stack)`
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
@ -57,7 +60,8 @@ const CardShell = styled('div')`
|
||||||
|
|
||||||
const Card = styled('div')`
|
const Card = styled('div')`
|
||||||
background-color: #C7C7C7;
|
background-color: #C7C7C7;
|
||||||
width: 1000px;
|
width: 50%;
|
||||||
|
min-width: 750px;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
|
|
@ -113,14 +117,16 @@ const InnerCard = styled('div')`
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
width: 50%;
|
width: 50%;
|
||||||
|
|
||||||
|
${({ centered }) => centered && `
|
||||||
|
align-items: center;
|
||||||
|
`}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const InnerCardRow = styled('div')`
|
const InnerCardRow = styled('div')`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
align-items: center;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const InnerCardRowLabel = styled('label')`
|
const InnerCardRowLabel = styled('label')`
|
||||||
|
|
@ -169,114 +175,13 @@ const FormInputButton = styled('input')`
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const settingsFields = [
|
|
||||||
{
|
|
||||||
id: 'deptInfo',
|
|
||||||
title: 'Information',
|
|
||||||
tab: 'department',
|
|
||||||
cards: [
|
|
||||||
{
|
|
||||||
id: 'companyInfo',
|
|
||||||
label: 'Company Information',
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
id: 'company',
|
|
||||||
label: 'Company Name',
|
|
||||||
type: 'text',
|
|
||||||
readOnly: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'billing_address',
|
|
||||||
label: 'Billing Address',
|
|
||||||
type: 'text'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'town',
|
|
||||||
label: 'Town',
|
|
||||||
type: 'text'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'state',
|
|
||||||
label: 'State',
|
|
||||||
type: 'text'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'postal',
|
|
||||||
label: 'Postal Code',
|
|
||||||
type: 'text'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'country',
|
|
||||||
label: 'Country',
|
|
||||||
type: 'text'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'phone',
|
|
||||||
label: 'Phone Number',
|
|
||||||
type: 'phone'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'display_time',
|
|
||||||
label: 'Display Time',
|
|
||||||
type: 'select',
|
|
||||||
options: [
|
|
||||||
{ label: '12 Hour AM/PM', value: '12' },
|
|
||||||
{ label: '24 Hour', value: '24' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'start_day',
|
|
||||||
label: 'Calendar Start Day',
|
|
||||||
type: 'select',
|
|
||||||
options: [
|
|
||||||
{ label: 'Sunday', value: 'sunday' },
|
|
||||||
{ label: 'Monday', value: 'monday' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'deptPerms',
|
|
||||||
title: 'Permissions',
|
|
||||||
tab: 'department',
|
|
||||||
cards: []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'deptMgrs',
|
|
||||||
title: 'Managers',
|
|
||||||
tab: 'department',
|
|
||||||
cards: []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'deptSubs',
|
|
||||||
title: 'Subscriptions',
|
|
||||||
tab: 'department',
|
|
||||||
cards: []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'personalInfo',
|
|
||||||
title: 'Information',
|
|
||||||
tab: 'personal',
|
|
||||||
cards: []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'personalNoti',
|
|
||||||
title: 'Notifications',
|
|
||||||
tab: 'personal',
|
|
||||||
cards: []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'deptNoti',
|
|
||||||
title: 'Notifications',
|
|
||||||
tab: 'department',
|
|
||||||
cards: []
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
export const Settings = () => {
|
export const Settings = () => {
|
||||||
const { user, department, setDepartment } = useLocalStore();
|
const { user, department, setDepartment } = useLocalStore();
|
||||||
|
|
||||||
|
const isAdministrator = user?.administrator;
|
||||||
|
const isManager = user?.manager;
|
||||||
|
const isScheduler = user?.scheduler;
|
||||||
|
|
||||||
const originalDepartmentRef = useRef(department);
|
const originalDepartmentRef = useRef(department);
|
||||||
const [formValues, setFormValues] = useState(() => {
|
const [formValues, setFormValues] = useState(() => {
|
||||||
const initial = {};
|
const initial = {};
|
||||||
|
|
@ -301,6 +206,7 @@ export const Settings = () => {
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
|
||||||
const [editMode, setEditMode] = useState(null);
|
const [editMode, setEditMode] = useState(null);
|
||||||
const [tabValue, setTabValue] = useState(tabs[0]);
|
const [tabValue, setTabValue] = useState(tabs[0]);
|
||||||
const [pageValue, setPageValue] = useState({});
|
const [pageValue, setPageValue] = useState({});
|
||||||
|
|
@ -354,6 +260,18 @@ export const Settings = () => {
|
||||||
document.title = 'ShiftSync | Settings';
|
document.title = 'ShiftSync | Settings';
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleResize = () => setWindowWidth(window.innerWidth);
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
|
|
||||||
|
// Initial trigger (in case something else needs it)
|
||||||
|
handleResize();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('resize', handleResize);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (pageValue?.id && pageRefs.current[pageValue.id]) {
|
if (pageValue?.id && pageRefs.current[pageValue.id]) {
|
||||||
const el = pageRefs.current[pageValue.id];
|
const el = pageRefs.current[pageValue.id];
|
||||||
|
|
@ -364,7 +282,7 @@ export const Settings = () => {
|
||||||
width: rect.width
|
width: rect.width
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [pageValue?.id]);
|
}, [pageValue?.id, windowWidth, window.innerHeight]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setPageValue(settingsFields?.filter((field) => field?.tab === tabValue?.value)[0]);
|
setPageValue(settingsFields?.filter((field) => field?.tab === tabValue?.value)[0]);
|
||||||
|
|
@ -372,7 +290,7 @@ export const Settings = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{user?.administrator ? (
|
{user?.administrator || user?.manager ? (
|
||||||
<OuterContainer>
|
<OuterContainer>
|
||||||
<ToggleTabs
|
<ToggleTabs
|
||||||
tabs={tabs}
|
tabs={tabs}
|
||||||
|
|
@ -383,7 +301,12 @@ export const Settings = () => {
|
||||||
</OuterContainer>
|
</OuterContainer>
|
||||||
) : null }
|
) : null }
|
||||||
<OuterContainer>
|
<OuterContainer>
|
||||||
{settingsFields?.filter((field) => field?.tab === tabValue?.value)?.map((field) => {
|
{settingsFields?.filter((field) => field?.tab === tabValue?.value)?.filter((field) => {
|
||||||
|
return ((field?.accessRequired === 'administrator' && isAdministrator) ||
|
||||||
|
(field?.accessRequired === 'manager' && isManager) ||
|
||||||
|
(field?.accessRequired === 'scheduler' && isScheduler) ||
|
||||||
|
(field?.accessRequired === 'user' || !field?.accessRequired))
|
||||||
|
})?.map((field) => {
|
||||||
return (
|
return (
|
||||||
<Tab
|
<Tab
|
||||||
key={field?.id}
|
key={field?.id}
|
||||||
|
|
@ -399,124 +322,153 @@ export const Settings = () => {
|
||||||
<Border />
|
<Border />
|
||||||
<CardShell>
|
<CardShell>
|
||||||
{pageValue?.cards?.map((card) => {
|
{pageValue?.cards?.map((card) => {
|
||||||
return (
|
if (
|
||||||
<Card
|
(card?.accessRequired === 'administrator' && isAdministrator) ||
|
||||||
key={`${card?.id}-card`}
|
(card?.accessRequired === 'manager' && isManager) ||
|
||||||
>
|
(card?.accessRequired === 'scheduler' && isScheduler)
|
||||||
<CardTitle
|
) {
|
||||||
key={`${card?.id}-card-title`}
|
return (
|
||||||
|
<Card
|
||||||
|
key={`${card?.id}-card`}
|
||||||
>
|
>
|
||||||
{card?.label}
|
<CardTitle
|
||||||
</CardTitle>
|
key={`${card?.id}-card-title`}
|
||||||
<Border key={`${card?.id}-border-1`}/>
|
|
||||||
<CardHeader
|
|
||||||
key={`${card?.id}-card-header`}
|
|
||||||
>
|
|
||||||
<p>
|
|
||||||
Employee Count: {department?.employeeCount}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Subscription Expiration: {department?.subscriptionExpiration}
|
|
||||||
</p>
|
|
||||||
</CardHeader>
|
|
||||||
<Border key={`${card?.id}-border-2`}/>
|
|
||||||
<form
|
|
||||||
onSubmit={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
onSubmit(changedFields);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<EditArea>
|
|
||||||
{editMode === card?.id ? (
|
|
||||||
<EditTextButton onClick={() => setEditMode(null)}>
|
|
||||||
<EditOffIcon sx={{ fontSize: 20 }} />
|
|
||||||
<p>View</p>
|
|
||||||
</EditTextButton>
|
|
||||||
) : (
|
|
||||||
<EditTextButton onClick={() => setEditMode(card?.id)}>
|
|
||||||
<EditIcon sx={{ fontSize: 20 }} />
|
|
||||||
<p>Edit</p>
|
|
||||||
</EditTextButton>
|
|
||||||
)}
|
|
||||||
</EditArea>
|
|
||||||
<CardBody
|
|
||||||
key={`${card?.id}-card-body`}
|
|
||||||
>
|
>
|
||||||
<InnerCard
|
{card?.label}
|
||||||
key={`${card?.id}-inner-card`}
|
</CardTitle>
|
||||||
>
|
{card?.fields?.find((field) => field?.type === 'header') !== undefined && (
|
||||||
{card?.fields?.map((field) => {
|
<div>
|
||||||
let fieldType;
|
<Border key={`${card?.id}-border-1`}/>
|
||||||
if (field?.type === 'text') {
|
<CardHeader
|
||||||
fieldType = <InnerCardRowInput
|
key={`${card?.id}-card-header`}
|
||||||
name={field?.id}
|
>
|
||||||
disabled={card?.id !== editMode || field?.readOnly}
|
{card?.fields?.map((field) => {
|
||||||
value={formValues[field?.id] ?? 'Not Provided'}
|
return field?.type === 'header' && (
|
||||||
onChange={(e) => handleChange(e, 'text')}
|
<InnerCardRow key={`${field?.id}-row`}>
|
||||||
/>;
|
<p style={{ fontSize: 14 }}>
|
||||||
} else if (field?.type === 'phone') {
|
{field?.label}:
|
||||||
fieldType = <InnerCardRowInput
|
</p>
|
||||||
type="tel"
|
<p style={{ paddingLeft: 10, fontSize: 14 }}>
|
||||||
name="phone"
|
{department[field?.id]}
|
||||||
placeholder="(123) 456-7890"
|
</p>
|
||||||
value={formValues[field?.id]}
|
</InnerCardRow>
|
||||||
disabled={card?.id !== editMode || field?.readOnly}
|
|
||||||
onChange={(e) => handleChange(e, 'phone')}
|
|
||||||
pattern="\(\d{3}\) \d{3}-\d{4}"
|
|
||||||
maxlength="14"
|
|
||||||
/>
|
|
||||||
} else if (field?.type === 'select') {
|
|
||||||
fieldType = (
|
|
||||||
<InnerCardRowRadioDiv>
|
|
||||||
{field?.options?.map((option) => {
|
|
||||||
const inputId = `${field.id}-${option.value}`;
|
|
||||||
return (
|
|
||||||
<FormRadioButtonLabel htmlFor={inputId} key={inputId}>
|
|
||||||
<InnerCardRadioInput
|
|
||||||
type="radio"
|
|
||||||
id={inputId}
|
|
||||||
name={field?.id}
|
|
||||||
value={option?.value}
|
|
||||||
checked={formValues[field.id] === option.value}
|
|
||||||
disabled={card?.id !== editMode || field?.readOnly}
|
|
||||||
onChange={(e) => handleChange(e, 'text')}
|
|
||||||
/>
|
|
||||||
<InnerCardRadioLabel htmlFor={inputId} key={inputId}>
|
|
||||||
{option?.label}
|
|
||||||
</InnerCardRadioLabel>
|
|
||||||
</FormRadioButtonLabel>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</InnerCardRowRadioDiv>
|
|
||||||
)
|
)
|
||||||
}
|
})}
|
||||||
return (
|
</CardHeader>
|
||||||
<InnerCardRow key={`${field?.id}-row`}>
|
</div>
|
||||||
<InnerCardRowLabel>
|
|
||||||
{field?.label}:
|
|
||||||
</InnerCardRowLabel>
|
|
||||||
{fieldType}
|
|
||||||
</InnerCardRow>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</InnerCard>
|
|
||||||
</CardBody>
|
|
||||||
{card?.id === editMode && (
|
|
||||||
<FormInputButtonDiv>
|
|
||||||
<FormInputButton
|
|
||||||
type="submit"
|
|
||||||
value="Save"
|
|
||||||
disabled={!hasChanges}
|
|
||||||
style={{
|
|
||||||
backgroundColor: hasChanges ? '#4D79FF' : '',
|
|
||||||
color: hasChanges ? 'white' : ''
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</FormInputButtonDiv>
|
|
||||||
)}
|
)}
|
||||||
</form>
|
<Border key={`${card?.id}-border-2`}/>
|
||||||
</Card>
|
<form
|
||||||
)
|
onSubmit={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
onSubmit(changedFields);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<EditArea>
|
||||||
|
{!card?.removeEdit && (
|
||||||
|
editMode === card?.id ? (
|
||||||
|
<EditTextButton onClick={() => setEditMode(null)}>
|
||||||
|
<EditOffIcon sx={{ fontSize: 20 }} />
|
||||||
|
<p>View</p>
|
||||||
|
</EditTextButton>
|
||||||
|
) : (
|
||||||
|
<EditTextButton onClick={() => setEditMode(card?.id)}>
|
||||||
|
<EditIcon sx={{ fontSize: 20 }} />
|
||||||
|
<p>Edit</p>
|
||||||
|
</EditTextButton>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</EditArea>
|
||||||
|
<CardBody
|
||||||
|
key={`${card?.id}-card-body`}
|
||||||
|
>
|
||||||
|
<InnerCard
|
||||||
|
key={`${card?.id}-inner-card`}
|
||||||
|
centered={card.fields.some(f => f.type === 'transfer')}
|
||||||
|
>
|
||||||
|
{card?.fields?.map((field) => {
|
||||||
|
let fieldType;
|
||||||
|
if (field?.type === 'text') {
|
||||||
|
fieldType = <InnerCardRowInput
|
||||||
|
name={field?.id}
|
||||||
|
disabled={card?.id !== editMode || field?.readOnly}
|
||||||
|
value={formValues[field?.id] ?? 'Not Provided'}
|
||||||
|
onChange={(e) => handleChange(e, 'text')}
|
||||||
|
/>;
|
||||||
|
} else if (field?.type === 'phone') {
|
||||||
|
fieldType = <InnerCardRowInput
|
||||||
|
type="tel"
|
||||||
|
name="phone"
|
||||||
|
placeholder="(123) 456-7890"
|
||||||
|
value={formValues[field?.id]}
|
||||||
|
disabled={card?.id !== editMode || field?.readOnly}
|
||||||
|
onChange={(e) => handleChange(e, 'phone')}
|
||||||
|
pattern="\(\d{3}\) \d{3}-\d{4}"
|
||||||
|
maxlength="14"
|
||||||
|
/>
|
||||||
|
} else if (field?.type === 'select') {
|
||||||
|
fieldType = (
|
||||||
|
<InnerCardRowRadioDiv>
|
||||||
|
{field?.options?.map((option) => {
|
||||||
|
const inputId = `${field.id}-${option.value}`;
|
||||||
|
return (
|
||||||
|
<FormRadioButtonLabel htmlFor={inputId} key={inputId}>
|
||||||
|
<InnerCardRadioInput
|
||||||
|
type="radio"
|
||||||
|
id={inputId}
|
||||||
|
name={field?.id}
|
||||||
|
value={option?.value}
|
||||||
|
checked={formValues[field.id] === option.value}
|
||||||
|
disabled={card?.id !== editMode || field?.readOnly}
|
||||||
|
onChange={(e) => handleChange(e, 'text')}
|
||||||
|
/>
|
||||||
|
<InnerCardRadioLabel htmlFor={inputId} key={inputId}>
|
||||||
|
{option?.label}
|
||||||
|
</InnerCardRadioLabel>
|
||||||
|
</FormRadioButtonLabel>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</InnerCardRowRadioDiv>
|
||||||
|
)
|
||||||
|
} else if (field?.type === 'transfer') {
|
||||||
|
fieldType = <TransferBox
|
||||||
|
style={{ display: 'flex', flexDirection: 'row' }}
|
||||||
|
fields={field}
|
||||||
|
leftGroup={department[field?.origList]}
|
||||||
|
rightGroup={department[field?.id]}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
return field?.type !== 'header' && (
|
||||||
|
<InnerCardRow key={`${field?.id}-row`}>
|
||||||
|
{field?.label ? (
|
||||||
|
<InnerCardRowLabel>
|
||||||
|
{field?.label}:
|
||||||
|
</InnerCardRowLabel>
|
||||||
|
) : null }
|
||||||
|
{fieldType}
|
||||||
|
</InnerCardRow>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</InnerCard>
|
||||||
|
</CardBody>
|
||||||
|
{card?.id === editMode && (
|
||||||
|
<FormInputButtonDiv>
|
||||||
|
<FormInputButton
|
||||||
|
type="submit"
|
||||||
|
value="Save"
|
||||||
|
disabled={!hasChanges}
|
||||||
|
style={{
|
||||||
|
backgroundColor: hasChanges ? '#4D79FF' : '',
|
||||||
|
color: hasChanges ? 'white' : ''
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</FormInputButtonDiv>
|
||||||
|
)}
|
||||||
|
</form>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return null;
|
||||||
})}
|
})}
|
||||||
</CardShell>
|
</CardShell>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
170
src/pages/Settings/helpers.js
Normal file
170
src/pages/Settings/helpers.js
Normal file
|
|
@ -0,0 +1,170 @@
|
||||||
|
export const settingsFields = [
|
||||||
|
{
|
||||||
|
id: 'deptInfo',
|
||||||
|
title: 'Information',
|
||||||
|
tab: 'department',
|
||||||
|
cards: [
|
||||||
|
{
|
||||||
|
id: 'companyInfo',
|
||||||
|
label: 'Company Information',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
id: 'employee_count',
|
||||||
|
label: 'Employee Count',
|
||||||
|
type: 'header',
|
||||||
|
readOnly: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'subs_expiration',
|
||||||
|
label: 'Subscription Expiration',
|
||||||
|
type: 'header',
|
||||||
|
readOnly: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'company',
|
||||||
|
label: 'Company Name',
|
||||||
|
type: 'text',
|
||||||
|
readOnly: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'billing_address',
|
||||||
|
label: 'Billing Address',
|
||||||
|
type: 'text'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'town',
|
||||||
|
label: 'Town',
|
||||||
|
type: 'text'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'state',
|
||||||
|
label: 'State',
|
||||||
|
type: 'text'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'postal',
|
||||||
|
label: 'Postal Code',
|
||||||
|
type: 'text'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'country',
|
||||||
|
label: 'Country',
|
||||||
|
type: 'text'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'phone',
|
||||||
|
label: 'Phone Number',
|
||||||
|
type: 'phone'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'display_time',
|
||||||
|
label: 'Display Time',
|
||||||
|
type: 'select',
|
||||||
|
options: [
|
||||||
|
{ label: '12 Hour AM/PM', value: '12' },
|
||||||
|
{ label: '24 Hour', value: '24' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'start_day',
|
||||||
|
label: 'Calendar Start Day',
|
||||||
|
type: 'select',
|
||||||
|
options: [
|
||||||
|
{ label: 'Sunday', value: 'sunday' },
|
||||||
|
{ label: 'Monday', value: 'monday' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
accessRequired: 'administrator'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
accessRequired: 'administrator'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'deptRoles',
|
||||||
|
title: 'Roles',
|
||||||
|
tab: 'department',
|
||||||
|
cards: [
|
||||||
|
{
|
||||||
|
id: 'companyAdmins',
|
||||||
|
label: 'Company Administrators',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
id: 'administrators',
|
||||||
|
type: 'transfer',
|
||||||
|
exclusionList: [],
|
||||||
|
origList: 'users',
|
||||||
|
oldListLabel: 'Users',
|
||||||
|
newListLabel: 'Administrators'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
accessRequired: 'administrator',
|
||||||
|
removeEdit: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'companyMgrs',
|
||||||
|
label: 'Company Managers',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
id: 'managers',
|
||||||
|
type: 'transfer',
|
||||||
|
exclusionList: [
|
||||||
|
'administrators'
|
||||||
|
],
|
||||||
|
origList: 'users',
|
||||||
|
oldListLabel: 'Users',
|
||||||
|
newListLabel: 'Managers'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
accessRequired: 'administrator',
|
||||||
|
removeEdit: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'companySched',
|
||||||
|
label: 'Company Schedulers',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
id: 'schedulers',
|
||||||
|
type: 'transfer',
|
||||||
|
exclusionList: [
|
||||||
|
'administrators',
|
||||||
|
'managers'
|
||||||
|
],
|
||||||
|
origList: 'users',
|
||||||
|
oldListLabel: 'Users',
|
||||||
|
newListLabel: 'Schedulers'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
accessRequired: 'manager',
|
||||||
|
removeEdit: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
accessRequired: 'manager'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'deptSubs',
|
||||||
|
title: 'Subscriptions',
|
||||||
|
tab: 'department',
|
||||||
|
cards: [],
|
||||||
|
accessRequired: 'administrator'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'personalInfo',
|
||||||
|
title: 'Information',
|
||||||
|
tab: 'personal',
|
||||||
|
cards: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'personalNoti',
|
||||||
|
title: 'Notifications',
|
||||||
|
tab: 'personal',
|
||||||
|
cards: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'deptNoti',
|
||||||
|
title: 'Notifications',
|
||||||
|
tab: 'department',
|
||||||
|
cards: [],
|
||||||
|
accessRequired: 'administrator'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
@ -19,26 +19,85 @@ const dept = {
|
||||||
company_logo: '',
|
company_logo: '',
|
||||||
employee_count: 1,
|
employee_count: 1,
|
||||||
subscription_expiration: '10/01/2025',
|
subscription_expiration: '10/01/2025',
|
||||||
schedulers: [],
|
schedulers: [3],
|
||||||
managers: [],
|
managers: [2],
|
||||||
administrators: [1]
|
administrators: [1]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const users = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
first_name: 'ShiftSync-Administrator',
|
||||||
|
last_name: 'Test-User',
|
||||||
|
email: 'testuserA@shift-sync.com',
|
||||||
|
is_ss_admin: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
first_name: 'ShiftSync-Manager',
|
||||||
|
last_name: 'Test-User',
|
||||||
|
email: 'testuserM@shift-sync.com',
|
||||||
|
is_ss_admin: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
first_name: 'ShiftSync-Scheduler',
|
||||||
|
last_name: 'Test-User',
|
||||||
|
email: 'testuserS@shift-sync.com',
|
||||||
|
is_ss_admin: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
first_name: 'ShiftSync-User',
|
||||||
|
last_name: 'Test-User',
|
||||||
|
email: 'testuserU@shift-sync.com',
|
||||||
|
is_ss_admin: false
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
const AppRouter = () => {
|
const AppRouter = () => {
|
||||||
const { user, setUser, setDepartment } = useLocalStore();
|
const { user, setUser, setDepartment } = useLocalStore();
|
||||||
const [userChanged, setUserChanged] = useState(false);
|
const [userChanged, setUserChanged] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setDepartment(dept);
|
// await call for getting the count of employees and any other calls to db.
|
||||||
|
const employee_count = 1;
|
||||||
|
const subs_expiration = '10/22/2025';
|
||||||
setUser({
|
setUser({
|
||||||
id: 1,
|
...users[0],
|
||||||
first_name: 'ShiftSync-Manager',
|
|
||||||
last_name: 'Test-User',
|
|
||||||
email: 'testuser@shift-sync.com',
|
|
||||||
scheduler: dept?.schedulers?.includes(1),
|
scheduler: dept?.schedulers?.includes(1),
|
||||||
manager: dept?.managers?.includes(1),
|
manager: dept?.managers?.includes(1),
|
||||||
administrator: dept?.administrators?.includes(1),
|
administrator: dept?.administrators?.includes(1)
|
||||||
is_ss_admin: false
|
});
|
||||||
|
const newAdministrators = dept?.administrators?.map((admin) => {
|
||||||
|
const user = users?.find((user) => {
|
||||||
|
return user?.id === admin;
|
||||||
|
});
|
||||||
|
return { id: user?.id, value: `${user?.last_name}, ${user?.first_name}` };
|
||||||
|
});
|
||||||
|
const newManagers = dept?.managers?.map((manager) => {
|
||||||
|
const user = users?.find((user) => {
|
||||||
|
return user?.id === manager;
|
||||||
|
});
|
||||||
|
return { id: user?.id, value: `${user?.last_name}, ${user?.first_name}` };
|
||||||
|
});
|
||||||
|
const newSchedulers = dept?.schedulers?.map((scheduler) => {
|
||||||
|
const user = users?.find((user) => {
|
||||||
|
return user?.id === scheduler;
|
||||||
|
});
|
||||||
|
return { id: user?.id, value: `${user?.last_name}, ${user?.first_name}` };
|
||||||
|
});
|
||||||
|
const newUsers = users?.map((user) => {
|
||||||
|
return { id: user?.id, value: `${user?.last_name}, ${user?.first_name}` };
|
||||||
|
});
|
||||||
|
setDepartment({
|
||||||
|
...dept,
|
||||||
|
users: newUsers,
|
||||||
|
schedulers: newSchedulers,
|
||||||
|
managers: newManagers,
|
||||||
|
administrators: newAdministrators,
|
||||||
|
employee_count,
|
||||||
|
subs_expiration
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue