diff --git a/components/core/Shell/Footer/Footer.jsx b/components/core/Shell/Footer/Footer.jsx index be39b71..c0f194c 100644 --- a/components/core/Shell/Footer/Footer.jsx +++ b/components/core/Shell/Footer/Footer.jsx @@ -21,7 +21,7 @@ export const Footer = () => { return ( {`© ${new Date().getFullYear()} ShiftSync`} - {department?.name} + {department?.company} ) } \ No newline at end of file diff --git a/src/global.css b/src/global.css index 1068e61..8b62413 100644 --- a/src/global.css +++ b/src/global.css @@ -2,4 +2,5 @@ margin: 0; padding: 0; box-sizing: border-box; + text-align: initial; } \ No newline at end of file diff --git a/src/pages/Settings/Settings.jsx b/src/pages/Settings/Settings.jsx index c09cbec..d202f19 100644 --- a/src/pages/Settings/Settings.jsx +++ b/src/pages/Settings/Settings.jsx @@ -1,7 +1,8 @@ import React, { useEffect, useRef, useState } from 'react'; import styled from '@emotion/styled'; -import { Link } from 'react-router-dom'; import { Stack } from '@mui/material'; +import EditIcon from '@mui/icons-material/Edit'; +import EditOffIcon from '@mui/icons-material/EditOff'; import { ToggleTabs, useLocalStore } from '@components'; const OuterContainer = styled(Stack)` @@ -46,62 +47,224 @@ const SlidingIndicator = styled('div')` transition: left 0.3s ease, width 0.3s ease; `; +const CardShell = styled('div')` + display: flex; + justify-content: center; + padding: 10px; +`; + +const Card = styled('div')` + background-color: #C7C7C7; + width: 50%; + padding: 20px; + border-radius: 10px; +`; + +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; +`; + +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%; +`; + +const InnerCardRow = styled('div')` + display: flex; + flex-direction: row; + justify-content: space-between; + padding: 5px; + align-items: center; +`; + +const InnerCardRowLabel = styled('label')` + display: flex; + justify-content: flex-end; + text-align: right; + width: 60%; + padding-right: 10px; + font-size: 14px; +`; + +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; +`; + +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; +`; + const settingsFields = [ { - id: 'dept-info', + id: 'deptInfo', title: 'Information', tab: 'department', cards: [ { - id: 'company-info', + id: 'companyInfo', label: 'Company Information', fields: [ { id: 'company', label: 'Company Name', + type: 'text', + readOnly: true + }, + { + id: 'billingAddress', + label: 'Billing Address', type: 'text' }, { - id: 'billing-address', - label: 'Billing Address', + 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: 'displayTime', + label: 'Display Time', + type: 'select', + options: [ + { label: '12 Hour AM/PM', value: '12' }, + { label: '24 Hour', value: '24' } + ] + }, + { + id: 'startDay', + label: 'Calendar Start Day', + type: 'select', + options: [ + { label: 'Sunday', value: 'sunday' }, + { label: 'Monday', value: 'monday' } + ] } ] } ] }, { - id: 'dept-perms', + id: 'deptPerms', title: 'Permissions', tab: 'department', cards: [] }, { - id: 'dept-mgrs', + id: 'deptMgrs', title: 'Managers', tab: 'department', cards: [] }, { - id: 'dept-subs', + id: 'deptSubs', title: 'Subscriptions', tab: 'department', cards: [] }, { - id: 'personal-info', + id: 'personalInfo', title: 'Information', tab: 'personal', cards: [] }, { - id: 'personal-noti', + id: 'personalNoti', title: 'Notifications', tab: 'personal', cards: [] }, { - id: 'dept-noti', + id: 'deptNoti', title: 'Notifications', tab: 'department', cards: [] @@ -109,7 +272,19 @@ const settingsFields = [ ]; export const Settings = () => { - const { user } = useLocalStore(); + const { user, department, setDepartment } = useLocalStore(); + 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 = [ { @@ -122,12 +297,54 @@ export const Settings = () => { } ]; - + const [editMode, setEditMode] = useState(null); const [tabValue, setTabValue] = useState(tabs[0]); const [pageValue, setPageValue] = useState({}); const [indicatorStyle, setIndicatorStyle] = useState({ left: 0, width: 0 }); - console.log('pageValue: ', pageValue); + 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'; @@ -176,16 +393,128 @@ export const Settings = () => { - {pageValue?.cards?.map((card) => { - return (
- {card?.label} - {card?.fields?.map((field) => { - return ( -

{field?.label}

- ) - })} -
) - })} + + {pageValue?.cards?.map((card) => { + return ( + + + {card?.label} + + + +

+ Employee Count: {department?.employeeCount} +

+

+ Subscription Expiration: {department?.subscriptionExpiration} +

+
+ +
{ + e.preventDefault(); + onSubmit(changedFields); + }} + > + + {editMode === card?.id ? ( + setEditMode(null)}> + +

View

+
+ ) : ( + setEditMode(card?.id)}> + +

Edit

+
+ )} +
+ + + {card?.fields?.map((field) => { + let fieldType; + if (field?.type === 'text') { + fieldType = handleChange(e, 'text')} + />; + } else if (field?.type === 'phone') { + fieldType = handleChange(e, 'phone')} + pattern="\(\d{3}\) \d{3}-\d{4}" + maxlength="14" + /> + } else if (field?.type === 'select') { + fieldType = ( + + {field?.options?.map((option) => { + const inputId = `${field.id}-${option.value}`; + return ( + + handleChange(e, 'text')} + /> + + {option?.label} + + + ) + })} + + ) + } + return ( + + + {field?.label}: + + {fieldType} + + ) + })} + + + {card?.id === editMode && ( + + + + )} +
+
+ ) + })} +
); }; diff --git a/src/router/AppRouter.jsx b/src/router/AppRouter.jsx index 3794ef3..4a33f34 100644 --- a/src/router/AppRouter.jsx +++ b/src/router/AppRouter.jsx @@ -6,8 +6,19 @@ import { useLocalStore } from '@components'; const dept = { id: 1, - name: 'Darien EMS - Post 53', + company: 'Darien EMS - Post 53', Abv: 'DEMS', + billingAddress: '0 Ledge Road', + town: 'Darien', + state: 'Connecticut', + postal: '06820', + country: 'United States', + phone: '', + displayTime: '12', + startDay: 'sunday', + companyLogo: '', + employeeCount: 1, + subscriptionExpiration: '10/01/2025', schedulers: [], managers: [], administrators: [1]