Aplikacja Magico Pracownik

This commit is contained in:
2026-05-28 12:56:03 +02:00
parent 9b3c3848a7
commit 83c055cc09
10 changed files with 1248 additions and 0 deletions

View File

@@ -0,0 +1,297 @@
:root {
--primary-color: #696cff;
--primary-hover: #5f61e6;
--bg-light: #f5f5f9;
--text-dark: #32475c;
--text-muted: #8592a3;
--white: #ffffff;
--border-color: #e4e6f4;
--shadow-sm: 0 0.125rem 0.25rem rgba(161, 172, 184, 0.2);
--shadow-md: 0 0.25rem 0.5rem rgba(161, 172, 184, 0.3);
--radius-md: 0.5rem;
--radius-lg: 0.75rem;
}
body {
background-color: var(--bg-light);
color: var(--text-dark);
font-family: 'Public Sans', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
-webkit-font-smoothing: antialiased;
max-width: 500px;
margin: 0 auto;
position: relative;
box-shadow: 0 0 20px rgba(0,0,0,0.05);
min-height: 100vh;
}
html {
background-color: #e9ecef;
}
/* Utilities */
.text-primary-custom { color: var(--primary-color) !important; }
.bg-primary-custom { background-color: var(--primary-color) !important; color: var(--white); }
/* Buttons */
.btn-primary {
background-color: var(--primary-color);
border-color: var(--primary-color);
border-radius: var(--radius-md);
padding: 0.6rem 1.2rem;
font-weight: 600;
}
.btn-primary:hover, .btn-primary:focus {
background-color: var(--primary-hover);
border-color: var(--primary-hover);
}
/* Cards & Tiles */
.card-custom {
background: var(--white);
border: none;
border-radius: var(--radius-lg);
box-shadow: var(--shadow-sm);
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.card-custom:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-md);
}
/* Form inputs */
.form-control {
border-radius: var(--radius-md);
padding: 0.75rem 1rem;
border: 1px solid var(--border-color);
}
.form-control:focus {
border-color: var(--primary-color);
box-shadow: 0 0 0 0.25rem rgba(105, 108, 255, 0.1);
}
/* Topbar */
.app-topbar {
background: var(--white);
box-shadow: var(--shadow-sm);
padding: 1rem;
display: flex;
justify-content: space-between;
align-items: center;
position: sticky;
top: 0;
z-index: 1000;
}
.app-topbar .app-title {
font-weight: 700;
font-size: 1.1rem;
margin: 0;
color: var(--text-dark);
}
.user-avatar {
width: 38px;
height: 38px;
border-radius: 50%;
background-color: rgba(105, 108, 255, 0.1);
color: var(--primary-color);
display: flex;
align-items: center;
justify-content: center;
font-size: 1.2rem;
}
/* RCP Hero Button */
.btn-rcp {
border-radius: var(--radius-lg);
padding: 1.25rem;
font-size: 1.1rem;
font-weight: 600;
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
box-shadow: 0 0.5rem 1rem rgba(105, 108, 255, 0.2);
}
/* Grid Tiles */
.tile {
text-decoration: none;
color: var(--text-dark);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 1.5rem 1rem;
text-align: center;
height: 100%;
}
.tile .tile-icon {
font-size: 2.5rem;
color: var(--primary-color);
margin-bottom: 0.75rem;
background: rgba(105, 108, 255, 0.1);
width: 64px;
height: 64px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.tile .tile-title {
font-weight: 600;
font-size: 0.95rem;
margin: 0;
}
/* Select Company List */
.company-list-item {
display: flex;
align-items: center;
padding: 1rem;
border-bottom: 1px solid var(--border-color);
text-decoration: none;
color: var(--text-dark);
transition: background-color 0.2s;
}
.company-list-item:hover {
background-color: var(--bg-light);
}
.company-list-item:last-child {
border-bottom: none;
}
.company-logo-placeholder {
width: 48px;
height: 48px;
border-radius: var(--radius-md);
background-color: var(--primary-color);
color: var(--white);
display: flex;
align-items: center;
justify-content: center;
font-size: 1.2rem;
font-weight: bold;
margin-right: 1rem;
}
/* Location Loader & Animations */
.location-loader {
position: relative;
width: 80px;
height: 80px;
margin: 0 auto;
display: flex;
align-items: center;
justify-content: center;
}
.location-loader .pulse {
position: absolute;
width: 100%;
height: 100%;
background-color: rgba(105, 108, 255, 0.4);
border-radius: 50%;
z-index: 1;
animation: pulse-animation 1.5s infinite cubic-bezier(0.215, 0.61, 0.355, 1);
}
@keyframes pulse-animation {
0% { transform: scale(0.5); opacity: 1; }
100% { transform: scale(1.5); opacity: 0; }
}
@keyframes bounce-pin {
0%, 100% { transform: translateY(0) rotate(0deg); }
25% { transform: translateY(-15px) rotate(-10deg); }
50% { transform: translateY(0) rotate(0deg); }
75% { transform: translateY(-5px) rotate(10deg); }
}
.bouncing-pin {
animation: bounce-pin 1.2s infinite ease-in-out;
display: inline-block;
}
/* Text Fade Transition */
.fade-transition {
transition: opacity 0.4s ease-in-out;
}
.fade-out {
opacity: 0 !important;
}
/* Calendar Grid */
.calendar-grid {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 5px;
margin-bottom: 1rem;
}
.calendar-header-day {
text-align: center;
font-size: 0.7rem;
font-weight: 700;
color: var(--text-muted);
text-transform: uppercase;
padding-bottom: 5px;
}
.calendar-day {
aspect-ratio: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: var(--radius-md);
background-color: var(--white);
font-size: 0.85rem;
font-weight: 600;
color: var(--text-dark);
position: relative;
box-shadow: 0 2px 4px rgba(161, 172, 184, 0.1);
cursor: pointer;
transition: transform 0.2s, background-color 0.2s;
}
.calendar-day.empty {
background-color: transparent;
box-shadow: none;
cursor: default;
}
.calendar-day:active:not(.empty) {
transform: scale(0.95);
}
.calendar-day.active {
background-color: var(--primary-color);
color: var(--white);
}
.calendar-day .shift-dot {
width: 6px;
height: 6px;
border-radius: 50%;
margin-top: 3px;
}
.calendar-day .shift-dot.blue { background-color: var(--primary-color); }
.calendar-day .shift-dot.green { background-color: #71dd37; }
.calendar-day .shift-dot.purple { background-color: #e83e8c; }
.calendar-day.active .shift-dot { background-color: var(--white) !important; }
/* Custom Badges (Sneat style) */
.bg-label-primary {
background-color: rgba(105, 108, 255, 0.16) !important;
color: var(--primary-color) !important;
}
.bg-label-success {
background-color: rgba(113, 221, 55, 0.16) !important;
color: #71dd37 !important;
}
.bg-label-warning {
background-color: rgba(255, 171, 0, 0.16) !important;
color: #ffab00 !important;
}
.bg-label-danger {
background-color: rgba(255, 62, 29, 0.16) !important;
color: #ff3e1d !important;
}
.bg-label-secondary {
background-color: rgba(133, 146, 163, 0.16) !important;
color: #8592a3 !important;
}

View File

@@ -0,0 +1,12 @@
<!-- Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<!-- Magico Feedback JS -->
<script>
const MAGICO_BASE_URL = <?= json_encode($basePath); ?>;
</script>
<?php if (!empty($enablePrototypeComments) && $enablePrototypeComments): ?>
<script src="<?= $basePath ?>/assets/js/comments.js"></script>
<?php endif; ?>
</body>
</html>

View File

@@ -0,0 +1,33 @@
<?php
$basePath = '';
if ($_SERVER['HTTP_HOST'] === 'localhost' || $_SERVER['HTTP_HOST'] === '127.0.0.1') {
$basePath = '/magico-prototype';
}
?>
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Pracownik Magico</title>
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Public+Sans:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Boxicons -->
<link href="https://cdn.jsdelivr.net/npm/boxicons@2.1.4/css/boxicons.min.css" rel="stylesheet">
<!-- Custom CSS -->
<link rel="stylesheet" href="assets/css/style.css">
<!-- Magico Feedback CSS -->
<?php if (!empty($enablePrototypeComments) && $enablePrototypeComments): ?>
<link rel="stylesheet" href="<?= $basePath ?>/assets/css/comments.css">
<?php endif; ?>
</head>
<body>

View File

@@ -0,0 +1,304 @@
<?php
$enablePrototypeComments = true;
include 'header.php';
?>
<div class="app-topbar">
<div class="d-flex align-items-center">
<div class="d-flex justify-content-center align-items-center bg-primary-custom rounded-circle me-2"
style="width: 32px; height: 32px;">
<i class='bx bx-cube-alt text-white'></i>
</div>
<h1 class="app-title">Acme Corp</h1>
</div>
<div class="user-avatar shadow-sm">
<i class='bx bx-user'></i>
</div>
</div>
<div class="container py-4">
<!-- Hero / RCP Button -->
<div class="mb-4" id="rcp-container">
<h5 class="fw-bold mb-3">Dzień dobry, Marcin 👋</h5>
<!-- Stan 1: Rozpocznij -->
<div id="rcp-start-state">
<button class="btn btn-primary w-100 btn-rcp" data-bs-toggle="modal" data-bs-target="#rcpModal">
<i class='bx bx-fingerprint fs-3'></i>
Rozpocznij pracę
</button>
<div class="text-center mt-2">
<small class="text-muted">Zarejestruj wejście do firmy</small>
</div>
</div>
<!-- Stan 2: W trakcie pracy -->
<div id="rcp-active-state" class="d-none">
<div class="d-flex gap-2">
<button class="btn btn-outline-warning w-50 btn-rcp" style="padding: 1rem; font-size: 1rem;"
data-bs-toggle="modal" data-bs-target="#breakModal">
<i class='bx bx-coffee fs-4'></i>
<span>Przerwa</span>
</button>
<button class="btn btn-danger w-50 btn-rcp" style="padding: 1rem; font-size: 1rem;"
data-bs-toggle="modal" data-bs-target="#endWorkModal">
<i class='bx bx-log-out fs-4'></i>
Zakończ
</button>
</div>
<div class="text-center mt-2">
<small class="text-success fw-bold"><i class='bx bx-check-circle'></i> Pracujesz od 08:00</small>
</div>
</div>
</div>
<!-- Grid -->
<div class="row g-3">
<div class="col-6">
<a href="schedule.php" class="card-custom tile">
<div class="tile-icon">
<i class='bx bx-calendar-event'></i>
</div>
<h2 class="tile-title">Grafik Pracy</h2>
</a>
</div>
<div class="col-6">
<a href="vacations.php" class="card-custom tile">
<div class="tile-icon text-success" style="background: rgba(113, 221, 55, 0.1);">
<i class='bx bx-sun'></i>
</div>
<h2 class="tile-title mt-2">Urlopy</h2>
</a>
</div>
</div>
</div>
<!-- Modal RCP -->
<div class="modal fade" id="rcpModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content border-0 shadow" style="border-radius: var(--radius-lg);">
<div class="modal-body p-4 text-center">
<!-- Krok 1: Potwierdzenie -->
<div id="rcp-step-confirm">
<div class="mb-3">
<i class='bx bx-map-pin text-primary' style="font-size: 4rem;"></i>
</div>
<h4 class="fw-bold mb-2">Rozpocząć pracę?</h4>
<p class="text-muted mb-4">System zweryfikuje Twoją lokalizację GPS z dozwoloną strefą dla tej
firmy.</p>
<div class="d-flex gap-2">
<button type="button" class="btn btn-outline-secondary w-50"
data-bs-dismiss="modal">Anuluj</button>
<button type="button" class="btn btn-primary w-50" id="btn-confirm-start">Tak,
rozpocznij</button>
</div>
</div>
<!-- Krok 2: Ładowanie (Lokalizacja) -->
<div id="rcp-step-loading" class="d-none py-3">
<div class="location-loader mb-4">
<div class="pulse"></div>
<i class='bx bxs-map-pin text-primary bouncing-pin'
style="font-size: 3.5rem; position: relative; z-index: 2;"></i>
</div>
<h5 class="fw-bold mb-1">Weryfikacja lokalizacji...</h5>
<p class="text-muted small fade-transition" id="loading-text-dynamic" style="min-height: 20px;">
Rozglądamy się za Tobą 🛰️</p>
</div>
<!-- Krok 3: Sukces -->
<div id="rcp-step-success" class="d-none py-3">
<div class="mb-3">
<i class='bx bx-check-circle text-success' style="font-size: 4rem;"></i>
</div>
<h4 class="fw-bold mb-1">Zalogowano pomyślnie!</h4>
<p class="text-muted">Twoja praca została rozpoczęta.</p>
</div>
</div>
</div>
</div>
</div>
<!-- Modal Przerwy -->
<div class="modal fade" id="breakModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content border-0 shadow" style="border-radius: var(--radius-lg);">
<div class="modal-body p-4 text-center">
<div class="mb-3">
<i class='bx bx-coffee text-warning' style="font-size: 4rem;" id="break-modal-icon"></i>
</div>
<h4 class="fw-bold mb-2" id="break-modal-title">Rozpocząć przerwę?</h4>
<p class="text-muted mb-4" id="break-modal-desc">Twój czas pracy zostanie wstrzymany na czas trwania
przerwy.</p>
<div class="d-flex gap-2">
<button type="button" class="btn btn-outline-secondary w-50" data-bs-dismiss="modal">Anuluj</button>
<button type="button" class="btn btn-warning w-50 text-white" id="btn-confirm-break"
data-bs-dismiss="modal">Tak, rozpocznij</button>
</div>
</div>
</div>
</div>
</div>
<!-- Modal Zakończenia Pracy -->
<div class="modal fade" id="endWorkModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content border-0 shadow" style="border-radius: var(--radius-lg);">
<div class="modal-body p-4 text-center">
<div class="mb-3">
<i class='bx bx-log-out-circle text-danger' style="font-size: 4rem;"></i>
</div>
<h4 class="fw-bold mb-2">Zakończyć pracę?</h4>
<p class="text-muted mb-4">Twój dzisiejszy czas pracy zostanie podsumowany i zapisany.</p>
<div class="d-flex gap-2">
<button type="button" class="btn btn-outline-secondary w-50" data-bs-dismiss="modal">Anuluj</button>
<button type="button" class="btn btn-danger w-50" id="btn-confirm-end" data-bs-dismiss="modal">Tak,
zakończ</button>
</div>
</div>
</div>
</div>
</div>
<?php include 'footer.php'; ?>
<script>
document.addEventListener('DOMContentLoaded', function () {
const btnConfirm = document.getElementById('btn-confirm-start');
const stepConfirm = document.getElementById('rcp-step-confirm');
const stepLoading = document.getElementById('rcp-step-loading');
const stepSuccess = document.getElementById('rcp-step-success');
const stateStart = document.getElementById('rcp-start-state');
const stateActive = document.getElementById('rcp-active-state');
const rcpModalEl = document.getElementById('rcpModal');
let rcpModal;
if (typeof bootstrap !== 'undefined') {
rcpModal = new bootstrap.Modal(rcpModalEl);
}
// Po zamknięciu modala, resetuj widoki, jeśli był w trakcie itp
rcpModalEl.addEventListener('hidden.bs.modal', event => {
// Resetujemy tylko jeśli nie jesteśmy w trakcie pokazywania sukcesu
if (stepSuccess.classList.contains('d-none')) {
stepConfirm.classList.remove('d-none');
stepLoading.classList.add('d-none');
stepSuccess.classList.add('d-none');
}
});
btnConfirm.addEventListener('click', function () {
// Pokaż ładowanie
stepConfirm.classList.add('d-none');
stepLoading.classList.remove('d-none');
const textElement = document.getElementById('loading-text-dynamic');
const messages = [
"Rozglądamy się za Tobą 🛰️",
"Sprawdzamy współrzędne GPS 🛰️",
"Kalibrujemy pozycję 📍",
"Łączymy się z satelitą 📡",
"Weryfikujemy strefę pracy 🗺️",
"Analizujemy zasięg sygnału 📶",
"Pobieramy dane lokalizacyjne ⏳",
"Jeszcze chwilę... prawie gotowe! 🚀"
];
let msgIndex = 0;
textElement.textContent = messages[0];
const intervalId = setInterval(() => {
// Rozpocznij zanikanie
textElement.classList.add('fade-out');
setTimeout(() => {
// Po zaniknięciu (400ms), zmień tekst i pokaż ponownie
msgIndex = (msgIndex + 1) % messages.length;
textElement.textContent = messages[msgIndex];
textElement.classList.remove('fade-out');
}, 400);
}, 2500);
// Symulacja weryfikacji GPS (Wydłużona do 8.5 sekund)
setTimeout(() => {
clearInterval(intervalId);
stepLoading.classList.add('d-none');
stepSuccess.classList.remove('d-none');
// Zamknij modal po 1.5 sekundy od sukcesu i zmień stan
setTimeout(() => {
if (rcpModal) rcpModal.hide();
stateStart.classList.add('d-none');
stateActive.classList.remove('d-none');
// Przywróć stan początkowy modala do ponownego użycia w przyszłości
setTimeout(() => {
stepConfirm.classList.remove('d-none');
stepLoading.classList.add('d-none');
stepSuccess.classList.add('d-none');
}, 500);
}, 1500);
}, 8500);
});
// Obsługa przerwy
const btnConfirmBreak = document.getElementById('btn-confirm-break');
const breakBtnElement = document.querySelector('button[data-bs-target="#breakModal"]');
let isBreakActive = false;
btnConfirmBreak.addEventListener('click', function () {
if (!isBreakActive) {
// Rozpocznij przerwę
isBreakActive = true;
breakBtnElement.innerHTML = "<i class='bx bx-play-circle fs-4'></i><span>Wznów</span>";
breakBtnElement.classList.replace('btn-outline-warning', 'btn-warning');
breakBtnElement.classList.add('text-white');
// Zmiana tekstów modala na "Powrót z przerwy"
document.getElementById('break-modal-icon').className = "bx bx-play-circle text-warning";
document.getElementById('break-modal-title').textContent = "Zakończyć przerwę?";
document.getElementById('break-modal-desc').textContent = "Twój czas pracy zostanie wznowiony.";
btnConfirmBreak.textContent = "Tak, wznów";
} else {
// Zakończ przerwę
isBreakActive = false;
breakBtnElement.innerHTML = "<i class='bx bx-coffee fs-4'></i><span>Przerwa</span>";
breakBtnElement.classList.replace('btn-warning', 'btn-outline-warning');
breakBtnElement.classList.remove('text-white');
// Zmiana tekstów modala z powrotem na "Rozpocznij przerwę"
document.getElementById('break-modal-icon').className = "bx bx-coffee text-warning";
document.getElementById('break-modal-title').textContent = "Rozpocząć przerwę?";
document.getElementById('break-modal-desc').textContent = "Twój czas pracy zostanie wstrzymany na czas trwania przerwy.";
btnConfirmBreak.textContent = "Tak, rozpocznij";
}
});
// Obsługa zakończenia pracy
const btnConfirmEnd = document.getElementById('btn-confirm-end');
btnConfirmEnd.addEventListener('click', function () {
// Wróć do ekranu startowego
stateActive.classList.add('d-none');
stateStart.classList.remove('d-none');
// Resetuj stan przerwy jeśli była aktywna
if (isBreakActive) {
isBreakActive = false;
breakBtnElement.innerHTML = "<i class='bx bx-coffee fs-4'></i><span>Przerwa</span>";
breakBtnElement.classList.replace('btn-warning', 'btn-outline-warning');
breakBtnElement.classList.remove('text-white');
document.getElementById('break-modal-icon').className = "bx bx-coffee text-warning";
document.getElementById('break-modal-title').textContent = "Rozpocząć przerwę?";
document.getElementById('break-modal-desc').textContent = "Twój czas pracy zostanie wstrzymany na czas trwania przerwy.";
btnConfirmBreak.textContent = "Tak, rozpocznij";
}
});
});
</script>

View File

@@ -0,0 +1,48 @@
<?php
$enablePrototypeComments = true;
include 'header.php';
?>
<div class="container d-flex flex-column justify-content-center align-items-center min-vh-100 py-5">
<div class="text-center mb-5">
<div class="d-inline-flex align-items-center justify-content-center bg-primary-custom rounded-circle mb-3"
style="width: 80px; height: 80px;">
<i class='bx bx-cube-alt text-white' style="font-size: 3rem;"></i>
</div>
<h2 class="fw-bold mb-1">Pracownik Magico</h2>
<p class="text-muted">Zaloguj się do swojego konta</p>
</div>
<div class="card-custom w-100 p-4" style="max-width: 400px;">
<form action="select-company.php" method="GET">
<div class="mb-3">
<label for="email" class="form-label text-muted small fw-semibold text-uppercase">Adres e-mail</label>
<input type="email" class="form-control" id="email" placeholder="jan.kowalski@firma.pl"
value="jan@magico.pl">
</div>
<div class="mb-4">
<div class="d-flex justify-content-between">
<label for="password" class="form-label text-muted small fw-semibold text-uppercase">Hasło</label>
<a href="#" class="text-primary-custom small text-decoration-none">Zapomniałeś hasła?</a>
</div>
<div class="input-group input-group-merge">
<input type="password" id="password" class="form-control"
placeholder="&#xb7;&#xb7;&#xb7;&#xb7;&#xb7;&#xb7;&#xb7;&#xb7;&#xb7;&#xb7;&#xb7;&#xb7;"
value="fdsaf45tfsgtyr">
</div>
</div>
<div class="mb-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="remember-me" checked>
<label class="form-check-label" for="remember-me"> Zapamiętaj mnie </label>
</div>
</div>
<button class="btn btn-primary w-100" type="submit">Zaloguj się</button>
</form>
</div>
</div>
<?php include 'footer.php'; ?>

View File

@@ -0,0 +1,126 @@
<?php
$enablePrototypeComments = true;
include 'header.php';
?>
<!-- Główny Topbar -->
<div class="app-topbar">
<div class="d-flex align-items-center">
<div class="d-flex justify-content-center align-items-center bg-primary-custom rounded-circle me-2" style="width: 32px; height: 32px;">
<i class='bx bx-cube-alt text-white'></i>
</div>
<h1 class="app-title">Acme Corp</h1>
</div>
<div class="user-avatar shadow-sm">
<i class='bx bx-user'></i>
</div>
</div>
<!-- Pasek tytułowy sekcji -->
<div class="container pt-4">
<div class="d-flex justify-content-between align-items-center pb-3 mb-4" style="border-bottom: 1px solid var(--border-color);">
<div class="d-flex align-items-center">
<a href="home.php" class="text-dark me-2 d-flex align-items-center justify-content-center" style="width: 32px; height: 32px; background: rgba(0,0,0,0.05); border-radius: 50%;">
<i class='bx bx-arrow-back fs-4'></i>
</a>
<h2 class="fw-bold mb-0" style="font-size: 1.25rem;">Mój Grafik</h2>
</div>
<!-- Zmieniona ikona na widok listy -->
<a href="schedule.php" class="text-primary-custom d-flex align-items-center justify-content-center" style="width: 36px; height: 36px; background: rgba(105, 108, 255, 0.1); border-radius: 8px;">
<i class='bx bx-list-ul fs-4'></i>
</a>
</div>
</div>
<div class="container pb-4">
<!-- Przełącznik miesiąca -->
<div class="d-flex justify-content-between align-items-center mb-3">
<button class="btn btn-sm btn-link text-dark text-decoration-none"><i class='bx bx-chevron-left fs-4'></i></button>
<span class="fw-bold">Sierpień 2026</span>
<button class="btn btn-sm btn-link text-dark text-decoration-none"><i class='bx bx-chevron-right fs-4'></i></button>
</div>
<!-- Siatka Kalendarza -->
<div class="calendar-grid">
<div class="calendar-header-day">Pn</div>
<div class="calendar-header-day">Wt</div>
<div class="calendar-header-day">Śr</div>
<div class="calendar-header-day">Cz</div>
<div class="calendar-header-day">Pt</div>
<div class="calendar-header-day">So</div>
<div class="calendar-header-day">Nd</div>
<!-- Tydzień 1 (zaczynamy od pustych dni) -->
<div class="calendar-day empty"></div>
<div class="calendar-day empty"></div>
<div class="calendar-day empty"></div>
<div class="calendar-day empty"></div>
<div class="calendar-day empty"></div>
<div class="calendar-day text-muted" style="opacity: 0.5;">1</div>
<div class="calendar-day text-muted" style="opacity: 0.5;">2</div>
<!-- Tydzień 2 -->
<div class="calendar-day">3<div class="shift-dot blue"></div></div>
<div class="calendar-day">4<div class="shift-dot green"></div></div>
<div class="calendar-day">5</div>
<div class="calendar-day">6<div class="shift-dot blue"></div></div>
<div class="calendar-day">7<div class="shift-dot blue"></div></div>
<div class="calendar-day text-muted" style="opacity: 0.5;">8</div>
<div class="calendar-day text-muted" style="opacity: 0.5;">9</div>
<!-- Tydzień 3 (Aktywny tydzień) -->
<div class="calendar-day">10</div>
<div class="calendar-day">11<div class="shift-dot green"></div></div>
<div class="calendar-day active shadow-md">12<div class="shift-dot blue"></div></div>
<div class="calendar-day">13<div class="shift-dot green"></div></div>
<div class="calendar-day">14</div>
<div class="calendar-day text-muted" style="opacity: 0.5;">15</div>
<div class="calendar-day text-muted" style="opacity: 0.5;">16</div>
<!-- Tydzień 4 -->
<div class="calendar-day">17<div class="shift-dot blue"></div></div>
<div class="calendar-day">18<div class="shift-dot blue"></div></div>
<div class="calendar-day">19<div class="shift-dot green"></div></div>
<div class="calendar-day">20</div>
<div class="calendar-day">21<div class="shift-dot blue"></div></div>
<div class="calendar-day text-muted" style="opacity: 0.5;">22</div>
<div class="calendar-day text-muted" style="opacity: 0.5;">23</div>
<!-- Tydzień 5 -->
<div class="calendar-day">24</div>
<div class="calendar-day">25<div class="shift-dot blue"></div></div>
<div class="calendar-day">26<div class="shift-dot green"></div></div>
<div class="calendar-day">27<div class="shift-dot green"></div></div>
<div class="calendar-day">28</div>
<div class="calendar-day text-muted" style="opacity: 0.5;">29</div>
<div class="calendar-day text-muted" style="opacity: 0.5;">30</div>
<!-- Ostatni dzień -->
<div class="calendar-day">31<div class="shift-dot blue"></div></div>
<div class="calendar-day empty"></div>
<div class="calendar-day empty"></div>
<div class="calendar-day empty"></div>
<div class="calendar-day empty"></div>
<div class="calendar-day empty"></div>
<div class="calendar-day empty"></div>
</div>
<!-- Szczegóły dla wybranego dnia -->
<div class="mt-4">
<h6 class="fw-bold mb-3 text-muted text-uppercase small">Wybrany dzień: 12 Sierpnia</h6>
<div class="card-custom shift-card" style="border-left: 4px solid var(--primary-color);">
<div class="p-2 px-3">
<div class="d-flex justify-content-between align-items-center mb-2">
<div>
<h5 class="fw-bold mb-0" style="font-size: 1.1rem;">08:00 - 16:00</h5>
<span class="text-primary-custom fw-semibold" style="font-size: 0.75rem;">Specjalista ds. Obsługi</span>
</div>
<span class="badge bg-label-primary">8h</span>
</div>
</div>
</div>
</div>
</div>
<?php include 'footer.php'; ?>

View File

@@ -0,0 +1,106 @@
<?php
$enablePrototypeComments = true;
include 'header.php';
?>
<!-- Główny Topbar (taki sam jak w home.php) -->
<div class="app-topbar">
<div class="d-flex align-items-center">
<div class="d-flex justify-content-center align-items-center bg-primary-custom rounded-circle me-2" style="width: 32px; height: 32px;">
<i class='bx bx-cube-alt text-white'></i>
</div>
<h1 class="app-title">Acme Corp</h1>
</div>
<div class="user-avatar shadow-sm">
<i class='bx bx-user'></i>
</div>
</div>
<!-- Pasek tytułowy sekcji -->
<div class="container pt-4">
<div class="d-flex justify-content-between align-items-center pb-3 mb-4" style="border-bottom: 1px solid var(--border-color);">
<div class="d-flex align-items-center">
<a href="home.php" class="text-dark me-2 d-flex align-items-center justify-content-center" style="width: 32px; height: 32px; background: rgba(0,0,0,0.05); border-radius: 50%;">
<i class='bx bx-arrow-back fs-4'></i>
</a>
<h2 class="fw-bold mb-0" style="font-size: 1.25rem;">Mój Grafik</h2>
</div>
<a href="schedule-calendar.php" class="text-primary-custom d-flex align-items-center justify-content-center" style="width: 36px; height: 36px; background: rgba(105, 108, 255, 0.1); border-radius: 8px;">
<i class='bx bx-calendar fs-4'></i>
</a>
</div>
</div>
<div class="container pb-4">
<!-- Dzień: Poniedziałek -->
<div class="schedule-day mb-3">
<h6 class="fw-bold mb-2 text-muted text-uppercase" style="font-size: 0.7rem;">Poniedziałek, 12 Sierpnia</h6>
<div class="card-custom shift-card" style="border-left: 4px solid var(--primary-color);">
<div class="p-2 px-3">
<div class="d-flex justify-content-between align-items-center">
<div>
<h5 class="fw-bold mb-0" style="font-size: 1.1rem;">08:00 - 16:00</h5>
<span class="text-primary-custom fw-semibold" style="font-size: 0.75rem;">Specjalista ds. Obsługi</span>
</div>
<span class="badge bg-label-primary">8h</span>
</div>
</div>
</div>
</div>
<!-- Dzień: Wtorek -->
<div class="schedule-day mb-3">
<h6 class="fw-bold mb-2 text-muted text-uppercase" style="font-size: 0.7rem;">Wtorek, 13 Sierpnia</h6>
<div class="card-custom shift-card" style="border-left: 4px solid #71dd37;">
<div class="p-2 px-3">
<div class="d-flex justify-content-between align-items-center mb-2">
<div>
<h5 class="fw-bold mb-0" style="font-size: 1.1rem;">10:00 - 18:00</h5>
<span class="text-success fw-semibold" style="font-size: 0.75rem;">Zastępca Kierownika</span>
</div>
<span class="badge bg-label-success" style="background: rgba(113, 221, 55, 0.1); color: #71dd37;">8h</span>
</div>
<!-- Notatka od managera (bardzo kompaktowa) -->
<div class="bg-light p-2 rounded text-muted d-flex align-items-start gap-2" style="font-size: 0.75rem;">
<i class='bx bx-message-square-detail text-warning mt-1'></i>
<div>
<strong class="text-dark">Anna M.:</strong> Pamiętaj o odbiorze dużej dostawy przed południem.
</div>
</div>
</div>
</div>
</div>
<!-- Dzień: Środa -->
<div class="schedule-day mb-3">
<h6 class="fw-bold mb-2 text-muted text-uppercase" style="font-size: 0.7rem;">Środa, 14 Sierpnia</h6>
<div class="card-custom bg-transparent border border-dashed border-secondary opacity-50" style="box-shadow: none;">
<div class="p-2 text-center">
<span class="text-muted fw-semibold" style="font-size: 0.8rem;">Dzień wolny</span>
</div>
</div>
</div>
<!-- Dzień: Czwartek -->
<div class="schedule-day mb-3">
<h6 class="fw-bold mb-2 text-muted text-uppercase" style="font-size: 0.7rem;">Czwartek, 15 Sierpnia</h6>
<div class="card-custom shift-card" style="border-left: 4px solid var(--primary-color);">
<div class="p-2 px-3">
<div class="d-flex justify-content-between align-items-center">
<div>
<h5 class="fw-bold mb-0" style="font-size: 1.1rem;">08:00 - 16:00</h5>
<span class="text-primary-custom fw-semibold" style="font-size: 0.75rem;">Specjalista ds. Obsługi</span>
</div>
<span class="badge bg-label-primary">8h</span>
</div>
</div>
</div>
</div>
</div>
<?php include 'footer.php'; ?>

View File

@@ -0,0 +1,58 @@
<?php
$enablePrototypeComments = true;
include 'header.php';
?>
<div class="app-topbar">
<div class="d-flex align-items-center">
<a href="index.php" class="text-dark me-2"><i class='bx bx-arrow-back fs-4'></i></a>
<h1 class="app-title">Wybierz firmę</h1>
</div>
</div>
<div class="container py-4">
<p class="text-muted mb-4">Wybierz firmę, dla której chcesz dzisiaj pracować, aby kontynuować logowanie.</p>
<div class="card-custom overflow-hidden">
<a href="home.php" class="company-list-item">
<div class="company-logo-placeholder bg-primary-custom">
A
</div>
<div class="flex-grow-1">
<h6 class="mb-0 fw-bold">Acme Corp Sp. z o.o.</h6>
<small class="text-muted">NIP: 1234567890</small>
</div>
<div>
<i class='bx bx-chevron-right fs-3 text-muted'></i>
</div>
</a>
<a href="home.php" class="company-list-item">
<div class="company-logo-placeholder bg-dark text-white">
G
</div>
<div class="flex-grow-1">
<h6 class="mb-0 fw-bold">Global Industries</h6>
<small class="text-muted">NIP: 9876543210</small>
</div>
<div>
<i class='bx bx-chevron-right fs-3 text-muted'></i>
</div>
</a>
<a href="home.php" class="company-list-item">
<div class="company-logo-placeholder bg-info text-white">
M
</div>
<div class="flex-grow-1">
<h6 class="mb-0 fw-bold">Magico Sp. z o.o.</h6>
<small class="text-muted">Oddział Główny</small>
</div>
<div>
<i class='bx bx-chevron-right fs-3 text-muted'></i>
</div>
</a>
</div>
</div>
<?php include 'footer.php'; ?>

View File

@@ -0,0 +1,215 @@
<?php
$enablePrototypeComments = true;
include 'header.php';
?>
<!-- Główny Topbar -->
<div class="app-topbar">
<div class="d-flex align-items-center">
<div class="d-flex justify-content-center align-items-center bg-primary-custom rounded-circle me-2" style="width: 32px; height: 32px;">
<i class='bx bx-cube-alt text-white'></i>
</div>
<h1 class="app-title">Acme Corp</h1>
</div>
<div class="user-avatar shadow-sm">
<i class='bx bx-user'></i>
</div>
</div>
<!-- Pasek tytułowy sekcji -->
<div class="container pt-4">
<div class="d-flex justify-content-between align-items-center pb-3 mb-4" style="border-bottom: 1px solid var(--border-color);">
<div class="d-flex align-items-center">
<a href="home.php" class="text-dark me-2 d-flex align-items-center justify-content-center" style="width: 32px; height: 32px; background: rgba(0,0,0,0.05); border-radius: 50%;">
<i class='bx bx-arrow-back fs-4'></i>
</a>
<h2 class="fw-bold mb-0" style="font-size: 1.25rem;">Moje Urlopy</h2>
</div>
</div>
</div>
<div class="container pb-4">
<!-- Akcja Główna: Wniosek o urlop -->
<div class="mb-4">
<button class="btn btn-primary w-100 py-3 fw-bold shadow-sm" data-bs-toggle="modal" data-bs-target="#vacationModal" style="border-radius: var(--radius-md);">
<i class='bx bx-plus-circle fs-5 me-1 align-middle'></i> Nowy wniosek o urlop
</button>
</div>
<!-- Lista Nadchodzących Urlopów -->
<h6 class="fw-bold mb-3 text-muted text-uppercase small">Nadchodzące wnioski</h6>
<!-- Wniosek 1: Zaakceptowany -->
<div class="card-custom mb-3 border-0 shadow-sm" style="border-left: 4px solid #71dd37 !important;">
<div class="p-3">
<div class="d-flex justify-content-between align-items-start mb-2">
<div>
<span class="badge bg-label-success mb-1">Zaakceptowany</span>
<h5 class="fw-bold mb-0" style="font-size: 1.1rem;">Urlop wypoczynkowy</h5>
</div>
<div class="text-end">
<span class="fw-bold text-dark fs-5">5</span>
<span class="text-muted small d-block" style="margin-top: -5px;">dni</span>
</div>
</div>
<div class="d-flex align-items-center text-muted small mt-3">
<i class='bx bx-calendar me-2 fs-5 text-primary-custom'></i>
<span class="fw-semibold">12 Sierpnia 2026 - 16 Sierpnia 2026</span>
</div>
</div>
</div>
<!-- Wniosek 2: Oczekujący -->
<div class="card-custom mb-3 border-0 shadow-sm" style="border-left: 4px solid #8592a3 !important;">
<div class="p-3">
<div class="d-flex justify-content-between align-items-start mb-2">
<div>
<span class="badge bg-label-secondary mb-1">Oczekuje na akceptację</span>
<h5 class="fw-bold mb-0" style="font-size: 1.1rem;">Urlop wypoczynkowy</h5>
</div>
<div class="text-end">
<span class="fw-bold text-dark fs-5">2</span>
<span class="text-muted small d-block" style="margin-top: -5px;">dni</span>
</div>
</div>
<div class="d-flex align-items-center text-muted small mt-3">
<i class='bx bx-calendar me-2 fs-5 text-primary-custom'></i>
<span class="fw-semibold">27 Sierpnia 2026 - 28 Sierpnia 2026</span>
</div>
</div>
</div>
<!-- Wniosek 3: Odrzucony -->
<div class="card-custom mb-3 border-0 shadow-sm" style="border-left: 4px solid #ff3e1d !important;">
<div class="p-3">
<div class="d-flex justify-content-between align-items-start mb-2">
<div>
<span class="badge bg-label-danger mb-1">Odrzucony</span>
<h5 class="fw-bold mb-0" style="font-size: 1.1rem;">Urlop na żądanie</h5>
</div>
<div class="text-end">
<span class="fw-bold text-dark fs-5">1</span>
<span class="text-muted small d-block" style="margin-top: -5px;">dzień</span>
</div>
</div>
<div class="d-flex align-items-center text-muted small mt-3 mb-2">
<i class='bx bx-calendar me-2 fs-5 text-primary-custom'></i>
<span class="fw-semibold">05 Września 2026</span>
</div>
<div class="bg-light p-2 rounded text-muted small d-flex align-items-start gap-2 mt-2">
<i class='bx bx-info-circle text-danger mt-1'></i>
<div>
<strong class="text-dark">Kierownik:</strong> Niestety w tym terminie mamy inwentaryzację, brak możliwości udzielenia urlopu.
</div>
</div>
</div>
</div>
</div>
<!-- Modal: Nowy Wniosek -->
<div class="modal fade" id="vacationModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content border-0 shadow" style="border-radius: var(--radius-lg);">
<div class="modal-header border-bottom-0 pb-0">
<h5 class="modal-title fw-bold">Nowy wniosek o urlop</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form id="vacation-form">
<div class="mb-3 text-start">
<label class="form-label fw-semibold">Początek urlopu</label>
<div class="input-group input-group-merge">
<span class="input-group-text"><i class="bx bx-calendar"></i></span>
<input type="text" id="date-start" class="form-control datepicker" placeholder="Wybierz datę początkową">
</div>
</div>
<div class="mb-3 text-start">
<label class="form-label fw-semibold">Koniec urlopu</label>
<div class="input-group input-group-merge">
<span class="input-group-text"><i class="bx bx-calendar"></i></span>
<input type="text" id="date-end" class="form-control datepicker" placeholder="Wybierz datę końcową">
</div>
</div>
<div class="mb-3 text-start">
<label class="form-label fw-semibold">Powód</label>
<select class="form-select">
<option value="2">Urlop wypoczynkowy</option>
<option value="4">Zwolnienie - opieka</option>
<option value="3">Zwolnienie lekarskie</option>
<option value="9">Służba wojskowa</option>
<option value="8" selected>Urlop bezpłatny</option>
<option value="5">Urlop macierzyński</option>
<option value="7">Urlop rehabilitacyjny</option>
<option value="6">Urlop wychowawczy</option>
</select>
</div>
<div class="mb-4 text-start">
<label class="form-label fw-semibold">Dodatkowe informacje</label>
<textarea class="form-control" rows="3" placeholder="Opcjonalna uwaga do przełożonego..."></textarea>
</div>
<button type="button" class="btn btn-primary w-100 py-3 fw-bold fs-6" id="btn-submit-vacation">
Wyślij wniosek
</button>
</form>
</div>
</div>
</div>
</div>
<!-- Flatpickr CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
<!-- Flatpickr Theme (optional, fits well) -->
<link rel="stylesheet" type="text/css" href="https://npmcdn.com/flatpickr/dist/themes/airbnb.css">
<?php include 'footer.php'; ?>
<!-- Flatpickr JS -->
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
<script src="https://npmcdn.com/flatpickr/dist/l10n/pl.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Inicjalizacja datepickera (Flatpickr) z polskim językiem
flatpickr(".datepicker", {
locale: "pl",
dateFormat: "Y-m-d",
disableMobile: "true" // Pozwala na ładny natywny wygląd flatpickr na mobilkach
});
// Symulacja wysyłania
const btnSubmit = document.getElementById('btn-submit-vacation');
if (btnSubmit) {
btnSubmit.addEventListener('click', function() {
const originalText = this.innerHTML;
this.innerHTML = "<i class='bx bx-loader-alt bx-spin me-2'></i> Wysyłanie...";
this.disabled = true;
setTimeout(() => {
this.innerHTML = "<i class='bx bx-check me-2'></i> Wysłano pomyślnie!";
this.classList.replace('btn-primary', 'btn-success');
setTimeout(() => {
const modalEl = document.getElementById('vacationModal');
const modal = bootstrap.Modal.getInstance(modalEl);
if (modal) modal.hide();
// Reset buttona
this.innerHTML = originalText;
this.classList.replace('btn-success', 'btn-primary');
this.disabled = false;
}, 1500);
}, 1500);
});
}
});
</script>

View File

@@ -529,6 +529,18 @@ include '../../header-travel.php';
<div class="tab-pane fade" id="navs-faktury" role="tabpanel">
<div class="card shadow-sm">
<div class="card-header border-bottom d-flex justify-content-between align-items-center py-3">
<h5 class="card-title mb-0">Baza faktur</h5>
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" id="bulkOperationsDropdown" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bx bx-check-double me-1"></i> Operacje masowe
</button>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="bulkOperationsDropdown">
<h6 class="dropdown-header text-uppercase ps-3">Finanse</h6>
<li><a class="dropdown-item" href="javascript:void(0);" data-bs-toggle="modal" data-bs-target="#pekaoConnectModal"><i class="bx bx-transfer-alt me-2"></i> Prześlij do PeKaO Connect</a></li>
</ul>
</div>
</div>
<div class="table-responsive text-nowrap">
<table class="table table-hover">
<thead class="table-light">
@@ -829,6 +841,43 @@ include '../../header-travel.php';
</div>
<!-- Modal: PeKaO Connect Bulk Transfer -->
<div class="modal fade" id="pekaoConnectModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header border-bottom py-3">
<h5 class="modal-title" id="pekaoConnectModalTitle"><i class="bx bx-transfer-alt text-primary me-2"></i> Przesyłanie do PeKaO Connect</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body p-4">
<div class="alert alert-info d-flex" role="alert">
<span class="badge badge-center rounded-pill bg-info border-label-info p-3 me-3"><i class="bx bx-info-circle fs-5"></i></span>
<div class="d-flex flex-column ps-1">
<h6 class="alert-heading d-flex align-items-center mb-1">Wymagana autoryzacja w banku</h6>
<span>Zaznaczone faktury zostaną przesłane i dodane do koszyka w systemie PeKaO Connect. Aby zrealizować płatności, musisz następnie zalogować się do bankowości elektronicznej i zautoryzować przygotowaną paczkę przelewów.</span>
</div>
</div>
<div class="card bg-lighter shadow-none border border-dashed mb-0">
<div class="card-body p-3">
<div class="d-flex justify-content-between align-items-center mb-2">
<span class="text-muted">Wybranych faktur:</span>
<span class="fw-bold">4</span>
</div>
<div class="d-flex justify-content-between align-items-center">
<span class="text-muted">Łączna kwota paczki:</span>
<span class="fw-bold fs-5 text-primary">12 450,00 PLN</span>
</div>
</div>
</div>
</div>
<div class="modal-footer border-top py-3">
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Anuluj</button>
<button type="button" class="btn btn-primary" data-bs-dismiss="modal"><i class="bx bx-send me-1"></i> Utwórz paczkę</button>
</div>
</div>
</div>
</div>
<!-- Modal: Invoice Preview -->
<div class="modal fade" id="invoicePreviewModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable" role="document">