Company: Widok wyboru firmy

This commit is contained in:
2026-04-29 00:04:44 +02:00
parent 31641b0ec8
commit d494349c6f
2 changed files with 864 additions and 46 deletions

View File

@@ -0,0 +1,427 @@
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Wybierz firmę - company.magico</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Public+Sans:wght@400;500;600;700&display=swap"
rel="stylesheet">
<style>
/* === STYLE WZOROWANE NA SNEAT (Standalone) === */
body {
background-color: #f5f5f9;
/* Charakterystyczne tło Sneat */
font-family: 'Public Sans', sans-serif;
color: #566a7f;
}
/* Kontener ograniczający szerokość siatki */
.tenant-container {
max-width: 1000px;
width: 100%;
}
/* Logo tekstowe */
.brand-logo {
font-size: 2rem;
font-weight: 700;
color: #696cff;
letter-spacing: -0.5px;
}
/* Kafelki firm */
.tenant-card {
background-color: #fff;
border-radius: 0.5rem;
border: 1px solid transparent;
box-shadow: 0 2px 6px 0 rgba(67, 89, 113, 0.12);
transition: all 0.2s ease-in-out;
cursor: pointer;
position: relative;
height: 100%;
display: flex;
align-items: center;
padding: 1.25rem;
text-decoration: none;
color: inherit;
}
.tenant-card:hover {
transform: translateY(-4px);
box-shadow: 0 4px 12px 0 rgba(67, 89, 113, 0.16);
border-color: rgba(105, 108, 255, 0.2);
}
/* Avatary firm */
.tenant-avatar {
width: 48px;
height: 48px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
font-size: 1.1rem;
flex-shrink: 0;
background-color: #e7e7ff;
color: #696cff;
}
/* Gwiazdka (Ulubione) */
.star-btn {
position: absolute;
top: 12px;
right: 12px;
background: none;
border: none;
padding: 5px;
font-size: 1.3rem;
color: #d9dee3;
/* Wygaszony szary */
transition: 0.2s ease;
z-index: 10;
}
.star-btn:hover {
color: #ffab00;
transform: scale(1.1);
}
.star-btn.active {
color: #ffab00;
}
.tenant-card>div:last-child {
padding-right: 2rem;
}
/* === Alert: brak firm === */
.no-company-alert {
background: #fff;
border-radius: 0.5rem;
border: 1px solid #e7e7ff;
box-shadow: 0 2px 6px 0 rgba(67, 89, 113, 0.08);
padding: 1.5rem 1.75rem;
}
.no-company-alert .alert-divider {
width: 1px;
background: #e4e6ea;
align-self: stretch;
flex-shrink: 0;
}
.no-company-alert .alert-section {
flex: 1;
min-width: 0;
}
.no-company-alert .alert-icon {
width: 38px;
height: 38px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.15rem;
flex-shrink: 0;
}
.no-company-alert .create-link {
display: inline-flex;
align-items: center;
gap: 0.35rem;
color: #696cff;
font-weight: 600;
text-decoration: none;
font-size: 0.875rem;
transition: opacity 0.15s;
}
.no-company-alert .create-link:hover {
opacity: 0.75;
}
@media (max-width: 575px) {
.no-company-alert .alert-divider {
display: none;
}
.no-company-alert .alert-section+.alert-section {
border-top: 1px solid #e4e6ea;
padding-top: 1rem;
margin-top: 1rem;
}
}
</style>
</head>
<body>
<div class="d-flex flex-column align-items-center justify-content-center min-vh-100 py-5 px-3">
<div class="tenant-container">
<div class="text-center mb-5">
<div class="brand-logo mb-3">
<img src="https://cdn.magico.pro/logo/company.svg" width="300" class="mb-3">
</div>
<h3 class="fw-bold mb-2" style="color: #435971;">Wybierz firmę</h3>
<p class="text-muted">Wybierz kontekst roboczy, do którego chcesz się zalogować.</p>
</div>
<!-- Soft alert: brak firm -->
<div class="d-flex align-items-center gap-3 mt-4 px-4 py-3 rounded-2 mb-4"
style="background:#fffbeb; border:1px solid #fde68a;">
<i class='bx bx-info-circle fs-5' style="color:#d97706; flex-shrink:0;"></i>
<p class="mb-0 small" style="color:#92400e; line-height:1.6;">
<strong>Nie masz jeszcze przypisanej żadnej firmy.</strong>
Twoje konto jest aktywne, ale nie należy jeszcze do żadnej organizacji w systemie.
</p>
</div>
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4">
<div class="col">
<div class="tenant-card" onclick="loginToTenant('1')">
<button class="star-btn active" title="Usuń z ulubionych">
<i class='bx bx-star'></i>
</button>
<div class="tenant-avatar me-3 bg-label-primary">
AM
</div>
<div>
<h6 class="mb-1 text-dark">Agencja Magico Software Sp. z o.o.</h6>
<div class="d-flex align-items-center text-muted small">
<i class='bx bx-group me-1'></i> 142 użytkowników
</div>
</div>
</div>
</div>
<div class="col">
<div class="tenant-card" onclick="loginToTenant('2')">
<button class="star-btn" title="Dodaj do ulubionych">
<i class='bx bx-star'></i>
</button>
<div class="tenant-avatar me-3" style="background-color: #e8fadf; color: #71dd37;">
TR
</div>
<div>
<h6 class="mb-1 text-dark">Travel Pay</h6>
<div class="d-flex align-items-center text-muted small">
<i class='bx bx-group me-1'></i> 12 użytkowników
</div>
</div>
</div>
</div>
<div class="col">
<div class="tenant-card" onclick="loginToTenant('3')">
<button class="star-btn" title="Dodaj do ulubionych">
<i class='bx bx-star'></i>
</button>
<div class="tenant-avatar me-3 p-0 overflow-hidden">
<img src="https://ui-avatars.com/api/?name=Artex&background=fff2d6&color=ffab00" alt="Logo"
class="w-100 h-100 object-fit-cover">
</div>
<div>
<h6 class="mb-1 text-dark">Artex S.C.</h6>
<div class="d-flex align-items-center text-muted small">
<i class='bx bx-group me-1'></i> 5 użytkowników
</div>
</div>
</div>
</div>
<div class="col">
<div class="tenant-card" onclick="loginToTenant('4')">
<button class="star-btn" title="Dodaj do ulubionych">
<i class='bx bx-star'></i>
</button>
<div class="tenant-avatar me-3" style="background-color: #ffe1e1; color: #ff3e1d;">
FL
</div>
<div>
<h6 class="mb-1 text-dark">Flixbus Polska</h6>
<div class="d-flex align-items-center text-muted small">
<i class='bx bx-group me-1'></i> 48 użytkowników
</div>
</div>
</div>
</div>
<div class="col">
<div class="tenant-card" onclick="loginToTenant('5')">
<button class="star-btn" title="Dodaj do ulubionych">
<i class='bx bx-star'></i>
</button>
<div class="tenant-avatar me-3" style="background-color: #e1f0ff; color: #03c3ec;">
GW
</div>
<div>
<h6 class="mb-1 text-dark">Global Wings Tour</h6>
<div class="d-flex align-items-center text-muted small">
<i class='bx bx-group me-1'></i> 2 użytkowników
</div>
</div>
</div>
</div>
</div>
<!-- Alert: brak firm do wyboru (pokazywany gdy lista jest pusta) -->
<div class="no-company-alert mt-4 d-flex flex-column flex-sm-row gap-3 align-items-sm-center">
<!-- Sekcja: pracownik -->
<div class="alert-section d-flex align-items-start gap-3">
<div class="alert-icon" style="background:#e1f0ff; color:#03c3ec;">
<i class='bx bx-user'></i>
</div>
<div>
<p class="mb-1 fw-semibold" style="color:#435971; font-size:.875rem;">Jestem pracownikiem</p>
<p class="mb-0 text-muted" style="font-size:.8125rem; line-height:1.5;">
Jeśli powinieneś mieć dostęp do firmy, skontaktuj się z administratorem
systemu &mdash; to on nadaje uprawnienia i przypisuje konta do organizacji.
</p>
</div>
</div>
<div class="alert-divider d-none d-sm-block"></div>
<!-- Sekcja: właściciel / manager -->
<div class="alert-section d-flex align-items-start gap-3">
<div class="alert-icon" style="background:#e7e7ff; color:#696cff;">
<i class='bx bx-buildings'></i>
</div>
<div>
<p class="mb-1 fw-semibold" style="color:#435971; font-size:.875rem;">Jestem właścicielem lub
managerem</p>
<p class="mb-0 text-muted" style="font-size:.8125rem; line-height:1.5;">
Nie masz jeszcze żadnej firmy w systemie?
</p>
<a href="/create-company" class="create-link mt-2">
<i class='bx bx-plus-circle'></i> Załóż nową firmę
</a>
</div>
</div>
</div>
<div class="text-center mt-5">
<p class="text-muted small">
Nie widzisz swojej firmy? <a href="#" class="text-primary text-decoration-none fw-semibold">Zaloguj
się na inne konto</a>
</p>
</div>
</div>
</div>
<script>
// Zapisz oryginalne indeksy kolumn przy starcie strony
const grid = document.querySelector('.row');
[...grid.children].forEach((col, i) => {
col.dataset.originalIndex = i;
});
// FLIP animation helper — przesuwa kolumnę do zadanego miejsca w DOM
function flipMove(colToMove, insertFn) {
const cols = [...grid.children];
// FIRST: zapisz pozycje wszystkich kolumn
const firstRects = cols.map(col => col.getBoundingClientRect());
// Wykonaj przestawienie w DOM
insertFn();
// LAST + INVERT + PLAY
cols.forEach((col, i) => {
const lastRect = col.getBoundingClientRect();
const dx = firstRects[i].left - lastRect.left;
const dy = firstRects[i].top - lastRect.top;
if (dx === 0 && dy === 0) return;
col.style.transition = 'none';
col.style.transform = `translate(${dx}px, ${dy}px)`;
requestAnimationFrame(() => {
requestAnimationFrame(() => {
col.style.transition = 'transform 0.45s cubic-bezier(0.25, 0.46, 0.45, 0.94)';
col.style.transform = '';
});
});
});
}
// Przenieś na początek listy
function moveToFront(col) {
flipMove(col, () => grid.insertBefore(col, grid.firstChild));
}
// Wróć na oryginalną pozycję
function moveToOriginal(col) {
const targetIndex = parseInt(col.dataset.originalIndex);
flipMove(col, () => {
const allCols = [...grid.children];
// Znajdź element, przed którym należy wstawić (pierwszy z oryginalnym indeksem >= targetIndex, pomijając col)
const ref = allCols.find(c => c !== col && parseInt(c.dataset.originalIndex) > targetIndex);
if (ref) {
grid.insertBefore(col, ref);
} else {
grid.appendChild(col);
}
});
}
// Obsługa gwiazdek (Ulubione)
document.querySelectorAll('.star-btn').forEach(btn => {
// Ustaw poprawną ikonę przy starcie
const icon = btn.querySelector('i');
if (btn.classList.contains('active')) {
icon.className = 'bx bxs-star';
}
btn.addEventListener('click', function (e) {
e.stopPropagation();
this.classList.toggle('active');
const icon = this.querySelector('i');
const col = this.closest('.col');
if (this.classList.contains('active')) {
icon.className = 'bx bxs-star';
this.setAttribute('title', 'Usuń z ulubionych');
moveToFront(col);
// Tutaj wrzucisz request do API zapisujący ulubione
} else {
icon.className = 'bx bx-star';
this.setAttribute('title', 'Dodaj do ulubionych');
moveToOriginal(col);
}
});
});
// Obsługa wyboru firmy
function loginToTenant(tenantId) {
console.log('Logowanie do firmy ID:', tenantId);
// window.location.href = '/dashboard?tenant=' + tenantId;
}
</script>
</body>
</html>

