clean
This commit is contained in:
parent
ba33de6564
commit
2dcf62c597
@ -1,16 +1,83 @@
|
||||
#root {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100dvh;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
main {
|
||||
width: min(var(--content-max), 100%);
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
flex: 1 1 auto;
|
||||
margin: 0 auto;
|
||||
overflow-y: auto;
|
||||
padding: 2rem clamp(1.25rem, 3vw, 2.75rem);
|
||||
}
|
||||
|
||||
.page-route {
|
||||
width: 100%;
|
||||
max-width: var(--content-max);
|
||||
min-height: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
main.main--bounded {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
main.main--bounded .page-route {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
main.main--flow .page-route {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.page-route > .card,
|
||||
.page-route > .page-panel,
|
||||
.page-route > .page-container,
|
||||
.page-route > .weekly-schedule,
|
||||
.page-route > .home-page {
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
margin-right: 0;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.page-container {
|
||||
width: 100%;
|
||||
max-width: var(--content-max);
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.page-panel,
|
||||
.card {
|
||||
padding: clamp(1.35rem, 4vw, 2.25rem);
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.page-heading {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.page-heading h2,
|
||||
.page-panel > h2,
|
||||
.card > h2 {
|
||||
margin: 0;
|
||||
color: var(--text);
|
||||
font-size: clamp(1.35rem, 3vw, 1.8rem);
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.page-heading p {
|
||||
margin: 0.5rem 0 0;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
footer {
|
||||
flex-shrink: 0;
|
||||
padding: 1.5rem;
|
||||
@ -87,10 +154,6 @@ input:focus-visible {
|
||||
border-color: var(--danger);
|
||||
}
|
||||
|
||||
.admin-page h2 {
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.admin-toolbar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@ -157,16 +220,6 @@ input:focus-visible {
|
||||
margin-top: 0.45rem;
|
||||
}
|
||||
|
||||
form,
|
||||
.card,
|
||||
.profile-card {
|
||||
padding: clamp(1.35rem, 4vw, 2.25rem);
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
form {
|
||||
max-width: none;
|
||||
margin: 0;
|
||||
@ -176,29 +229,14 @@ form {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.card {
|
||||
width: 100%;
|
||||
max-width: var(--content-max);
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.admin-page,
|
||||
.weekly-summary-page,
|
||||
.time-clock-page,
|
||||
.profile-card,
|
||||
.home-container {
|
||||
.home-page {
|
||||
width: 100%;
|
||||
max-width: var(--content-max);
|
||||
}
|
||||
|
||||
.card h2,
|
||||
.profile-card h2 {
|
||||
margin: 0 0 1.5rem;
|
||||
color: var(--text);
|
||||
font-size: clamp(1.35rem, 3vw, 1.8rem);
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 1.2rem;
|
||||
}
|
||||
@ -211,9 +249,9 @@ form {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
input[type="text"],
|
||||
input[type="password"] {
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
width: 100%;
|
||||
min-height: 46px;
|
||||
padding: 0.7rem 0.8rem;
|
||||
@ -224,14 +262,24 @@ input[type="password"] {
|
||||
transition: var(--transition);
|
||||
}
|
||||
|
||||
.form-group input:focus,
|
||||
input[type="text"]:focus,
|
||||
input[type="password"]:focus {
|
||||
input:focus,
|
||||
select:focus,
|
||||
textarea:focus {
|
||||
border-color: var(--accent);
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 3px rgba(168, 93, 42, 0.12);
|
||||
}
|
||||
|
||||
.role-admin {
|
||||
color: var(--accent);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.role-user {
|
||||
color: var(--text);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Routes, Route, Navigate } from 'react-router-dom';
|
||||
import { Routes, Route, Navigate, useLocation } from 'react-router-dom';
|
||||
import LoginPage from './pages/LoginPage';
|
||||
import HomePage from './pages/HomePage';
|
||||
import ProtectedRoute from './components/ProtectedRoute';
|
||||
@ -11,38 +11,41 @@ import WeeklySummaryPage from './pages/WeeklySummaryPage';
|
||||
import './App.css';
|
||||
|
||||
function App() {
|
||||
const { pathname } = useLocation();
|
||||
const boundedPages = ['/weekly-summary'];
|
||||
const layoutMode = boundedPages.includes(pathname) ? 'bounded' : 'flow';
|
||||
|
||||
return (
|
||||
<div id="root">
|
||||
<Header />
|
||||
<main>
|
||||
<Routes>
|
||||
<Route path="/login" element={<LoginPage />} />
|
||||
<Route path="/register" element={<RegisterPage />} />
|
||||
<Route path="/pointage" element={
|
||||
<ProtectedRoute>
|
||||
<TimeClockPage />
|
||||
</ProtectedRoute>
|
||||
} />
|
||||
<Route
|
||||
path="/"
|
||||
element={
|
||||
<main className={`main--${layoutMode}`}>
|
||||
<div className="page-route">
|
||||
<Routes>
|
||||
<Route path="/login" element={<LoginPage />} />
|
||||
<Route path="/register" element={<RegisterPage />} />
|
||||
<Route path="/pointage" element={
|
||||
<ProtectedRoute>
|
||||
<TimeClockPage />
|
||||
</ProtectedRoute>
|
||||
} />
|
||||
<Route path="/" element={
|
||||
<ProtectedRoute>
|
||||
<HomePage />
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
<Route path="/users" element={
|
||||
<AdminRoute>
|
||||
<AdminUsersPage />
|
||||
</AdminRoute>
|
||||
} />
|
||||
<Route path="/weekly-summary" element={
|
||||
<ProtectedRoute>
|
||||
<WeeklySummaryPage />
|
||||
</ProtectedRoute>
|
||||
} />
|
||||
<Route path="*" element={<Navigate to="/" replace />} />
|
||||
</Routes>
|
||||
} />
|
||||
<Route path="/users" element={
|
||||
<AdminRoute>
|
||||
<AdminUsersPage />
|
||||
</AdminRoute>
|
||||
} />
|
||||
<Route path="/weekly-summary" element={
|
||||
<ProtectedRoute>
|
||||
<WeeklySummaryPage />
|
||||
</ProtectedRoute>
|
||||
} />
|
||||
<Route path="*" element={<Navigate to="/" replace />} />
|
||||
</Routes>
|
||||
</div>
|
||||
</main>
|
||||
<footer className="site-footer">
|
||||
<p>© 2026 Le Fournil du Bocage. Tous droits réservés.</p>
|
||||
|
||||
@ -46,6 +46,8 @@
|
||||
|
||||
.hamburger-btn {
|
||||
display: flex;
|
||||
position: relative;
|
||||
z-index: 1001;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
flex-direction: column;
|
||||
@ -95,14 +97,17 @@
|
||||
.hamburger-menu-overlay {
|
||||
position: fixed;
|
||||
inset: 76px 0 0;
|
||||
z-index: 99;
|
||||
z-index: 1000;
|
||||
overflow: hidden;
|
||||
background: rgba(15, 23, 42, 0.32);
|
||||
animation: fade-in 0.2s ease;
|
||||
}
|
||||
|
||||
.hamburger-menu-content {
|
||||
width: min(360px, 100%);
|
||||
min-height: calc(100% - 1rem);
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
overflow-y: auto;
|
||||
margin-left: auto;
|
||||
padding: 1.25rem;
|
||||
background: var(--surface);
|
||||
@ -215,6 +220,6 @@
|
||||
}
|
||||
|
||||
.hamburger-menu-content {
|
||||
min-height: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,6 +12,12 @@ const Header = () => {
|
||||
setIsMenuOpen((isOpen) => !isOpen);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
document.body.classList.toggle('menu-open', isMenuOpen);
|
||||
|
||||
return () => document.body.classList.remove('menu-open');
|
||||
}, [isMenuOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
const handleEscape = (event) => {
|
||||
if (event.key === 'Escape') {
|
||||
@ -30,26 +36,27 @@ const Header = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<header className="site-header">
|
||||
<div className="header-container">
|
||||
<Link to="/" className="brand" aria-label="Retour à l'accueil">
|
||||
<span className="brand-mark" aria-hidden="true">🍞</span>
|
||||
<span>Le Fournil du Bocage</span>
|
||||
</Link>
|
||||
<button
|
||||
className={`hamburger-btn${isMenuOpen ? ' open' : ''}`}
|
||||
onClick={toggleMenu}
|
||||
aria-expanded={isMenuOpen}
|
||||
aria-controls="main-menu"
|
||||
aria-label={isMenuOpen ? 'Fermer le menu' : 'Ouvrir le menu'}
|
||||
>
|
||||
<span className="hamburger-line" />
|
||||
<span className="hamburger-line" />
|
||||
<span className="hamburger-line" />
|
||||
</button>
|
||||
</div>
|
||||
<>
|
||||
<header className="site-header">
|
||||
<div className="header-container">
|
||||
<Link to="/" className="brand" aria-label="Retour à l'accueil">
|
||||
<span className="brand-mark" aria-hidden="true">🍞</span>
|
||||
<span>Le Fournil du Bocage</span>
|
||||
</Link>
|
||||
<button
|
||||
className={`hamburger-btn${isMenuOpen ? ' open' : ''}`}
|
||||
onClick={toggleMenu}
|
||||
aria-expanded={isMenuOpen}
|
||||
aria-controls="main-menu"
|
||||
aria-label={isMenuOpen ? 'Fermer le menu' : 'Ouvrir le menu'}
|
||||
>
|
||||
<span className="hamburger-line" />
|
||||
<span className="hamburger-line" />
|
||||
<span className="hamburger-line" />
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Menu hamburger */}
|
||||
{isMenuOpen && (
|
||||
<div className="hamburger-menu-overlay" onClick={toggleMenu}>
|
||||
<div
|
||||
@ -60,11 +67,7 @@ const Header = () => {
|
||||
onClick={(event) => event.stopPropagation()}
|
||||
>
|
||||
<div className="menu-heading">
|
||||
<div>
|
||||
<span className="menu-eyebrow">Navigation</span>
|
||||
<strong>{user ? `Bonjour ${user.username}` : 'Bienvenue'}</strong>
|
||||
</div>
|
||||
<button className="close-btn" onClick={toggleMenu} aria-label="Fermer le menu">×</button>
|
||||
<strong>{user ? `Bonjour ${user.username}` : 'Bienvenue'}</strong>
|
||||
</div>
|
||||
<div className="menu-links">
|
||||
{user ? (
|
||||
@ -86,7 +89,7 @@ const Header = () => {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</header>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -82,7 +82,7 @@ const AdminUsersPage = () => {
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="card admin-page">
|
||||
<div className="card page-container admin-page">
|
||||
<h2>Gestion des comptes</h2>
|
||||
<p>Chargement des utilisateurs...</p>
|
||||
</div>
|
||||
@ -90,7 +90,7 @@ const AdminUsersPage = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="card admin-page">
|
||||
<div className="card page-container admin-page">
|
||||
<h2>Gestion des comptes</h2>
|
||||
{error && <div className="alert alert-danger">{error}</div>}
|
||||
|
||||
@ -135,9 +135,9 @@ const AdminUsersPage = () => {
|
||||
<td>{user.username}</td>
|
||||
<td>
|
||||
{user.is_admin ? (
|
||||
<span style={{ color: 'var(--accent)', fontWeight: '500' }}>Administrateur</span>
|
||||
<span className="role-admin">Administrateur</span>
|
||||
) : (
|
||||
<span style={{ color: 'var(--text)', fontWeight: '500' }}>Utilisateur</span>
|
||||
<span className="role-user">Utilisateur</span>
|
||||
)}
|
||||
</td>
|
||||
<td>{new Date(user.date_joined).toLocaleDateString('fr-FR')}</td>
|
||||
|
||||
@ -1,12 +1,3 @@
|
||||
.home-container {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.profile-card {
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
display: grid;
|
||||
gap: 0.75rem;
|
||||
|
||||
@ -26,8 +26,8 @@ const HomePage = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="home-container">
|
||||
<div className="profile-card">
|
||||
<div className="page-panel page-container home-page">
|
||||
<div className="page-heading">
|
||||
<h2>Profil Utilisateur</h2>
|
||||
{userData && (
|
||||
<div className="user-info">
|
||||
|
||||
@ -1,24 +1,24 @@
|
||||
.login-container {
|
||||
.auth-page {
|
||||
display: grid;
|
||||
min-height: min(620px, calc(100vh - 190px));
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
.login-card {
|
||||
.auth-card {
|
||||
width: min(100%, 460px);
|
||||
padding: clamp(1.35rem, 5vw, 2.5rem);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.login-card h2 {
|
||||
.auth-card h2 {
|
||||
margin-bottom: 0.45rem;
|
||||
}
|
||||
|
||||
.login-card .form-group {
|
||||
.auth-card .form-group {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.login-card .btn {
|
||||
.auth-card .btn {
|
||||
width: 100%;
|
||||
margin-top: 0.4rem;
|
||||
}
|
||||
|
||||
@ -26,8 +26,8 @@ const LoginPage = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="login-container">
|
||||
<div className="card login-card">
|
||||
<div className="auth-page">
|
||||
<div className="page-panel auth-card">
|
||||
<h2>Connexion</h2>
|
||||
{error && <div className="alert alert-danger">{error}</div>}
|
||||
<form onSubmit={handleSubmit}>
|
||||
|
||||
@ -23,16 +23,16 @@ const RegisterPage = () => {
|
||||
};
|
||||
|
||||
if (!invite) {
|
||||
return <div className="login-container"><div className="card login-card"><h2>Lien invalide</h2><p>Un lien d’invitation est nécessaire pour créer un compte.</p></div></div>;
|
||||
return <div className="auth-page"><div className="page-panel auth-card"><h2>Lien invalide</h2><p>Un lien d’invitation est nécessaire pour créer un compte.</p></div></div>;
|
||||
}
|
||||
|
||||
if (isCreated) {
|
||||
return <div className="login-container"><div className="card login-card"><h2>Compte créé</h2><p>Votre compte est prêt. Vous pouvez maintenant vous connecter.</p><button className="btn btn-primary" onClick={() => navigate('/login')}>Se connecter</button></div></div>;
|
||||
return <div className="auth-page"><div className="page-panel auth-card"><h2>Compte créé</h2><p>Votre compte est prêt. Vous pouvez maintenant vous connecter.</p><button className="btn btn-primary" onClick={() => navigate('/login')}>Se connecter</button></div></div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="login-container">
|
||||
<div className="card login-card">
|
||||
<div className="auth-page">
|
||||
<div className="page-panel auth-card">
|
||||
<h2>Créer un compte</h2>
|
||||
{error && <div className="alert alert-danger">{error}</div>}
|
||||
<form onSubmit={handleSubmit}>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
.time-clock-page {
|
||||
min-height: 100%;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
@ -75,94 +76,58 @@
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
/* New styles for time tracking */
|
||||
.time-tracking-section {
|
||||
margin-top: 30px;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.current-time-display {
|
||||
text-align: center;
|
||||
margin: 20px 0;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
.admin-time-layout {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(280px, 0.42fr);
|
||||
gap: 24px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.admin-entry-panel {
|
||||
grid-column: 2;
|
||||
grid-row: 1;
|
||||
}
|
||||
|
||||
.admin-time-layout .time-entries-list {
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
min-width: 0;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.time-entry-form {
|
||||
background-color: #f8f9fa;
|
||||
padding: 20px;
|
||||
border: 1px solid var(--accent);
|
||||
border-radius: 8px;
|
||||
margin: 20px 0;
|
||||
margin: 1.25rem 0;
|
||||
padding: 1.25rem;
|
||||
background: var(--surface-muted);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
|
||||
.time-entry-form h4 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.form-group input {
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
.time-entries-list {
|
||||
margin: 20px 0;
|
||||
margin: 1.25rem 0;
|
||||
}
|
||||
|
||||
.time-entries-list h4 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 15px;
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 12px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #f8f9fa;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.btn-small {
|
||||
padding: 5px 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.total-hours {
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
padding: 15px;
|
||||
background-color: #e9ecef;
|
||||
margin-top: 1.25rem;
|
||||
padding: 1rem;
|
||||
background: var(--surface-muted);
|
||||
}
|
||||
|
||||
.scan-conflict {
|
||||
@ -182,4 +147,16 @@ th {
|
||||
|
||||
.scan-conflict input {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.admin-time-layout {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.admin-entry-panel,
|
||||
.admin-time-layout .time-entries-list {
|
||||
grid-column: auto;
|
||||
grid-row: auto;
|
||||
}
|
||||
}
|
||||
@ -368,100 +368,89 @@ const TimeClockPage = () => {
|
||||
|
||||
{/* Time tracking section */}
|
||||
<div className="time-tracking-section">
|
||||
|
||||
{/* Current time display */}
|
||||
<div className="current-time-display">
|
||||
<p>Heure actuelle: {currentTime.toLocaleTimeString('fr-FR')}</p>
|
||||
</div>
|
||||
|
||||
{ (isAdmin && editingEntry) ?
|
||||
(
|
||||
<div className="time-entry-form">
|
||||
<h4>Modifier le pointage du {formatDate(editingEntry.date)}</h4>
|
||||
<form onSubmit={handleUpdateEntry}>
|
||||
<div className="form-group">
|
||||
<label htmlFor="edit-start-time">Heure d'entrée :</label>
|
||||
<input
|
||||
id="edit-start-time"
|
||||
type="time"
|
||||
value={editForm.start_time}
|
||||
onChange={(e) => setEditForm({ ...editForm, start_time: e.target.value })}
|
||||
/>
|
||||
<div className={isAdmin ? 'admin-time-layout' : undefined}>
|
||||
{isAdmin && (
|
||||
<div className="admin-entry-panel">
|
||||
{editingEntry ? (
|
||||
<div className="time-entry-form">
|
||||
<h4>Modifier le pointage du {formatDate(editingEntry.date)}</h4>
|
||||
<form onSubmit={handleUpdateEntry}>
|
||||
<div className="form-group">
|
||||
<label htmlFor="edit-start-time">Heure d'entrée :</label>
|
||||
<input
|
||||
id="edit-start-time"
|
||||
type="time"
|
||||
value={editForm.start_time}
|
||||
onChange={(e) => setEditForm({ ...editForm, start_time: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label htmlFor="edit-end-time">Heure de sortie :</label>
|
||||
<input
|
||||
id="edit-end-time"
|
||||
type="time"
|
||||
value={editForm.end_time}
|
||||
onChange={(e) => setEditForm({ ...editForm, end_time: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div className="btn-group">
|
||||
<button type="submit" className="btn btn-primary">Enregistrer</button>
|
||||
<button type="button" className="btn btn-secondary" onClick={() => setEditingEntry(null)}>
|
||||
Annuler
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label htmlFor="edit-end-time">Heure de sortie :</label>
|
||||
<input
|
||||
id="edit-end-time"
|
||||
type="time"
|
||||
value={editForm.end_time}
|
||||
onChange={(e) => setEditForm({ ...editForm, end_time: e.target.value })}
|
||||
/>
|
||||
) : (
|
||||
<div className="time-entry-form">
|
||||
<h4>Ajouter un pointage manuel</h4>
|
||||
<form onSubmit={handleAddEntry}>
|
||||
<div className="form-group">
|
||||
<label>Date:</label>
|
||||
<input
|
||||
type="date"
|
||||
value={newEntry.date}
|
||||
onChange={(e) => setNewEntry({...newEntry, date: e.target.value})}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label>Date de sortie:</label>
|
||||
<input
|
||||
type="date"
|
||||
value={newEntry.end_date}
|
||||
min={newEntry.date}
|
||||
onChange={(e) => setNewEntry({...newEntry, end_date: e.target.value})}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label>Heure d'entrée:</label>
|
||||
<input
|
||||
type="time"
|
||||
value={newEntry.start_time}
|
||||
onChange={(e) => setNewEntry({...newEntry, start_time: e.target.value})}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label>Heure de sortie:</label>
|
||||
<input
|
||||
type="time"
|
||||
value={newEntry.end_time}
|
||||
onChange={(e) => setNewEntry({...newEntry, end_time: e.target.value})}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<button type="submit" className="btn btn-primary">Ajouter le pointage</button>
|
||||
</form>
|
||||
</div>
|
||||
<div className="btn-group">
|
||||
<button type="submit" className="btn btn-primary">Enregistrer</button>
|
||||
<button type="button" className="btn btn-secondary" onClick={() => setEditingEntry(null)}>
|
||||
Annuler
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
:
|
||||
(
|
||||
<div>
|
||||
{isAdmin &&
|
||||
(
|
||||
<div className="time-entry-form">
|
||||
<h4>Ajouter un pointage manuel</h4>
|
||||
<form onSubmit={handleAddEntry}>
|
||||
<div className="form-group">
|
||||
<label>Date:</label>
|
||||
<input
|
||||
type="date"
|
||||
value={newEntry.date}
|
||||
onChange={(e) => setNewEntry({...newEntry, date: e.target.value})}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label>Date de sortie:</label>
|
||||
<input
|
||||
type="date"
|
||||
value={newEntry.end_date}
|
||||
min={newEntry.date}
|
||||
onChange={(e) => setNewEntry({...newEntry, end_date: e.target.value})}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label>Heure d'entrée:</label>
|
||||
<input
|
||||
type="time"
|
||||
value={newEntry.start_time}
|
||||
onChange={(e) => setNewEntry({...newEntry, start_time: e.target.value})}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="form-group">
|
||||
<label>Heure de sortie:</label>
|
||||
<input
|
||||
type="time"
|
||||
value={newEntry.end_time}
|
||||
onChange={(e) => setNewEntry({...newEntry, end_time: e.target.value})}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<button type="submit" className="btn btn-primary">Ajouter le pointage</button>
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)}
|
||||
|
||||
{/* Time entries list */}
|
||||
<div className="time-entries-list">
|
||||
{/* Time entries list */}
|
||||
<div className="time-entries-list">
|
||||
<h4>Historique des pointages</h4>
|
||||
{loading ? (
|
||||
<p>Chargement des pointages...</p>
|
||||
@ -514,6 +503,7 @@ const TimeClockPage = () => {
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
.weekly-schedule {
|
||||
margin: 0;
|
||||
padding: 24px;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
flex-direction: column;
|
||||
color: var(--text);
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.weekly-schedule.loading,
|
||||
@ -111,6 +109,7 @@
|
||||
border-radius: var(--radius-sm);
|
||||
scrollbar-color: #cbbbae transparent;
|
||||
scrollbar-width: thin;
|
||||
max-height: 80vh; /* Ajout pour limiter la hauteur maximale */
|
||||
}
|
||||
|
||||
.schedule-day-header {
|
||||
@ -265,5 +264,4 @@
|
||||
.nav-button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
}
|
||||
@ -231,7 +231,7 @@ const WeeklySummaryPage = ({ userId }) => {
|
||||
.map((username) => ({ username, color: getUserColor(username) }));
|
||||
|
||||
return (
|
||||
<div className={`weekly-schedule${isAdmin ? ' multi-user-schedule' : ''}`}>
|
||||
<div className={`weekly-schedule card${isAdmin ? ' multi-user-schedule' : ''}`}>
|
||||
<div className="schedule-header">
|
||||
<div>
|
||||
<span className="page-eyebrow">{isAdmin ? 'Vue équipe' : 'Votre présence'}</span>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user