Feature/settings page #17

Closed
mattdimegs wants to merge 26 commits from feature/settings-page into main
2 changed files with 666 additions and 671 deletions
Showing only changes of commit 941110abc1 - Show all commits

View file

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

View file

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