Settings add

This commit is contained in:
Matt DiMeglio 2025-12-01 22:55:54 -05:00
parent a0bb4bef4a
commit 941110abc1
2 changed files with 666 additions and 671 deletions

View file

@ -1,501 +1,496 @@
import React, { useEffect, useRef, useState } from 'react';
import styled from '@emotion/styled';
import { Stack } from '@mui/material';
import EditIcon from '@mui/icons-material/Edit';
import EditOffIcon from '@mui/icons-material/EditOff';
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)`
position: relative;
display: flex;
align-items: center;
flex-direction: row;
justify-content: center;
padding: 10px 10px 0px 0px;
`;
const Border = styled('div')`
height: 1px;
width: 100%;
background-color: #A8A8A8;
`;
const Tab = styled('div')`
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-end;
height: 100%;
padding: 6px 16px;
font-size: 20px;
font-weight: 800;
color: grey;
background: none;
border: none;
cursor: pointer;
font-family: "WDXL Lubrifont TC";
letter-spacing: .05em;
word-spacing: .2em;
`;
const SlidingIndicator = styled('div')`
position: absolute;
height: 1px;
bottom: -1px;
background-color: #4D79FF;
transition: left 0.3s ease, width 0.3s ease;
`;
const CardShell = styled('div')`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 10px;
`;
const Card = styled('div')`
background-color: #C7C7C7;
width: 50%;
min-width: 750px;
padding: 20px;
border-radius: 10px;
margin: 5px;
`;
const CardTitle = styled('p')`
color: white;
font-weight: 400;
font-size: 20px;
font-family: "WDXL Lubrifont TC";
padding-bottom: 5px;
`;
const CardHeader = styled('div')`
display: flex;
justify-content: space-between;
flex-direction: row;
padding: 10px;
`;
const EditArea = styled('div')`
display: flex;
flex-direction: row;
justify-content: flex-end;
padding-top: 10px;
color: #4D79FF;
font-weight: 600;
`;
const EditTextButton = styled('div')`
display: flex;
flex-direction: row;
align-items: center;
cursor: pointer;
gap: 4px;
padding-bottom: 2px;
border-bottom: 2px solid transparent;
transition: border-bottom 0.2s ease;
&:hover {
border-bottom: 2px solid #4D79FF;
}
`;
const CardBody = styled('div')`
display: flex;
flex-direction: column;
align-items: center;
`;
const InnerCard = styled('div')`
display: flex;
flex-direction: column;
padding: 10px;
width: 50%;
${({ centered }) => centered && `
align-items: center;
`}
`;
const InnerCardRow = styled('div')`
display: flex;
flex-direction: row;
padding: 5px;
`;
const InnerCardRowLabel = styled('label')`
display: flex;
justify-content: flex-end;
text-align: right;
width: 60%;
padding-right: 10px;
font-size: 14px;
align-items: center;
`;
const InnerCardRowInput = styled('input')`
display: flex;
justify-content: flex-end;
width: 100%;
padding: 4px;
`;
const InnerCardRadioInput = styled('input')`
padding-right: 5px;
`;
const InnerCardRadioLabel = styled('label')`
font-size: 14px;
padding-left: 5px;
align-items: center;
`;
const InnerCardRowRadioDiv = styled('div')`
display: flex;
justify-content: space-evenly;
width: 100%;
padding: 4px;
`;
const FormRadioButtonLabel = styled('label')``;
const FormInputButtonDiv = styled('div')`
display: flex;
flex-direction: row;
justify-content: flex-end;
padding-top: 10px;
`;
const FormInputButton = styled('input')`
padding: 4px 10px;
border-radius: 4px;
`;
export const Settings = () => {
const { user, department, setDepartment } = useLocalStore();
const isAdministrator = user?.administrator;
const isManager = user?.manager;
const isScheduler = user?.scheduler;
const originalDepartmentRef = useRef(department);
const [formValues, setFormValues] = useState(() => {
const initial = {};
settingsFields.forEach(section => {
section.cards.forEach(card => {
card.fields.forEach(field => {
initial[field.id] = department?.[field.id] || '';
});
});
});
return initial;
});
const pageRefs = useRef({});
const tabs = [
{
label: 'Personal',
value: 'personal'
},
{
label: 'Department',
value: 'department'
}
];
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
const [editMode, setEditMode] = useState(null);
const [tabValue, setTabValue] = useState(tabs[0]);
const [pageValue, setPageValue] = useState({});
const [indicatorStyle, setIndicatorStyle] = useState({ left: 0, width: 0 });
const getChangedFields = (original, current) => {
const changed = {};
for (const key in current) {
if (current[key] !== original[key]) {
changed[key] = current[key];
}
}
return changed;
};
const changedFields = getChangedFields(originalDepartmentRef.current, formValues);
const hasChanges = Object.keys(changedFields).length > 0;
const onSubmit = (data) => {
console.log('data: ', data);
setDepartment({
...department,
...data
});
originalDepartmentRef.current = {
...originalDepartmentRef.current,
...data
};
setEditMode(null);
};
const formatPhoneNumber = (value) => {
const cleaned = value.replace(/\D/g, '').slice(0, 10); // Only digits, max 10
const length = cleaned.length;
if (length === 0) return '';
if (length < 4) return `(${cleaned}`;
if (length < 7) return `(${cleaned.slice(0, 3)}) ${cleaned.slice(3)}`;
return `(${cleaned.slice(0, 3)}) ${cleaned.slice(3, 6)}-${cleaned.slice(6)}`;
};
const handleChange = (e, type) => {
let { name, value } = e.target;
if (type === 'phone') {
value = formatPhoneNumber(value);
}
setFormValues(prev => ({ ...prev, [name]: value }));
};
useEffect(() => {
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(() => {
if (pageValue?.id && pageRefs.current[pageValue.id]) {
const el = pageRefs.current[pageValue.id];
const rect = el.getBoundingClientRect();
const containerRect = el.parentNode.getBoundingClientRect();
setIndicatorStyle({
left: rect.left - containerRect.left,
width: rect.width
});
}
}, [pageValue?.id, windowWidth, window.innerHeight]);
useEffect(() => {
const filteredFields = settingsFields?.filter((field) => {
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]);
useEffect(() => {
}, [department]);
return (
<div>
{user?.administrator || user?.manager ? (
<OuterContainer>
<ToggleTabs
tabs={tabs}
tabValue={tabValue}
setTabValue={setTabValue}
tabColor='#4D79FF'
/>
</OuterContainer>
) : null }
<OuterContainer>
{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 (
<Tab
key={field?.id}
ref={(el) => { pageRefs.current[field?.id] = el; }}
onClick={() => setPageValue(field)}
>
{field?.title}
</Tab>
)
})}
<SlidingIndicator style={indicatorStyle} />
</OuterContainer>
<Border />
<CardShell>
{pageValue?.cards?.map((card) => {
if (
(card?.accessRequired === 'administrator' && isAdministrator) ||
(card?.accessRequired === 'manager' && isManager) ||
(card?.accessRequired === 'scheduler' && isScheduler)
) {
return (
<Card
key={`${card?.id}-card`}
>
<CardTitle
key={`${card?.id}-card-title`}
>
{card?.label}
</CardTitle>
{card?.fields?.find((field) => field?.type === 'header') !== undefined && (
<div>
<Border key={`${card?.id}-border-1`}/>
<CardHeader
key={`${card?.id}-card-header`}
>
{card?.fields?.map((field) => {
return field?.type === 'header' && (
<InnerCardRow key={`${field?.id}-row`}>
<p style={{ fontSize: 14 }}>
{field?.label}:
</p>
<p style={{ paddingLeft: 10, fontSize: 14 }}>
{department[field?.id]}
</p>
</InnerCardRow>
)
})}
</CardHeader>
</div>
)}
<Border key={`${card?.id}-border-2`}/>
<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' }}
user={user}
fields={field}
leftGroup={department[field?.origList]}
rightGroup={department[field?.id]}
onSave={(t) => {
return onSubmit({ [field.id]: t });
}}
/>
}
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>
</div>
);
};
import React, { useEffect, useRef, useState } from 'react';
import styled from '@emotion/styled';
import { Stack } from '@mui/material';
import EditIcon from '@mui/icons-material/Edit';
import EditOffIcon from '@mui/icons-material/EditOff';
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)`
position: relative;
display: flex;
align-items: center;
flex-direction: row;
justify-content: center;
padding: 10px 10px 0px 0px;
`;
const Border = styled('div')`
height: 1px;
width: 100%;
background-color: #A8A8A8;
`;
const Tab = styled('div')`
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-end;
height: 100%;
padding: 6px 16px;
font-size: 20px;
font-weight: 800;
color: grey;
background: none;
border: none;
cursor: pointer;
font-family: "WDXL Lubrifont TC";
letter-spacing: .05em;
word-spacing: .2em;
`;
const SlidingIndicator = styled('div')`
position: absolute;
height: 1px;
bottom: -1px;
background-color: #4D79FF;
transition: left 0.3s ease, width 0.3s ease;
`;
const CardShell = styled('div')`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 10px;
`;
const Card = styled('div')`
background-color: #C7C7C7;
width: 50%;
min-width: 750px;
padding: 20px;
border-radius: 10px;
margin: 5px;
`;
const CardTitle = styled('p')`
color: white;
font-weight: 400;
font-size: 20px;
font-family: "WDXL Lubrifont TC";
padding-bottom: 5px;
`;
const CardHeader = styled('div')`
display: flex;
justify-content: space-between;
flex-direction: row;
padding: 10px;
`;
const EditArea = styled('div')`
display: flex;
flex-direction: row;
justify-content: flex-end;
padding-top: 10px;
color: #4D79FF;
font-weight: 600;
`;
const EditTextButton = styled('div')`
display: flex;
flex-direction: row;
align-items: center;
cursor: pointer;
gap: 4px;
padding-bottom: 2px;
border-bottom: 2px solid transparent;
transition: border-bottom 0.2s ease;
&:hover {
border-bottom: 2px solid #4D79FF;
}
`;
const CardBody = styled('div')`
display: flex;
flex-direction: column;
align-items: center;
`;
const InnerCard = styled('div')`
display: flex;
flex-direction: column;
padding: 10px;
width: 50%;
${({ centered }) => centered && `
align-items: center;
`}
`;
const InnerCardRow = styled('div')`
display: flex;
flex-direction: row;
padding: 5px;
`;
const InnerCardRowLabel = styled('label')`
display: flex;
justify-content: flex-end;
text-align: right;
width: 60%;
padding-right: 10px;
font-size: 14px;
align-items: center;
`;
const InnerCardRowInput = styled('input')`
display: flex;
justify-content: flex-end;
width: 100%;
padding: 4px;
`;
const InnerCardRadioInput = styled('input')`
padding-right: 5px;
`;
const InnerCardRadioLabel = styled('label')`
font-size: 14px;
padding-left: 5px;
align-items: center;
`;
const InnerCardRowRadioDiv = styled('div')`
display: flex;
justify-content: space-evenly;
width: 100%;
padding: 4px;
`;
const FormRadioButtonLabel = styled('label')``;
const FormInputButtonDiv = styled('div')`
display: flex;
flex-direction: row;
justify-content: flex-end;
padding-top: 10px;
`;
const FormInputButton = styled('input')`
padding: 4px 10px;
border-radius: 4px;
`;
export const Settings = () => {
const { user, department, setDepartment } = useLocalStore();
const isAdministrator = user?.administrator;
const isManager = user?.manager;
const isScheduler = user?.scheduler;
const originalDepartmentRef = useRef(department);
const [formValues, setFormValues] = useState(() => {
const initial = {};
settingsFields.forEach(section => {
section.cards.forEach(card => {
card.fields.forEach(field => {
initial[field.id] = department?.[field.id] || '';
});
});
});
return initial;
});
const pageRefs = useRef({});
const tabs = [
{
label: 'Personal',
value: 'personal'
},
{
label: 'Department',
value: 'department'
}
];
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
const [editMode, setEditMode] = useState(null);
const [tabValue, setTabValue] = useState(tabs[0]);
const [pageValue, setPageValue] = useState({});
const [indicatorStyle, setIndicatorStyle] = useState({ left: 0, width: 0 });
const getChangedFields = (original, current) => {
const changed = {};
for (const key in current) {
if (current[key] !== original[key]) {
changed[key] = current[key];
}
}
return changed;
};
const changedFields = getChangedFields(originalDepartmentRef.current, formValues);
const hasChanges = Object.keys(changedFields).length > 0;
const onSubmit = (data) => {
setDepartment({
...department,
...data
});
originalDepartmentRef.current = {
...originalDepartmentRef.current,
...data
};
setEditMode(null);
};
const formatPhoneNumber = (value) => {
const cleaned = value.replace(/\D/g, '').slice(0, 10); // Only digits, max 10
const length = cleaned.length;
if (length === 0) return '';
if (length < 4) return `(${cleaned}`;
if (length < 7) return `(${cleaned.slice(0, 3)}) ${cleaned.slice(3)}`;
return `(${cleaned.slice(0, 3)}) ${cleaned.slice(3, 6)}-${cleaned.slice(6)}`;
};
const handleChange = (e, type) => {
let { name, value } = e.target;
if (type === 'phone') {
value = formatPhoneNumber(value);
}
setFormValues(prev => ({ ...prev, [name]: value }));
};
useEffect(() => {
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(() => {
if (pageValue?.id && pageRefs.current[pageValue.id]) {
const el = pageRefs.current[pageValue.id];
const rect = el.getBoundingClientRect();
const containerRect = el.parentNode.getBoundingClientRect();
setIndicatorStyle({
left: rect.left - containerRect.left,
width: rect.width
});
}
}, [pageValue?.id, windowWidth, window.innerHeight]);
useEffect(() => {
const filteredFields = settingsFields?.filter((field) => {
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 (
<div>
{user?.administrator || user?.manager ? (
<OuterContainer>
<ToggleTabs
tabs={tabs}
tabValue={tabValue}
setTabValue={setTabValue}
tabColor='#4D79FF'
/>
</OuterContainer>
) : null }
<OuterContainer>
{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 (
<Tab
key={field?.id}
ref={(el) => { pageRefs.current[field?.id] = el; }}
onClick={() => setPageValue(field)}
>
{field?.title}
</Tab>
)
})}
<SlidingIndicator style={indicatorStyle} />
</OuterContainer>
<Border />
<CardShell>
{pageValue?.cards?.map((card) => {
if (
(card?.accessRequired === 'administrator' && isAdministrator) ||
(card?.accessRequired === 'manager' && isManager) ||
(card?.accessRequired === 'scheduler' && isScheduler)
) {
return (
<Card
key={`${card?.id}-card`}
>
<CardTitle
key={`${card?.id}-card-title`}
>
{card?.label}
</CardTitle>
{card?.fields?.find((field) => field?.type === 'header') !== undefined && (
<div>
<Border key={`${card?.id}-border-1`}/>
<CardHeader
key={`${card?.id}-card-header`}
>
{card?.fields?.map((field) => {
return field?.type === 'header' && (
<InnerCardRow key={`${field?.id}-row`}>
<p style={{ fontSize: 14 }}>
{field?.label}:
</p>
<p style={{ paddingLeft: 10, fontSize: 14 }}>
{department[field?.id]}
</p>
</InnerCardRow>
)
})}
</CardHeader>
</div>
)}
<Border key={`${card?.id}-border-2`}/>
<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' }}
user={user}
fields={field}
leftGroup={department[field?.origList]}
rightGroup={department[field?.id]}
onSave={(t) => {
return onSubmit({ [field.id]: t });
}}
/>
}
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>
</div>
);
};

View file

@ -1,170 +1,170 @@
import React, { useEffect, useState } from 'react';
import { Routes, Route } from 'react-router-dom';
import { Home, Profile, Schedule, Settings } from '@src/pages';
import { Shell } from '@components';
import { useLocalStore } from '@components';
import { fetchAPI } from './axios.js';
const dept = {
id: 1,
company: 'Darien EMS - Post 53',
abv: 'DEMS',
billing_address: '0 Ledge Road',
town: 'Darien',
state: 'Connecticut',
postal: '06820',
country: 'United States',
phone: '',
display_time: '12',
start_day: 'sunday',
company_logo: '',
employee_count: 1,
subscription_expiration: '10/01/2025',
schedulers: [3],
managers: [2],
administrators: [1]
};
const users = [
{
id: 1,
first_name: 'ShiftSync-Administrator',
last_name: 'Test-User',
email: 'testuserA@shift-sync.com',
accessLevel: 150,
is_ss_admin: false
},
{
id: 2,
first_name: 'ShiftSync-Manager',
last_name: 'Test-User',
email: 'testuserM@shift-sync.com',
accessLevel: 100,
is_ss_admin: false
},
{
id: 3,
first_name: 'ShiftSync-Scheduler',
last_name: 'Test-User',
email: 'testuserS@shift-sync.com',
accessLevel: 50,
is_ss_admin: false
},
{
id: 4,
first_name: 'ShiftSync-User',
last_name: 'Test-User',
email: 'testuserU@shift-sync.com',
accessLevel: 1,
is_ss_admin: false
},
];
const AppRouter = () => {
const { user, setUser, setDepartment } = useLocalStore();
const [userChanged, setUserChanged] = useState(false);
useEffect(() => {
const init = async () => {
const localVersion = localStorage.getItem("APP_VERSION");
const currentVersion = window.APP_VERSION;
if (localVersion && localVersion !== currentVersion) {
console.log("Version changed, forcing reload");
localStorage.setItem("APP_VERSION", currentVersion);
window.location.reload(true);
return;
} else {
localStorage.setItem("APP_VERSION", currentVersion);
}
const data = await fetchAPI('userData', 'get');
console.log('data:', data);
// TODO: Replace this with real data from your API
// const users = data?.users || []; // Example fix
// const dept = data?.dept || {}; // Example fix
const employee_count = 1;
const subs_expiration = '10/22/2025';
setUser({
...users[0],
scheduler: dept?.schedulers?.includes(1),
manager: dept?.managers?.includes(1),
administrator: dept?.administrators?.includes(1)
});
const newAdministrators = dept?.administrators?.map((admin) => {
const user = users?.find((user) => 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) => 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) => user?.id === scheduler);
return { id: user?.id, value: `${user?.last_name}, ${user?.first_name}` };
});
const newUsers = users?.map((user) => ({
id: user?.id,
value: `${user?.last_name}, ${user?.first_name}`
}));
setDepartment({
...dept,
users: newUsers,
schedulers: newSchedulers,
managers: newManagers,
administrators: newAdministrators,
employee_count,
subs_expiration
});
};
init();
}, []);
useEffect(() => {
if (!userChanged && user) {
if (user?.is_ss_admin) {
setUser({
...user,
scheduler: true,
manager: true,
administrator: true,
});
} else if (user?.administrator) {
setUser({
...user,
scheduler: true,
manager: true,
});
} else if (user?.manager) {
setUser({
...user,
scheduler: true,
});
}
setUserChanged(true);
}
}, [user]);
return (
<Shell>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/schedule" element={<Schedule />} />
<Route path="/settings" element={<Settings />} />
<Route path="/profile" element={<Profile />} />
</Routes>
</Shell>
);
};
export default AppRouter
import React, { useEffect, useState } from 'react';
import { Routes, Route } from 'react-router-dom';
import { Home, Profile, Schedule, Settings } from '@src/pages';
import { Shell } from '@components';
import { useLocalStore } from '@components';
import { fetchAPI } from './axios.js';
const dept = {
id: 1,
company: 'Darien EMS - Post 53',
abv: 'DEMS',
billing_address: '0 Ledge Road',
town: 'Darien',
state: 'Connecticut',
postal: '06820',
country: 'United States',
phone: '',
display_time: '12',
start_day: 'sunday',
company_logo: '',
employee_count: 1,
subscription_expiration: '10/01/2025',
schedulers: [3],
managers: [2],
administrators: [1]
};
const users = [
{
id: 1,
first_name: 'ShiftSync-Administrator',
last_name: 'Test-User',
email: 'testuserA@shift-sync.com',
accessLevel: 150,
is_ss_admin: false
},
{
id: 2,
first_name: 'ShiftSync-Manager',
last_name: 'Test-User',
email: 'testuserM@shift-sync.com',
accessLevel: 100,
is_ss_admin: false
},
{
id: 3,
first_name: 'ShiftSync-Scheduler',
last_name: 'Test-User',
email: 'testuserS@shift-sync.com',
accessLevel: 50,
is_ss_admin: false
},
{
id: 4,
first_name: 'ShiftSync-User',
last_name: 'Test-User',
email: 'testuserU@shift-sync.com',
accessLevel: 1,
is_ss_admin: false
},
];
const AppRouter = () => {
const { user, setUser, setDepartment } = useLocalStore();
const [userChanged, setUserChanged] = useState(false);
useEffect(() => {
const init = async () => {
const localVersion = localStorage.getItem("APP_VERSION");
const currentVersion = window.APP_VERSION;
if (localVersion && localVersion !== currentVersion) {
console.log("Version changed, forcing reload");
localStorage.setItem("APP_VERSION", currentVersion);
window.location.reload(true);
return;
} else {
localStorage.setItem("APP_VERSION", currentVersion);
}
const data = await fetchAPI('userData', 'get');
console.log('data:', data);
// TODO: Replace this with real data from your API
// const users = data?.users || []; // Example fix
// const dept = data?.dept || {}; // Example fix
const employee_count = 1;
const subs_expiration = '10/22/2025';
setUser({
...users[0],
scheduler: dept?.schedulers?.includes(1),
manager: dept?.managers?.includes(1),
administrator: dept?.administrators?.includes(1)
});
const newAdministrators = dept?.administrators?.map((admin) => {
const user = users?.find((user) => 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) => 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) => user?.id === scheduler);
return { id: user?.id, value: `${user?.last_name}, ${user?.first_name}` };
});
const newUsers = users?.map((user) => ({
id: user?.id,
value: `${user?.last_name}, ${user?.first_name}`
}));
setDepartment({
...dept,
users: newUsers,
schedulers: newSchedulers,
managers: newManagers,
administrators: newAdministrators,
employee_count,
subs_expiration
});
};
init();
}, []);
useEffect(() => {
if (!userChanged && user) {
if (user?.is_ss_admin) {
setUser({
...user,
scheduler: true,
manager: true,
administrator: true,
});
} else if (user?.administrator) {
setUser({
...user,
scheduler: true,
manager: true,
});
} else if (user?.manager) {
setUser({
...user,
scheduler: true,
});
}
setUserChanged(true);
}
}, [user]);
return (
<Shell>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/schedule" element={<Schedule />} />
<Route path="/settings" element={<Settings />} />
<Route path="/profile" element={<Profile />} />
</Routes>
</Shell>
);
};
export default AppRouter