Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 60 additions & 27 deletions app-frontend/employer-panel/src/App.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BrowserRouter as Router, Routes, Route, useNavigate } from 'react-router-dom';
import { useEffect } from 'react';
import { useState, useEffect } from 'react';
import { attach401Handler } from './lib/http';

import ExpressionOfInterest from './pages/ExpressionOfInterest';
Expand All @@ -23,15 +23,12 @@ import PageTitleHandler from './components/PageTitleHandler';

import ProtectedRoute from './routes/ProtectedRoute';

import Timesheet from "./pages/Timesheet";
import Timesheet from './pages/Timesheet';
import DailyMonitoring from './pages/DailyMonitoring';
import Payroll from './pages/Payroll';
import PrivacyPolicy from './pages/PrivacyPolicy';
import TermsAndConditions from './pages/TermsAndConditions';

/**
* PUBLIC ROUTE: Task Detail (no layout)
*/
function TaskRoute() {
return (
<Routes>
Expand All @@ -40,27 +37,30 @@ function TaskRoute() {
);
}

/**
* PROTECTED LAYOUT WRAPPER
*/
function ProtectedLayout({ children }) {
function ProtectedLayout({ children, language, setLanguage }) {
return (
<ProtectedRoute>
<div style={{ display: 'flex', flexDirection: 'column', minHeight: '100vh' }}>
<Header />
<Header language={language} setLanguage={setLanguage} />
<main style={{ flex: 1, paddingBottom: '20px' }}>{children}</main>
<Footer />
<Footer language={language} />
</div>
</ProtectedRoute>
);
}

function AppRoutes() {
function AppRoutes({ language, setLanguage }) {
const navigate = useNavigate();

useEffect(() => {
attach401Handler(() => navigate('/login'));
}, []);
}, [navigate]);

const protectedLayout = (children) => (
<ProtectedLayout language={language} setLanguage={setLanguage}>
{children}
</ProtectedLayout>
);

return (
<>
Expand All @@ -77,28 +77,61 @@ function AppRoutes() {
<Route path="/terms-and-condition" element={<TermsAndConditions />} />

{/* PROTECTED ROUTES */}
<Route path="/employer-dashboard" element={<ProtectedLayout><EmployerDashboard /></ProtectedLayout>} />
<Route path="/create-shift" element={<ProtectedLayout><CreateShift /></ProtectedLayout>} />
<Route path="/timesheet" element={<ProtectedLayout><Timesheet /></ProtectedLayout>} />
<Route path="/manage-shift" element={<ProtectedLayout><ManageShift /></ProtectedLayout>} />
<Route path="/guard-profiles" element={<ProtectedLayout><GuardProfiles /></ProtectedLayout>} />
<Route path="/guard-profiles/:guardId" element={<ProtectedLayout><GuardProfilePage /></ProtectedLayout>} />
<Route path="/company-profile" element={<ProtectedLayout><CompanyProfile /></ProtectedLayout>} />
<Route path="/email-settings" element={<ProtectedLayout><EmailSettings /></ProtectedLayout>} />
<Route
path="/employer-dashboard"
element={protectedLayout(<EmployerDashboard language={language} />)}
/>
<Route
path="/create-shift"
element={protectedLayout(<CreateShift language={language} />)}
/>
<Route
path="/timesheet"
element={protectedLayout(<Timesheet language={language} />)}
/>
<Route
path="/manage-shift"
element={protectedLayout(<ManageShift language={language} />)}
/>
<Route
path="/guard-profiles"
element={protectedLayout(<GuardProfiles language={language} />)}
/>
<Route
path="/guard-profiles/:guardId"
element={protectedLayout(<GuardProfilePage language={language} />)}
/>
<Route
path="/company-profile"
element={protectedLayout(<CompanyProfile language={language} />)}
/>
<Route
path="/email-settings"
element={protectedLayout(<EmailSettings language={language} />)}
/>
<Route
path="/daily-monitoring"
element={protectedLayout(<DailyMonitoring language={language} />)}
/>
</Routes>
</>
);
}
/**
* MAIN APP ROUTES
*/

function App() {
const [language, setLanguage] = useState(
localStorage.getItem('language') || 'en'
);

useEffect(() => {
localStorage.setItem('language', language);
}, [language]);

return (
<Router>

<AppRoutes />
<AppRoutes language={language} setLanguage={setLanguage} />
</Router>
);
}

export default App;
export default App;
8 changes: 5 additions & 3 deletions app-frontend/employer-panel/src/components/Footer.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import React from 'react';
import CompanyLogo from './company_logo.svg';
import { Link } from 'react-router-dom';
import translations from "../i18n/translations";

export default function Footer() {
export default function Footer({ language }) {
const t = translations[language || "en"] || translations.en;
const footerNavList = [
{ title: 'Privacy Policy', link: '/privacy-policy' },
{ title: 'Terms and Conditions', link: '/terms-and-condition' },
Expand Down Expand Up @@ -35,11 +37,11 @@ export default function Footer() {

const buttonList = [
{
title: 'Expression of Interest', // fixed title
title: t.expressionInterest, // fixed title
link: '/expression-of-interest', // ✅ now routes correctly
},
{
title: 'Login',
title: t.login,
link: '/login',
},
];
Expand Down
133 changes: 110 additions & 23 deletions app-frontend/employer-panel/src/components/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ import { Link, useNavigate } from 'react-router-dom';
import CompanyLogo from './company_logo.svg';
import ProfilePicPlaceHolder from './ProfilePicPlaceHolder.svg';
import NotificationsPopup from '../pages/NotificationsPopup';
import translations from "../i18n/translations";
import Logo from '../pages/logo.png';

export default function Header({ language, setLanguage }) {
const t = translations[language || "en"] || translations.en;

export default function Header() {
const navigate = useNavigate();
const [showMenu, setShowMenu] = useState(false);

Expand Down Expand Up @@ -48,42 +52,49 @@ export default function Header() {
{/* Logo */}
<div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
<img src={CompanyLogo} alt="Company Logo" style={{ height: '66px' }} />
<div style={{ fontWeight: '600', fontSize: '24px' }}>Secure Shift</div>
<div style={{ fontWeight: '600', fontSize: '24px' }}>
Secure Shift
</div>
</div>

{/* Navigation */}
<div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>

<div onClick={handleHomeClick} style={navButtonStyle}>
Home
{t.home}
</div>

<Link to="/manage-shift" style={navButtonStyle}>
Shifts
{t.shifts}
</Link>

<Link to="/guard-profiles" style={navButtonStyle}>
Guard
{t.guard}
</Link>

<Link to="/daily-monitoring" style={navButtonStyle}>
Activity
<Link to="/timesheet" style={navButtonStyle}>
{t.timesheet}
</Link>

<Link to="/timesheet" style={navButtonStyle}>
Timesheet
<Link to="/daily-monitoring" style={navButtonStyle}>
{t.dailyMonitoring}
</Link>


{localStorage.getItem('userRole') === 'admin' && (
<Link to="/email-settings" style={navButtonStyle}>
Email
{t.email}
</Link>
)}

<NotificationsPopup />

{/* Avatar + Dropdown */}
<div style={{ position: 'relative' }}>
<div onClick={() => setShowMenu(!showMenu)} style={{ cursor: 'pointer' }}>
<div
onClick={() => setShowMenu(!showMenu)}
style={{ cursor: 'pointer' }}
>
<img
src={ProfilePicPlaceHolder}
alt="Profile"
Expand All @@ -97,28 +108,104 @@ export default function Header() {
position: 'absolute',
right: 0,
top: '70px',
background: 'white',
color: 'black',
borderRadius: '8px',
padding: '10px',
boxShadow: '0 4px 10px rgba(0,0,0,0.2)',
minWidth: '140px',
width: '220px',
background: '#fff',
borderRadius: '16px',
boxShadow: '0 6px 18px rgba(0,0,0,0.15)',
overflow: 'hidden',
zIndex: 1000,
}}
>
{/* Profile Section */}
<div
style={{ padding: '8px', cursor: 'pointer' }}
onClick={() => {
navigate('/company-profile');
setShowMenu(false);
style={{
display: 'flex',
alignItems: 'center',
gap: '12px',
padding: '16px',
borderBottom: '1px solid #eee',
}}
>
Profile
<img
src={Logo}
alt="Profile"
style={{
width: '52px',
height: '52px',
borderRadius: '50%',
}}
/>

<div>
<div
style={{
fontWeight: '700',
fontSize: '15px',
color: '#111',
}}
>
ABC Security
</div>

<div
style={{
fontSize: '13px',
color: '#666',
marginTop: '2px',
}}
>
{localStorage.getItem('email') || 'User'}
</div>
</div>
</div>

{/* Language Section */}
<div style={{ padding: '14px 16px' }}>
<div
style={{
fontWeight: '600',
fontSize: '13px',
marginBottom: '10px',
color: '#111',
}}
>
🌐 Language
</div>

{[
{ code: 'en', label: 'English' },
{ code: 'hi', label: 'Hindi' },
{ code: 'pa', label: 'Punjabi' },
{ code: 'zh', label: 'Chinese' },
].map((item) => (
<div
key={item.code}
onClick={() => setLanguage(item.code)}
style={{
padding: '7px 0',
cursor: 'pointer',
fontSize: '14px',
color:
language === item.code ? '#274B93' : '#333',
fontWeight:
language === item.code ? '700' : '400',
}}
>
{item.label}
</div>
))}
</div>

{/* Logout */}
<div
style={{ padding: '8px', cursor: 'pointer', color: 'red' }}
onClick={handleLogout}
style={{
padding: '14px 16px',
borderTop: '1px solid #eee',
cursor: 'pointer',
color: 'red',
fontWeight: '600',
}}
>
Logout
</div>
Expand Down
Loading
Loading