View File

@@ -13,9 +13,6 @@ include '../../header-travel.php';
<p class="text-muted small mb-0">Zarządzaj fakturami od dostawców i przypisuj je do wycieczek.</p>
</div>
<div class="d-flex gap-2">
<button class="btn btn-label-secondary btn-icon" data-bs-toggle="tooltip" title="Ustawienia integracji">
<i class="bx bx-cog"></i>
</button>
<div class="btn-group" id="filtersButtonGroup">
<button class="btn btn-outline-secondary d-flex align-items-center position-relative"
id="btnToggleFilters" onclick="toggleFilters()">
@@ -69,26 +66,32 @@ include '../../header-travel.php';
<div class="col-md-3">
<label class="form-label small mb-1">Status rozliczenia</label>
<div class="dropdown w-100" id="statusDropdown">
<button class="btn btn-white border form-select text-start fw-normal d-flex align-items-center justify-content-between w-100"
type="button" id="statusDropdownBtn"
onclick="toggleStatusDropdown(event)"
<button
class="btn btn-white border form-select text-start fw-normal d-flex align-items-center justify-content-between w-100"
type="button" id="statusDropdownBtn" onclick="toggleStatusDropdown(event)"
style="background-color:#fff;">
<span id="statusDropdownLabel" class="text-truncate">Wszystkie statusy</span>
</button>
<ul class="dropdown-menu w-100 p-2 shadow-sm" id="statusDropdownMenu" style="min-width:100%;">
<li>
<label class="dropdown-item d-flex align-items-center gap-2 py-1 px-2 rounded cursor-pointer">
<input type="checkbox" class="status-check form-check-input mt-0" value="settled"> Rozliczone
<label
class="dropdown-item d-flex align-items-center gap-2 py-1 px-2 rounded cursor-pointer">
<input type="checkbox" class="status-check form-check-input mt-0" value="settled">
Rozliczone
</label>
</li>
<li>
<label class="dropdown-item d-flex align-items-center gap-2 py-1 px-2 rounded cursor-pointer">
<input type="checkbox" class="status-check form-check-input mt-0" value="partial"> Częściowo rozliczone
<label
class="dropdown-item d-flex align-items-center gap-2 py-1 px-2 rounded cursor-pointer">
<input type="checkbox" class="status-check form-check-input mt-0" value="partial">
Częściowo rozliczone
</label>
</li>
<li>
<label class="dropdown-item d-flex align-items-center gap-2 py-1 px-2 rounded cursor-pointer">
<input type="checkbox" class="status-check form-check-input mt-0" value="unsettled"> Nierozliczone
<label
class="dropdown-item d-flex align-items-center gap-2 py-1 px-2 rounded cursor-pointer">
<input type="checkbox" class="status-check form-check-input mt-0" value="unsettled">
Nierozliczone
</label>
</li>
</ul>
@@ -190,7 +193,8 @@ include '../../header-travel.php';
<td class="text-center"><span class="badge bg-label-danger" data-bs-toggle="tooltip"
title="Brak przypiętej faktury">Nierozliczone</span></td>
<td class="text-end">
<button class="btn btn-sm btn-primary" href="javascript:void(0);"><i class="bx bx-link me-1"></i> Przypisz fakturę</button>
<button class="btn btn-sm btn-primary" href="javascript:void(0);"><i
class="bx bx-link me-1"></i> Przypisz fakturę</button>
</td>
</tr>
@@ -216,7 +220,8 @@ include '../../header-travel.php';
</td>
<td class="text-end">
<div class="btn-group">
<button class="btn btn-sm btn-outline-secondary"
<button class="btn btn-sm btn-outline-secondary" data-bs-toggle="modal"
data-bs-target="#modalLinkedInvoicePreview"
href="javascript:void(0);"><i class="bx bx-show me-1"></i>
Szczegóły</button>
<button type="button"
@@ -251,11 +256,18 @@ include '../../header-travel.php';
<td class="text-center"><span class="badge bg-label-success">Rozliczone</span></td>
<td class="text-end">
<div class="btn-group">
<button class="btn btn-sm btn-outline-secondary" href="javascript:void(0);"><i class="bx bx-show me-1"></i> Szczegóły</button>
<button type="button" class="btn btn-sm btn-outline-secondary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown"></button>
<button class="btn btn-sm btn-outline-secondary" data-bs-toggle="modal"
data-bs-target="#modalLinkedInvoicePreview"
href="javascript:void(0);"><i class="bx bx-show me-1"></i>
Szczegóły</button>
<button type="button"
class="btn btn-sm btn-outline-secondary dropdown-toggle dropdown-toggle-split"
data-bs-toggle="dropdown"></button>
<ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item disabled" href="javascript:void(0);"><i class="bx bx-link me-1"></i> Przypisz fakturę</a></li>
<li><a class="dropdown-item" href="javascript:void(0);"><i class="bx bx-edit me-1"></i> Edytuj</a></li>
<li><a class="dropdown-item disabled" href="javascript:void(0);"><i
class="bx bx-link me-1"></i> Przypisz fakturę</a></li>
<li><a class="dropdown-item" href="javascript:void(0);"><i
class="bx bx-edit me-1"></i> Edytuj</a></li>
</ul>
</div>
</td>
@@ -280,11 +292,18 @@ include '../../header-travel.php';
<td class="text-center"><span class="badge bg-label-success">Rozliczone</span></td>
<td class="text-end">
<div class="btn-group">
<button class="btn btn-sm btn-outline-secondary" href="javascript:void(0);"><i class="bx bx-show me-1"></i> Szczegóły</button>
<button type="button" class="btn btn-sm btn-outline-secondary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown"></button>
<button class="btn btn-sm btn-outline-secondary" data-bs-toggle="modal"
data-bs-target="#modalLinkedInvoicePreview"
href="javascript:void(0);"><i class="bx bx-show me-1"></i>
Szczegóły</button>
<button type="button"
class="btn btn-sm btn-outline-secondary dropdown-toggle dropdown-toggle-split"
data-bs-toggle="dropdown"></button>
<ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item disabled" href="javascript:void(0);"><i class="bx bx-link me-1"></i> Przypisz fakturę</a></li>
<li><a class="dropdown-item" href="javascript:void(0);"><i class="bx bx-edit me-1"></i> Edytuj</a></li>
<li><a class="dropdown-item disabled" href="javascript:void(0);"><i
class="bx bx-link me-1"></i> Przypisz fakturę</a></li>
<li><a class="dropdown-item" href="javascript:void(0);"><i
class="bx bx-edit me-1"></i> Edytuj</a></li>
</ul>
</div>
</td>
@@ -309,7 +328,8 @@ include '../../header-travel.php';
<td class="text-center"><span class="badge bg-label-danger">Nierozliczone</span>
</td>
<td class="text-end">
<button class="btn btn-sm btn-primary" href="javascript:void(0);"><i class="bx bx-link me-1"></i> Przypisz fakturę</button>
<button class="btn btn-sm btn-primary" href="javascript:void(0);"><i
class="bx bx-link me-1"></i> Przypisz fakturę</button>
</td>
</tr>
@@ -334,7 +354,8 @@ include '../../header-travel.php';
rozliczone</span></td>
<td class="text-end">
<div class="btn-group">
<button class="btn btn-sm btn-outline-secondary"
<button class="btn btn-sm btn-outline-secondary" data-bs-toggle="modal"
data-bs-target="#modalLinkedInvoicePreview"
href="javascript:void(0);"><i class="bx bx-show me-1"></i>
Szczegóły</button>
<button type="button"
@@ -369,11 +390,18 @@ include '../../header-travel.php';
<td class="text-center"><span class="badge bg-label-success">Rozliczone</span></td>
<td class="text-end">
<div class="btn-group">
<button class="btn btn-sm btn-outline-secondary" href="javascript:void(0);"><i class="bx bx-show me-1"></i> Szczegóły</button>
<button type="button" class="btn btn-sm btn-outline-secondary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown"></button>
<button class="btn btn-sm btn-outline-secondary" data-bs-toggle="modal"
data-bs-target="#modalLinkedInvoicePreview"
href="javascript:void(0);"><i class="bx bx-show me-1"></i>
Szczegóły</button>
<button type="button"
class="btn btn-sm btn-outline-secondary dropdown-toggle dropdown-toggle-split"
data-bs-toggle="dropdown"></button>
<ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item disabled" href="javascript:void(0);"><i class="bx bx-link me-1"></i> Przypisz fakturę</a></li>
<li><a class="dropdown-item" href="javascript:void(0);"><i class="bx bx-edit me-1"></i> Edytuj</a></li>
<li><a class="dropdown-item disabled" href="javascript:void(0);"><i
class="bx bx-link me-1"></i> Przypisz fakturę</a></li>
<li><a class="dropdown-item" href="javascript:void(0);"><i
class="bx bx-edit me-1"></i> Edytuj</a></li>
</ul>
</div>
</td>
@@ -398,7 +426,8 @@ include '../../header-travel.php';
<td class="text-center"><span class="badge bg-label-danger">Nierozliczone</span>
</td>
<td class="text-end">
<button class="btn btn-sm btn-primary" href="javascript:void(0);"><i class="bx bx-link me-1"></i> Przypisz fakturę</button>
<button class="btn btn-sm btn-primary" href="javascript:void(0);"><i
class="bx bx-link me-1"></i> Przypisz fakturę</button>
</td>
</tr>
@@ -424,7 +453,8 @@ include '../../header-travel.php';
rozliczone</span></td>
<td class="text-end">
<div class="btn-group">
<button class="btn btn-sm btn-outline-secondary"
<button class="btn btn-sm btn-outline-secondary" data-bs-toggle="modal"
data-bs-target="#modalLinkedInvoicePreview"
href="javascript:void(0);"><i class="bx bx-show me-1"></i>
Szczegóły</button>
<button type="button"
@@ -459,11 +489,17 @@ include '../../header-travel.php';
<td class="text-center"><span class="badge bg-label-success">Rozliczone</span></td>
<td class="text-end">
<div class="btn-group">
<button class="btn btn-sm btn-outline-secondary" href="javascript:void(0);"><i class="bx bx-show me-1"></i> Szczegóły</button>
<button type="button" class="btn btn-sm btn-outline-secondary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown"></button>
<button class="btn btn-sm btn-outline-secondary"
href="javascript:void(0);"><i class="bx bx-show me-1"></i>
Szczegóły</button>
<button type="button"
class="btn btn-sm btn-outline-secondary dropdown-toggle dropdown-toggle-split"
data-bs-toggle="dropdown"></button>
<ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item disabled" href="javascript:void(0);"><i class="bx bx-link me-1"></i> Przypisz fakturę</a></li>
<li><a class="dropdown-item" href="javascript:void(0);"><i class="bx bx-edit me-1"></i> Edytuj</a></li>
<li><a class="dropdown-item disabled" href="javascript:void(0);"><i
class="bx bx-link me-1"></i> Przypisz fakturę</a></li>
<li><a class="dropdown-item" href="javascript:void(0);"><i
class="bx bx-edit me-1"></i> Edytuj</a></li>
</ul>
</div>
</td>
@@ -582,6 +618,122 @@ include '../../header-travel.php';
</div>
<div class="modal fade" id="modalLinkedInvoicePreview" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content border-0 shadow-lg">
<div class="modal-header border-bottom">
<h5 class="modal-title"><i class="bx bx-receipt text-primary me-2"></i>Podgląd powiązanej faktury</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body p-4">
<div class="card shadow-none border mb-3">
<div class="card-body">
<div class="row g-3">
<div class="col-md-6">
<div class="small text-muted">Numer faktury</div>
<div class="fw-semibold">FV/2026/05/1234</div>
</div>
<div class="col-md-6">
<div class="small text-muted">Dostawca</div>
<div class="fw-semibold">Flixbus Polska Sp. z o.o.</div>
</div>
<div class="col-md-4">
<div class="small text-muted">Data wystawienia</div>
<div class="fw-semibold">04.05.2026</div>
</div>
<div class="col-md-4">
<div class="small text-muted">Kwota brutto</div>
<div class="fw-bold text-primary">4 200,00 PLN</div>
</div>
<div class="col-md-4">
<div class="small text-muted">Status</div>
<span class="badge bg-label-success">Powiązana</span>
</div>
</div>
</div>
</div>
<h6 class="mb-2">Pozycje faktury</h6>
<div class="table-responsive">
<table class="table table-sm modal-linked-table">
<thead class="table-light">
<tr>
<th>Pozycja</th>
<th class="text-end">Kwota brutto</th>
</tr>
</thead>
<tbody>
<tr>
<td>Przejazd autokarowy WarszawaZakopane</td>
<td class="text-end">2 808,00 PLN</td>
</tr>
<tr>
<td>Przejazd autokarowy ZakopaneWarszawa</td>
<td class="text-end">648,00 PLN</td>
</tr>
<tr>
<td>Opłata za rezerwację + obsługa</td>
<td class="text-end">744,00 PLN</td>
</tr>
</tbody>
<tfoot>
<tr>
<th>Razem</th>
<th class="text-end text-primary">4 200,00 PLN</th>
</tr>
</tfoot>
</table>
</div>
<h6 class="mb-2 mt-4">Powiązane zlecenia</h6>
<div class="table-responsive">
<table class="table table-sm modal-linked-table">
<thead class="table-light">
<tr>
<th>Zlecenie / Wycieczka</th>
<th>Data realizacji</th>
<th class="text-end">Przypisana kwota</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="d-flex flex-column">
<span class="fw-semibold text-primary">ZL/2026/05/089</span>
<small class="text-muted">#WYC-098 (Tatry Maj)</small>
</div>
</td>
<td>05.05.2026</td>
<td class="text-end">2 100,00 PLN</td>
</tr>
<tr>
<td>
<div class="d-flex flex-column">
<span class="fw-semibold text-primary">ZL/2026/05/156</span>
<small class="text-muted">#WYC-103 (Kraków)</small>
</div>
</td>
<td>08.05.2026</td>
<td class="text-end">2 100,00 PLN</td>
</tr>
</tbody>
<tfoot>
<tr>
<th colspan="2">Razem przypisano</th>
<th class="text-end text-primary">4 200,00 PLN</th>
</tr>
</tfoot>
</table>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-label-secondary" data-bs-dismiss="modal">Zamknij</button>
<button type="button" class="btn btn-primary">Przejdź do faktury</button>
</div>
</div>
</div>
</div>
<div class="modal fade" id="modalUploadInvoice" tabindex="-1" aria-hidden="true" data-bs-backdrop="static">
<div class="modal-dialog modal-xl modal-dialog-centered">
<div class="modal-content border-0 shadow-lg">
@@ -747,7 +899,7 @@ include '../../header-travel.php';
<label class="form-label">Kwota brutto <span
class="text-danger">*</span></label>
<input type="number" class="form-control fw-bold text-primary"
value="4200.00">
id="invoiceGrossAmount" value="4200.00">
</div>
<div class="col-sm-4">
<label class="form-label">Waluta</label>
@@ -821,6 +973,104 @@ include '../../header-travel.php';
</div>
</div>
<!-- Card: Podsumowanie odczytanej faktury -->
<div class="card shadow-none border mb-3" id="invoiceSummaryCard">
<div class="card-header py-2 px-3 d-flex align-items-center justify-content-between"
style="background: linear-gradient(135deg, #f0f4ff 0%, #e8f0fe 100%); border-bottom: 1px solid #d0deff;">
<div class="d-flex align-items-center gap-2">
<i class="bx bx-receipt text-primary fs-5"></i>
<span class="fw-semibold text-dark small">Dane odczytane z faktury</span>
</div>
<div class="d-flex align-items-center gap-3">
<div class="d-flex align-items-center gap-2">
<span class="text-muted small">Nr faktury:</span>
<span class="badge bg-label-primary fw-semibold">FV/2026/05/123</span>
</div>
<div class="d-flex align-items-center gap-2">
<span class="text-muted small">Dostawca:</span>
<span class="fw-semibold small text-dark">Flixbus Polska Sp. z o.o.</span>
</div>
<div class="vr opacity-25"></div>
<div class="d-flex align-items-center gap-2">
<span class="text-muted small">Netto:</span>
<span class="fw-semibold small">3 414,63 PLN</span>
</div>
<div class="d-flex align-items-center gap-2">
<span class="text-muted small">VAT:</span>
<span class="fw-semibold small">785,37 PLN</span>
</div>
<div class="d-flex align-items-center gap-2">
<span class="text-muted small">Brutto:</span>
<span class="fw-bold text-primary">4 200,00 PLN</span>
</div>
</div>
</div>
<div class="table-responsive">
<table class="table table-sm mb-0" style="font-size: 0.82rem;">
<thead style="background-color: #f8f9ff;">
<tr>
<th class="px-3 py-2 text-muted fw-semibold" style="width: 40%;">Nazwa
pozycji</th>
<th class="px-3 py-2 text-muted fw-semibold text-center" style="width: 8%;">
Ilość</th>
<th class="px-3 py-2 text-muted fw-semibold text-center" style="width: 8%;">
J.m.</th>
<th class="px-3 py-2 text-muted fw-semibold text-end" style="width: 13%;">
Cena netto</th>
<th class="px-3 py-2 text-muted fw-semibold text-center" style="width: 6%;">
VAT</th>
<th class="px-3 py-2 text-muted fw-semibold text-end" style="width: 12%;">
Kwota VAT</th>
<th class="px-3 py-2 text-muted fw-semibold text-end" style="width: 13%;">
Kwota brutto</th>
</tr>
</thead>
<tbody>
<tr class="border-top">
<td class="px-3 py-2">Przejazd autokarowy WarszawaZakopane (gr. 24 os.)
</td>
<td class="px-3 py-2 text-center">24</td>
<td class="px-3 py-2 text-center text-muted">os.</td>
<td class="px-3 py-2 text-end">2 600,00</td>
<td class="px-3 py-2 text-center"><span
class="badge bg-label-secondary">8%</span></td>
<td class="px-3 py-2 text-end">208,00</td>
<td class="px-3 py-2 text-end fw-semibold">2 808,00</td>
</tr>
<tr>
<td class="px-3 py-2">Przejazd autokarowy ZakopaneWarszawa (gr. 24 os.)
</td>
<td class="px-3 py-2 text-center">24</td>
<td class="px-3 py-2 text-center text-muted">os.</td>
<td class="px-3 py-2 text-end">600,00</td>
<td class="px-3 py-2 text-center"><span
class="badge bg-label-secondary">8%</span></td>
<td class="px-3 py-2 text-end">48,00</td>
<td class="px-3 py-2 text-end fw-semibold">648,00</td>
</tr>
<tr>
<td class="px-3 py-2">Opłata za rezerwację + obsługa</td>
<td class="px-3 py-2 text-center">1</td>
<td class="px-3 py-2 text-center text-muted">szt.</td>
<td class="px-3 py-2 text-end">214,63</td>
<td class="px-3 py-2 text-center"><span
class="badge bg-label-secondary">23%</span></td>
<td class="px-3 py-2 text-end">49,37</td>
<td class="px-3 py-2 text-end fw-semibold">264,00</td>
</tr>
<tr class="table-light border-top">
<td class="px-3 py-2 fw-semibold" colspan="3">Razem</td>
<td class="px-3 py-2 text-end fw-semibold">3 414,63</td>
<td class="px-3 py-2"></td>
<td class="px-3 py-2 text-end fw-semibold">785,37</td>
<td class="px-3 py-2 text-end fw-bold text-primary">4 200,00 PLN</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- /Card: Podsumowanie odczytanej faktury -->
<div class="card shadow-sm border">
<div
class="card-header bg-label-secondary d-flex justify-content-between align-items-center py-3">
@@ -832,7 +1082,7 @@ include '../../header-travel.php';
</div>
<div class="table-responsive" style="max-height: 300px;">
<table class="table table-hover mb-0">
<thead class="table-light sticky-top">
<thead class="table-light sticky-top text-nowrap">
<tr>
<th width="40"></th>
<th>Zlecenie / Wycieczka</th>
@@ -842,45 +1092,67 @@ include '../../header-travel.php';
</tr>
</thead>
<tbody>
<tr>
<tr class="assign-order-row" data-order-amount="4200.00">
<td><input class="form-check-input" type="checkbox" name="orderSelect"></td>
<td>
<div class="d-flex flex-column">
<span class="fw-semibold text-primary">ZL/2026/05/089</span>
<span
class="fw-semibold text-primary d-flex align-items-center gap-2">ZL/2026/05/089
<span
class="badge bg-label-success order-suggestion-badge">Sugerowane
zlecenie</span>
</span>
<small class="text-muted">#WYC-098 (Tatry)</small>
</div>
</td>
<td>05.05.2026</td>
<td class="text-end fw-semibold">4 200,00 PLN</td>
<td class="split-col d-none text-end"><input type="number"
class="form-control form-control-sm text-end" placeholder="0.00">
class="form-control form-control-sm text-end split-amount-input"
placeholder="0.00" min="0" step="0.01">
</td>
</tr>
<tr>
<tr class="assign-order-row" data-order-amount="2100.00">
<td><input class="form-check-input" type="checkbox" name="orderSelect"></td>
<td>
<div class="d-flex flex-column">
<span class="fw-semibold text-primary">ZL/2026/05/156</span>
<span
class="fw-semibold text-primary d-flex align-items-center gap-2">ZL/2026/05/156
<span
class="badge bg-label-success order-suggestion-badge d-none">Sugerowane
zlecenie</span>
</span>
<small class="text-muted">#WYC-103 (Kraków)</small>
</div>
</td>
<td>08.05.2026</td>
<td class="text-end fw-semibold">2 100,00 PLN</td>
<td class="split-col d-none text-end"><input type="number"
class="form-control form-control-sm text-end" placeholder="0.00">
class="form-control form-control-sm text-end split-amount-input"
placeholder="0.00" min="0" step="0.01">
</td>
</tr>
</tbody>
<tfoot>
<tr id="splitTotalRow" class="table-light d-none">
<td colspan="4" class="text-end fw-semibold">Suma przypisanych kwot:</td>
<td class="text-end fw-bold" id="splitTotalValue">0,00 PLN</td>
</tr>
</tfoot>
</table>
</div>
</div>
<div class="alert alert-danger d-none mt-3 mb-0" id="splitValidationAlert" role="alert">
Suma przypisanych pozycji musi być równa kwocie faktury.
</div>
<div class="d-flex justify-content-between mt-4 pt-3 border-top">
<button type="button" class="btn btn-label-secondary"
onclick="prevTab('step-validate-tab')">
<i class="bx bx-chevron-left me-1"></i> Wróć
</button>
<button type="button" class="btn btn-success">
<button type="button" class="btn btn-success" id="btnSaveAssign">
<i class="bx bx-check me-1"></i> Zapisz i Powiąż
</button>
</div>
@@ -1041,7 +1313,115 @@ include '../../header-travel.php';
// Zmiana na radio w tabeli, aby można było wybrać tylko jedno
document.querySelectorAll('input[name="orderSelect"]').forEach(el => el.type = 'radio');
}
updateSplitAmountSummary();
}
function formatPln(value) {
return value.toLocaleString('pl-PL', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
}) + ' PLN';
}
function getInvoiceGrossAmount() {
const invoiceInput = document.getElementById('invoiceGrossAmount');
const amount = parseFloat(invoiceInput ? invoiceInput.value : 0);
return Number.isFinite(amount) ? amount : 0;
}
function updateSplitAmountSummary() {
const isSplit = document.getElementById('assignSplit')?.checked;
const totalRow = document.getElementById('splitTotalRow');
const totalValue = document.getElementById('splitTotalValue');
const alertBox = document.getElementById('splitValidationAlert');
const saveBtn = document.getElementById('btnSaveAssign');
if (!isSplit) {
totalRow?.classList.add('d-none');
alertBox?.classList.add('d-none');
if (saveBtn) saveBtn.disabled = false;
return;
}
let sum = 0;
document.querySelectorAll('#step-assign .table-responsive table tbody tr').forEach(function (row) {
const selector = row.querySelector('input[name="orderSelect"]');
const amountInput = row.querySelector('.split-amount-input');
if (!selector || !amountInput || !selector.checked) return;
const value = parseFloat(amountInput.value);
if (Number.isFinite(value)) sum += value;
});
const invoiceAmount = getInvoiceGrossAmount();
const isMatch = Math.abs(sum - invoiceAmount) < 0.01;
totalRow?.classList.remove('d-none');
if (totalValue) {
totalValue.textContent = formatPln(sum);
totalValue.classList.toggle('text-danger', !isMatch);
totalValue.classList.toggle('text-success', isMatch);
}
alertBox?.classList.toggle('d-none', isMatch);
if (saveBtn) saveBtn.disabled = !isMatch;
}
function updateSuggestedOrder() {
const tbody = document.querySelector('#step-assign .table-responsive table tbody');
if (!tbody) return;
const rows = Array.from(tbody.querySelectorAll('.assign-order-row'));
if (!rows.length) return;
const invoiceAmount = getInvoiceGrossAmount();
let bestRow = null;
let bestDiff = Number.POSITIVE_INFINITY;
rows.forEach(function (row) {
row.classList.remove('table-success');
row.querySelectorAll('.order-suggestion-badge').forEach(function (badge) {
badge.classList.add('d-none');
});
const orderAmount = parseFloat(row.dataset.orderAmount || '0');
const diff = Math.abs(orderAmount - invoiceAmount);
if (diff < bestDiff) {
bestDiff = diff;
bestRow = row;
}
});
if (!bestRow) return;
tbody.prepend(bestRow);
bestRow.classList.add('table-success');
bestRow.querySelectorAll('.order-suggestion-badge').forEach(function (badge) {
badge.classList.remove('d-none');
});
}
document.querySelectorAll('input[name="orderSelect"], .split-amount-input').forEach(function (el) {
el.addEventListener('change', updateSplitAmountSummary);
el.addEventListener('input', updateSplitAmountSummary);
});
document.querySelectorAll('.split-amount-input').forEach(function (input) {
input.addEventListener('input', function () {
const row = input.closest('tr');
const selector = row ? row.querySelector('input[name="orderSelect"]') : null;
const value = parseFloat(input.value);
if (selector && Number.isFinite(value) && value > 0) {
selector.checked = true;
}
});
});
document.getElementById('invoiceGrossAmount')?.addEventListener('input', function () {
updateSplitAmountSummary();
updateSuggestedOrder();
});
updateSuggestedOrder();
updateSplitAmountSummary();
</script>
<style>
@@ -1099,6 +1479,17 @@ include '../../header-travel.php';
.option-card:hover {
border-color: #696cff !important;
}
/* Spójne rozmiary i odstępy dla tabel w podglądzie powiązanej faktury */
#modalLinkedInvoicePreview .modal-linked-table {
font-size: 0.82rem;
}
#modalLinkedInvoicePreview .modal-linked-table th,
#modalLinkedInvoicePreview .modal-linked-table td {
padding: 0.5rem 0.75rem;
vertical-align: middle;
}
</style>
<script>
@@ -1115,19 +1506,19 @@ include '../../header-travel.php';
if (checks.length === 0) {
label.textContent = 'Wszystkie statusy';
} else {
var names = Array.from(checks).map(function(c) {
var names = Array.from(checks).map(function (c) {
return c.closest('label').textContent.trim();
});
label.textContent = names.join(', ');
}
}
document.querySelectorAll('.status-check').forEach(function(cb) {
document.querySelectorAll('.status-check').forEach(function (cb) {
cb.addEventListener('change', updateStatusLabel);
});
// Zamknij po kliknięciu poza dropdownem
document.addEventListener('click', function(e) {
document.addEventListener('click', function (e) {
var dropdown = document.getElementById('statusDropdown');
if (dropdown && !dropdown.contains(e.target)) {
document.getElementById('statusDropdownMenu').classList.remove('show');