Compare commits
16 Commits
c0beb640e6
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| ad9279dbce | |||
| f2e1fa6134 | |||
| eed545736d | |||
| c63e7e6c9c | |||
| a0a4cd28aa | |||
| 5b1b4ec768 | |||
| 144aa81358 | |||
| da4d77a808 | |||
| bed52bdcbd | |||
| bb114ced7b | |||
| c9845b2df9 | |||
| 3da90baf4a | |||
| 2496b34bdd | |||
| d4355e3ee2 | |||
| e7549c6f00 | |||
| a282dd2080 |
154
api-comments.php
Normal file
154
api-comments.php
Normal file
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
// api-comments.php
|
||||
header('Content-Type: application/json');
|
||||
|
||||
// Dołączamy połączenie do bazy (upewnij się, że plik db_connect.php istnieje i ma poprawne dane)
|
||||
require_once 'db_connect.php';
|
||||
|
||||
session_start();
|
||||
|
||||
$action = $_GET['action'] ?? '';
|
||||
|
||||
// 0. AUTORYZACJA (LOGOWANIE)
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $action === 'auth') {
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$pass = $input['password'] ?? '';
|
||||
|
||||
// $PROTOTYPE_PASSWORD jest zdefiniowane w db_connect.php
|
||||
if (isset($PROTOTYPE_PASSWORD) && $pass === $PROTOTYPE_PASSWORD) {
|
||||
$_SESSION['prototype_auth'] = true;
|
||||
echo json_encode(['status' => 'success']);
|
||||
} else {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Nieprawidłowe hasło']);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
// 0. SPRAWDZENIE SESJI (Opcjonalne dla list, wymagane dla add)
|
||||
function isAuthorized()
|
||||
{
|
||||
return !empty($_SESSION['prototype_auth']);
|
||||
}
|
||||
|
||||
// 0.5 SPRAWDZENIE STANU AUTORYZACJI (GET) - dla frontendowego odtworzenia sesji
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'GET' && $action === 'check_auth') {
|
||||
if (isAuthorized()) {
|
||||
echo json_encode(['status' => 'success']);
|
||||
} else {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Brak sesji']);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
// 1. POBIERANIE KOMENTARZY (GET)
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'GET' && $action === 'list') {
|
||||
$pagePath = $_GET['page_path'] ?? '';
|
||||
|
||||
if (!$pagePath) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Brak ścieżki pliku']);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare("SELECT * FROM prototype_comments WHERE page_path = ? ORDER BY created_at DESC");
|
||||
$stmt->execute([$pagePath]);
|
||||
$comments = $stmt->fetchAll();
|
||||
|
||||
// XSS PROTECTION: Escaping danych przed wysłaniem
|
||||
foreach ($comments as &$c) {
|
||||
$c['author'] = htmlspecialchars($c['author'] ?? '', ENT_QUOTES, 'UTF-8');
|
||||
$c['comment'] = htmlspecialchars($c['comment'] ?? '', ENT_QUOTES, 'UTF-8');
|
||||
// Selector musi zostać oryginalny, bo JS go używa do querySelector!
|
||||
// $c['dom_selector'] = htmlspecialchars($c['dom_selector'] ?? '', ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
|
||||
echo json_encode(['status' => 'success', 'data' => $comments]);
|
||||
} catch (PDOException $e) {
|
||||
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
// 2. DODAWANIE KOMENTARZA (POST)
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $action === 'add') {
|
||||
// Wymagana autoryzacja
|
||||
if (!isAuthorized()) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Brak autoryzacji. Odśwież stronę i podaj hasło.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Odczyt danych JSON z body requestu
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
$pagePath = $input['page_path'] ?? '';
|
||||
$selector = $input['selector'] ?? '';
|
||||
$comment = $input['comment'] ?? '';
|
||||
$author = $input['author'] ?? 'Anonim'; // Możesz tu potem wpiąć sesję użytkownika
|
||||
|
||||
if (!$pagePath || !$selector || !$comment) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Brakuje danych']);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare("INSERT INTO prototype_comments (page_path, dom_selector, author, comment) VALUES (?, ?, ?, ?)");
|
||||
$stmt->execute([$pagePath, $selector, $author, $comment]);
|
||||
|
||||
echo json_encode(['status' => 'success', 'id' => $pdo->lastInsertId()]);
|
||||
} catch (PDOException $e) {
|
||||
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
// 3. ROZWIĄZYWANIE KOMENTARZA (POST)
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $action === 'resolve') {
|
||||
if (!isAuthorized()) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Brak autoryzacji']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$id = $input['id'] ?? 0;
|
||||
|
||||
if (!$id) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Brak ID']);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
// Zmieniamy flagę is_resolved na 1
|
||||
$stmt = $pdo->prepare("UPDATE prototype_comments SET is_resolved = 1 WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
echo json_encode(['status' => 'success']);
|
||||
} catch (PDOException $e) {
|
||||
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
// 4. USUWANIE KOMENTARZA (POST)
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $action === 'delete') {
|
||||
if (!isAuthorized()) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Brak autoryzacji']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$id = $input['id'] ?? 0;
|
||||
|
||||
if (!$id) {
|
||||
echo json_encode(['status' => 'error', 'message' => 'Brak ID']);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare("DELETE FROM prototype_comments WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
echo json_encode(['status' => 'success']);
|
||||
} catch (PDOException $e) {
|
||||
echo json_encode(['status' => 'error', 'message' => $e->getMessage()]);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
298
assets/css/comments.css
Normal file
298
assets/css/comments.css
Normal file
@@ -0,0 +1,298 @@
|
||||
/* assets/css/comments.css */
|
||||
|
||||
/* Pasek narzędzi na górze */
|
||||
#prototype-topbar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
background: #232f3e;
|
||||
color: white;
|
||||
z-index: 100000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 20px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
}
|
||||
|
||||
#prototype-topbar .mode-switch {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
/* Przełącznik (Toggle) */
|
||||
.switch-label {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 40px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.switch-label input {
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #ccc;
|
||||
transition: .4s;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
left: 2px;
|
||||
bottom: 2px;
|
||||
background-color: white;
|
||||
transition: .4s;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
input:checked+.slider {
|
||||
background-color: #2196F3;
|
||||
}
|
||||
|
||||
input:checked+.slider:before {
|
||||
transform: translateX(20px);
|
||||
}
|
||||
|
||||
/* Pinezki (Markery) */
|
||||
.comment-marker {
|
||||
position: absolute;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background: #ff3e1d;
|
||||
border: 2px solid white;
|
||||
border-radius: 50% 50% 50% 0;
|
||||
transform: rotate(-45deg) translate(-50%, -100%);
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
|
||||
cursor: pointer;
|
||||
z-index: 10000;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.comment-marker:hover {
|
||||
z-index: 10001;
|
||||
transform: rotate(-45deg) translate(-50%, -100%) scale(1.2);
|
||||
}
|
||||
|
||||
.comment-marker.resolved {
|
||||
background: #71dd37;
|
||||
/* Zielony dla rozwiązanych */
|
||||
}
|
||||
|
||||
/* Dymek z komentarzem (Tooltip) */
|
||||
.comment-popover {
|
||||
position: absolute;
|
||||
background: white;
|
||||
border: 1px solid #d9dee3;
|
||||
border-radius: 6px;
|
||||
padding: 10px;
|
||||
width: 250px;
|
||||
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.15);
|
||||
z-index: 100002;
|
||||
/* Musi być wyżej niż marker (100001) i topbar (100000) */
|
||||
font-size: 13px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.comment-popover h6 {
|
||||
margin: 0 0 5px 0;
|
||||
font-size: 12px;
|
||||
color: #888;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.comment-popover p {
|
||||
margin: 0;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* Tryb wyboru - podświetlanie elementów */
|
||||
.comment-mode-active *:hover {
|
||||
outline: 2px dashed #2196F3 !important;
|
||||
cursor: comment !important;
|
||||
}
|
||||
|
||||
/* Wykluczenia, żeby nie podświetlać samego UI komentarzy */
|
||||
.comment-mode-active #prototype-topbar *:hover,
|
||||
.comment-mode-active .comment-marker:hover,
|
||||
.comment-mode-active .comment-popover *:hover {
|
||||
outline: none !important;
|
||||
cursor: default !important;
|
||||
}
|
||||
|
||||
/* Modal do dodawania (prosty) */
|
||||
#comment-input-box {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
|
||||
z-index: 100002;
|
||||
width: 300px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#comment-input-box textarea {
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
margin-bottom: 10px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#comment-input-box-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 100001;
|
||||
display: none;
|
||||
backdrop-filter: blur(2px);
|
||||
}
|
||||
|
||||
/* --- POPRAWKA: Wykluczenie okienka edycji z efektów wizualnych --- */
|
||||
|
||||
/* Nawet w trybie comment-mode-active, nasze okno dialogowe ma wyglądać normalnie */
|
||||
.comment-mode-active #comment-input-box,
|
||||
.comment-mode-active #comment-input-box * {
|
||||
outline: none !important;
|
||||
cursor: auto !important;
|
||||
/* Przywraca normalny kursor (strzałkę/łapkę) */
|
||||
}
|
||||
|
||||
/* --- POPRAWKA: Wykluczenie okienka edycji z efektów wizualnych --- */
|
||||
|
||||
/* assets/css/comments.css */
|
||||
|
||||
/* ... poprzednie style bez zmian ... */
|
||||
|
||||
/* POPRAWKI DLA MODALA I FOCUSU */
|
||||
#comment-input-box {
|
||||
/* Ustawiamy fixed/absolute dynamicznie w JS, ale bazowo: */
|
||||
z-index: 100000;
|
||||
/* Musi być wyżej niż Bootstrap Modal (zwykle 1055) */
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
|
||||
width: 320px;
|
||||
display: none;
|
||||
/* Centrowanie - teraz zrobimy to sprytniej w CSS */
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
#comment-input-box-overlay {
|
||||
position: fixed;
|
||||
/* JS zmieni na absolute jeśli w modalu */
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
backdrop-filter: blur(2px);
|
||||
z-index: 99999;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Ważne: Pineski muszą być nad wszystkim */
|
||||
.comment-marker {
|
||||
z-index: 100001;
|
||||
pointer-events: auto !important;
|
||||
/* Żeby dało się w nie klikać nawet w trybie blokady */
|
||||
}
|
||||
|
||||
/* Ukrywanie pinesek */
|
||||
body.comments-hidden .comment-marker {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Dialog listy wszystkich komentarzy */
|
||||
#all-comments-dialog {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.4);
|
||||
z-index: 100005;
|
||||
width: 500px;
|
||||
max-width: 90vw;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#all-comments-dialog-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 100004;
|
||||
display: none;
|
||||
backdrop-filter: blur(2px);
|
||||
}
|
||||
|
||||
.comment-list-item {
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.comment-list-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.comment-list-item:hover {
|
||||
background: #f9f9f9;
|
||||
}
|
||||
|
||||
/* --- FIX DLA MODALI PROTOTYPU --- */
|
||||
/* Wymuszamy, aby standardowe modale (Bootstrap) nie chowały się pod paskiem */
|
||||
.modal {
|
||||
padding-top: 50px !important;
|
||||
/* Odsuwamy od góry o wysokość paska */
|
||||
}
|
||||
|
||||
/* Opcjonalnie: Jeśli modal ma backdrop, też go przesuwamy,
|
||||
albo po prostu upewniamy się że modal-dialog ma margines */
|
||||
.modal-dialog {
|
||||
margin-top: 20px !important;
|
||||
/* Dodatkowy margines żeby nie dotykało paska */
|
||||
}
|
||||
|
||||
/* Jeśli używasz offcanvas lub innych overlayów */
|
||||
.offcanvas {
|
||||
top: 50px !important;
|
||||
height: calc(100% - 50px) !important;
|
||||
}
|
||||
|
||||
/* Poprawka dla backdropu, żeby nie zakrywał paska (jeśli pasek ma być na wierzchu) */
|
||||
.modal-backdrop {
|
||||
top: 50px !important;
|
||||
height: calc(100% - 50px) !important;
|
||||
}
|
||||
870
assets/js/comments.js
Normal file
870
assets/js/comments.js
Normal file
@@ -0,0 +1,870 @@
|
||||
// assets/js/comments.js
|
||||
|
||||
(function () {
|
||||
// Konfiguracja API
|
||||
const baseUrl = (typeof MAGICO_BASE_URL !== 'undefined') ? MAGICO_BASE_URL : '';
|
||||
const API_URL = baseUrl + '/api-comments.php';
|
||||
const CURRENT_PATH = window.location.pathname.replace(/^\/|\/$/g, '');
|
||||
|
||||
let isCommentMode = false;
|
||||
let pendingElement = null; // Element, który chcemy skomentować
|
||||
let markersData = []; // Przechowujemy dane o markerach lokalnie do szybkiego odświeżania
|
||||
|
||||
// --- 1. GENEROWANIE UI ---
|
||||
function initUI() {
|
||||
document.body.style.paddingTop = '50px';
|
||||
|
||||
const bar = document.createElement('div');
|
||||
bar.id = 'prototype-topbar';
|
||||
bar.innerHTML = `
|
||||
<div style="display:flex; align-items:center;">
|
||||
<div style="font-weight: bold; font-size: 14px; margin-right: 20px;">
|
||||
<span style="color: #696cff;">Magico</span> Feedback
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display:flex; align-items:center; gap: 20px;">
|
||||
<!-- Licznik -->
|
||||
<div id="comments-count-badge" style="cursor:pointer; font-size:13px; display:flex; align-items:center; gap:5px; padding: 5px 10px; background: rgba(255,255,255,0.1); border-radius: 4px;">
|
||||
<span style="opacity:0.8;">Komentarzy:</span>
|
||||
<span id="comments-count-val" style="background:#696cff; padding:2px 8px; border-radius:10px; font-weight:bold; font-size:11px;">0</span>
|
||||
</div>
|
||||
|
||||
<!-- Pokaż/Ukryj -->
|
||||
<div style="display:flex; align-items:center; font-size:13px; gap: 5px;">
|
||||
<input type="checkbox" id="comments-visibility-toggle" checked style="cursor:pointer;">
|
||||
<label for="comments-visibility-toggle" style="cursor:pointer; margin-bottom:0;">Pokaż pineski</label>
|
||||
</div>
|
||||
|
||||
<div style="width: 1px; height: 20px; background: rgba(255,255,255,0.2);"></div>
|
||||
|
||||
<!-- Tryb -->
|
||||
<div class="mode-switch">
|
||||
<span style="font-size: 13px; margin-right: 8px;">Tryb Komentowania</span>
|
||||
<label class="switch-label">
|
||||
<input type="checkbox" id="comment-toggle">
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
document.body.appendChild(bar);
|
||||
|
||||
// Kontener na input (domyślnie w body)
|
||||
const modalHtml = `
|
||||
<div id="comment-input-box-overlay"></div>
|
||||
<div id="comment-input-box">
|
||||
<h6 style="margin-top:0;">Dodaj notatkę</h6>
|
||||
<input type="text" id="new-comment-author" class="form-control mb-2" placeholder="Twój podpis (np. Jan)" style="font-size: 0.9rem;">
|
||||
<textarea id="new-comment-text" class="form-control mb-2" rows="3" placeholder="Wpisz uwagę..."></textarea>
|
||||
<div style="text-align: right; gap: 5px; display: flex; justify-content: flex-end;">
|
||||
<button id="cancel-comment" class="btn btn-sm btn-outline-secondary">Anuluj</button>
|
||||
<button id="save-comment" class="btn btn-sm btn-primary">Zapisz</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Lista Wszystkich -->
|
||||
<div id="all-comments-dialog-overlay"></div>
|
||||
<div id="all-comments-dialog">
|
||||
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:15px; border-bottom:1px solid #eee; padding-bottom:10px;">
|
||||
<h5 style="margin:0;">Wszystkie komentarze</h5>
|
||||
<button id="close-all-comments" class="btn btn-sm btn-outline-secondary">X</button>
|
||||
</div>
|
||||
<div id="all-comments-list" style="max-height:60vh; overflow-y:auto; padding-right:5px;"></div>
|
||||
</div>
|
||||
`;
|
||||
document.body.insertAdjacentHTML('beforeend', modalHtml);
|
||||
|
||||
// Listenery UI
|
||||
const toggle = document.getElementById('comment-toggle');
|
||||
|
||||
toggle.addEventListener('change', function (e) {
|
||||
if (e.target.checked) {
|
||||
// Próba włączenia - autoryzacja
|
||||
checkAuth().then(ok => {
|
||||
if (ok) {
|
||||
isCommentMode = true;
|
||||
localStorage.setItem('magico_comment_mode', 'true');
|
||||
toggleCommentMode(true);
|
||||
} else {
|
||||
e.target.checked = false; // Cofnij switch
|
||||
}
|
||||
});
|
||||
} else {
|
||||
isCommentMode = false;
|
||||
localStorage.removeItem('magico_comment_mode');
|
||||
toggleCommentMode(false);
|
||||
}
|
||||
});
|
||||
|
||||
// Toggle visibility
|
||||
const visToggle = document.getElementById('comments-visibility-toggle');
|
||||
const savedVis = localStorage.getItem('magico_markers_visible');
|
||||
if (savedVis === 'false') {
|
||||
visToggle.checked = false;
|
||||
document.body.classList.add('comments-hidden');
|
||||
}
|
||||
|
||||
visToggle.addEventListener('change', (e) => {
|
||||
if (e.target.checked) {
|
||||
document.body.classList.remove('comments-hidden');
|
||||
localStorage.setItem('magico_markers_visible', 'true');
|
||||
} else {
|
||||
document.body.classList.add('comments-hidden');
|
||||
localStorage.setItem('magico_markers_visible', 'false');
|
||||
}
|
||||
});
|
||||
|
||||
// Open list dialog
|
||||
document.getElementById('comments-count-badge').addEventListener('click', showAllCommentsDialog);
|
||||
document.getElementById('close-all-comments').addEventListener('click', () => {
|
||||
document.getElementById('all-comments-dialog').style.display = 'none';
|
||||
document.getElementById('all-comments-dialog-overlay').style.display = 'none';
|
||||
});
|
||||
|
||||
// --- RESTORE SESSION ---
|
||||
const savedMode = localStorage.getItem('magico_comment_mode');
|
||||
if (savedMode === 'true') {
|
||||
// Sprawdź cicho czy sesja PHP jest aktywna
|
||||
checkAuth(true).then(ok => {
|
||||
if (ok) {
|
||||
toggle.checked = true;
|
||||
isCommentMode = true;
|
||||
toggleCommentMode(true);
|
||||
} else {
|
||||
localStorage.removeItem('magico_comment_mode'); // Sesja wygasła
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementById('cancel-comment').addEventListener('click', closeInputBox);
|
||||
document.getElementById('save-comment').addEventListener('click', saveComment);
|
||||
|
||||
// Scroll listener (capture) - żeby aktualizować pineski przy każdym przewinięciu (okna lub modala)
|
||||
window.addEventListener('scroll', updateMarkerPositions, true);
|
||||
}
|
||||
|
||||
// --- 1.5 AUTORYZACJA ---
|
||||
// Prosta weryfikacja - czy mamy flagę w sesji JS?
|
||||
// Lepiej: przy włączeniu zapytać o hasło jeśli nie mamy, i wysłać do API.
|
||||
// API ustawi sesję PHP.
|
||||
|
||||
let isAuthorized = false; // Lokalna flaga, aby nie pytać co chwilę
|
||||
|
||||
async function checkAuth(silent = false) {
|
||||
if (isAuthorized) return true;
|
||||
|
||||
// Najpierw zapytaj API czy już jesteśmy zalogowani (sesja PHP)
|
||||
try {
|
||||
const check = await fetch(API_URL + '?action=check_auth');
|
||||
const checkData = await check.json();
|
||||
if (checkData.status === 'success') {
|
||||
isAuthorized = true;
|
||||
return true;
|
||||
}
|
||||
} catch (e) { }
|
||||
|
||||
if (silent) return false;
|
||||
|
||||
const pass = prompt("Podaj hasło do trybu komentowania:");
|
||||
if (!pass) return false;
|
||||
|
||||
try {
|
||||
const res = await fetch(API_URL + '?action=auth', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ password: pass })
|
||||
});
|
||||
const data = await res.json();
|
||||
|
||||
if (data.status === 'success') {
|
||||
isAuthorized = true;
|
||||
return true;
|
||||
} else {
|
||||
alert("Błąd: " + (data.message || "Nieprawidłowe hasło"));
|
||||
return false;
|
||||
}
|
||||
} catch (e) {
|
||||
alert("Błąd połączenia z API");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// --- 2. LOGIKA TRYBU (AGRESYWNE BLOKOWANIE) ---
|
||||
function toggleCommentMode(active) {
|
||||
if (active) {
|
||||
document.body.classList.add('comment-mode-active');
|
||||
// Blokujemy wszystko: click, mousedown, mouseup, submit
|
||||
['click', 'mousedown', 'mouseup', 'submit'].forEach(evt =>
|
||||
window.addEventListener(evt, handleInteraction, true)
|
||||
);
|
||||
} else {
|
||||
document.body.classList.remove('comment-mode-active');
|
||||
['click', 'mousedown', 'mouseup', 'submit'].forEach(evt =>
|
||||
window.removeEventListener(evt, handleInteraction, true)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// --- 3. OBSŁUGA INTERAKCJI ---
|
||||
function handleInteraction(e) {
|
||||
// ZAWSZE pozwalamy na interakcję z naszym UI
|
||||
if (e.target.closest('#prototype-topbar') ||
|
||||
e.target.closest('#comment-input-box') ||
|
||||
e.target.closest('.comment-marker') ||
|
||||
e.target.closest('.comment-popover')) { // Dodano popover do wykluczeń
|
||||
return;
|
||||
}
|
||||
|
||||
// Blokujemy natywną akcję
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
|
||||
// Reagujemy tylko na 'click' (żeby nie odpalać input boxa 3 razy na mousedown/up/click)
|
||||
if (e.type === 'click') {
|
||||
pendingElement = e.target;
|
||||
openInputBox();
|
||||
}
|
||||
}
|
||||
|
||||
// --- 4. SELEKTOR CSS ---
|
||||
function getCssSelector(el) {
|
||||
if (!(el instanceof Element)) return;
|
||||
const path = [];
|
||||
while (el.nodeType === Node.ELEMENT_NODE && el.tagName !== 'BODY') {
|
||||
let selector = el.tagName.toLowerCase();
|
||||
if (el.id) {
|
||||
selector += '#' + el.id;
|
||||
path.unshift(selector);
|
||||
break;
|
||||
} else {
|
||||
let sib = el, nth = 1;
|
||||
while (sib = sib.previousElementSibling) {
|
||||
if (sib.tagName.toLowerCase() == selector) nth++;
|
||||
}
|
||||
if (nth > 1) selector += ":nth-of-type(" + nth + ")";
|
||||
|
||||
if (el.classList.length > 0) {
|
||||
for (let cls of el.classList) {
|
||||
if (cls !== 'active' && cls !== 'show' && cls !== 'collapsed' && cls !== 'fade') {
|
||||
selector += "." + cls;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
path.unshift(selector);
|
||||
el = el.parentNode;
|
||||
}
|
||||
return path.join(" > ");
|
||||
}
|
||||
|
||||
// --- 5. OBSŁUGA INPUTA (PRZENOSZENIE DO MODALA) ---
|
||||
function openInputBox() {
|
||||
const box = document.getElementById('comment-input-box');
|
||||
const overlay = document.getElementById('comment-input-box-overlay');
|
||||
|
||||
// FIX: Sprawdź czy jest otwarty modal Bootstrapa
|
||||
const activeModal = document.querySelector('.modal.show .modal-content');
|
||||
|
||||
if (activeModal) {
|
||||
// Jeśli tak, przenieś nasz box do modala (żeby działało pisanie i focus)
|
||||
activeModal.appendChild(box);
|
||||
// Overlay też, żeby przykrył modal
|
||||
activeModal.appendChild(overlay);
|
||||
box.style.position = 'absolute'; // W modalu pozycjonujemy absolutnie względem modala
|
||||
} else {
|
||||
// Jeśli nie, wracamy do body
|
||||
document.body.appendChild(overlay);
|
||||
document.body.appendChild(box);
|
||||
box.style.position = 'fixed';
|
||||
}
|
||||
|
||||
// Tymczasowe wyłączenie trybu wybierania, żeby można było klikać w Boxie
|
||||
// Ale NIE zdejmujemy listenerów blokujących tło (bo tło nadal ma być nieklikalne)
|
||||
// Po prostu nasza funkcja handleInteraction przepuszcza kliknięcia w #comment-input-box
|
||||
|
||||
overlay.style.display = 'block';
|
||||
box.style.display = 'block';
|
||||
|
||||
// Focus po małym timeout, żeby przeglądarka zdążyła przenieść element
|
||||
setTimeout(() => {
|
||||
const authorInput = document.getElementById('new-comment-author');
|
||||
const savedAuthor = localStorage.getItem('magico_comment_author');
|
||||
if (savedAuthor) authorInput.value = savedAuthor;
|
||||
|
||||
// Focus na tekst, chyba że brak autora
|
||||
if (!savedAuthor) authorInput.focus();
|
||||
else document.getElementById('new-comment-text').focus();
|
||||
}, 50);
|
||||
}
|
||||
|
||||
function closeInputBox() {
|
||||
const box = document.getElementById('comment-input-box');
|
||||
const overlay = document.getElementById('comment-input-box-overlay');
|
||||
|
||||
overlay.style.display = 'none';
|
||||
box.style.display = 'none';
|
||||
document.getElementById('new-comment-text').value = '';
|
||||
pendingElement = null;
|
||||
|
||||
// Wracamy z boxem do body na wszelki wypadek
|
||||
document.body.appendChild(overlay);
|
||||
document.body.appendChild(box);
|
||||
}
|
||||
|
||||
function saveComment() {
|
||||
const text = document.getElementById('new-comment-text').value;
|
||||
const author = document.getElementById('new-comment-author').value || 'Anonim';
|
||||
|
||||
if (!text || !pendingElement) {
|
||||
closeInputBox();
|
||||
return;
|
||||
}
|
||||
|
||||
// Zapisz autora na przyszłość
|
||||
localStorage.setItem('magico_comment_author', author);
|
||||
|
||||
const selector = getCssSelector(pendingElement);
|
||||
|
||||
fetch(API_URL + '?action=add', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
page_path: CURRENT_PATH,
|
||||
selector: selector,
|
||||
comment: text,
|
||||
author: author
|
||||
})
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.status === 'success') {
|
||||
closeInputBox();
|
||||
loadComments();
|
||||
} else {
|
||||
alert('Błąd: ' + data.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// --- 6. PINESKI I AKTUALIZACJA POZYCJI ---
|
||||
function loadComments() {
|
||||
fetch(API_URL + '?action=list&page_path=' + encodeURIComponent(CURRENT_PATH))
|
||||
.then(res => res.json())
|
||||
.then(resp => {
|
||||
if (resp.status === 'success') {
|
||||
markersData = resp.data; // Zapisz dane
|
||||
renderMarkers(); // Narysuj
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let activePopover = null;
|
||||
|
||||
function renderMarkers() {
|
||||
window.magicoIsUpdating = true;
|
||||
try {
|
||||
// Usuń stare
|
||||
document.querySelectorAll('.comment-marker').forEach(el => el.remove());
|
||||
if (activePopover) { activePopover.remove(); activePopover = null; }
|
||||
|
||||
// Grupowanie komentarzy po selektorze
|
||||
const grouped = {};
|
||||
let activeCount = 0;
|
||||
|
||||
markersData.forEach((c) => {
|
||||
if (c.is_resolved == 0) activeCount++;
|
||||
|
||||
// Pomiń rozwiązane, jeśli chcemy je ukrywać (na razie pokazujemy wszystkie, albo tylko nierozwiązane?)
|
||||
// User: "archiwum zmienia flagę is_resolved". Zakładamy że archiwum = ukryte?
|
||||
// "Archiwum" zwykle oznacza ukryte. Ukryjmy rozwiązane.
|
||||
if (c.is_resolved == 1) return;
|
||||
|
||||
if (!grouped[c.dom_selector]) grouped[c.dom_selector] = [];
|
||||
grouped[c.dom_selector].push(c);
|
||||
});
|
||||
|
||||
// Aktualizacja licznika na pasku
|
||||
const cntEl = document.getElementById('comments-count-val');
|
||||
if (cntEl) cntEl.textContent = activeCount;
|
||||
|
||||
Object.keys(grouped).forEach((selector, index) => {
|
||||
const commentsList = grouped[selector];
|
||||
if (!commentsList.length) return;
|
||||
|
||||
try {
|
||||
const el = document.querySelector(selector);
|
||||
if (el && el.offsetParent !== null) { // Tylko widoczne elementy
|
||||
const marker = document.createElement('div');
|
||||
marker.className = 'comment-marker';
|
||||
marker.dataset.selector = selector;
|
||||
|
||||
// Jeśli więcej niż 1 komentarz, pokaż licznik
|
||||
if (commentsList.length > 1) {
|
||||
marker.textContent = commentsList.length;
|
||||
marker.style.display = 'flex';
|
||||
marker.style.alignItems = 'center';
|
||||
marker.style.justifyContent = 'center';
|
||||
marker.style.color = 'white';
|
||||
marker.style.fontSize = '12px';
|
||||
marker.style.fontWeight = 'bold';
|
||||
// Resetuejmu transform dla tekstu żeby był czytelny? Nie, rotacja jest na pinezce.
|
||||
// Tekst też się obróci. Trzeba by go odkręcić.
|
||||
// Prościej: dodajmy span w środku który odkręcimy.
|
||||
marker.innerHTML = `<span style="transform: rotate(45deg); display:block;">${commentsList.length}</span>`;
|
||||
}
|
||||
|
||||
// Zdarzenie HOVER (najazd myszką)
|
||||
marker.addEventListener('mouseenter', (e) => {
|
||||
showPopover(marker, commentsList);
|
||||
});
|
||||
|
||||
marker.addEventListener('mouseleave', (e) => {
|
||||
marker._leaveTimeout = setTimeout(() => {
|
||||
if (activePopover && activePopover._associatedMarker === marker) {
|
||||
if (!activePopover.matches(':hover')) {
|
||||
activePopover.remove();
|
||||
activePopover = null;
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
});
|
||||
|
||||
document.body.appendChild(marker);
|
||||
}
|
||||
} catch (err) { }
|
||||
});
|
||||
|
||||
// Po stworzeniu od razu ustaw pozycje
|
||||
updateMarkerPositions();
|
||||
} finally {
|
||||
setTimeout(() => { window.magicoIsUpdating = false; }, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function showPopover(marker, commentsList) {
|
||||
if (activePopover) activePopover.remove();
|
||||
|
||||
const pop = document.createElement('div');
|
||||
pop.className = 'comment-popover';
|
||||
|
||||
// Budowanie listy komentarzy
|
||||
let html = '<div style="max-height: 600px; overflow-y: auto;">';
|
||||
|
||||
commentsList.forEach(data => {
|
||||
// Escape (chociaż API to robi, warto mieć warstwę w JS w razie czego, ale API już robi htmlspecialchars)
|
||||
// Skoro API robi htmlspecialchars, to tutaj możemy bezpiecznie wstawić
|
||||
// Ale uwaga: JS textContent jest bezpieczniejszy.
|
||||
|
||||
// Hack na szybkie budowanie bezpiecznego HTML w pętli stringów jest trudny.
|
||||
// Zbudujmy to jako elementy DOM potem? Albo zaufajmy API + textContent buildera.
|
||||
|
||||
// Zrobimy placeholder i podstawimy wartości.
|
||||
|
||||
html += `
|
||||
<div class="comment-item" style="border-bottom:1px solid #eee; padding-bottom:8px; margin-bottom:8px;">
|
||||
<div style="display:flex; justify-content:space-between; margin-bottom:4px;">
|
||||
<h6 style="margin:0;">${data.author || 'Anonim'}</h6>
|
||||
<span style="font-size:10px; color:#999;">${data.created_at}</span>
|
||||
</div>
|
||||
<p style="margin-bottom:5px;">${data.comment}</p>
|
||||
<div style="text-align:right; gap:5px; display:flex; justify-content:flex-end;">
|
||||
${isAuthorized ? `<button class="btn btn-xs btn-outline-success btn-resolve" data-id="${data.id}" style="font-size:10px; padding: 2px 5px;">Rozwiąż</button>
|
||||
<button class="btn btn-xs btn-outline-danger btn-delete" data-id="${data.id}" style="font-size:10px; padding: 2px 5px;">Usuń</button>` : ''}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
html += '</div>';
|
||||
|
||||
pop.innerHTML = html;
|
||||
document.body.appendChild(pop);
|
||||
activePopover = pop;
|
||||
pop._associatedMarker = marker;
|
||||
|
||||
// Bindowanie akcji z stopPropagation
|
||||
pop.querySelectorAll('.btn-resolve').forEach(btn => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.stopPropagation(); // Ważne!
|
||||
resolveComment(btn.dataset.id);
|
||||
});
|
||||
});
|
||||
pop.querySelectorAll('.btn-delete').forEach(btn => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.stopPropagation(); // Ważne!
|
||||
deleteComment(btn.dataset.id);
|
||||
});
|
||||
});
|
||||
|
||||
// Obsługa interakcji (np. scrollbar)
|
||||
pop.addEventListener('mousedown', () => {
|
||||
pop._isInteracting = true;
|
||||
});
|
||||
|
||||
// Obsługa zamykania przy wyjechaniu z popovera
|
||||
pop.addEventListener('mouseleave', () => {
|
||||
pop._leaveTimeout = setTimeout(() => {
|
||||
if (activePopover === pop) {
|
||||
// Jeśli user trzyma przycisk myszy (np. na scrollbarze), nie zamykaj
|
||||
if (pop._isInteracting) return;
|
||||
|
||||
if (!activePopover.matches(':hover') && !marker.matches(':hover')) {
|
||||
activePopover.remove();
|
||||
activePopover = null;
|
||||
}
|
||||
}
|
||||
}, 500); // Zwiększono do 500ms
|
||||
});
|
||||
|
||||
pop.addEventListener('mouseenter', () => {
|
||||
if (pop._leaveTimeout) clearTimeout(pop._leaveTimeout);
|
||||
if (marker._leaveTimeout) clearTimeout(marker._leaveTimeout);
|
||||
});
|
||||
|
||||
// Pozycjonowanie
|
||||
const rect = marker.getBoundingClientRect();
|
||||
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
||||
const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
|
||||
|
||||
pop.style.top = (rect.top + scrollTop - 5) + 'px';
|
||||
pop.style.left = (rect.right + scrollLeft) + 'px'; // Usunięto przerwę +2px
|
||||
|
||||
if (rect.right + 260 > window.innerWidth) {
|
||||
pop.style.left = (rect.left + scrollLeft - 260) + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
function resolveComment(id) {
|
||||
if (!confirm('Czy na pewno chcesz rozwiązać/zarchiwizować ten komentarz?')) return;
|
||||
fetch(API_URL + '?action=resolve', {
|
||||
method: 'POST', body: JSON.stringify({ id: id })
|
||||
}).then(res => res.json()).then(res => {
|
||||
if (res.status === 'success') loadComments();
|
||||
else alert('Błąd: ' + res.message);
|
||||
});
|
||||
}
|
||||
|
||||
function deleteComment(id) {
|
||||
if (!confirm('Czy na pewno chcesz trwale usunąć ten komentarz?')) return;
|
||||
fetch(API_URL + '?action=delete', {
|
||||
method: 'POST', body: JSON.stringify({ id: id })
|
||||
}).then(res => res.json()).then(res => {
|
||||
if (res.status === 'success') loadComments();
|
||||
else alert('Błąd: ' + res.message);
|
||||
});
|
||||
}
|
||||
|
||||
// (Usunięto click-outside listener, bo teraz działamy na hover)
|
||||
|
||||
// Aktualizuj też pozycję otwartego popovera przy scrollu
|
||||
const originalUpdatePositions = updateMarkerPositions;
|
||||
// ... w sumie updateMarkerPositions jest niżej zdefiniowana,
|
||||
// lepiej wrzucimy to w updateMarkerPositions bezpośrednio.
|
||||
|
||||
// Funkcja wywoływana przy scrollowaniu - musi być szybka
|
||||
function updateMarkerPositions() {
|
||||
window.magicoIsUpdating = true; // Zaczynamy aktualizację
|
||||
try {
|
||||
const markers = document.querySelectorAll('.comment-marker');
|
||||
|
||||
markers.forEach(marker => {
|
||||
const selector = marker.dataset.selector;
|
||||
if (!selector) return;
|
||||
|
||||
try {
|
||||
const el = document.querySelector(selector);
|
||||
if (el && el.offsetParent !== null) {
|
||||
const rect = el.getBoundingClientRect();
|
||||
|
||||
// Jeśli element wyjechał poza ekran (jest w scrollowanym divie ale schowany)
|
||||
marker.style.top = (rect.top + window.scrollY) + 'px';
|
||||
marker.style.left = (rect.left + window.scrollX + (rect.width / 2)) + 'px';
|
||||
marker.style.display = (marker.textContent.length > 0) ? 'flex' : 'block';
|
||||
// Flex dla licznika, block dla zwykłego? A w stylach mamy display?
|
||||
// W renderMarkers ustawilismy display:flex ręcznie dla licznika.
|
||||
// Tu musimy uwazac zeby tego nie zepsuc. Pominmy style.display='block' jesli ma flex.
|
||||
if (marker.style.display !== 'flex') marker.style.display = 'block';
|
||||
|
||||
if (activePopover && activePopover._associatedMarker === marker) {
|
||||
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
||||
const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
|
||||
|
||||
// Recalculate position
|
||||
let top = (rect.top + scrollTop - 5);
|
||||
let left = (rect.right + scrollLeft);
|
||||
if (rect.right + 260 > window.innerWidth) {
|
||||
left = (rect.left + scrollLeft - 260);
|
||||
}
|
||||
|
||||
activePopover.style.top = top + 'px';
|
||||
activePopover.style.left = left + 'px';
|
||||
}
|
||||
} else {
|
||||
marker.style.display = 'none';
|
||||
if (activePopover && activePopover._associatedMarker === marker) {
|
||||
// Jeśli element zniknął (np. scroll), ale user trzyma myszkę na popoverze - nie usuwaj
|
||||
if (!activePopover.matches(':hover') && !activePopover._isInteracting) {
|
||||
activePopover.remove();
|
||||
activePopover = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) { }
|
||||
});
|
||||
} finally {
|
||||
// Mały timeout, bo MutationObserver jest asynchroniczny (microtask)
|
||||
// Ale my chcemy zablokować detekcję zmian, które WŁAŚNIE zaszły.
|
||||
// Ponieważ observer odpala się "później", flaga false może zostać ustawiona ZA WCZEŚNIE?
|
||||
// Nie, observer zbiera zmiany i odpala callback.
|
||||
// Jeśli callback odpali się kiedy flaga jest true, to return.
|
||||
// Ale callback odpali się w następnym ticku.
|
||||
// Więc musimy przetrzymać flagę true do następnego ticku?
|
||||
// Tak, bezpieczniej setTimeout(..., 0).
|
||||
setTimeout(() => { window.magicoIsUpdating = false; }, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Global mouseup do resetowania flagi interakcji
|
||||
document.addEventListener('mouseup', () => {
|
||||
if (activePopover) {
|
||||
activePopover._isInteracting = false;
|
||||
// Opcjonalnie: sprawdź czy zamknąć, jeśli myszka jest poza
|
||||
if (activePopover && !activePopover.matches(':hover') && (!activePopover._associatedMarker || !activePopover._associatedMarker.matches(':hover'))) {
|
||||
// Możemy wywołać logikę zamykania, ale ona jest w mouseleave.
|
||||
// Jeśli user puścił myszkę POZA popoverem, mouseleave już dawno poszło (i timeout mógł zostać zablokowany przez flagę).
|
||||
// Więc tutaj warto sprawdzić.
|
||||
setTimeout(() => {
|
||||
// Sprawdź ponownie (bezpiecznik)
|
||||
if (activePopover && !activePopover._isInteracting && !activePopover.matches(':hover')) {
|
||||
activePopover.remove();
|
||||
activePopover = null;
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// START
|
||||
initUI();
|
||||
// Sprawdź autoryzację w tle (nawet wyłączony tryb komentowania), w celu wyświetlenia przycisków
|
||||
checkAuth(true).then(() => {
|
||||
loadComments();
|
||||
});
|
||||
|
||||
// Odświeżanie przy zmianie rozmiaru okna
|
||||
window.addEventListener('resize', updateMarkerPositions);
|
||||
|
||||
// MutationObserver - odświeżaj pozycje jak coś się zmieni w wygenerowanym DOM (ale ignoruj nasze markery)
|
||||
// Helper sprawdzający czy element jest częścią naszego UI
|
||||
function isOurElement(node) {
|
||||
if (!node || node.nodeType !== 1) return false;
|
||||
|
||||
// Lista ID elementów systemu
|
||||
const ourIds = [
|
||||
'prototype-topbar',
|
||||
'comment-input-box',
|
||||
'comment-input-box-overlay',
|
||||
'all-comments-dialog',
|
||||
'all-comments-dialog-overlay'
|
||||
];
|
||||
|
||||
if (ourIds.includes(node.id)) return true;
|
||||
|
||||
if (node.classList && (
|
||||
node.classList.contains('comment-marker') ||
|
||||
node.classList.contains('comment-popover')
|
||||
)) return true;
|
||||
|
||||
// Sprawdź rodziców
|
||||
if (node.closest) {
|
||||
for (const id of ourIds) {
|
||||
if (node.closest('#' + id)) return true;
|
||||
}
|
||||
if (node.closest('.comment-marker') || node.closest('.comment-popover')) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// --- 8. OBSŁUGA OBSERVERA I PĘTLI ---
|
||||
|
||||
// Zmienna na observer zdefiniowana niżej, ale potrzebujemy jej tu.
|
||||
// Przenieśmy definicję observera wyżej albo użyjmy funkcji.
|
||||
|
||||
let observer; // deklaracja wstępna
|
||||
|
||||
function ignoreObserver(action) {
|
||||
if (observer) observer.disconnect();
|
||||
try {
|
||||
action();
|
||||
} finally {
|
||||
if (observer) startObserver();
|
||||
}
|
||||
}
|
||||
|
||||
function startObserver() {
|
||||
observer.observe(document.body, {
|
||||
childList: true, subtree: true, attributes: true,
|
||||
attributeFilter: ['class', 'style', 'hidden']
|
||||
});
|
||||
}
|
||||
|
||||
// --- MODYFIKACJA renderMarkers i updateMarkerPositions ---
|
||||
|
||||
// Przechwytujemy stare funkcje i opakowujemy je
|
||||
// Ale lepiej po prostu zmienić ich ciała w kodzie (co robię tym replace'm)
|
||||
|
||||
// Nadpiszmy renderMarkers, żeby używało ignoreObserver
|
||||
// Uwaga: Funkcja renderMarkers i updateMarkerPositions są wyżej.
|
||||
// Ten tool replace musi być sprytny.
|
||||
// Zamiast nadpisywać, zmienię logikę observera na dole pliku i podmienię wywołania.
|
||||
|
||||
// W tym bloku (EndLine: 734) jest końcówka pliku i definicja observera.
|
||||
// Zdefiniujmy observera tutaj poprawnie.
|
||||
|
||||
observer = new MutationObserver((mutations) => {
|
||||
// Jeśli my sami aktualizujemy, ignoruj wszystko
|
||||
if (window.magicoIsUpdating) return;
|
||||
|
||||
let shouldUpdate = false;
|
||||
|
||||
// Optymalizacja: Sprawdzamy czy zmiany są ISTOTNE
|
||||
for (const mutation of mutations) {
|
||||
// Ignorujemy zmiany na naszych elementach (nawet jeśli disconnect nie zadziałał idealnie)
|
||||
if (isOurElement(mutation.target)) continue;
|
||||
|
||||
// Zmiany childList
|
||||
if (mutation.type === 'childList') {
|
||||
let externalChanges = false;
|
||||
// Sprawdź dodane
|
||||
for (let i = 0; i < mutation.addedNodes.length; i++) {
|
||||
const node = mutation.addedNodes[i];
|
||||
if (node.nodeType === 1 && !isOurElement(node)) {
|
||||
externalChanges = true; break;
|
||||
}
|
||||
if (node.nodeType === 3 && node.textContent.trim() !== '') {
|
||||
externalChanges = true; break;
|
||||
}
|
||||
}
|
||||
// Sprawdź usunięte
|
||||
if (!externalChanges) {
|
||||
for (let i = 0; i < mutation.removedNodes.length; i++) {
|
||||
const node = mutation.removedNodes[i];
|
||||
if (node.nodeType === 1 && !isOurElement(node)) {
|
||||
externalChanges = true; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!externalChanges) continue;
|
||||
}
|
||||
|
||||
shouldUpdate = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (shouldUpdate) {
|
||||
if (window.commentUpdateTimeout) clearTimeout(window.commentUpdateTimeout);
|
||||
window.commentUpdateTimeout = setTimeout(() => {
|
||||
// Renderowanie wyzwolone przez zmiany zewnętrzne
|
||||
// Nie musimy tu robić ignoreObserver bo renderMarkers samo to zrobi wewnątrz?
|
||||
// Nie, bo renderMarkers to funkcja.
|
||||
// Wywołajmy renderMarkers.
|
||||
renderMarkers();
|
||||
}, 200);
|
||||
}
|
||||
});
|
||||
|
||||
startObserver();
|
||||
|
||||
// EXPORT funkcji do użycia wewnątrz renderMarkers/update
|
||||
// Ponieważ nie edytuję całego pliku, musimy jakoś wstrzyknąć ignoreObserver do wywołań wyżej?
|
||||
// Nie da się bez edycji tamtych funkcji.
|
||||
// WIĘC: Zostawiam observera jak jest (z ulepszonym isOurElement),
|
||||
// ALE w renderMarkers i updateMarkerPositions dodam wywołania disconnect/connect.
|
||||
|
||||
// Czekaj, nie mam dostępu do zmiennej `observer` wewnątrz funkcji zadeklarowanych wyżej, jeśli zadeklaruję ją na dole.
|
||||
// Ale w JS var/let w tym samym scope (IIFE) są widoczne.
|
||||
// Muszę przenieść deklarację `let observer` na górę IIFE (innym replacem) lub
|
||||
// Zmienić observer na `window.magicoObserver`? Nieładnie.
|
||||
|
||||
// Zrobię tak: Zdefiniuję `ignoreObserver` tutaj, i użyję `observer.disconnect()` wewnątrz.
|
||||
// Ale muszę mieć pewność że `observer` jest zdefiniowany.
|
||||
// W obecnym kodzie jest zdefiniowany jako `const observer = ...` na dole.
|
||||
// const nie jest hoisted.
|
||||
|
||||
// PLAN B:
|
||||
// Zmienię definicję `const observer` na `let observer` i przesunę definicję funkcji `isOurElement` i observera na dół,
|
||||
// a potem w replace'ach wyżej dodam wywołania wrapperów.
|
||||
|
||||
// LUB PROŚCIEJ:
|
||||
// Zmodyfikujmy `renderMarkers` i `updateMarkerPositions` żeby sprawdzały flagę globalną `window.magicoIsUpdating`.
|
||||
// A observer będzie sprawdzał tę flagę.
|
||||
|
||||
// IMPLEMENTACJA FLAGI:
|
||||
window.magicoIsUpdating = false;
|
||||
|
||||
// --- 7. DIALOG Z LISTĄ WSZYSTKICH ---
|
||||
function showAllCommentsDialog() {
|
||||
const dialog = document.getElementById('all-comments-dialog');
|
||||
const overlay = document.getElementById('all-comments-dialog-overlay');
|
||||
const list = document.getElementById('all-comments-list');
|
||||
|
||||
// Budowanie listy
|
||||
// Filtrujemy tylko nierozwiązane??? W sumie user chciał "wszystkimi zebranymi z tego ekranu".
|
||||
// Pokażmy wszystkie uporządkowane od najnowszych, z oznaczeniem rozwiązanych.
|
||||
|
||||
// Kopia i sortowanie
|
||||
const sorted = [...markersData].sort((a, b) => b.id - a.id);
|
||||
|
||||
if (sorted.length === 0) {
|
||||
list.innerHTML = '<p style="text-align:center; color:#999; padding:20px;">Brak komentarzy na tym ekranie.</p>';
|
||||
} else {
|
||||
let html = '';
|
||||
sorted.forEach(c => {
|
||||
const bg = c.is_resolved == 1 ? '#f0fff0' : '#fff';
|
||||
const status = c.is_resolved == 1 ? '<span class="badge bg-success" style="font-size:10px;">Rozwiązany</span>' : '';
|
||||
|
||||
html += `
|
||||
<div class="comment-list-item" style="background:${bg};">
|
||||
<div style="display:flex; justify-content:space-between; margin-bottom:5px;">
|
||||
<div>
|
||||
<strong>${c.author || 'Anonim'}</strong>
|
||||
${status}
|
||||
</div>
|
||||
<small style="color:#999;">${c.created_at}</small>
|
||||
</div>
|
||||
<p style="margin-bottom:8px;">${c.comment}</p>
|
||||
<div style="font-size:11px; color:#888; margin-bottom:5px;">
|
||||
Element: <code>${c.dom_selector.substring(0, 30)}...</code>
|
||||
</div>
|
||||
<div style="text-align:right;">
|
||||
${isAuthorized && c.is_resolved == 0 ? `<button class="btn btn-sm btn-outline-success btn-resolve-list" data-id="${c.id}">Rozwiąż</button>` : ''}
|
||||
${isAuthorized ? `<button class="btn btn-sm btn-outline-danger btn-delete-list" data-id="${c.id}">Usuń</button>` : ''}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
list.innerHTML = html;
|
||||
|
||||
// Listenery w liście
|
||||
list.querySelectorAll('.btn-resolve-list').forEach(btn => {
|
||||
btn.addEventListener('click', () => resolveComment(btn.dataset.id));
|
||||
});
|
||||
list.querySelectorAll('.btn-delete-list').forEach(btn => {
|
||||
btn.addEventListener('click', () => deleteComment(btn.dataset.id));
|
||||
});
|
||||
}
|
||||
|
||||
dialog.style.display = 'block';
|
||||
overlay.style.display = 'block';
|
||||
}
|
||||
|
||||
// Dodajmy do renderMarkers aktualizację licznika
|
||||
// Musimy przechwycić oryginalny renderMarkers wyżej
|
||||
// Ale jesteśmy w module, więc po prostu dopiszmy to do renderMarkers
|
||||
|
||||
// W renderMarkers (linia ~300) dodać:
|
||||
// document.getElementById('comments-count-val').textContent = markersData.filter(c => c.is_resolved == 0).length;
|
||||
// Albo wszystkich? "Liczba komentarzy". Raczej wszystkich aktywnych.
|
||||
|
||||
})();
|
||||
25
db_connect.php
Normal file
25
db_connect.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
$host = 'localhost';
|
||||
$db = 'srv105686_magicoprototype';
|
||||
$user = 'srv105686_magicoprototype';
|
||||
$pass = 'pMMdmYHXSBs6wM5LHNjd';
|
||||
$pass = 'pMMdmYHXSBs6wM5LHNjd';
|
||||
$charset = 'utf8mb4';
|
||||
|
||||
// Hasło do trybu komentowania
|
||||
$PROTOTYPE_PASSWORD = 'magic'; // Zmień to hasło!
|
||||
|
||||
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
|
||||
$options = [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
];
|
||||
|
||||
try {
|
||||
$pdo = new PDO($dsn, $user, $pass, $options);
|
||||
} catch (\PDOException $e) {
|
||||
// W środowisku produkcyjnym nie pokazuj błędów użytkownikom, ale tu to prototyp:
|
||||
throw new \PDOException($e->getMessage(), (int) $e->getCode());
|
||||
}
|
||||
?>
|
||||
@@ -27,4 +27,13 @@
|
||||
<!-- Vendors JS -->
|
||||
|
||||
<!-- Main JS -->
|
||||
<script src="<?= $basePath ?>/assets/js/main.js"></script>
|
||||
<script src="<?= $basePath ?>/assets/js/main.js"></script>
|
||||
<script>
|
||||
// Przekazujemy ścieżkę z PHP do globalnej zmiennej JS
|
||||
// Używamy json_encode dla bezpieczeństwa typów
|
||||
const MAGICO_BASE_URL = <?= json_encode($basePath); ?>;
|
||||
</script>
|
||||
|
||||
<?php if (!empty($enablePrototypeComments) && $enablePrototypeComments): ?>
|
||||
<script src="<?= $basePath ?>/assets/js/comments.js"></script>
|
||||
<?php endif; ?>
|
||||
61
footer.php
Normal file
61
footer.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<!-- Footer -->
|
||||
<footer class="content-footer footer bg-footer-theme">
|
||||
<div class="container-xxl d-flex flex-wrap justify-content-between py-2 flex-md-row flex-column">
|
||||
<div class="mb-2 mb-md-0">
|
||||
©
|
||||
<script>
|
||||
document.write(new Date().getFullYear());
|
||||
</script>
|
||||
, made with ❤️ by
|
||||
<a href="https://themeselection.com" target="_blank" class="footer-link fw-medium">ThemeSelection</a>
|
||||
</div>
|
||||
<div class="d-none d-lg-inline-block">
|
||||
<a href="https://demos.themeselection.com/sneat-bootstrap-html-admin-template/documentation/"
|
||||
target="_blank" class="footer-link me-4">Documentation</a>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<!-- / Footer -->
|
||||
|
||||
<div class="content-backdrop fade"></div>
|
||||
</div>
|
||||
<!-- Content wrapper -->
|
||||
</div>
|
||||
<!-- / Layout page -->
|
||||
</div>
|
||||
|
||||
<!-- Overlay -->
|
||||
<div class="layout-overlay layout-menu-toggle"></div>
|
||||
|
||||
<!-- Drag Target Area To SlideIn Menu On Small Screens -->
|
||||
<div class="drag-target"></div>
|
||||
</div>
|
||||
<!-- / Layout wrapper -->
|
||||
|
||||
<!-- Core JS -->
|
||||
<!-- build:js assets/vendor/js/core.js -->
|
||||
|
||||
<script src="<?= $basePath ?>/assets/vendor/libs/jquery/jquery.js"></script>
|
||||
<script src="<?= $basePath ?>/assets/vendor/libs/popper/popper.js"></script>
|
||||
<script src="<?= $basePath ?>/assets/vendor/js/bootstrap.js"></script>
|
||||
<script src="<?= $basePath ?>/assets/vendor/libs/perfect-scrollbar/perfect-scrollbar.js"></script>
|
||||
<script src="<?= $basePath ?>/assets/vendor/libs/hammer/hammer.js"></script>
|
||||
|
||||
<script src="<?= $basePath ?>/assets/vendor/js/menu.js"></script>
|
||||
|
||||
<!-- endbuild -->
|
||||
|
||||
<!-- Vendors JS -->
|
||||
|
||||
<!-- Main JS -->
|
||||
<script src="<?= $basePath ?>/assets/js/main.js"></script>
|
||||
|
||||
<script>
|
||||
// Przekazujemy ścieżkę z PHP do globalnej zmiennej JS
|
||||
// Używamy json_encode dla bezpieczeństwa typów
|
||||
const MAGICO_BASE_URL = <?= json_encode($basePath); ?>;
|
||||
</script>
|
||||
|
||||
<?php if (!empty($enablePrototypeComments) && $enablePrototypeComments): ?>
|
||||
<script src="<?= $basePath ?>/assets/js/comments.js"></script>
|
||||
<?php endif; ?>
|
||||
80
header-company.php
Normal file
80
header-company.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
$basePath = '';
|
||||
if ($_SERVER['HTTP_HOST'] === 'localhost' || $_SERVER['HTTP_HOST'] === '127.0.0.1') {
|
||||
$basePath = '/magico-prototype';
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en" class="light-style layout-navbar-fixed layout-menu-fixed layout-compact" dir="ltr"
|
||||
data-theme="theme-default" data-assets-path="<?= $basePath ?>/assets/"
|
||||
data-template="vertical-menu-template-no-customizer-starter">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" />
|
||||
|
||||
<title>company.magico</title>
|
||||
|
||||
<meta name="description" content="" />
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/x-icon" href="<?= $basePath ?>/assets/img/favicon/favicon.ico" />
|
||||
|
||||
<!-- 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:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap"
|
||||
rel="stylesheet" />
|
||||
|
||||
<link rel="stylesheet" href="<?= $basePath ?>/assets/vendor/fonts/boxicons.css" />
|
||||
<!-- <link rel="stylesheet" href="<?= $basePath ?>/assets/vendor/fonts/fontawesome.css" /> -->
|
||||
<!-- <link rel="stylesheet" href="<?= $basePath ?>/assets/vendor/fonts/flag-icons.css" /> -->
|
||||
|
||||
<!-- Core CSS -->
|
||||
<link rel="stylesheet" href="<?= $basePath ?>/assets/vendor/css/rtl/core.css" />
|
||||
<link rel="stylesheet" href="<?= $basePath ?>/assets/vendor/css/rtl/theme-default.css" />
|
||||
<link rel="stylesheet" href="<?= $basePath ?>/assets/css/demo.css" />
|
||||
|
||||
<!-- Vendors CSS -->
|
||||
<link rel="stylesheet" href="<?= $basePath ?>/assets/vendor/libs/perfect-scrollbar/perfect-scrollbar.css" />
|
||||
|
||||
<!-- Page CSS -->
|
||||
|
||||
<!-- Helpers -->
|
||||
<script src="<?= $basePath ?>/assets/vendor/js/helpers.js"></script>
|
||||
<!--! Template customizer & Theme config files MUST be included after core stylesheets and helpers.js in the <head> section -->
|
||||
<!--? Config: Mandatory theme config file contain global vars & default theme options, Set your preferred theme option in this file. -->
|
||||
<script src="<?= $basePath ?>/assets/js/config.js"></script>
|
||||
|
||||
<?php if (!empty($enablePrototypeComments) && $enablePrototypeComments): ?>
|
||||
<link rel="stylesheet" href="<?= $basePath ?>/assets/css/comments.css">
|
||||
<?php endif; ?>
|
||||
|
||||
<style>
|
||||
@media (min-width: 1200px) {
|
||||
|
||||
.layout-menu-fixed .layout-menu,
|
||||
.layout-menu-fixed-offcanvas .layout-menu {
|
||||
padding-top: 50px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- Layout wrapper -->
|
||||
<div class="layout-wrapper layout-content-navbar">
|
||||
<div class="layout-container">
|
||||
<!-- Menu -->
|
||||
|
||||
<?php include 'menu.php'; ?>
|
||||
<!-- / Menu -->
|
||||
|
||||
<!-- Layout container -->
|
||||
<div class="layout-page pt-0" style="padding-top: 0 !important;">
|
||||
|
||||
<!-- Content wrapper -->
|
||||
<div class="content-wrapper">
|
||||
80
header-invoice.php
Normal file
80
header-invoice.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
$basePath = '';
|
||||
if ($_SERVER['HTTP_HOST'] === 'localhost' || $_SERVER['HTTP_HOST'] === '127.0.0.1') {
|
||||
$basePath = '/magico-prototype';
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en" class="light-style layout-navbar-fixed layout-menu-fixed layout-compact" dir="ltr"
|
||||
data-theme="theme-default" data-assets-path="<?= $basePath ?>/assets/"
|
||||
data-template="vertical-menu-template-no-customizer-starter">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" />
|
||||
|
||||
<title>invoice.magico</title>
|
||||
|
||||
<meta name="description" content="" />
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/x-icon" href="<?= $basePath ?>/assets/img/favicon/favicon.ico" />
|
||||
|
||||
<!-- 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:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap"
|
||||
rel="stylesheet" />
|
||||
|
||||
<link rel="stylesheet" href="<?= $basePath ?>/assets/vendor/fonts/boxicons.css" />
|
||||
<!-- <link rel="stylesheet" href="<?= $basePath ?>/assets/vendor/fonts/fontawesome.css" /> -->
|
||||
<!-- <link rel="stylesheet" href="<?= $basePath ?>/assets/vendor/fonts/flag-icons.css" /> -->
|
||||
|
||||
<!-- Core CSS -->
|
||||
<link rel="stylesheet" href="<?= $basePath ?>/assets/vendor/css/rtl/core.css" />
|
||||
<link rel="stylesheet" href="<?= $basePath ?>/assets/vendor/css/rtl/theme-default.css" />
|
||||
<link rel="stylesheet" href="<?= $basePath ?>/assets/css/demo.css" />
|
||||
|
||||
<!-- Vendors CSS -->
|
||||
<link rel="stylesheet" href="<?= $basePath ?>/assets/vendor/libs/perfect-scrollbar/perfect-scrollbar.css" />
|
||||
|
||||
<!-- Page CSS -->
|
||||
|
||||
<!-- Helpers -->
|
||||
<script src="<?= $basePath ?>/assets/vendor/js/helpers.js"></script>
|
||||
<!--! Template customizer & Theme config files MUST be included after core stylesheets and helpers.js in the <head> section -->
|
||||
<!--? Config: Mandatory theme config file contain global vars & default theme options, Set your preferred theme option in this file. -->
|
||||
<script src="<?= $basePath ?>/assets/js/config.js"></script>
|
||||
|
||||
<?php if (!empty($enablePrototypeComments) && $enablePrototypeComments): ?>
|
||||
<link rel="stylesheet" href="<?= $basePath ?>/assets/css/comments.css">
|
||||
<?php endif; ?>
|
||||
|
||||
<style>
|
||||
@media (min-width: 1200px) {
|
||||
|
||||
.layout-menu-fixed .layout-menu,
|
||||
.layout-menu-fixed-offcanvas .layout-menu {
|
||||
padding-top: 50px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- Layout wrapper -->
|
||||
<div class="layout-wrapper layout-content-navbar">
|
||||
<div class="layout-container">
|
||||
<!-- Menu -->
|
||||
|
||||
<?php include 'menu.php'; ?>
|
||||
<!-- / Menu -->
|
||||
|
||||
<!-- Layout container -->
|
||||
<div class="layout-page pt-0" style="padding-top: 0 !important;">
|
||||
|
||||
<!-- Content wrapper -->
|
||||
<div class="content-wrapper">
|
||||
@@ -44,6 +44,10 @@ if ($_SERVER['HTTP_HOST'] === 'localhost' || $_SERVER['HTTP_HOST'] === '127.0.0.
|
||||
<!-- Vendors CSS -->
|
||||
<link rel="stylesheet" href="<?= $basePath ?>/assets/vendor/libs/perfect-scrollbar/perfect-scrollbar.css" />
|
||||
|
||||
<?php if (!empty($enablePrototypeComments) && $enablePrototypeComments): ?>
|
||||
<link rel="stylesheet" href="<?= $basePath ?>/assets/css/comments.css">
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Page CSS -->
|
||||
|
||||
<!-- Helpers -->
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
foreach ($structure as &$files) {
|
||||
sort($files);
|
||||
}
|
||||
unset($files); // Break the reference with the last element
|
||||
}
|
||||
|
||||
foreach ($structure as $folder => $files): ?>
|
||||
|
||||
257
prototype/company/app-billing.php
Normal file
257
prototype/company/app-billing.php
Normal file
@@ -0,0 +1,257 @@
|
||||
<?php
|
||||
$enablePrototypeComments = true;
|
||||
include '../../header-invoice.php';
|
||||
?>
|
||||
|
||||
<div class="container-xxl flex-grow-1 container-p-y">
|
||||
|
||||
<h4 class="fw-bold py-3 mb-4">
|
||||
<span class="text-muted fw-light">Zarządzanie firmą /</span> Rozliczenia
|
||||
</h4>
|
||||
|
||||
<!-- Karta: Rozliczenia (Podsumowanie) -->
|
||||
<div class="card mb-4">
|
||||
<h5 class="card-header border-bottom">Rozliczenia</h5>
|
||||
<div class="card-body pt-5 pb-5">
|
||||
|
||||
<!-- Wycentrowany Alert z tłem ze screena -->
|
||||
<div class="d-flex justify-content-center mb-5">
|
||||
<div class="p-3 rounded text-white d-inline-flex align-items-center shadow-sm"
|
||||
style="background-color: #f04e76; font-weight: 500; width: 100%; max-width: 800px;">
|
||||
<i class='bx bxs-error-alt me-2 fs-5'></i>
|
||||
Dokonaj płatności aby zachować subskrypcję. Usługi pozostaną aktywne do 2026-03-31.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Parametry -->
|
||||
<div class="d-flex flex-column flex-md-row justify-content-center gap-5">
|
||||
<div class="text-start">
|
||||
<small class="text-muted text-uppercase fw-semibold" style="letter-spacing: 0.5px;">Aktualny okres
|
||||
rozliczeniowy:</small>
|
||||
<h5 class="mt-2 mb-0 fw-bold text-dark">2026-03-01 - 2026-03-31</h5>
|
||||
</div>
|
||||
|
||||
<div class="text-start">
|
||||
<small class="text-muted text-uppercase fw-semibold" style="letter-spacing: 0.5px;">Szacowane
|
||||
rozliczenie</small>
|
||||
<h3 class="mt-1 mb-1 fw-bold" style="color: #696cff;">425 zł</h3>
|
||||
<small class="text-muted">Następna płatność:: 2026-04-01</small>
|
||||
</div>
|
||||
|
||||
<div class="text-start">
|
||||
<small class="text-muted text-uppercase fw-semibold" style="letter-spacing: 0.5px;">Ilość miejsca na
|
||||
dysku</small>
|
||||
<h3 class="mt-1 mb-0 fw-bold" style="color: #696cff;">0.04 GB</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Karta: Historia płatności -->
|
||||
<div class="card">
|
||||
<h5 class="card-header border-bottom">Historia płatności</h5>
|
||||
<div class="table-responsive text-nowrap pb-2">
|
||||
<table class="table table-hover">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th class="fw-bold">Nr dokumentu</th>
|
||||
<th class="fw-bold">Status</th>
|
||||
<th class="fw-bold">Kwota (netto)</th>
|
||||
<th class="fw-bold">Data wystawienia</th>
|
||||
<th class="fw-bold">Faktura VAT</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="table-border-bottom-0">
|
||||
|
||||
<!-- Wiersz 1 -->
|
||||
<tr>
|
||||
<td><a href="#" class="fw-bold text-primary">5/05/2025</a></td>
|
||||
<td><span class="badge bg-label-warning px-2 py-1" style="font-size: 0.75rem;">Opóźniona</span>
|
||||
</td>
|
||||
<td class="fw-semibold">365 zł</td>
|
||||
<td class="text-dark">2025-06-01</td>
|
||||
<td>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<button class="btn btn-sm btn-outline-secondary text-nowrap disabled"
|
||||
style="background-color: #f8f9fa;"><i class="bx bx-cloud-download me-1"></i> Faktura
|
||||
VAT</button>
|
||||
<button class="btn btn-sm btn-outline-secondary text-nowrap"><i
|
||||
class="bx bx-cloud-download me-1"></i> Faktura proforma</button>
|
||||
|
||||
<span class="text-muted mx-2">|</span>
|
||||
|
||||
<button class="btn btn-sm btn-outline-secondary text-nowrap" data-bs-toggle="modal"
|
||||
data-bs-target="#billingDetailsModal">
|
||||
<i class="bx bx-list-ul me-1"></i> Szczegóły
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-secondary text-nowrap"
|
||||
style="background-color: #f8f9fa;">
|
||||
<i class="bx bx-credit-card me-1"></i> company.payonline
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Wiersz 2 -->
|
||||
<tr>
|
||||
<td><a href="#" class="fw-bold text-primary">5/02/2025</a></td>
|
||||
<td><span class="badge bg-label-warning px-2 py-1" style="font-size: 0.75rem;">Opóźniona</span>
|
||||
</td>
|
||||
<td class="fw-semibold">345 zł</td>
|
||||
<td class="text-dark">2025-03-10</td>
|
||||
<td>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<button class="btn btn-sm btn-outline-secondary text-nowrap disabled"
|
||||
style="background-color: #f8f9fa;"><i class="bx bx-cloud-download me-1"></i> Faktura
|
||||
VAT</button>
|
||||
<button class="btn btn-sm btn-outline-secondary text-nowrap"><i
|
||||
class="bx bx-cloud-download me-1"></i> Faktura proforma</button>
|
||||
|
||||
<span class="text-muted mx-2">|</span>
|
||||
|
||||
<button class="btn btn-sm btn-outline-secondary text-nowrap" data-bs-toggle="modal"
|
||||
data-bs-target="#billingDetailsModal">
|
||||
<i class="bx bx-list-ul me-1"></i> Szczegóły
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-secondary text-nowrap"
|
||||
style="background-color: #f8f9fa;">
|
||||
<i class="bx bx-credit-card me-1"></i> company.payonline
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Wiersz 3 - Przykładowy opłacony dodany dla logiki -->
|
||||
<tr>
|
||||
<td><a href="#" class="fw-bold text-muted">2/01/2025</a></td>
|
||||
<td><span class="badge bg-label-success px-2 py-1" style="font-size: 0.75rem;">Opłacona</span>
|
||||
</td>
|
||||
<td class="fw-semibold">345 zł</td>
|
||||
<td class="text-dark">2025-01-05</td>
|
||||
<td>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<button class="btn btn-sm btn-outline-secondary text-nowrap"><i
|
||||
class="bx bx-cloud-download me-1"></i> Faktura VAT</button>
|
||||
<button class="btn btn-sm btn-outline-secondary text-nowrap disabled"
|
||||
style="background-color: #f8f9fa;"><i class="bx bx-cloud-download me-1"></i> Faktura
|
||||
proforma</button>
|
||||
|
||||
<span class="text-muted mx-2">|</span>
|
||||
|
||||
<button class="btn btn-sm btn-outline-secondary text-nowrap" data-bs-toggle="modal"
|
||||
data-bs-target="#billingDetailsModal">
|
||||
<i class="bx bx-list-ul me-1"></i> Szczegóły
|
||||
</button>
|
||||
<!-- Brak przycisku opłać, bo jest opłacona -->
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Modal Szczegóły Rozliczenia -->
|
||||
<div class="modal fade" id="billingDetailsModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header border-bottom pb-3">
|
||||
<h5 class="modal-title fw-bold" id="exampleModalLabel1">Szczegóły rozliczenia dla dokumentu: <span
|
||||
class="text-primary">5/05/2025</span></h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body py-4 bg-lighter">
|
||||
|
||||
<div class="card shadow-none border">
|
||||
<div class="card-body p-0">
|
||||
<ul class="list-group list-group-flush mb-0">
|
||||
<!-- Pozycja 1 -->
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start py-3">
|
||||
<div>
|
||||
<h6 class="mb-1 fw-bold text-dark">Opłata podstawowa (Abonament Baza)</h6>
|
||||
<small class="text-muted mt-0 d-block">Utrzymanie rdzenia systemu. Nielimitowana
|
||||
ilość przestrzeni i kont właścicielskich.</small>
|
||||
</div>
|
||||
<span class="fw-bold text-dark fs-6 mt-1">199.00 zł</span>
|
||||
</li>
|
||||
|
||||
<!-- Pozycja 2 -->
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start py-3">
|
||||
<div>
|
||||
<h6 class="mb-1 fw-bold text-dark">Aplikacja: helpdesk.magico</h6>
|
||||
<small class="text-muted mt-0 d-block">Liczba przypisanych kont pracowników w danym
|
||||
cyklu: <strong>4 stanowiska</strong><br>Opłata: 4 x 30.00 zł</small>
|
||||
</div>
|
||||
<span class="fw-bold text-dark fs-6 mt-1">120.00 zł</span>
|
||||
</li>
|
||||
|
||||
<!-- Pozycja 3 -->
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start py-3">
|
||||
<div>
|
||||
<h6 class="mb-1 fw-bold text-dark">Bramka komunikacji SMS (Powiadomienia)</h6>
|
||||
<small class="text-muted mt-0 d-block">Wysłane wiadomości autoryzacyjne i systemowe:
|
||||
<strong>247 SMS</strong><br>Koszt jednostkowy API: 0.15 zł</small>
|
||||
</div>
|
||||
<span class="fw-bold text-dark fs-6 mt-1">37.05 zł</span>
|
||||
</li>
|
||||
|
||||
<!-- Pozycja 4 -->
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start py-3">
|
||||
<div>
|
||||
<h6 class="mb-1 fw-bold text-dark">Aplikacja: invoice.magico</h6>
|
||||
<small class="text-muted mt-0 d-block">Moduł wbudowany bezpłatnie jako fundament
|
||||
profilu.</small>
|
||||
</div>
|
||||
<span class="fw-bold text-dark fs-6 mt-1 text-success">0.00 zł</span>
|
||||
</li>
|
||||
|
||||
<!-- Suma Rozliczenia -->
|
||||
<li
|
||||
class="list-group-item d-flex justify-content-between align-items-center py-4 bg-label-primary bg-opacity-10 border-top-2">
|
||||
<div>
|
||||
<h5 class="mb-0 fw-bold text-primary">Kwota netto dokumentu</h5>
|
||||
<small class="text-primary text-opacity-75">Suma zliczona przed nałożeniem podatku
|
||||
VAT (23%)</small>
|
||||
</div>
|
||||
<span class="fw-bold text-primary fs-3">356.05 zł</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-secondary mb-0 mt-4 d-flex align-items-center overflow-hidden">
|
||||
<i class="bx bx-info-circle fs-3 me-3 text-secondary"></i>
|
||||
<small class="lh-sm">Koszt aplikacji stanowiskowych wyliczany jest na podstawie największej liczby
|
||||
kont pracowników z uprawnieniami w trakcie całego ubiegłego cyku rozliczeniowego.</small>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer border-top pt-3">
|
||||
<button type="button" class="btn btn-label-secondary" data-bs-dismiss="modal">Zamknij podgląd</button>
|
||||
<button type="button" class="btn btn-primary"><i class="bx bx-credit-card me-2"></i> Przejdź do
|
||||
opłacenia faktury</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-backdrop fade"></div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
// ...
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
291
prototype/company/app-company-info.php
Normal file
291
prototype/company/app-company-info.php
Normal file
@@ -0,0 +1,291 @@
|
||||
<?php
|
||||
$enablePrototypeComments = true;
|
||||
include '../../header-invoice.php';
|
||||
?>
|
||||
|
||||
<!-- Vendor CSS -->
|
||||
<link rel="stylesheet" href="../../assets/vendor/libs/select2/select2.css" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.css" />
|
||||
|
||||
<style>
|
||||
/* Obłe krawędzie dla kółka wykadrowania w Cropper JS */
|
||||
.cropper-view-box,
|
||||
.cropper-face {
|
||||
border-radius: 50%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container-xxl flex-grow-1 container-p-y">
|
||||
|
||||
<h4 class="fw-bold py-3 mb-4">
|
||||
<span class="text-muted fw-light">Zarządzanie firmą /</span> Informacje o firmie
|
||||
</h4>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
|
||||
<div class="card mb-4">
|
||||
<h5 class="card-header border-bottom">Profil firmy</h5>
|
||||
|
||||
<div class="card-body mt-3">
|
||||
<div class="d-flex align-items-start align-items-sm-center gap-4">
|
||||
<img src="https://ui-avatars.com/api/?name=Firma&background=e7e7ff&color=696cff&size=150"
|
||||
alt="Logo firmy" class="d-block rounded-circle" height="100" width="100" id="uploadedLogo"
|
||||
style="object-fit: cover;">
|
||||
<div class="button-wrapper">
|
||||
<label for="upload" class="btn btn-primary me-2 mb-3" tabindex="0">
|
||||
<span class="d-none d-sm-block">Wgraj nowe logo</span>
|
||||
<i class="bx bx-upload d-block d-sm-none"></i>
|
||||
<input type="file" id="upload" class="account-file-input" hidden
|
||||
accept="image/png, image/jpeg, image/jpg">
|
||||
</label>
|
||||
<button type="button" class="btn btn-label-secondary account-image-reset mb-3">
|
||||
<i class="bx bx-reset d-block d-sm-none"></i>
|
||||
<span class="d-none d-sm-block">Usuń</span>
|
||||
</button>
|
||||
<p class="text-muted mb-0">Dozwolone formaty: JPG, GIF lub PNG. Max rozmiar 800K</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="my-0">
|
||||
|
||||
<div class="card-body">
|
||||
<form id="formCompanyProfile" onsubmit="return false">
|
||||
<div class="row">
|
||||
<div class="mb-3 col-md-6">
|
||||
<label for="companyShortName" class="form-label">
|
||||
Krótka nazwa firmy
|
||||
<i class="bx bx-info-circle text-muted ms-1 cursor-pointer" data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
title="Nazwa będzie widoczna tylko dla Ciebie i współpracowników. Wykorzystywana w aplikacjach magico."></i>
|
||||
</label>
|
||||
<input class="form-control" type="text" id="companyShortName" name="companyShortName"
|
||||
placeholder="Wpisz krótką nazwę..." value="" autofocus>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-4">
|
||||
<h5 class="card-header border-bottom">Dane rozliczeniowe</h5>
|
||||
<div class="card-body mt-3">
|
||||
<form id="formBillingSettings" onsubmit="return false">
|
||||
<div class="row g-4">
|
||||
<div class="col-md-6">
|
||||
<label for="locationLabel" class="form-label">Kraj</label>
|
||||
<select id="locationLabel" class="form-select select2-country">
|
||||
<option value="pl" selected>Polska</option>
|
||||
<option value="us">Stany Zjednoczone</option>
|
||||
<option value="gb">Wielka Brytania</option>
|
||||
<option value="de">Niemcy</option>
|
||||
<option value="fr">Francja</option>
|
||||
<option value="it">Włochy</option>
|
||||
<option value="es">Hiszpania</option>
|
||||
<option value="ua">Ukraina</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<label for="nipNumber" class="form-label">Numer NIP</label>
|
||||
<input type="text" name="nipNumber" id="nipNumber" placeholder="___-___-__-__"
|
||||
class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
<label for="companyFullName" class="form-label">Pełna nazwa firmy</label>
|
||||
<input type="text" name="companyFullName" id="companyFullName"
|
||||
placeholder="Wpisz pełną nazwę podmiotu..." class="form-control">
|
||||
<div class="form-text">Do użytku w rozliczeniach i fakturach</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label for="zipCode" class="form-label">Kod pocztowy</label>
|
||||
<input type="text" name="zipCode" id="zipCode" placeholder="__-___"
|
||||
class="form-control">
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<label for="cityName" class="form-label">Miasto</label>
|
||||
<input type="text" name="cityName" id="cityName" placeholder="Wpisz miasto..."
|
||||
class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
<label for="addressDetails" class="form-label">Adres</label>
|
||||
<input type="text" name="addressDetails" id="addressDetails"
|
||||
placeholder="Ulica i numer budynku/lokalu" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="col-md-12 mt-4">
|
||||
<div class="border-top pt-4">
|
||||
<label for="billingEmail" class="form-label">Dodatkowy adres e-mail do
|
||||
rozliczeń</label>
|
||||
<input type="email" name="billingEmail" id="billingEmail"
|
||||
placeholder="np. ksiegowosc@twojafirma.pl" class="form-control mb-2">
|
||||
|
||||
<div class="alert alert-primary d-flex align-items-baseline mb-0" role="alert">
|
||||
<span class="alert-icon align-middle me-2">
|
||||
<i class="bx bx-info-circle"></i>
|
||||
</span>
|
||||
<div>
|
||||
Dokumenty rozliczeniowe będą automatycznie wysyłane na powyższy adres
|
||||
(opcjonalnie) oraz do wszystkich użytkowników posiadających rolę
|
||||
<strong>"Właściciel"</strong> ustawioną w sekcji Zespół.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal dla Cropper.js -->
|
||||
<div class="modal fade" id="cropModal" tabindex="-1" aria-hidden="true" data-bs-backdrop="static">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="cropModalLabel">Wykadruj logo (koło)</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Zamknij"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="img-container"
|
||||
style="max-height: 400px; display: flex; justify-content: center; background-color: #f5f5f9;">
|
||||
<img id="imageToCrop" src="" alt="Obraz do wykadrowania" style="max-width: 100%; display: block;">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-label-secondary" data-bs-dismiss="modal">Anuluj</button>
|
||||
<button type="button" class="btn btn-primary" id="cropButton">Zatwierdź logo</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="footer" class="footer" style="background: #e7e7ff; position: sticky; bottom: 0px; right: 0px;">
|
||||
<footer class="content-footer footer">
|
||||
<div class="container-xxl d-flex py-3 justify-content-center">
|
||||
<button class="btn btn-primary btn-lg">Zapisz</button>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<div class="content-backdrop fade"></div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script src="../../assets/vendor/libs/select2/select2.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.13/cropper.min.js"></script>
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
// --- Inicjalizacja Tooltipów ---
|
||||
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
|
||||
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
|
||||
return new bootstrap.Tooltip(tooltipTriggerEl);
|
||||
});
|
||||
|
||||
// --- Inicjalizacja Select2 ---
|
||||
function renderIcons(option) {
|
||||
if (!option.id) { return option.text; }
|
||||
var $icon = $(
|
||||
"<span class='d-flex align-items-center'><img src='https://flagcdn.com/w20/" + option.id.toLowerCase() + ".png' class='me-2' style='width: 20px; border-radius: 2px;' alt='flag' />" + option.text + "</span>"
|
||||
);
|
||||
return $icon;
|
||||
}
|
||||
|
||||
if ($('.select2-country').length) {
|
||||
$('.select2-country').select2({
|
||||
templateResult: renderIcons,
|
||||
templateSelection: renderIcons,
|
||||
escapeMarkup: function (es) { return es; }
|
||||
});
|
||||
}
|
||||
|
||||
// --- Inicjalizacja Cropper JS ---
|
||||
let cropper;
|
||||
const image = document.getElementById('imageToCrop');
|
||||
const input = document.getElementById('upload');
|
||||
const cropModalEl = document.getElementById('cropModal');
|
||||
const uploadedLogo = document.getElementById('uploadedLogo');
|
||||
let cropModal;
|
||||
|
||||
if (cropModalEl) {
|
||||
cropModal = new bootstrap.Modal(cropModalEl);
|
||||
}
|
||||
|
||||
if (input) {
|
||||
input.addEventListener('change', function (e) {
|
||||
const files = e.target.files;
|
||||
if (files && files.length > 0) {
|
||||
const file = files[0];
|
||||
const reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
image.src = e.target.result;
|
||||
cropModal.show();
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
input.value = ''; // reset value to allow choosing the same file again
|
||||
});
|
||||
}
|
||||
|
||||
if (cropModalEl) {
|
||||
cropModalEl.addEventListener('shown.bs.modal', function () {
|
||||
cropper = new Cropper(image, {
|
||||
aspectRatio: 1, // kwadrat = koło po zaokrągleniu
|
||||
viewMode: 1,
|
||||
dragMode: 'move',
|
||||
autoCropArea: 0.8,
|
||||
restore: false,
|
||||
guides: false,
|
||||
center: false,
|
||||
highlight: false,
|
||||
cropBoxMovable: true,
|
||||
cropBoxResizable: true,
|
||||
toggleDragModeOnDblclick: false,
|
||||
});
|
||||
});
|
||||
|
||||
cropModalEl.addEventListener('hidden.bs.modal', function () {
|
||||
if (cropper) {
|
||||
cropper.destroy();
|
||||
cropper = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const cropBtn = document.getElementById('cropButton');
|
||||
if (cropBtn) {
|
||||
cropBtn.addEventListener('click', function () {
|
||||
if (!cropper) return;
|
||||
const canvas = cropper.getCroppedCanvas({
|
||||
width: 300,
|
||||
height: 300
|
||||
});
|
||||
uploadedLogo.src = canvas.toDataURL(); // aktualizacja logo
|
||||
cropModal.hide();
|
||||
});
|
||||
}
|
||||
|
||||
// Reset obrazka
|
||||
const resetBtn = document.querySelector('.account-image-reset');
|
||||
if (resetBtn) {
|
||||
resetBtn.addEventListener('click', () => {
|
||||
uploadedLogo.src = 'https://ui-avatars.com/api/?name=Firma&background=e7e7ff&color=696cff&size=150';
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
304
prototype/company/app-group-edit.php
Normal file
304
prototype/company/app-group-edit.php
Normal file
@@ -0,0 +1,304 @@
|
||||
<?php
|
||||
$enablePrototypeComments = true;
|
||||
include '../../header-invoice.php';
|
||||
?>
|
||||
|
||||
<div class="container-xxl flex-grow-1 container-p-y">
|
||||
|
||||
<h4 class="fw-bold py-3 mb-4">
|
||||
<span class="text-muted fw-light">Zarządzanie zespołem / <a href="app-groups.php"
|
||||
class="text-muted text-decoration-none">Grupy</a> /</span> Edycja grupy
|
||||
</h4>
|
||||
|
||||
<div class="row">
|
||||
<!-- Formularz informacji ogólnych -->
|
||||
<div class="col-md-12 col-lg-4 mb-4">
|
||||
<div class="card h-100">
|
||||
<h5 class="card-header border-bottom">Informacje ogólne</h5>
|
||||
<div class="card-body mt-4">
|
||||
<form id="formGroupEdit" onsubmit="return false">
|
||||
<div class="mb-3">
|
||||
<label for="groupName" class="form-label">Nazwa grupy <span
|
||||
class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" id="groupName" value="Kadra Kierownicza" autofocus>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label for="groupDescription" class="form-label">Opis / Notatka dla użytkowników</label>
|
||||
<textarea class="form-control" id="groupDescription"
|
||||
rows="4">Pełny wgląd w raporty finansowe, listę pracowników oraz obieg dokumentów.</textarea>
|
||||
<div class="form-text">Zwięzły opis pomoże innym administratorom zrozumieć przeznaczenie tej
|
||||
grupy.</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label d-block">Status grupy</label>
|
||||
<div class="form-check form-switch mb-2">
|
||||
<input class="form-check-input" type="checkbox" id="flexSwitchCheckChecked" checked>
|
||||
<label class="form-check-label" for="flexSwitchCheckChecked">Aktywna</label>
|
||||
</div>
|
||||
<div class="form-text">Wyłączenie grupy tymczasowo odbierze dostęp do jej zasobów wszystkim
|
||||
uprawnionym użytkownikom, ale nie usunie z niej członków.</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Przypisywanie użytkowników -->
|
||||
<div class="col-md-12 col-lg-8 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header border-bottom d-flex justify-content-between align-items-center">
|
||||
<h5 class="m-0">Przypisani członkowie zespołu (3)</h5>
|
||||
<div class="input-group input-group-merge" style="max-width: 250px;">
|
||||
<span class="input-group-text"><i class="bx bx-search"></i></span>
|
||||
<input type="text" id="searchUser" class="form-control form-control-sm"
|
||||
placeholder="Szukaj osoby...">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive text-nowrap" style="max-height: 500px; overflow-y: auto;">
|
||||
<table class="table table-hover">
|
||||
<thead class="table-light sticky-top">
|
||||
<tr>
|
||||
<th style="width: 50px;" class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center">
|
||||
<input class="form-check-input m-0" type="checkbox" id="selectAll"
|
||||
style="cursor: pointer;">
|
||||
</div>
|
||||
</th>
|
||||
<th>Użytkownik</th>
|
||||
<th>Rola w firmie</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="table-border-bottom-0">
|
||||
|
||||
<!-- Aktywny przypisany właściciel -->
|
||||
<tr class="table-primary">
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center">
|
||||
<input class="form-check-input m-0" type="checkbox" checked
|
||||
style="cursor: pointer;">
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex justify-content-start align-items-center">
|
||||
<div class="avatar avatar-sm me-3">
|
||||
<img src="https://ui-avatars.com/api/?name=Bartłomiej+Banaczyk&background=e7e7ff&color=696cff"
|
||||
alt="Avatar" class="rounded-circle">
|
||||
</div>
|
||||
<div class="d-flex flex-column">
|
||||
<h6 class="mb-0 fw-semibold text-primary">Bartłomiej Banaczyk (Ty)</h6>
|
||||
<small class="text-muted">banaczyk@magico.pl</small>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-label-warning"><i class="bx bx-crown me-1"></i>
|
||||
Właściciel</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Aktywny przypisany 1 -->
|
||||
<tr class="table-primary">
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center">
|
||||
<input class="form-check-input m-0" type="checkbox" checked
|
||||
style="cursor: pointer;">
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex justify-content-start align-items-center">
|
||||
<div class="avatar avatar-sm me-3">
|
||||
<img src="https://ui-avatars.com/api/?name=Jan+Kowalski&background=e7e7ff&color=696cff"
|
||||
alt="Avatar" class="rounded-circle">
|
||||
</div>
|
||||
<div class="d-flex flex-column">
|
||||
<h6 class="mb-0 fw-semibold text-primary">Jan Kowalski</h6>
|
||||
<small class="text-muted">jan.kowalski@firma.pl</small>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td><span class="text-muted small">Menadżer</span></td>
|
||||
</tr>
|
||||
|
||||
<!-- Aktywny przypisany 2 -->
|
||||
<tr class="table-primary">
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center">
|
||||
<input class="form-check-input m-0" type="checkbox" checked
|
||||
style="cursor: pointer;">
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex justify-content-start align-items-center">
|
||||
<div class="avatar avatar-sm me-3">
|
||||
<img src="https://ui-avatars.com/api/?name=Anna+Nowak&background=ffe7e7&color=ff6969"
|
||||
alt="Avatar" class="rounded-circle">
|
||||
</div>
|
||||
<div class="d-flex flex-column">
|
||||
<h6 class="mb-0 fw-semibold text-primary">Anna Nowak</h6>
|
||||
<small class="text-muted">anna.nowak@firma.pl</small>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td><span class="text-muted small">Menadżer</span></td>
|
||||
</tr>
|
||||
|
||||
<!-- Nieprzypisany 1 -->
|
||||
<tr>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center">
|
||||
<input class="form-check-input m-0" type="checkbox" style="cursor: pointer;">
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex justify-content-start align-items-center">
|
||||
<div class="avatar avatar-sm me-3">
|
||||
<img src="https://ui-avatars.com/api/?name=Katarzyna+Lewandowska&background=e7f0ff&color=69a6ff"
|
||||
alt="Avatar" class="rounded-circle">
|
||||
</div>
|
||||
<div class="d-flex flex-column">
|
||||
<h6 class="mb-0 fw-semibold text-body">Katarzyna Lewandowska</h6>
|
||||
<small class="text-muted">k.lewandowska@firma.pl</small>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td><span class="text-muted small">Pracownik</span></td>
|
||||
</tr>
|
||||
|
||||
<!-- Nieprzypisany 2 -->
|
||||
<tr>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center">
|
||||
<input class="form-check-input m-0" type="checkbox" style="cursor: pointer;">
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex justify-content-start align-items-center">
|
||||
<div class="avatar avatar-sm me-3">
|
||||
<img src="https://ui-avatars.com/api/?name=Piotr+Wiśniewski&background=e7ffe7&color=69ff69"
|
||||
alt="Avatar" class="rounded-circle">
|
||||
</div>
|
||||
<div class="d-flex flex-column">
|
||||
<h6 class="mb-0 fw-semibold text-body">Piotr Wiśniewski</h6>
|
||||
<small class="text-muted">p.wisniewski@firma.pl</small>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td><span class="text-muted small">Pracownik</span></td>
|
||||
</tr>
|
||||
|
||||
<!-- Nieprzypisany 3 w trakcie rejestracji -->
|
||||
<tr>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center">
|
||||
<input class="form-check-input m-0" type="checkbox" style="cursor: pointer;">
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex justify-content-start align-items-center opacity-50">
|
||||
<div class="avatar avatar-sm me-3">
|
||||
<span class="avatar-initial rounded-circle bg-label-secondary"><i
|
||||
class="bx bx-time-five"></i></span>
|
||||
</div>
|
||||
<div class="d-flex flex-column">
|
||||
<h6 class="mb-0 fw-semibold text-muted">Zuzanna Szymańska</h6>
|
||||
<small class="text-muted">zuzanna@firma.pl</small>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-label-secondary">Oczekuje na rejestrację</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="footer" class="footer" style="background: #e7e7ff; position: sticky; bottom: 0px; right: 0px; z-index: 1000;">
|
||||
<footer class="content-footer footer border-top">
|
||||
<div class="container-xxl d-flex py-3 justify-content-center">
|
||||
<a href="app-groups.php" class="btn btn-label-secondary btn-lg me-3">Anuluj</a>
|
||||
<button class="btn btn-primary btn-lg px-5">Zapisz ustawienia grupy</button>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<div class="content-backdrop fade"></div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
// Logika zaznaczania / odznaczania wszystkich checkboxów
|
||||
const selectAllCheckbox = document.getElementById('selectAll');
|
||||
const userCheckboxes = document.querySelectorAll('tbody .form-check-input');
|
||||
|
||||
// Klikanie w dowolne miejsce wiersza zaznacza/odznacza checkboxa
|
||||
const tbodyRows = document.querySelectorAll('tbody tr');
|
||||
tbodyRows.forEach(row => {
|
||||
row.style.cursor = 'pointer'; // Kursor łapki na całym wierszu
|
||||
row.addEventListener('click', function (e) {
|
||||
// Pomijamy sytuację, gdy kliknięto bezpośrednio w checkbox (żeby nie wywoływać podwójnego toggle)
|
||||
if (e.target.tagName !== 'INPUT') {
|
||||
const checkbox = this.querySelector('.form-check-input');
|
||||
if (checkbox) {
|
||||
checkbox.checked = !checkbox.checked;
|
||||
// Ręczne wymuszenie eventu 'change' by reszta skryptów (np. zmiana koloru) prawidłowo zareagowała
|
||||
checkbox.dispatchEvent(new Event('change'));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (selectAllCheckbox) {
|
||||
selectAllCheckbox.addEventListener('change', function () {
|
||||
const isChecked = this.checked;
|
||||
userCheckboxes.forEach(checkbox => {
|
||||
checkbox.checked = isChecked;
|
||||
updateRowHighlight(checkbox);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
userCheckboxes.forEach(checkbox => {
|
||||
checkbox.addEventListener('change', function () {
|
||||
updateRowHighlight(this);
|
||||
// Aktualizuj stan selectAll
|
||||
const allChecked = Array.from(userCheckboxes).every(cb => cb.checked);
|
||||
if (selectAllCheckbox) selectAllCheckbox.checked = allChecked;
|
||||
|
||||
const someChecked = Array.from(userCheckboxes).some(cb => cb.checked);
|
||||
if (selectAllCheckbox) selectAllCheckbox.indeterminate = someChecked && !allChecked;
|
||||
});
|
||||
});
|
||||
|
||||
function updateRowHighlight(checkbox) {
|
||||
const tr = checkbox.closest('tr');
|
||||
const h6 = tr.querySelector('h6');
|
||||
if (checkbox.checked) {
|
||||
tr.classList.add('table-primary');
|
||||
if (h6) {
|
||||
h6.classList.remove('text-body');
|
||||
h6.classList.add('text-primary');
|
||||
}
|
||||
} else {
|
||||
tr.classList.remove('table-primary');
|
||||
if (h6) {
|
||||
h6.classList.remove('text-primary');
|
||||
h6.classList.add('text-body');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
339
prototype/company/app-groups.php
Normal file
339
prototype/company/app-groups.php
Normal file
@@ -0,0 +1,339 @@
|
||||
<?php
|
||||
$enablePrototypeComments = true;
|
||||
include '../../header-invoice.php';
|
||||
?>
|
||||
|
||||
<div class="container-xxl flex-grow-1 container-p-y">
|
||||
|
||||
<h4 class="fw-bold py-3 mb-4 d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<span class="text-muted fw-light">Zarządzanie zespołem /</span> Grupy
|
||||
</div>
|
||||
<a href="app-group-edit.php" class="btn btn-primary">
|
||||
<i class="bx bx-plus me-1"></i> Utwórz grupę
|
||||
</a>
|
||||
</h4>
|
||||
|
||||
<!-- Filters/Search Card -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<div class="row gx-3 gy-2 align-items-center">
|
||||
<div class="col-md-4">
|
||||
<label class="form-label" for="searchGroup">Wyszukaj grupę</label>
|
||||
<div class="input-group input-group-merge">
|
||||
<span class="input-group-text"><i class="bx bx-search"></i></span>
|
||||
<input type="text" id="searchGroup" class="form-control" placeholder="Wpisz nazwę...">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label" for="filterStatus">Status</label>
|
||||
<select id="filterStatus" class="form-select">
|
||||
<option value="">Wszystkie</option>
|
||||
<option value="active">Aktywne</option>
|
||||
<option value="inactive">Nieaktywne</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-5 d-flex align-items-end justify-content-md-end mt-md-0 mt-3">
|
||||
<button class="btn btn-label-secondary"><i class="bx bx-reset me-1"></i> Wyczyść filtry</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Groups Table -->
|
||||
<div class="card">
|
||||
<h5 class="card-header border-bottom">Lista grup dostępu</h5>
|
||||
<div class="table-responsive text-nowrap pb-2">
|
||||
<table class="table table-hover">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th style="width: 250px;">Nazwa grupy</th>
|
||||
<th>Opis</th>
|
||||
<th style="width: 150px;">Członkowie</th>
|
||||
<th class="text-center" style="width: 100px;">Status</th>
|
||||
<th class="text-end" style="width: 120px;">Akcje</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="table-border-bottom-0">
|
||||
|
||||
<!-- Wiersz 1: Kadra Kierownicza -->
|
||||
<tr>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<div
|
||||
class="avatar avatar-sm me-3 bg-label-primary rounded p-1 flex-shrink-0 d-flex align-items-center justify-content-center">
|
||||
<i class="bx bx-briefcase fs-4"></i>
|
||||
</div>
|
||||
<div class="d-flex flex-column">
|
||||
<h6 class="mb-0 fw-semibold"><a href="app-group-edit.php"
|
||||
class="text-body text-truncate">Kadra Kierownicza</a></h6>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span class="text-muted small text-truncate d-block" style="max-width: 300px;">
|
||||
Pełny wgląd w raporty finansowe, listę pracowników oraz obieg dokumentów.
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex align-items-center avatar-group">
|
||||
<div class="avatar avatar-sm" data-bs-toggle="tooltip" data-bs-placement="top"
|
||||
title="Jan Kowalski">
|
||||
<img src="https://ui-avatars.com/api/?name=Jan+Kowalski&background=e7e7ff&color=696cff"
|
||||
alt="Avatar" class="rounded-circle pull-up">
|
||||
</div>
|
||||
<div class="avatar avatar-sm" data-bs-toggle="tooltip" data-bs-placement="top"
|
||||
title="Anna Nowak">
|
||||
<img src="https://ui-avatars.com/api/?name=Anna+Nowak&background=ffe7e7&color=ff6969"
|
||||
alt="Avatar" class="rounded-circle pull-up">
|
||||
</div>
|
||||
<div class="avatar avatar-sm" data-bs-toggle="tooltip" data-bs-placement="top"
|
||||
title="Piotr Wiśniewski">
|
||||
<img src="https://ui-avatars.com/api/?name=Piotr+Wiśniewski&background=e7ffe7&color=69ff69"
|
||||
alt="Avatar" class="rounded-circle pull-up">
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<span class="badge bg-label-success">Aktywna</span>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<div class="d-flex justify-content-end align-items-center">
|
||||
<div class="btn-group" role="group">
|
||||
<a href="app-group-edit.php" class="btn btn-outline-secondary btn-sm">
|
||||
<i class="bx bx-edit-alt me-1 d-none d-sm-inline-block"></i> Edytuj
|
||||
</a>
|
||||
<div class="btn-group">
|
||||
<button type="button"
|
||||
class="btn btn-outline-secondary btn-sm dropdown-toggle dropdown-toggle-split"
|
||||
data-bs-toggle="dropdown" aria-expanded="false"></button>
|
||||
<div class="dropdown-menu dropdown-menu-end mt-1">
|
||||
<a href="javascript:void(0);" class="dropdown-item"><i
|
||||
class="bx bx-copy me-2"></i> Duplikuj</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a href="javascript:void(0);" class="dropdown-item text-danger"><i
|
||||
class="bx bx-trash me-2"></i> Usuń</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Wiersz 2: Dział Marketingu -->
|
||||
<tr>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<div
|
||||
class="avatar avatar-sm me-3 bg-label-info rounded p-1 flex-shrink-0 d-flex align-items-center justify-content-center">
|
||||
<i class="bx bx-broadcast fs-4"></i>
|
||||
</div>
|
||||
<div class="d-flex flex-column">
|
||||
<h6 class="mb-0 fw-semibold"><a href="app-group-edit.php"
|
||||
class="text-body text-truncate">Dział Marketingu</a></h6>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span class="text-muted small text-truncate d-block" style="max-width: 300px;">
|
||||
Dostęp do lejków sprzedażowych, mailingów i zarządzania ofertami.
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex align-items-center avatar-group">
|
||||
<div class="avatar avatar-sm" data-bs-toggle="tooltip" data-bs-placement="top"
|
||||
title="Katarzyna Lewandowska">
|
||||
<img src="https://ui-avatars.com/api/?name=Katarzyna+Lewandowska&background=e7f0ff&color=69a6ff"
|
||||
alt="Avatar" class="rounded-circle pull-up">
|
||||
</div>
|
||||
<div class="avatar avatar-sm" data-bs-toggle="tooltip" data-bs-placement="top"
|
||||
title="Michał Zieliński">
|
||||
<img src="https://ui-avatars.com/api/?name=Michał+Zieliński&background=fff4e7&color=ffb869"
|
||||
alt="Avatar" class="rounded-circle pull-up">
|
||||
</div>
|
||||
<div class="avatar avatar-sm" data-bs-toggle="tooltip" data-bs-placement="top"
|
||||
title="Zuzanna Szymańska">
|
||||
<span class="avatar-initial rounded-circle bg-label-warning pull-up">ZS</span>
|
||||
</div>
|
||||
<div class="avatar avatar-sm" data-bs-toggle="tooltip" data-bs-placement="top"
|
||||
title="Tomasz Dąbrowski">
|
||||
<img src="https://ui-avatars.com/api/?name=Tomasz+Dąbrowski&background=e7ebff&color=697fff"
|
||||
alt="Avatar" class="rounded-circle pull-up">
|
||||
</div>
|
||||
<div class="avatar avatar-sm">
|
||||
<span class="avatar-initial rounded-circle bg-lighter text-body pull-up"
|
||||
data-bs-toggle="tooltip" data-bs-placement="top"
|
||||
title="5 kolejnych osób">+5</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<span class="badge bg-label-success">Aktywna</span>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<div class="d-flex justify-content-end align-items-center">
|
||||
<div class="btn-group" role="group">
|
||||
<a href="app-group-edit.php" class="btn btn-outline-secondary btn-sm">
|
||||
<i class="bx bx-edit-alt me-1 d-none d-sm-inline-block"></i> Edytuj
|
||||
</a>
|
||||
<div class="btn-group">
|
||||
<button type="button"
|
||||
class="btn btn-outline-secondary btn-sm dropdown-toggle dropdown-toggle-split"
|
||||
data-bs-toggle="dropdown" aria-expanded="false"></button>
|
||||
<div class="dropdown-menu dropdown-menu-end mt-1">
|
||||
<a href="javascript:void(0);" class="dropdown-item"><i
|
||||
class="bx bx-copy me-2"></i> Duplikuj</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a href="javascript:void(0);" class="dropdown-item text-danger"><i
|
||||
class="bx bx-trash me-2"></i> Usuń</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Wiersz 3: Dział Obsługi Klienta -->
|
||||
<tr>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<div
|
||||
class="avatar avatar-sm me-3 bg-label-success rounded p-1 flex-shrink-0 d-flex align-items-center justify-content-center">
|
||||
<i class="bx bx-support fs-4"></i>
|
||||
</div>
|
||||
<div class="d-flex flex-column">
|
||||
<h6 class="mb-0 fw-semibold"><a href="app-group-edit.php"
|
||||
class="text-body text-truncate">Dział Obsługi Klienta</a></h6>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span class="text-muted small text-truncate d-block" style="max-width: 300px;">
|
||||
Dostęp do ticketów, korespondencji i podstawowych danych konrahentów.
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex align-items-center avatar-group">
|
||||
<div class="avatar avatar-sm" data-bs-toggle="tooltip" data-bs-placement="top"
|
||||
title="Magdalena Kaczmarek">
|
||||
<img src="https://ui-avatars.com/api/?name=Magdalena+Kaczmarek&background=f4ffe7&color=b8ff69"
|
||||
alt="Avatar" class="rounded-circle pull-up">
|
||||
</div>
|
||||
<div class="avatar avatar-sm" data-bs-toggle="tooltip" data-bs-placement="top"
|
||||
title="Kamil Piotrowski">
|
||||
<span class="avatar-initial rounded-circle bg-label-dark pull-up">KP</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<span class="badge bg-label-success">Aktywna</span>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<div class="d-flex justify-content-end align-items-center">
|
||||
<div class="btn-group" role="group">
|
||||
<a href="app-group-edit.php" class="btn btn-outline-secondary btn-sm">
|
||||
<i class="bx bx-edit-alt me-1 d-none d-sm-inline-block"></i> Edytuj
|
||||
</a>
|
||||
<div class="btn-group">
|
||||
<button type="button"
|
||||
class="btn btn-outline-secondary btn-sm dropdown-toggle dropdown-toggle-split"
|
||||
data-bs-toggle="dropdown" aria-expanded="false"></button>
|
||||
<div class="dropdown-menu dropdown-menu-end mt-1">
|
||||
<a href="javascript:void(0);" class="dropdown-item"><i
|
||||
class="bx bx-copy me-2"></i> Duplikuj</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a href="javascript:void(0);" class="dropdown-item text-danger"><i
|
||||
class="bx bx-trash me-2"></i> Usuń</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Wiersz 4: Zewnętrzna Księgowość (Przykład nieaktywnej) -->
|
||||
<tr>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<div
|
||||
class="avatar avatar-sm me-3 bg-label-secondary rounded p-1 flex-shrink-0 d-flex align-items-center justify-content-center">
|
||||
<i class="bx bx-calculator fs-4"></i>
|
||||
</div>
|
||||
<div class="d-flex flex-column">
|
||||
<h6 class="mb-0 fw-semibold text-muted"><a href="app-group-edit.php"
|
||||
class="text-muted text-truncate">Zewnętrzna Księgowość</a></h6>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span class="text-muted small text-truncate d-block" style="max-width: 300px;">
|
||||
Tymczasowy dostęp audytowy – tylko odczyt sekcji finansowej.
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-label-secondary">Brak przypisań</span>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<span class="badge bg-label-secondary">Nieaktywna</span>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<div class="d-flex justify-content-end align-items-center">
|
||||
<div class="btn-group" role="group">
|
||||
<a href="app-group-edit.php" class="btn btn-outline-secondary btn-sm">
|
||||
<i class="bx bx-edit-alt me-1 d-none d-sm-inline-block"></i> Edytuj
|
||||
</a>
|
||||
<div class="btn-group">
|
||||
<button type="button"
|
||||
class="btn btn-outline-secondary btn-sm dropdown-toggle dropdown-toggle-split"
|
||||
data-bs-toggle="dropdown" aria-expanded="false"></button>
|
||||
<div class="dropdown-menu dropdown-menu-end mt-1">
|
||||
<a href="javascript:void(0);" class="dropdown-item"><i
|
||||
class="bx bx-copy me-2"></i> Duplikuj</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a href="javascript:void(0);" class="dropdown-item text-danger"><i
|
||||
class="bx bx-trash me-2"></i> Usuń</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<div class="card-footer d-flex justify-content-center border-top">
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination pagination-sm mb-0">
|
||||
<li class="page-item prev disabled"><a class="page-link" href="javascript:void(0);"><i
|
||||
class="tf-icon bx bx-chevron-left"></i></a></li>
|
||||
<li class="page-item active"><a class="page-link" href="javascript:void(0);">1</a></li>
|
||||
<li class="page-item next disabled"><a class="page-link" href="javascript:void(0);"><i
|
||||
class="tf-icon bx bx-chevron-right"></i></a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="content-backdrop fade"></div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
// Inicjalizacja Tooltipów dla awatarów
|
||||
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
|
||||
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
|
||||
return new bootstrap.Tooltip(tooltipTriggerEl);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
425
prototype/company/app-permissions-acl.php
Normal file
425
prototype/company/app-permissions-acl.php
Normal file
@@ -0,0 +1,425 @@
|
||||
<?php
|
||||
$enablePrototypeComments = true;
|
||||
include '../../header-invoice.php';
|
||||
?>
|
||||
|
||||
<div class="container-xxl flex-grow-1 container-p-y">
|
||||
|
||||
<h4 class="fw-bold py-3 mb-4">
|
||||
<span class="text-muted fw-light">Zarządzanie zespołem / <a href="app-permissions.php"
|
||||
class="text-muted text-decoration-none">Uprawnienia</a> /</span> invoice.magico (ACL)
|
||||
</h4>
|
||||
|
||||
<!-- Nagłówek kontekstu -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body d-flex flex-column flex-md-row align-items-md-center justify-content-between">
|
||||
<div class="d-flex align-items-center mb-3 mb-md-0">
|
||||
<div
|
||||
class="avatar avatar-lg bg-label-primary rounded p-2 me-3 d-flex align-items-center justify-content-center">
|
||||
<i class="bx bx-receipt fs-2"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="mb-1 fw-bold">invoice.magico</h5>
|
||||
<p class="text-muted small mb-0">Zarządzaj macierzą uprawnień systemowych (ACL) dla modułu
|
||||
księgowego. Każda kolumna to Grupa a każdy wiersz to konkretna funkcja dostępna w aplikacji.
|
||||
Właściciel posiada niemodyfikowalny, pełny dostęp.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ms-md-4">
|
||||
<button class="btn btn-outline-secondary" onclick="window.location.href='app-groups.php'">
|
||||
<i class="bx bx-group me-1"></i> Zarządzaj grupami
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tabela Macierzy (ACL Matrix) -->
|
||||
<div class="card">
|
||||
<div
|
||||
class="card-header border-bottom d-flex flex-column flex-md-row justify-content-between align-items-md-center">
|
||||
<h5 class="m-0 mb-3 mb-md-0">Macierz uprawnień</h5>
|
||||
<div class="d-flex flex-wrap gap-2 flex-grow-1 ms-md-4 justify-content-end">
|
||||
<div class="dropdown flex-grow-1" style="max-width: 250px;">
|
||||
<button
|
||||
class="btn btn-outline-secondary dropdown-toggle w-100 text-start d-flex justify-content-between align-items-center"
|
||||
type="button" id="columnFilterDropdown" data-bs-toggle="dropdown" data-bs-auto-close="outside"
|
||||
aria-expanded="false">
|
||||
<span><i class="bx bx-filter-alt me-1"></i> Wybierz grupy</span>
|
||||
</button>
|
||||
<div class="dropdown-menu p-3" aria-labelledby="columnFilterDropdown" style="min-width: 250px;">
|
||||
<h6 class="dropdown-header px-0 text-uppercase fw-bold pt-0">Wyświetlane kolumny (max 5)</h6>
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input column-toggle" type="checkbox" value="1" id="col_1" checked>
|
||||
<label class="form-check-label" for="col_1">Właściciel </label>
|
||||
</div>
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input column-toggle" type="checkbox" value="2" id="col_2" checked>
|
||||
<label class="form-check-label" for="col_2">Kadra Kierownicza</label>
|
||||
</div>
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input column-toggle" type="checkbox" value="3" id="col_3" checked>
|
||||
<label class="form-check-label" for="col_3">Dział Marketingu</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input column-toggle" type="checkbox" value="4" id="col_4" checked>
|
||||
<label class="form-check-label" for="col_4">Dział Obsługi Klienta</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group input-group-merge" style="max-width: 250px;">
|
||||
<span class="input-group-text"><i class="bx bx-search"></i></span>
|
||||
<input type="text" class="form-control form-control-sm" placeholder="Szukaj uprawnienia...">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive text-nowrap pb-2">
|
||||
<!-- Dodana klasa acl-table dla łatwiejszego stylowania przez JS -->
|
||||
<table class="table table-hover table-bordered mb-0 acl-table">
|
||||
<thead class="table-light align-middle sticky-top" style="z-index: 10;">
|
||||
<tr>
|
||||
<th style="min-width: 250px;">Moduł i Nazwa Uprawnienia</th>
|
||||
<th class="text-center" style="width: 150px;">
|
||||
<i class="bx bx-crown text-warning fs-5 mb-1 d-block"></i>
|
||||
Właściciel <br>
|
||||
<span class="badge bg-label-secondary mt-1">N/D</span>
|
||||
</th>
|
||||
<th class="text-center" style="width: 150px;">
|
||||
<i class="bx bx-briefcase text-primary fs-5 mb-1 d-block"></i>
|
||||
Kadra Kierownicza
|
||||
</th>
|
||||
<th class="text-center" style="width: 150px;">
|
||||
<i class="bx bx-broadcast text-info fs-5 mb-1 d-block"></i>
|
||||
Dział Marketingu
|
||||
</th>
|
||||
<th class="text-center" style="width: 150px;">
|
||||
<i class="bx bx-support text-success fs-5 mb-1 d-block"></i>
|
||||
Dział Obsługi Klienta
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="table-border-bottom-0">
|
||||
|
||||
<!-- SEKCJA: GŁÓWNE -->
|
||||
<tr class="table-secondary border-top-2 border-bottom-2">
|
||||
<td colspan="5" class="fw-bold fs-6 text-uppercase tracking-wider">
|
||||
<i class="bx bx-power-off me-2 text-muted"></i> Dostęp do modułu
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="global-access-row">
|
||||
<td>
|
||||
<h6 class="mb-0 text-body">Dostęp do aplikacji</h6>
|
||||
<small class="text-muted">Główny włącznik modułu dla tej grupy. Wyłączenie blokuje poniższe
|
||||
opcje.</small>
|
||||
</td>
|
||||
<td class="text-center align-middle bg-label-secondary"><i
|
||||
class="bx bx-check text-muted fs-4"></i></td>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center"><input
|
||||
class="form-check-input m-0 global-access-checkbox" type="checkbox" checked
|
||||
style="cursor: pointer;"></div>
|
||||
</td>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center"><input
|
||||
class="form-check-input m-0 global-access-checkbox" type="checkbox"
|
||||
style="cursor: pointer;"></div>
|
||||
</td>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center"><input
|
||||
class="form-check-input m-0 global-access-checkbox" type="checkbox" checked
|
||||
style="cursor: pointer;"></div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- SEKCJA: FAKTURY -->
|
||||
<tr class="table-secondary border-top-2 border-bottom-2">
|
||||
<td colspan="5" class="fw-bold fs-6 text-uppercase tracking-wider">
|
||||
<i class="bx bx-file me-2 text-muted"></i> Dokumenty Sprzedaży (Faktury)
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<h6 class="mb-0 text-body">Odczyt plików i listy faktur</h6>
|
||||
<small class="text-muted">Pozwala m.in przeglądać ekran głównego listingu.</small>
|
||||
</td>
|
||||
<td class="text-center align-middle bg-label-secondary"><i
|
||||
class="bx bx-check text-muted fs-4"></i></td>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center"><input
|
||||
class="form-check-input m-0" type="checkbox" checked style="cursor: pointer;"></div>
|
||||
</td>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center"><input
|
||||
class="form-check-input m-0" type="checkbox" style="cursor: pointer;"></div>
|
||||
</td>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center"><input
|
||||
class="form-check-input m-0" type="checkbox" checked style="cursor: pointer;"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<h6 class="mb-0 text-body">Wystawianie nowych</h6>
|
||||
<small class="text-muted">Ręczne kreowanie faktur przez formularz.</small>
|
||||
</td>
|
||||
<td class="text-center align-middle bg-label-secondary"><i
|
||||
class="bx bx-check text-muted fs-4"></i></td>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center"><input
|
||||
class="form-check-input m-0" type="checkbox" checked style="cursor: pointer;"></div>
|
||||
</td>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center"><input
|
||||
class="form-check-input m-0" type="checkbox" style="cursor: pointer;"></div>
|
||||
</td>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center"><input
|
||||
class="form-check-input m-0" type="checkbox" style="cursor: pointer;"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<h6 class="mb-0 text-body">Trwałe usunięcie (Delete)</h6>
|
||||
<small class="text-muted">Prawo do kasacji dokumentów z bazy danych.</small>
|
||||
</td>
|
||||
<td class="text-center align-middle bg-label-secondary"><i
|
||||
class="bx bx-check text-muted fs-4"></i></td>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center"><input
|
||||
class="form-check-input m-0" type="checkbox" style="cursor: pointer;"></div>
|
||||
</td>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center"><input
|
||||
class="form-check-input m-0" type="checkbox" style="cursor: pointer;"></div>
|
||||
</td>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center"><input
|
||||
class="form-check-input m-0" type="checkbox" style="cursor: pointer;"></div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- SEKCJA: BAZA KONTRAHENTÓW -->
|
||||
<tr class="table-secondary border-top-2 border-bottom-2">
|
||||
<td colspan="5" class="fw-bold fs-6 text-uppercase tracking-wider">
|
||||
<i class="bx bx-buildings me-2 text-muted"></i> Baza Kontrahentów (CRM)
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<h6 class="mb-0 text-body">Przeglądanie kontrahentów</h6>
|
||||
<small class="text-muted">Podstawowy dostęp do modułu z listą firm.</small>
|
||||
</td>
|
||||
<td class="text-center align-middle bg-label-secondary"><i
|
||||
class="bx bx-check text-muted fs-4"></i></td>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center"><input
|
||||
class="form-check-input m-0" type="checkbox" checked style="cursor: pointer;"></div>
|
||||
</td>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center"><input
|
||||
class="form-check-input m-0" type="checkbox" checked style="cursor: pointer;"></div>
|
||||
</td>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center"><input
|
||||
class="form-check-input m-0" type="checkbox" checked style="cursor: pointer;"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<h6 class="mb-0 text-body">Dodawanie i Edycja</h6>
|
||||
<small class="text-muted">Aktualizowanie adresów i nr NIP klientów.</small>
|
||||
</td>
|
||||
<td class="text-center align-middle bg-label-secondary"><i
|
||||
class="bx bx-check text-muted fs-4"></i></td>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center"><input
|
||||
class="form-check-input m-0" type="checkbox" checked style="cursor: pointer;"></div>
|
||||
</td>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center"><input
|
||||
class="form-check-input m-0" type="checkbox" checked style="cursor: pointer;"></div>
|
||||
</td>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center"><input
|
||||
class="form-check-input m-0" type="checkbox" style="cursor: pointer;"></div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- SEKCJA: USTAWIENIA KSIĘGOWE -->
|
||||
<tr class="table-secondary border-top-2 border-bottom-2">
|
||||
<td colspan="5" class="fw-bold fs-6 text-uppercase tracking-wider text-danger">
|
||||
<i class="bx bx-cog me-2 text-danger"></i> Krytyczne (Ustawienia Główne)
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<h6 class="mb-0 text-body">Edycja numeracji i rejestrów</h6>
|
||||
<small class="text-muted">Pozwala edytować schematy np: FV/2026/XX.</small>
|
||||
</td>
|
||||
<td class="text-center align-middle bg-label-secondary"><i
|
||||
class="bx bx-check text-muted fs-4"></i></td>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center"><input
|
||||
class="form-check-input m-0" type="checkbox" style="cursor: pointer;"></div>
|
||||
</td>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center"><input
|
||||
class="form-check-input m-0" type="checkbox" style="cursor: pointer;"></div>
|
||||
</td>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center"><input
|
||||
class="form-check-input m-0" type="checkbox" style="cursor: pointer;"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<h6 class="mb-0 text-body">Eksport pliku JPK_V7</h6>
|
||||
<small class="text-muted">Przesyłanie danych do Urzędu Skarbowego.</small>
|
||||
</td>
|
||||
<td class="text-center align-middle bg-label-secondary"><i
|
||||
class="bx bx-check text-muted fs-4"></i></td>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center"><input
|
||||
class="form-check-input m-0" type="checkbox" checked style="cursor: pointer;"></div>
|
||||
</td>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center"><input
|
||||
class="form-check-input m-0" type="checkbox" style="cursor: pointer;"></div>
|
||||
</td>
|
||||
<td class="text-center align-middle">
|
||||
<div class="d-flex justify-content-center align-items-center"><input
|
||||
class="form-check-input m-0" type="checkbox" style="cursor: pointer;"></div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sticky Save Footer -->
|
||||
<div id="footer" class="footer" style="background: #e7e7ff; position: sticky; bottom: 0px; right: 0px; z-index: 1000;">
|
||||
<footer class="content-footer footer border-top">
|
||||
<div class="container-xxl d-flex py-3 justify-content-center">
|
||||
<a href="app-permissions.php" class="btn btn-label-secondary btn-lg me-3">Anuluj</a>
|
||||
<button class="btn btn-primary btn-lg px-5">Zapisz</button>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<div class="content-backdrop fade"></div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
// Podobnie jak z członkami grup, uczyńmy całe komórki klikalnymi!
|
||||
const aclTds = document.querySelectorAll('.acl-table tbody tr td.text-center');
|
||||
|
||||
aclTds.forEach(td => {
|
||||
// Pomijamy komórki szare/zablokowane (Oznaczyliśmy Właściciela jako bg-label-secondary)
|
||||
if (!td.classList.contains('bg-label-secondary')) {
|
||||
td.style.cursor = 'pointer';
|
||||
td.addEventListener('click', function (e) {
|
||||
if (e.target.tagName !== 'INPUT') {
|
||||
const checkbox = this.querySelector('.form-check-input');
|
||||
// Zmieniamy tylko jeśli checkbox nie jest zablokowany (disabled)
|
||||
if (checkbox && !checkbox.disabled) {
|
||||
checkbox.checked = !checkbox.checked;
|
||||
checkbox.dispatchEvent(new Event('change'));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Sprawdzanie czy w komórce jest Główny Włącznik, aby odciąć resztę w dół
|
||||
const accessCheckbox = td.querySelector('.form-check-input.global-access-checkbox');
|
||||
if (accessCheckbox) {
|
||||
accessCheckbox.addEventListener('change', function () {
|
||||
toggleColumnAccess(td.cellIndex, this.checked);
|
||||
});
|
||||
|
||||
// Wymuś stan po wczytaniu strony, jeśli aplikacja jest odznaczona (np. marketing)
|
||||
if (!accessCheckbox.checked) {
|
||||
toggleColumnAccess(td.cellIndex, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Funkcja blokowania/odblokowania całej kolumny
|
||||
function toggleColumnAccess(colIndex, isEnabled) {
|
||||
const allRows = document.querySelectorAll('.acl-table tbody tr');
|
||||
allRows.forEach(row => {
|
||||
// Pomijamy szare wiersze podziału oraz sam wiersz głównego włącznika
|
||||
if (!row.classList.contains('table-secondary') && !row.classList.contains('global-access-row') && row.cells.length > colIndex) {
|
||||
const cell = row.cells[colIndex];
|
||||
const checkbox = cell.querySelector('.form-check-input');
|
||||
|
||||
if (checkbox && !cell.classList.contains('bg-label-secondary')) {
|
||||
if (!isEnabled) {
|
||||
checkbox.checked = false;
|
||||
checkbox.disabled = true;
|
||||
cell.style.opacity = '0.4';
|
||||
cell.style.pointerEvents = 'none'; // cała komórka staje się nieklikalna
|
||||
} else {
|
||||
checkbox.disabled = false;
|
||||
cell.style.opacity = '1';
|
||||
cell.style.pointerEvents = 'auto'; // przywraca klikalność
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Logika wyświetlania/ukrywania kolumn grupowych
|
||||
const maxColumns = 5; // Mamy w sumie 1(nazwa) + 4 (grupy). Limit 5 grup oznacza max 6 kolumn tabeli. Zostawiłem zmienną na przyszłość.
|
||||
const columnToggles = document.querySelectorAll('.column-toggle:not(:disabled)');
|
||||
|
||||
columnToggles.forEach(toggle => {
|
||||
toggle.addEventListener('change', function () {
|
||||
const checkedCount = document.querySelectorAll('.column-toggle:checked').length;
|
||||
|
||||
// Zabezpieczenie limitu 5 (wliczając właściciela)
|
||||
if (this.checked && checkedCount > 5) {
|
||||
this.checked = false;
|
||||
alert('Możesz wybrać maksymalnie 5 grup do jednoczesnego wyświetlania.');
|
||||
return;
|
||||
}
|
||||
|
||||
const colIndex = parseInt(this.value);
|
||||
const isVisible = this.checked;
|
||||
|
||||
// Ukrywamy nagłówek
|
||||
const theadRow = document.querySelector('.acl-table thead tr');
|
||||
if (theadRow && theadRow.cells[colIndex]) {
|
||||
theadRow.cells[colIndex].style.display = isVisible ? '' : 'none';
|
||||
}
|
||||
|
||||
// Ukrywamy komórki w ciele tabeli
|
||||
const tbodyRows = document.querySelectorAll('.acl-table tbody tr');
|
||||
tbodyRows.forEach(row => {
|
||||
// Wiersze sekcji (szare) mają colspan=5, trzeba go dynamicznie zaktualizować
|
||||
if (row.classList.contains('table-secondary')) {
|
||||
const th = row.querySelector('td');
|
||||
// Liczymy widoczne kolumny (nagłówek)
|
||||
const visibleCols = document.querySelectorAll('.acl-table thead th:not([style*="display: none"])').length;
|
||||
if (th) th.setAttribute('colspan', visibleCols || 2);
|
||||
} else if (row.cells[colIndex]) {
|
||||
row.cells[colIndex].style.display = isVisible ? '' : 'none';
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
192
prototype/company/app-permissions.php
Normal file
192
prototype/company/app-permissions.php
Normal file
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
$enablePrototypeComments = true;
|
||||
include '../../header-invoice.php';
|
||||
?>
|
||||
|
||||
<div class="container-xxl flex-grow-1 container-p-y">
|
||||
|
||||
<h4 class="fw-bold py-3 mb-4">
|
||||
<span class="text-muted fw-light">Zarządzanie zespołem /</span> Uprawnienia
|
||||
</h4>
|
||||
|
||||
<div class="card mb-4 bg-label-primary shadow-none border border-primary">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-start align-items-sm-center gap-3">
|
||||
<div
|
||||
class="avatar avatar-md p-1 bg-white rounded flex-shrink-0 shadow-sm d-flex justify-content-center align-items-center">
|
||||
<i class="bx bx-shield-quarter text-primary fs-3"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="text-dark mb-1 fw-bold">Uprawnienia w ekosystemie magico</h5>
|
||||
<p class="mb-0 text-dark small">
|
||||
Poniżej widzisz wszystkie aktywne aplikacje Twojej firmy. Ze względu na budowę systemu, każda z
|
||||
aplikacji
|
||||
operuje własnym, unikalnym zestawem uprawnień szczegółowych (Matrix ACL). Wybierz aplikację z
|
||||
listy, aby zarządzać szczegółowym poziomem dostępu poszczególnych <a href="app-groups.php"
|
||||
class="fw-bold">Grup</a> do jej poszczególnych modułów.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Układ 4 kart z Aplikacjami -->
|
||||
<div class="row g-4 mb-4">
|
||||
|
||||
<!-- Karta 1: invoice.magico -->
|
||||
<div class="col-md-6 col-lg-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<div
|
||||
class="avatar avatar-sm bg-label-primary rounded p-2 me-3 d-flex align-items-center justify-content-center">
|
||||
<i class="bx bx-receipt fs-4"></i>
|
||||
</div>
|
||||
<h5 class="mb-0 fw-bold">invoice.magico</h5>
|
||||
<span class="badge bg-label-success ms-auto">Aktywna</span>
|
||||
</div>
|
||||
|
||||
<p class="text-muted small mb-4">
|
||||
Moduł obsługi księgowej i wystawiania dokumentów sprzedaży. Zarządzanie fakturami VAT,
|
||||
proformami oraz bazą kontrahentów.
|
||||
</p>
|
||||
|
||||
<div class="mb-4">
|
||||
<h6 class="text-muted fw-normal small text-uppercase mb-2">Grupy posiadające dostęp (dowolny):
|
||||
</h6>
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<span class="badge bg-label-secondary">Właściciel</span>
|
||||
<span class="badge bg-label-secondary">Kadra Kierownicza</span>
|
||||
<span class="badge bg-label-secondary">Dział Obsługi Klienta</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer border-top bg-transparent text-end">
|
||||
<a href="app-permissions-acl.php" class="btn btn-primary w-100">
|
||||
Zarządzaj uprawnieniami ACL <i class="bx bx-right-arrow-alt ms-1"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Karta 2: sync.magico -->
|
||||
<div class="col-md-6 col-lg-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<div
|
||||
class="avatar avatar-sm bg-label-info rounded p-2 me-3 d-flex align-items-center justify-content-center">
|
||||
<i class="bx bx-refresh fs-4"></i>
|
||||
</div>
|
||||
<h5 class="mb-0 fw-bold">sync.magico</h5>
|
||||
<span class="badge bg-label-success ms-auto">Aktywna</span>
|
||||
</div>
|
||||
|
||||
<p class="text-muted small mb-4">
|
||||
Centrum integracji e-commerce. Kontrola wymiany danych produktowych i magazynowych z
|
||||
zewnętrznymi platformami (BaseLinker, Allegro).
|
||||
</p>
|
||||
|
||||
<div class="mb-4">
|
||||
<h6 class="text-muted fw-normal small text-uppercase mb-2">Grupy posiadające dostęp (dowolny):
|
||||
</h6>
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<span class="badge bg-label-secondary">Właściciel</span>
|
||||
<span class="badge bg-label-secondary">Kadra Kierownicza</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer border-top bg-transparent text-end">
|
||||
<a href="#" class="btn btn-outline-primary w-100">
|
||||
Zarządzaj uprawnieniami ACL <i class="bx bx-right-arrow-alt ms-1"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Karta 3: helpdesk.magico -->
|
||||
<div class="col-md-6 col-lg-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<div
|
||||
class="avatar avatar-sm bg-label-warning rounded p-2 me-3 d-flex align-items-center justify-content-center">
|
||||
<i class="bx bx-support fs-4"></i>
|
||||
</div>
|
||||
<h5 class="mb-0 fw-bold">helpdesk.magico</h5>
|
||||
<span class="badge bg-label-success ms-auto">Aktywna</span>
|
||||
</div>
|
||||
|
||||
<p class="text-muted small mb-4">
|
||||
System zarządzania zgłoszeniami i wsparcia klienta. Śledzenie statusu ticketów, komunikacja oraz
|
||||
baza wiedzy (BOK).
|
||||
</p>
|
||||
|
||||
<div class="mb-4">
|
||||
<h6 class="text-muted fw-normal small text-uppercase mb-2">Grupy posiadające dostęp (dowolny):
|
||||
</h6>
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<span class="badge bg-label-secondary">Właściciel</span>
|
||||
<span class="badge bg-label-secondary">Dział Obsługi Klienta</span>
|
||||
<span class="badge bg-label-secondary">Menadżer</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer border-top bg-transparent text-end">
|
||||
<a href="#" class="btn btn-outline-primary w-100">
|
||||
Zarządzaj uprawnieniami ACL <i class="bx bx-right-arrow-alt ms-1"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Karta 4: employee.magico -->
|
||||
<div class="col-md-6 col-lg-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<div
|
||||
class="avatar avatar-sm bg-label-success rounded p-2 me-3 d-flex align-items-center justify-content-center">
|
||||
<i class="bx bx-group fs-4"></i>
|
||||
</div>
|
||||
<h5 class="mb-0 fw-bold">employee.magico</h5>
|
||||
<span class="badge bg-label-secondary ms-auto">Nieaktywna</span>
|
||||
</div>
|
||||
|
||||
<p class="text-muted small mb-4">
|
||||
Dedykowany portal pracowniczy (HR). Zarządzanie urlopami, wnioskami pracowniczymi, ewidencją
|
||||
czasu pracy oraz komunikacją wewnętrzną firmy.
|
||||
</p>
|
||||
|
||||
<div class="mb-4">
|
||||
<h6 class="text-muted fw-normal small text-uppercase mb-2">Grupy posiadające dostęp (dowolny):
|
||||
</h6>
|
||||
<p class="text-muted small fst-italic mb-0">Ta usługa nie jest włączona w Twoim pakiecie,
|
||||
uprawnienia są uśpione.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer border-top bg-transparent text-end">
|
||||
<button class="btn btn-outline-secondary w-100" disabled>
|
||||
Aplikacja jest nieaktywna
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-backdrop fade"></div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
// ...
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
214
prototype/company/app-services-detail.php
Normal file
214
prototype/company/app-services-detail.php
Normal file
@@ -0,0 +1,214 @@
|
||||
<?php
|
||||
$enablePrototypeComments = true;
|
||||
include '../../header-invoice.php';
|
||||
|
||||
// Pobieranie przekazanej aplikacji, tu symulujemy, że otwieramy "employee.magico" jako system nieaktywny
|
||||
$appId = isset($_GET['id']) ? $_GET['id'] : 'employee';
|
||||
|
||||
// Symulowana baza dla demonstracji widoku
|
||||
$appData = [
|
||||
'title' => 'employee.magico',
|
||||
'badge' => 'Nieaktywna',
|
||||
'badgeClass' => 'bg-label-secondary',
|
||||
'icon' => 'bx-group',
|
||||
'desc' => 'Kompleksowy portal HR (Self-Service) dla pracowników Twojej firmy.',
|
||||
'isActive' => false
|
||||
];
|
||||
?>
|
||||
|
||||
<div class="container-xxl flex-grow-1 container-p-y">
|
||||
|
||||
<h4 class="fw-bold py-3 mb-4">
|
||||
<span class="text-muted fw-light">Zarządzanie firmą / <a href="app-services.php"
|
||||
class="text-muted text-decoration-none">Usługi i aplikacje</a> /</span>
|
||||
<?php echo $appData['title']; ?>
|
||||
</h4>
|
||||
|
||||
<!-- Nagłówek i status (Hero Banner) -->
|
||||
<div class="card mb-4 border-0 shadow-sm" style="background: linear-gradient(to right, #ffffff, #f8f9fa);">
|
||||
<div class="card-body p-5">
|
||||
<div class="row align-items-center text-center text-md-start">
|
||||
<div class="col-md-8 mb-4 mb-md-0">
|
||||
<div class="d-flex flex-column flex-md-row align-items-center mb-3">
|
||||
<div
|
||||
class="avatar avatar-xl bg-label-secondary rounded p-3 me-md-4 mb-3 mb-md-0 d-flex align-items-center justify-content-center">
|
||||
<i class="bx <?php echo $appData['icon']; ?> mb-0" style="font-size: 2.5rem;"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="d-flex align-items-center justify-content-center justify-content-md-start mb-1">
|
||||
<h2 class="mb-0 fw-bold me-3 text-dark">
|
||||
<?php echo $appData['title']; ?>
|
||||
</h2>
|
||||
<span class="badge <?php echo $appData['badgeClass']; ?> px-3 py-2 fs-6">
|
||||
<?php echo $appData['badge']; ?>
|
||||
</span>
|
||||
</div>
|
||||
<p class="text-muted fs-5 mb-0">
|
||||
<?php echo $appData['desc']; ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Przycisk Aktywacji -->
|
||||
<div class="col-md-4 text-md-end">
|
||||
<?php if (!$appData['isActive']): ?>
|
||||
<div class="border rounded p-4 text-center bg-white shadow-sm">
|
||||
<p class="mb-3 fw-semibold text-body">Aplikacja pozostaje uśpiona. Aby z niej korzystać,
|
||||
wymagana jest aktywacja licencji.</p>
|
||||
<button type="button" class="btn btn-primary btn-lg w-100" data-bs-toggle="modal"
|
||||
data-bs-target="#activationModal">
|
||||
<i class="bx bx-power-off me-2"></i> Aktywuj moduł
|
||||
</button>
|
||||
<small class="text-muted d-block mt-2">Bez żadnych umów długoterminowych. Płatność doliczana do
|
||||
faktury cyklicznej.</small>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<!-- Widok dla aktywnej np invoice.magico -->
|
||||
<button class="btn btn-outline-danger btn-lg">
|
||||
<i class="bx bx-power-off me-2"></i> Wyłącz moduł
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Prezentacja (Marketing / Zrzuty ekranu) -->
|
||||
<div class="row mb-5">
|
||||
<div class="col-12 text-center mb-4">
|
||||
<h3 class="fw-bold mb-2">Zapomnij o papierowych wnioskach urlopowych</h3>
|
||||
<p class="text-muted fs-5">Zautomatyzuj procesy kadrowe. Zyskaj jedno, spójne środowisko dla swojego
|
||||
zespołu.</p>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card h-100 shadow-none bg-transparent">
|
||||
<img class="card-img-top rounded-3 shadow-sm border"
|
||||
src="https://placehold.co/800x500/ebeef0/696cff?text=Ekran+Wniosk%C3%B3w+Pracowniczych&font=roboto"
|
||||
alt="Wnioski Urlopowe Screenshot">
|
||||
<div class="card-body px-0">
|
||||
<h5 class="card-title fw-bold"><i class="bx bx-check-circle text-primary me-2"></i>Samoobsługa
|
||||
pracownika (Self-Service)</h5>
|
||||
<p class="card-text text-muted">Pracownicy samodzielnie zgłaszają wnioski urlopowe, delegacje oraz
|
||||
odbiory nadgodzin z poziomu swojego konta. Przełożeni jednym kliknięciem akceptują prośby w
|
||||
systemie.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card h-100 shadow-none bg-transparent">
|
||||
<img class="card-img-top rounded-3 shadow-sm border"
|
||||
src="https://placehold.co/800x500/ebeef0/696cff?text=Ewidencja+Czasu+Pracy+(ECP)&font=roboto"
|
||||
alt="Ewidencja Czasu Pracy Screenshot">
|
||||
<div class="card-body px-0">
|
||||
<h5 class="card-title fw-bold"><i class="bx bx-pie-chart-alt text-primary me-2"></i>Ewidencja i
|
||||
Rozliczanie (ECP)</h5>
|
||||
<p class="card-text text-muted">Rejestruj wejścia, wyjścia i przerwy za pomocą elektronicznych kart
|
||||
(tzw. "odbijanie karty"). Raportowanie bezpośrednio na poczet rozliczeń kadrowo-płacowych.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cennik -->
|
||||
<div class="card mb-4 bg-label-secondary bg-opacity-10 border-0">
|
||||
<div class="card-body p-4 p-md-5">
|
||||
<div class="text-center mb-4">
|
||||
<h4 class="fw-bold"><i class="bx bx-wallet me-2 text-primary"></i>Przejrzysty model cenowy</h4>
|
||||
<p class="text-muted">Płacisz tylko wtedy, kiedy faktycznie potrzebujesz tej usługi dla swojego zespołu.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8 col-lg-5">
|
||||
<div class="card shadow-sm border-primary border">
|
||||
<div class="card-body text-center p-5">
|
||||
<span class="badge bg-label-primary px-3 py-2 fs-6 mb-4 rounded-pill">Model Per Seat
|
||||
(Zależny od załogi)</span>
|
||||
<h1 class="display-3 fw-bold text-dark mb-1">10 <span
|
||||
class="fs-4 fw-normal text-muted">PLN</span></h1>
|
||||
<p class="text-muted fw-semibold mb-4">Miesięcznie, <span
|
||||
class="text-primary text-decoration-underline">za każdego przypisanego
|
||||
pracownika</span></p>
|
||||
|
||||
<ul class="list-unstyled text-start mb-0">
|
||||
<li class="mb-3 d-flex"><i class="bx bx-check text-primary me-2 fs-5 mt-1"></i>
|
||||
<span>Możliwość przypisania konkretnych działów. Brak opłaty za uśpione
|
||||
konta.</span></li>
|
||||
<li class="mb-3 d-flex"><i class="bx bx-check text-primary me-2 fs-5 mt-1"></i>
|
||||
<span>Pełny dostęp do aplikacji mobilnej.</span></li>
|
||||
<li class="mb-3 d-flex"><i class="bx bx-check text-primary me-2 fs-5 mt-1"></i>
|
||||
<span>Zintegrowana wysyłka powiadomień na e-mail i push.</span></li>
|
||||
<li class="d-flex"><i class="bx bx-check text-primary me-2 fs-5 mt-1"></i> <span>Moduł
|
||||
kadrowy dla zewnętrznej księgowości (gratis).</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Modal Potwierdzający Aktywację -->
|
||||
<div class="modal fade" id="activationModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header border-bottom pb-3">
|
||||
<h5 class="modal-title fw-bold" id="exampleModalLabel1">Potwierdzenie aktywacji modułu</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body py-4">
|
||||
<div class="d-flex align-items-center mb-4">
|
||||
<div
|
||||
class="avatar avatar-md bg-label-warning rounded p-2 me-3 d-flex align-items-center justify-content-center">
|
||||
<i class="bx bx-error text-warning fs-3"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="mb-0 fw-bold">Uwaga o zmianie abonamentu</h6>
|
||||
<small class="text-muted">Aktywacja usług dodatkowych wpływa na wysokość opłat
|
||||
subskrypcyjnych.</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>Czy na pewno chcesz aktywować wybraną usługę <strong>
|
||||
<?php echo $appData['title']; ?>
|
||||
</strong> na koncie firmy?</p>
|
||||
|
||||
<div class="alert alert-secondary p-3 mb-0">
|
||||
<p class="mb-1 fw-bold"><i class="bx bx-info-circle me-1"></i> Informacje rozliczeniowe:</p>
|
||||
<ul class="mb-0 ps-3 small">
|
||||
<li>Koszty usługi to 10 PLN miesięcznie za każdego użytkownika podpiętego testowo pod tę
|
||||
strukturę.</li>
|
||||
<li>Kwota zostanie automatycznie doliczona do najbliższej zbiorczej faktury abonamentowej (cykl
|
||||
30-dniowy).</li>
|
||||
<li>Aplikację możesz w każdej chwili ponownie wyłączyć powracając do tego widoku.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer border-top pt-3">
|
||||
<button type="button" class="btn btn-label-secondary" data-bs-dismiss="modal">Zrezygnuj</button>
|
||||
<button type="button" class="btn btn-primary"
|
||||
onclick="alert('Moduł został aktywowany! Symulacja zakończenia procesu.'); bootstrap.Modal.getInstance(document.getElementById('activationModal')).hide();">Akceptuję,
|
||||
zaktualizuj usługi</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-backdrop fade"></div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
// ...
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
218
prototype/company/app-services.php
Normal file
218
prototype/company/app-services.php
Normal file
@@ -0,0 +1,218 @@
|
||||
<?php
|
||||
$enablePrototypeComments = true;
|
||||
include '../../header-invoice.php';
|
||||
?>
|
||||
|
||||
<div class="container-xxl flex-grow-1 container-p-y">
|
||||
|
||||
<h4 class="fw-bold py-3 mb-4">
|
||||
<span class="text-muted fw-light">Zarządzanie firmą /</span> Usługi i aplikacje
|
||||
</h4>
|
||||
|
||||
<div class="card mb-4 bg-label-primary shadow-none border border-primary">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-start align-items-sm-center gap-3">
|
||||
<div
|
||||
class="avatar avatar-md p-1 bg-white rounded flex-shrink-0 shadow-sm d-flex justify-content-center align-items-center">
|
||||
<i class="bx bx-grid-alt text-primary fs-3"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="text-dark mb-1 fw-bold">Twój ekosystem magico</h5>
|
||||
<p class="mb-0 text-dark small">
|
||||
Poniżej znajduje się lista wszystkich modułów i aplikacji dostępnych w ramach naszego systemu.
|
||||
Widzisz tutaj zarówno aplikacje, z których aktualnie korzystasz, jak i te, które możesz w każdej
|
||||
chwili aktywować.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Układ 3 kart (col-md-4) z Aplikacjami -->
|
||||
<div class="row g-4 mb-4">
|
||||
|
||||
<!-- Karta 1: invoice.magico -->
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center justify-content-between mb-3">
|
||||
<div class="d-flex align-items-center">
|
||||
<div
|
||||
class="avatar avatar-sm bg-label-primary rounded p-2 me-3 d-flex align-items-center justify-content-center">
|
||||
<i class="bx bx-receipt fs-4"></i>
|
||||
</div>
|
||||
<h5 class="mb-0 fw-bold">invoice.magico</h5>
|
||||
</div>
|
||||
<span class="badge bg-label-success">Aktywna</span>
|
||||
</div>
|
||||
|
||||
<p class="text-muted small mb-4 flex-grow-1">
|
||||
Moduł obsługi księgowej i wystawiania dokumentów sprzedaży. Zarządzanie fakturami VAT,
|
||||
proformami oraz bazą kontrahentów.
|
||||
</p>
|
||||
|
||||
<div class="d-flex flex-column gap-2 mt-auto">
|
||||
<div class="d-flex align-items-center text-muted small mb-2">
|
||||
<i class="bx bx-check text-success me-2"></i> KSeF Ready
|
||||
</div>
|
||||
<div class="d-flex align-items-center text-muted small mb-3">
|
||||
<i class="bx bx-check text-success me-2"></i> Automatyzacja faktur
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer border-top bg-transparent pt-3 pb-3">
|
||||
<a href="app-services-detail.php?id=invoice" class="btn btn-outline-primary w-100">
|
||||
Zarządzaj aplikacją <i class="bx bx-right-arrow-alt ms-1"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Karta 2: sync.magico -->
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-body d-flex flex-column">
|
||||
<div class="d-flex align-items-center justify-content-between mb-3">
|
||||
<div class="d-flex align-items-center">
|
||||
<div
|
||||
class="avatar avatar-sm bg-label-info rounded p-2 me-3 d-flex align-items-center justify-content-center">
|
||||
<i class="bx bx-refresh fs-4"></i>
|
||||
</div>
|
||||
<h5 class="mb-0 fw-bold">sync.magico</h5>
|
||||
</div>
|
||||
<span class="badge bg-label-success">Aktywna</span>
|
||||
</div>
|
||||
|
||||
<p class="text-muted small mb-4 flex-grow-1">
|
||||
Centrum integracji e-commerce. Kontrola wymiany danych produktowych i magazynowych z
|
||||
zewnętrznymi platformami.
|
||||
</p>
|
||||
|
||||
<div class="d-flex flex-column gap-2 mt-auto">
|
||||
<div class="d-flex align-items-center text-muted small mb-2">
|
||||
<i class="bx bx-check text-success me-2"></i> Integracja z BaseLinker
|
||||
</div>
|
||||
<div class="d-flex align-items-center text-muted small mb-3">
|
||||
<i class="bx bx-check text-success me-2"></i> Dwukierunkowa synch.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer border-top bg-transparent pt-3 pb-3">
|
||||
<a href="app-services-detail.php?id=sync" class="btn btn-outline-primary w-100">
|
||||
Zarządzaj aplikacją <i class="bx bx-right-arrow-alt ms-1"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Karta 3: helpdesk.magico -->
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-body d-flex flex-column">
|
||||
<div class="d-flex align-items-center justify-content-between mb-3">
|
||||
<div class="d-flex align-items-center">
|
||||
<div
|
||||
class="avatar avatar-sm bg-label-warning rounded p-2 me-3 d-flex align-items-center justify-content-center">
|
||||
<i class="bx bx-support fs-4"></i>
|
||||
</div>
|
||||
<h5 class="mb-0 fw-bold">helpdesk.magico</h5>
|
||||
</div>
|
||||
<span class="badge bg-label-success">Aktywna</span>
|
||||
</div>
|
||||
|
||||
<p class="text-muted small mb-4 flex-grow-1">
|
||||
System zarządzania zgłoszeniami i wsparcia klienta. Śledzenie statusu ticketów, system ticketowy
|
||||
oraz centrum BOK.
|
||||
</p>
|
||||
|
||||
<div class="d-flex flex-column gap-2 mt-auto">
|
||||
<div class="d-flex align-items-center text-muted small mb-2">
|
||||
<i class="bx bx-check text-success me-2"></i> Skrzynki e-mail (IMAP)
|
||||
</div>
|
||||
<div class="d-flex align-items-center text-muted small mb-3">
|
||||
<i class="bx bx-check text-success me-2"></i> Szablony odpowiedzi
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer border-top bg-transparent pt-3 pb-3">
|
||||
<a href="app-services-detail.php?id=helpdesk" class="btn btn-outline-primary w-100">
|
||||
Zarządzaj aplikacją <i class="bx bx-right-arrow-alt ms-1"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Karta 4: employee.magico -->
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card h-100 border border-secondary shadow-none">
|
||||
<div class="card-body d-flex flex-column">
|
||||
<div class="d-flex align-items-center justify-content-between mb-3">
|
||||
<div class="d-flex align-items-center opacity-75">
|
||||
<div
|
||||
class="avatar avatar-sm bg-label-secondary rounded p-2 me-3 d-flex align-items-center justify-content-center">
|
||||
<i class="bx bx-group fs-4"></i>
|
||||
</div>
|
||||
<h5 class="mb-0 fw-bold text-muted">employee.magico</h5>
|
||||
</div>
|
||||
<span class="badge bg-label-secondary">Nieaktywna</span>
|
||||
</div>
|
||||
|
||||
<p class="text-muted small mb-4 flex-grow-1">
|
||||
Dedykowany portal pracowniczy (HR). Zarządzanie urlopami, wnioskami pracowniczymi oraz ewidencją
|
||||
czasu pracy.
|
||||
</p>
|
||||
|
||||
<div class="d-flex flex-column gap-2 mt-auto">
|
||||
<div class="d-flex align-items-center text-muted small mb-2 opacity-50">
|
||||
<i class="bx bx-check me-2"></i> Portal pracownika (Self-Service)
|
||||
</div>
|
||||
<div class="d-flex align-items-center text-muted small mb-3 opacity-50">
|
||||
<i class="bx bx-check me-2"></i> Obieg wniosków urlopowych
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Przycisk z akcentem na włączenie -->
|
||||
<div class="card-footer border-top bg-secondary bg-opacity-10 pt-3 pb-3">
|
||||
<a href="app-services-detail.php?id=employee" class="btn btn-primary w-100">
|
||||
Dowiedz się więcej <i class="bx bx-right-arrow-alt ms-1"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Karta 5: pos.magico (zwiastun nowej aplikacji) -->
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="card h-100 border border-dashed border-secondary shadow-none bg-lighter">
|
||||
<div class="card-body d-flex flex-column justify-content-center align-items-center text-center">
|
||||
<div
|
||||
class="avatar avatar-md bg-label-secondary rounded p-2 mb-3 mt-4 d-flex align-items-center justify-content-center">
|
||||
<i class="bx bx-store-alt fs-2 text-muted"></i>
|
||||
</div>
|
||||
<h5 class="mb-1 fw-bold text-muted">pos.magico</h5>
|
||||
<span class="badge bg-label-dark mb-3">Wkrótce (Q3 2026)</span>
|
||||
|
||||
<p class="text-muted small mb-4">
|
||||
System kasowy (Point of Sale) dla sklepów stacjonarnych. Integracja z terminalami płatniczymi i
|
||||
drukarkami fiskalnymi.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-backdrop fade"></div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
// ...
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
242
prototype/company/app-team.php
Normal file
242
prototype/company/app-team.php
Normal file
@@ -0,0 +1,242 @@
|
||||
<?php
|
||||
$enablePrototypeComments = true;
|
||||
include '../../header-invoice.php';
|
||||
?>
|
||||
|
||||
<div class="container-xxl flex-grow-1 container-p-y">
|
||||
|
||||
<h4 class="fw-bold py-3 mb-4">
|
||||
<span class="text-muted fw-light">Zarządzanie zespołem /</span> Twój zespół
|
||||
</h4>
|
||||
|
||||
<div class="card mb-4 bg-label-primary shadow-none border border-primary">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-start align-items-sm-center gap-3">
|
||||
<div
|
||||
class="avatar avatar-md p-1 bg-white rounded flex-shrink-0 shadow-sm d-flex align-items-center justify-content-center">
|
||||
<i class="bx bx-info-circle text-primary fs-3"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="text-dark mb-1 fw-bold">Jak działa dodawanie pracowników i role?</h5>
|
||||
<p class="mb-2 text-dark small">
|
||||
System magico korzysta z centralnego konta <strong>id.magico</strong>. Wpisz e-mail poniżej, a
|
||||
my sprawdzimy, czy pracownik ma już konto. Jeśli tak – dodamy go do Twojej firmy. Jeśli nie –
|
||||
wyślemy mu link do założenia konta.
|
||||
</p>
|
||||
|
||||
<div class="row mt-3 text-dark">
|
||||
<div class="col-md-4 mb-2">
|
||||
<strong class="d-block mb-1"><i class="bx bx-crown text-warning me-1"></i>
|
||||
Właściciel</strong>
|
||||
<span class="small opacity-75">Otrzymuje faktury, zarządza zespołem i ma pełne prawo
|
||||
aktywacji/dezaktywacji wszystkich aplikacji.</span>
|
||||
</div>
|
||||
<div class="col-md-4 mb-2">
|
||||
<strong class="d-block mb-1"><i class="bx bx-briefcase text-info me-1"></i>
|
||||
Menadżer</strong>
|
||||
<span class="small opacity-75">Zarządza zespołem i widzi panel, ale nie ma dostępu do
|
||||
rozliczeń ani nie może kupować aplikacji.</span>
|
||||
</div>
|
||||
<div class="col-md-4 mb-2">
|
||||
<strong class="d-block mb-1"><i class="bx bx-user text-secondary me-1"></i>
|
||||
Pracownik</strong>
|
||||
<span class="small opacity-75">Domyślnie brak dostępu do tego panelu. Uprawnienia nadajesz w
|
||||
zakładce "Uprawnienia".</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title mb-1">Zaproś nowego członka zespołu</h5>
|
||||
<p class="text-muted small mb-3">Wprowadź adres e-mail osoby, którą chcesz dodać do Twojej firmy.</p>
|
||||
|
||||
<form onsubmit="return false;" class="d-flex mb-3">
|
||||
<div class="input-group input-group-merge shadow-sm" style="max-width: 500px;">
|
||||
<span class="input-group-text bg-white border-end-0"><i
|
||||
class="bx bx-envelope text-muted"></i></span>
|
||||
<input type="email" class="form-control border-start-0 ps-0" placeholder="np. jan.kowalski@firma.pl"
|
||||
required>
|
||||
<button type="button" class="btn btn-primary px-4" data-bs-toggle="modal"
|
||||
data-bs-target="#userSearchModal">
|
||||
Sprawdź <i class="bx bx-right-arrow-alt ms-1"></i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h5 class="card-header border-bottom d-flex justify-content-between align-items-center">
|
||||
Członkowie zespołu
|
||||
</h5>
|
||||
|
||||
<div class="table-responsive text-nowrap pb-2">
|
||||
<table class="table table-hover mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Użytkownik</th>
|
||||
<th>Rola w firmie</th>
|
||||
<th>Status</th>
|
||||
<th class="text-end">Akcje</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="table-border-bottom-0">
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<div class="d-flex justify-content-start align-items-center">
|
||||
<div class="avatar avatar-sm me-3">
|
||||
<span class="avatar-initial rounded-circle bg-label-primary">BB</span>
|
||||
</div>
|
||||
<div class="d-flex flex-column">
|
||||
<h6 class="mb-0 fw-semibold">
|
||||
Bartłomiej Banaczyk
|
||||
<i class="bx bxs-badge-check text-primary ms-1" data-bs-toggle="tooltip"
|
||||
title="Zweryfikowane konto id.magico"></i>
|
||||
</h6>
|
||||
<small class="text-muted">banaczyk@magico.pl</small>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td style="width: 250px;">
|
||||
<select class="form-select">
|
||||
<option value="owner" selected>Właściciel</option>
|
||||
<option value="manager">Menadżer</option>
|
||||
<option value="user">Pracownik</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-label-success">Aktywny</span>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<button type="button" class="btn btn-sm btn-icon btn-text-secondary rounded-circle"
|
||||
disabled>
|
||||
<i class="bx bx-trash fs-5 opacity-50"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<div class="d-flex justify-content-start align-items-center">
|
||||
<div class="avatar avatar-sm me-3">
|
||||
<span class="avatar-initial rounded-circle bg-label-secondary"><i
|
||||
class="bx bx-user"></i></span>
|
||||
</div>
|
||||
<div class="d-flex flex-column">
|
||||
<h6 class="mb-0 fw-semibold text-muted">
|
||||
Piotr Mierzwa
|
||||
</h6>
|
||||
<small class="text-muted">piotr@magico.pl</small>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td style="width: 250px;">
|
||||
<span class="text-muted small"><i class="bx bx-time-five me-1"></i>Oczekuje na
|
||||
rejestrację</span>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-label-warning px-2 py-1">
|
||||
<i class="bx bx-mail-send me-1"></i> Ponów zaproszenie
|
||||
</button>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<button type="button" class="btn btn-sm btn-icon btn-text-danger rounded-circle"
|
||||
data-bs-toggle="tooltip" title="Usuń z firmy">
|
||||
<i class="bx bx-trash fs-5"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<div class="d-flex justify-content-start align-items-center">
|
||||
<div class="avatar avatar-sm me-3">
|
||||
<img src="https://ui-avatars.com/api/?name=Tech+Magico&background=e7e7ff&color=696cff"
|
||||
alt="Avatar" class="rounded-circle">
|
||||
</div>
|
||||
<div class="d-flex flex-column">
|
||||
<h6 class="mb-0 fw-semibold">
|
||||
Tech Magico
|
||||
<i class="bx bxs-badge-check text-primary ms-1" data-bs-toggle="tooltip"
|
||||
title="Zweryfikowane konto id.magico"></i>
|
||||
</h6>
|
||||
<small class="text-muted">tech@magico.pl</small>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td style="width: 250px;">
|
||||
<select class="form-select">
|
||||
<option value="owner">Właściciel</option>
|
||||
<option value="manager">Menadżer</option>
|
||||
<option value="user" selected>Pracownik</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-label-success">Aktywny</span>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<button type="button" class="btn btn-sm btn-icon btn-text-danger rounded-circle"
|
||||
data-bs-toggle="tooltip" title="Usuń z firmy">
|
||||
<i class="bx bx-trash fs-5"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="userSearchModal" tabindex="-1" aria-hidden="true" data-bs-backdrop="static">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header border-bottom pb-3">
|
||||
<h5 class="modal-title">Dodawanie pracownika</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body p-4 text-center">
|
||||
|
||||
<div
|
||||
class="avatar avatar-md mx-auto mb-3 bg-label-success rounded-circle d-flex align-items-center justify-content-center">
|
||||
<i class="bx bx-user-check fs-2"></i>
|
||||
</div>
|
||||
<h5>Mamy go!</h5>
|
||||
<p class="text-muted mb-4">Użytkownik <strong>jan.kowalski@firma.pl</strong> posiada już konto w
|
||||
centralnym systemie magico.</p>
|
||||
<button class="btn btn-primary w-100" data-bs-dismiss="modal">
|
||||
<i class="bx bx-plus me-2"></i> Dodaj do mojej firmy
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="footer" class="footer" style="background: #e7e7ff; position: sticky; bottom: 0px; right: 0px;">
|
||||
<footer class="content-footer footer">
|
||||
<div class="container-xxl d-flex py-3 justify-content-center">
|
||||
<button class="btn btn-primary btn-lg">Zapisz</button>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<div class="content-backdrop fade"></div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
// Tu znajdą się skrypty odpowiedzialne za logikę widoku zespołu, np. obsługa tabeli
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
296
prototype/company/index.php
Normal file
296
prototype/company/index.php
Normal file
@@ -0,0 +1,296 @@
|
||||
<?php
|
||||
$enablePrototypeComments = true;
|
||||
include '../../header-invoice.php';
|
||||
?>
|
||||
|
||||
<div class="container-xxl flex-grow-1 container-p-y">
|
||||
|
||||
<h4 class="fw-bold py-3 mb-4">
|
||||
Zarządzanie firmą <span class="text-muted fw-light">/ Kokpit</span>
|
||||
</h4>
|
||||
|
||||
<!-- Baner Informacyjny -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="card bg-primary text-white text-center text-md-start"
|
||||
style="background: linear-gradient(135deg, #696cff 0%, #a481ff 100%);">
|
||||
<div
|
||||
class="card-body d-flex flex-column flex-md-row justify-content-between align-items-center py-4 px-5">
|
||||
<div class="mb-3 mb-md-0 d-flex gap-4 align-items-center">
|
||||
<div
|
||||
class="avatar avatar-lg bg-white rounded flex-shrink-0 d-flex align-items-center justify-content-center shadow-sm">
|
||||
<i class="bx bx-buildings text-primary fs-2"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="text-white fw-bold mb-1">Centrum Dowodzenia Twojej Firmy</h5>
|
||||
<p class="mb-0 text-white-50" style="max-width: 600px;">
|
||||
Aplikacja <strong>company.magico</strong> to miejsce, w którym kontrolujesz cały swój
|
||||
ekosystem. Od konfiguracji uprawnień i zapraszania współpracowników, po zarządzanie
|
||||
rozliczeniami, modułami i danymi fakturowymi firmy.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<a href="app-company-info.php" class="btn btn-white text-primary shadow-sm fw-bold">
|
||||
<i class="bx bx-cog me-2"></i> Konfiguracja danych
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 1. Sekcja KPI (Karty informacyjne) -->
|
||||
<div class="row g-4 mb-4">
|
||||
<!-- Aktywne aplikacje -->
|
||||
<div class="col-sm-6 col-xl-3">
|
||||
<div class="card h-100 shadow-sm border-0">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-start justify-content-between">
|
||||
<div class="content-left">
|
||||
<span class="text-muted text-uppercase small fw-bold" style="letter-spacing: 0.5px;">Aktywne
|
||||
moduły</span>
|
||||
<div class="d-flex align-items-end mt-2">
|
||||
<h3 class="mb-0 me-2 text-dark">3 <span class="fs-6 fw-normal text-muted">/ 5</span>
|
||||
</h3>
|
||||
</div>
|
||||
<small class="text-success"><i class="bx bx-check-circle"></i> Ekosystem działa
|
||||
poprawnie</small>
|
||||
</div>
|
||||
<span class="badge bg-label-primary rounded p-2">
|
||||
<i class="bx bx-grid-alt fs-4"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Wielkość zespołu -->
|
||||
<div class="col-sm-6 col-xl-3">
|
||||
<div class="card h-100 shadow-sm border-0">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-start justify-content-between">
|
||||
<div class="content-left">
|
||||
<span class="text-muted text-uppercase small fw-bold" style="letter-spacing: 0.5px;">Twój
|
||||
zespół</span>
|
||||
<div class="d-flex align-items-end mt-2">
|
||||
<h3 class="mb-0 me-2 text-dark">14</h3>
|
||||
</div>
|
||||
<small class="text-warning"><i class="bx bx-time"></i> 2 zaproszenia w toku</small>
|
||||
</div>
|
||||
<span class="badge bg-label-info rounded p-2">
|
||||
<i class="bx bx-group fs-4"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Najbliższa płatność -->
|
||||
<div class="col-sm-6 col-xl-3">
|
||||
<div class="card h-100 shadow-sm border-0 border-start border-danger border-3">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-start justify-content-between">
|
||||
<div class="content-left">
|
||||
<span class="text-muted text-uppercase small fw-bold"
|
||||
style="letter-spacing: 0.5px;">Najbliższa płatność</span>
|
||||
<div class="d-flex align-items-end mt-2">
|
||||
<h3 class="mb-0 me-2 text-danger">365 zł</h3>
|
||||
</div>
|
||||
<small class="text-danger fw-semibold"><i class="bx bx-error-circle"></i> Płatność
|
||||
opóźniona</small>
|
||||
</div>
|
||||
<span class="badge bg-label-danger rounded p-2">
|
||||
<i class="bx bx-credit-card fs-4"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Zużycie przestrzeni -->
|
||||
<div class="col-sm-6 col-xl-3">
|
||||
<div class="card h-100 shadow-sm border-0">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-start justify-content-between">
|
||||
<div class="content-left">
|
||||
<span class="text-muted text-uppercase small fw-bold"
|
||||
style="letter-spacing: 0.5px;">Składnica plików</span>
|
||||
<div class="d-flex align-items-end mt-2">
|
||||
<h3 class="mb-0 me-2 text-dark">0.04 <span class="fs-6 fw-normal text-muted">GB</span>
|
||||
</h3>
|
||||
</div>
|
||||
<small class="text-muted"><i class="bx bx-data"></i> Wykorzystano 1% z limitu</small>
|
||||
</div>
|
||||
<span class="badge bg-label-success rounded p-2">
|
||||
<i class="bx bx-hdd fs-4"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Główny układ dwukolumnowy -->
|
||||
<div class="row">
|
||||
|
||||
<!-- Lewa kolumna: Dziennik Aktywności (Timeline) -->
|
||||
<div class="col-xl-8 mb-4 col-md-12">
|
||||
<div class="card h-100">
|
||||
<div class="card-header d-flex justify-content-between align-items-center mb-3 border-bottom">
|
||||
<h5 class="card-title m-0 me-2"><i class="bx bx-list-ol text-primary me-2"></i>Dziennik aktywności w
|
||||
środowisku</h5>
|
||||
<div class="dropdown">
|
||||
<button class="btn p-0" type="button" id="timelineDropdown" data-bs-toggle="dropdown"
|
||||
aria-haspopup="true" aria-expanded="false">
|
||||
<i class="bx bx-dots-vertical-rounded"></i>
|
||||
</button>
|
||||
<div class="dropdown-menu dropdown-menu-end" aria-labelledby="timelineDropdown">
|
||||
<a class="dropdown-item" href="javascript:void(0);">Cała historia</a>
|
||||
<a class="dropdown-item" href="javascript:void(0);">Pobierz raport (.csv)</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-4 mb-2 pb-0">
|
||||
<ul class="timeline pb-0 mb-0">
|
||||
|
||||
<!-- Element 1 -->
|
||||
<li class="timeline-item timeline-item-transparent border-primary">
|
||||
<span class="timeline-indicator border-0 shadow-none bg-white">
|
||||
<span class="timeline-point timeline-point-primary position-static m-0"></span>
|
||||
</span>
|
||||
<div class="timeline-event">
|
||||
<div class="timeline-header">
|
||||
<h6 class="mb-0">Zaktualizowano uprawnienia grupy</h6>
|
||||
<small class="text-body-secondary">Dzisiaj, 14:30</small>
|
||||
</div>
|
||||
<p class="mt-3">Zmieniono reguły dostępu dla grupy <span
|
||||
class="fw-semibold text-dark">"Kadra kierownicza"</span> w ramach aplikacji
|
||||
<span class="badge bg-label-primary ms-1">invoice.magico</span>.
|
||||
</p>
|
||||
<div class="d-flex align-items-center mt-3">
|
||||
<div class="avatar avatar-xs me-2">
|
||||
<img src="../../assets/img/avatars/1.png" alt="Avatar" class="rounded-circle">
|
||||
</div>
|
||||
<span class="text-dark small fw-semibold">Jan Kowalski (Administrator)</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<!-- Element 2 -->
|
||||
<li class="timeline-item timeline-item-transparent border-primary">
|
||||
<span class="timeline-indicator border-0 shadow-none bg-white">
|
||||
<span class="timeline-point timeline-point-primary position-static m-0"></span>
|
||||
</span>
|
||||
<div class="timeline-event">
|
||||
<div class="timeline-header">
|
||||
<h6 class="mb-0">Nowy członek zespołu</h6>
|
||||
<small class="text-body-secondary">Wczoraj, 09:15</small>
|
||||
</div>
|
||||
<p class="mt-3 mb-3">Anna Nowak zaakceptowała Twoje zaproszenie e-mail i założyła
|
||||
konto w portalu pracowniczym.</p>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<!-- Element 3 -->
|
||||
<li class="timeline-item timeline-item-transparent border-primary">
|
||||
<span class="timeline-indicator border-0 shadow-none bg-white">
|
||||
<span class="timeline-point timeline-point-primary position-static m-0"></span>
|
||||
</span>
|
||||
<div class="timeline-event">
|
||||
<div class="timeline-header">
|
||||
<h6 class="mb-0">Moduł helpdesk aktywny</h6>
|
||||
<small class="text-body-secondary">Poniedziałek, 12:00</small>
|
||||
</div>
|
||||
<p class="mt-3 mb-3">Rozpoczęto naliczanie opłat za nową aplikację <span
|
||||
class="badge bg-label-warning ms-1">helpdesk.magico</span>. Dostęp przyznano dla
|
||||
4 stanowisk.</p>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<!-- Element 4 -->
|
||||
<li class="timeline-item timeline-item-transparent border-transparent pb-0">
|
||||
<span class="timeline-indicator border-0 shadow-none bg-white">
|
||||
<span class="timeline-point timeline-point-primary position-static m-0"></span>
|
||||
</span>
|
||||
<div class="timeline-event pb-0">
|
||||
<div class="timeline-header">
|
||||
<h6 class="mb-0">Wygenerowano nową fakturę VAT</h6>
|
||||
<small class="text-body-secondary">01.03.2026, 06:05</small>
|
||||
</div>
|
||||
<p class="mt-3 mb-0">System przygotował rozliczenie dokumentem <span
|
||||
class="fw-semibold text-primary">5/05/2025</span> za kolejny okres cykliczny.
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card-footer border-top bg-transparent text-center">
|
||||
<a href="javascript:void(0)" class="text-primary btn-link">Załaduj starsze wydarzenia <i
|
||||
class="bx bx-chevron-down"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Prawa kolumna: Skróty i Nowości -->
|
||||
<div class="col-xl-4 col-md-12">
|
||||
|
||||
<!-- Szybkie akcje -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header border-bottom">
|
||||
<h6 class="m-0 text-uppercase fw-bold text-muted" style="letter-spacing: 0.5px;">Szybkie akcje</h6>
|
||||
</div>
|
||||
<div class="card-body pt-3 pb-3">
|
||||
<div class="d-grid gap-2">
|
||||
<a href="app-team.php"
|
||||
class="btn btn-outline-secondary d-flex justify-content-between align-items-center text-start">
|
||||
<span><i class="bx bx-user-plus me-2 text-primary"></i> Zaproś pracownika</span>
|
||||
<i class="bx bx-chevron-right text-muted"></i>
|
||||
</a>
|
||||
<a href="app-billing.php"
|
||||
class="btn btn-outline-secondary d-flex justify-content-between align-items-center text-start">
|
||||
<span><i class="bx bx-credit-card mx-0 me-2 text-primary"></i> Twoje płatności i
|
||||
faktury</span>
|
||||
<i class="bx bx-chevron-right text-muted"></i>
|
||||
</a>
|
||||
<a href="app-services.php"
|
||||
class="btn btn-outline-secondary d-flex justify-content-between align-items-center text-start">
|
||||
<span><i class="bx bx-grid-alt me-2 text-primary"></i> Przeglądaj aplikacje</span>
|
||||
<i class="bx bx-chevron-right text-muted"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Magico News / Baner informacyjny -->
|
||||
<div class="card bg-primary text-white text-center rounded shadow-sm border-0"
|
||||
style="background: linear-gradient(135deg, #696cff 0%, #a481ff 100%);">
|
||||
<div class="card-body py-5">
|
||||
<div class="badge bg-white text-primary mb-3 rounded-pill px-3 py-2 fw-bold shadow-sm">magico
|
||||
roadmap 2026</div>
|
||||
<h5 class="text-white fw-bold mt-2 mb-3">Integracja KSeF gotowa do uruchomienia</h5>
|
||||
<p class="text-white-50 mb-4 px-2">Zabezpiecz procesy fakturowania w swojej firmie przed nowymi
|
||||
regulacjami państwowymi jednym przyciskiem.</p>
|
||||
<a href="#" class="btn btn-white text-primary shadow-sm"><i class="bx bx-book-open me-2"></i>
|
||||
Przeczytaj instrukcję</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="content-backdrop fade"></div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
73
prototype/company/menu.php
Normal file
73
prototype/company/menu.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
$currentPage = basename($_SERVER['PHP_SELF']);
|
||||
?>
|
||||
<aside id="layout-menu" class="layout-menu menu-vertical menu bg-menu-theme">
|
||||
<div class="app-brand demo">
|
||||
<a href="index.php" class="app-brand-link">
|
||||
<span class="app-brand-text demo menu-text fw-bold ms-2">company.magico</span>
|
||||
</a>
|
||||
<a href="javascript:void(0);" class="layout-menu-toggle menu-link text-large ms-auto">
|
||||
<i class="bx bx-chevron-left bx-sm align-middle"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="menu-inner-shadow"></div>
|
||||
|
||||
<ul class="menu-inner py-1">
|
||||
|
||||
<!-- Zarządzanie firmą -->
|
||||
<li class="menu-header small text-uppercase">
|
||||
<span class="menu-header-text" data-i18n="Zarządzanie firmą">Zarządzanie firmą</span>
|
||||
</li>
|
||||
|
||||
<li class="menu-item <?php echo ($currentPage == 'index.php') ? 'active' : ''; ?>">
|
||||
<a href="index.php" class="menu-link">
|
||||
<i class="menu-icon tf-icons bx bx-home-circle"></i>
|
||||
<div class="text-truncate" data-i18n="Kokpit">Kokpit</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu-item <?php echo ($currentPage == 'app-services.php') ? 'active' : ''; ?>">
|
||||
<a href="app-services.php" class="menu-link">
|
||||
<i class="menu-icon tf-icons bx bx-grid-alt"></i>
|
||||
<div class="text-truncate" data-i18n="Usługi i aplikacje">Usługi i aplikacje</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu-item <?php echo ($currentPage == 'app-billing.php') ? 'active' : ''; ?>">
|
||||
<a href="app-billing.php" class="menu-link">
|
||||
<i class="menu-icon tf-icons bx bx-receipt"></i>
|
||||
<div class="text-truncate" data-i18n="Rozliczenia">Rozliczenia</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu-item <?php echo ($currentPage == 'app-company-info.php') ? 'active' : ''; ?>">
|
||||
<a href="app-company-info.php" class="menu-link">
|
||||
<i class="menu-icon tf-icons bx bx-buildings"></i>
|
||||
<div class="text-truncate" data-i18n="Informacje o firmie">Informacje o firmie</div>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<!-- Zarządzanie zespołem -->
|
||||
<li class="menu-header small text-uppercase">
|
||||
<span class="menu-header-text" data-i18n="Zarządzanie zespołem">Zarządzanie zespołem</span>
|
||||
</li>
|
||||
|
||||
<li class="menu-item <?php echo ($currentPage == 'app-team.php') ? 'active' : ''; ?>">
|
||||
<a href="app-team.php" class="menu-link">
|
||||
<i class="menu-icon tf-icons bx bx-group"></i>
|
||||
<div class="text-truncate" data-i18n="Zespół">Zespół</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu-item <?php echo ($currentPage == 'app-groups.php') ? 'active' : ''; ?>">
|
||||
<a href="app-groups.php" class="menu-link">
|
||||
<i class="menu-icon tf-icons bx bx-sitemap"></i>
|
||||
<div class="text-truncate" data-i18n="Grupy">Grupy uprawnień</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu-item <?php echo ($currentPage == 'app-permissions.php') ? 'active' : ''; ?>">
|
||||
<a href="app-permissions.php" class="menu-link">
|
||||
<i class="menu-icon tf-icons bx bx-shield-quarter"></i>
|
||||
<div class="text-truncate" data-i18n="Uprawnienia">Uprawnienia</div>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</aside>
|
||||
20
prototype/invoice/app-contractors-list.php
Normal file
20
prototype/invoice/app-contractors-list.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
$enablePrototypeComments = false;
|
||||
include '../../header-invoice.php';
|
||||
?>
|
||||
|
||||
<div class="container-xxl flex-grow-1 container-p-y d-flex flex-column justify-content-center">
|
||||
<div class="card p-0 mb-4 h-100 mt-5 border-0 shadow-sm" style="min-height: 400px;">
|
||||
<div class="card-body d-flex flex-column justify-content-center align-items-center p-5 text-center">
|
||||
<h1 class="display-1 text-primary mb-4"><i class="bx bx-group"></i></h1>
|
||||
<h3 class="mb-2">Moduł "Kontrahenci" pojawi się wkrótce!</h3>
|
||||
<p class="text-muted mb-4 fs-5">
|
||||
Obecnie intensywnie pracujemy nad nowymi funkcjonalnościami dla tego modułu.<br>
|
||||
Zaglądaj tu regularnie, aby być na bieżąco z nowościami!
|
||||
</p>
|
||||
<a href="index.php" class="btn btn-primary btn-lg mt-3">Wróć na Kokpit</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
552
prototype/invoice/app-invoice-add.php
Normal file
552
prototype/invoice/app-invoice-add.php
Normal file
@@ -0,0 +1,552 @@
|
||||
<?php
|
||||
$enablePrototypeComments = false;
|
||||
include '../../header-invoice.php';
|
||||
?>
|
||||
|
||||
|
||||
<div class="container-fluid flex-grow-1 container-p-y">
|
||||
|
||||
<div
|
||||
class="d-flex flex-column flex-md-row justify-content-between align-items-start align-items-md-center mb-4 gap-3">
|
||||
<div class="d-flex flex-column justify-content-center">
|
||||
<h4 class="mb-1 text-body">Nowa Faktura</h4>
|
||||
<p class="text-muted mb-0">Wypełnij dane dokumentu</p>
|
||||
</div>
|
||||
<div class="d-flex align-content-center flex-wrap gap-2">
|
||||
<a href="app-invoice-list.php" class="btn btn-label-secondary">Anuluj</a>
|
||||
<button type="submit" form="invoiceForm" class="btn btn-primary"><i class="bx bx-save me-1"></i> Zapisz
|
||||
fakturę</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form id="invoiceForm" onsubmit="return false">
|
||||
|
||||
<div class="row mb-4">
|
||||
|
||||
<div class="col-lg-4 col-md-6 mb-3 mb-lg-0">
|
||||
<div class="card h-100">
|
||||
<div class="card-header border-bottom py-3">
|
||||
<h6 class="card-title m-0"><i class="bx bx-store me-2"></i>Sprzedawca</h6>
|
||||
</div>
|
||||
<div class="card-body pt-3">
|
||||
<div class="card shadow-none bg-lighter border mb-3">
|
||||
<div class="card-body p-3">
|
||||
<p class="mb-1 fw-bold">Magico Software sp. z o.o.</p>
|
||||
<p class="mb-1">Przemysłowa 11</p>
|
||||
<p class="mb-1">37-450 Stalowa Wola</p>
|
||||
<p class="mb-0">NIP: PL 865 258 23 86</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Miejscowość</label>
|
||||
<input type="text" class="form-control" value="Stalowa Wola">
|
||||
</div>
|
||||
<div class="mb-0">
|
||||
<label class="form-label">Wystawił</label>
|
||||
<input type="text" class="form-control" value="Bartłomiej Banaczyk">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4 col-md-6 mb-3 mb-lg-0">
|
||||
<div class="card h-100">
|
||||
<div class="card-header border-bottom py-3">
|
||||
<h6 class="card-title m-0"><i class="bx bx-user me-2"></i>Kontrahent</h6>
|
||||
</div>
|
||||
<div class="card-body pt-3">
|
||||
<div class="card shadow-none border mb-3 position-relative">
|
||||
<div class="card-body p-3 d-flex justify-content-between align-items-center"
|
||||
style="min-height: 105px;">
|
||||
<i class="text-muted">Wybierz kontrahenta z listy...</i>
|
||||
<button class="btn btn-outline-primary btn-sm position-absolute end-0 top-0 m-2"><i
|
||||
class="bx bx-search"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column gap-2 mb-3">
|
||||
<label class="form-check form-switch m-0">
|
||||
<input class="form-check-input" type="checkbox" id="descToggle">
|
||||
<span class="form-check-label text-muted">Dodatkowy opis kontrahenta</span>
|
||||
</label>
|
||||
<label class="form-check form-switch m-0">
|
||||
<input class="form-check-input" type="checkbox" id="recipientToggle">
|
||||
<span class="form-check-label text-muted">Odbiorca</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="mb-0">
|
||||
<label class="form-label">Odebrał</label>
|
||||
<input type="text" class="form-control" placeholder="Imię i nazwisko">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4 col-12">
|
||||
<div class="card h-100">
|
||||
<div class="card-header border-bottom py-3">
|
||||
<h6 class="card-title m-0"><i class="bx bx-cog me-2"></i>Ustawienia Dokumentu</h6>
|
||||
</div>
|
||||
<div class="card-body pt-3">
|
||||
<div class="row g-2 mb-3">
|
||||
<div class="col-6">
|
||||
<label class="form-label small text-uppercase fw-bold text-muted">Data wyst.</label>
|
||||
<input type="text" class="form-control date-picker" value="2026-02-17">
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="form-label small text-uppercase fw-bold text-muted">Data dostawy</label>
|
||||
<input type="text" class="form-control date-picker" value="2026-02-17">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-2 mb-3">
|
||||
<div class="col-6">
|
||||
<label class="form-label small text-uppercase fw-bold text-muted">Termin</label>
|
||||
<input type="text" class="form-control date-picker" value="2026-02-24">
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="form-label small text-uppercase fw-bold text-muted"> </label>
|
||||
<select class="form-select">
|
||||
<option value="7">7 dni</option>
|
||||
<option value="14">14 dni</option>
|
||||
<option value="30">30 dni</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-2 mb-3">
|
||||
<div class="col-6">
|
||||
<label class="form-label">Płatność</label>
|
||||
<select class="form-select">
|
||||
<option value="przelew">Przelew</option>
|
||||
<option value="gotowka">Gotówka</option>
|
||||
<option value="karta">Karta</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<label class="form-check form-switch m-0">
|
||||
<input class="form-check-input" type="checkbox" id="odsetki">
|
||||
<span class="form-check-label">Naliczaj odsetki</span>
|
||||
</label>
|
||||
<label class="form-check form-switch m-0">
|
||||
<input class="form-check-input" type="checkbox" checked>
|
||||
<span class="form-check-label">Wyświetl w panelu klienta</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-label-primary py-2 d-flex justify-content-between align-items-center">
|
||||
<span class="fw-bold">Pozycje na fakturze</span>
|
||||
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<div class="d-flex align-items-center">
|
||||
<label class="text-muted small me-2 text-nowrap">Licz od:</label>
|
||||
<select class="form-select form-select-sm" style="width: auto;">
|
||||
<option value="brutto">Brutto</option>
|
||||
<option value="netto">Netto</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th style="width: 40px;" class="text-center">Lp</th>
|
||||
<th style="min-width: 250px;">Towar / Usługa</th>
|
||||
<th style="width: 120px;">Kod</th>
|
||||
<th style="width: 90px;">JM</th>
|
||||
<th style="width: 100px;">Ilość</th>
|
||||
<th style="width: 130px;">Cena Netto</th>
|
||||
<th style="width: 100px;">VAT</th>
|
||||
<th style="width: 130px;" class="text-end">Wartość Netto</th>
|
||||
<th style="width: 130px;" class="text-end">Wartość Brutto</th>
|
||||
<th style="width: 50px;"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="align-middle text-center text-muted">1</td>
|
||||
<td class="p-2 align-middle">
|
||||
<div class="input-group input-group-merge border-0 shadow-none">
|
||||
<input type="text" class="form-control border-0 shadow-none fw-medium ps-0"
|
||||
placeholder="Wpisz nazwę towaru lub usługi..." value="">
|
||||
<span class="input-group-text border-0 ps-1 pe-0"
|
||||
style="background: transparent;">
|
||||
<button type="button" class="btn btn-icon btn-sm btn-label-secondary"
|
||||
data-bs-toggle="modal" data-bs-target="#searchProductModal"
|
||||
data-bs-toggle="tooltip" data-bs-placement="top" title="Wyszukaj">
|
||||
<i class="bx bx-search"></i>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="p-2">
|
||||
<input type="text" class="form-control border-0 shadow-none text-muted"
|
||||
placeholder="Kod">
|
||||
</td>
|
||||
<td class="p-2">
|
||||
<select class="form-select border-0 shadow-none px-1">
|
||||
<option value="szt">szt.</option>
|
||||
<option value="usl">usł.</option>
|
||||
<option value="godz">godz.</option>
|
||||
</select>
|
||||
</td>
|
||||
<td class="p-2">
|
||||
<input type="number" class="form-control border-0 shadow-none text-center fw-bold"
|
||||
value="1" step="0.01">
|
||||
</td>
|
||||
<td class="p-2">
|
||||
<input type="number" class="form-control border-0 shadow-none text-end" value="0.00"
|
||||
step="0.01">
|
||||
</td>
|
||||
<td class="p-2">
|
||||
<select class="form-select border-0 shadow-none px-1">
|
||||
<option value="23">23%</option>
|
||||
<option value="8">8%</option>
|
||||
<option value="5">5%</option>
|
||||
<option value="0">0%</option>
|
||||
<option value="zw">ZW</option>
|
||||
</select>
|
||||
</td>
|
||||
<td class="align-middle text-end pe-3 bg-lighter">0,00 zł</td>
|
||||
<td class="align-middle text-end pe-3 bg-lighter fw-bold">0,00 zł</td>
|
||||
<td class="align-middle text-center p-2">
|
||||
<button class="btn btn-icon btn-sm btn-label-danger"><i
|
||||
class="bx bx-trash"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="align-middle text-center text-muted">2</td>
|
||||
<td class="p-2"><input type="text" class="form-control border-0 shadow-none"
|
||||
placeholder="..."></td>
|
||||
<td class="p-2"><input type="text" class="form-control border-0 shadow-none"></td>
|
||||
<td class="p-2"><select class="form-select border-0 shadow-none px-1">
|
||||
<option>szt.</option>
|
||||
</select></td>
|
||||
<td class="p-2"><input type="number"
|
||||
class="form-control border-0 shadow-none text-center" value="1"></td>
|
||||
<td class="p-2"><input type="number" class="form-control border-0 shadow-none text-end"
|
||||
value="0.00"></td>
|
||||
<td class="p-2"><select class="form-select border-0 shadow-none px-1">
|
||||
<option>23%</option>
|
||||
</select></td>
|
||||
<td class="align-middle text-end pe-3 bg-lighter">0,00 zł</td>
|
||||
<td class="align-middle text-end pe-3 bg-lighter">0,00 zł</td>
|
||||
<td class="align-middle text-center p-2">
|
||||
<button class="btn btn-icon btn-sm btn-label-danger"><i
|
||||
class="bx bx-trash"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="border-top p-3 text-end bg-light">
|
||||
<button class="btn btn-primary btn-sm"><i class="bx bx-plus me-1"></i> Dodaj kolejną
|
||||
pozycję</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-lg-7 mb-4 mb-lg-0">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-end mb-4">
|
||||
<div class="me-3 flex-grow-1" style="max-width: 250px;">
|
||||
<label class="form-label fw-bold">Zapłacono:</label>
|
||||
<div class="input-group">
|
||||
<input type="number" class="form-control" value="0.00">
|
||||
<span class="input-group-text">PLN</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-outline-primary">Rozlicz całość</button>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label ">Uwagi do dokumentu</label>
|
||||
<textarea class="form-control" rows="3"
|
||||
placeholder="Wpisz uwagi widoczne na fakturze..."></textarea>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row g-2 mb-3">
|
||||
<div class="col-4">
|
||||
<label class="form-label d-flex align-items-center">
|
||||
Język faktury
|
||||
<i class="bx bx-info-circle ms-1 fs-6 text-muted" data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
title="Określa język wydruku dokumentu. Standardowe nagłówki i etykiety zostaną przetłumaczone automatycznie.">
|
||||
</i>
|
||||
</label>
|
||||
<select class="form-select">
|
||||
<option value="pl">Polski</option>
|
||||
<option value="en">Angielski</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-4">
|
||||
<label class="form-label d-flex align-items-center">
|
||||
Waluta podstawowa
|
||||
<i class="bx bx-info-circle ms-1 fs-6 text-muted" data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
title="Główna waluta transakcji i kwoty do zapłaty. Jest to waluta wiążąca dla wysyłki do KSeF.">
|
||||
</i>
|
||||
</label>
|
||||
<select class="form-select">
|
||||
<option value="PLN">PLN</option>
|
||||
<option value="EUR">EUR</option>
|
||||
<option value="USD">USD</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-4">
|
||||
<label class="form-label d-flex align-items-center">
|
||||
Oryginalna waluta
|
||||
<i class="bx bx-info-circle ms-1 fs-6 text-muted" data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
title="Służy do celów księgowych (np. przeliczenie VAT). Jeśli różni się od podstawowej, faktura wyświetli kwoty w dwóch walutach. Do KSeF trafia tylko waluta podstawowa.">
|
||||
</i>
|
||||
</label>
|
||||
<select class="form-select">
|
||||
<option value="PLN">PLN</option>
|
||||
<option value="EUR">EUR</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-5">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title mb-4">Podsumowanie</h6>
|
||||
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span class="text-muted">Suma Netto:</span>
|
||||
<span class="fw-semibold">0,00 zł</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-3 border-bottom pb-2">
|
||||
<span class="text-muted">Suma VAT:</span>
|
||||
<span class="fw-semibold">0,00 zł</span>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<span class="h5 mb-0">Do zapłaty:</span>
|
||||
<span class="h4 mb-0 text-primary">0,00 zł</span>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-warning d-flex align-items-start align-items-sm-center mb-0"
|
||||
role="alert">
|
||||
<i class="bx bx-bell me-2 fs-4 mt-1 mt-sm-0"></i>
|
||||
<div class="small">
|
||||
<strong>Status: Nierozliczona.</strong> Funkcja automatycznych przypomnień jest aktywna.
|
||||
Twój kontrahent otrzyma powiadomienie, gdy minie termin płatności.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
<div class="content-backdrop fade"></div>
|
||||
|
||||
<!-- Modal Wyszukiwania Produktu -->
|
||||
<div class="modal fade" id="searchProductModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="modalCenterTitle">Wyszukaj towar lub usługę</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row mb-3">
|
||||
<div class="col-12 text-center">
|
||||
<div class="btn-group" role="group" aria-label="Database toggle">
|
||||
<button type="button" class="btn btn-label-primary active" data-bs-toggle="button"
|
||||
aria-pressed="true">Towary i usługi</button>
|
||||
<button type="button" class="btn btn-label-primary active" data-bs-toggle="button"
|
||||
aria-pressed="true">sync.magico</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="input-group input-group-merge">
|
||||
<span class="input-group-text" id="basic-addon-search31"><i class="bx bx-search"></i></span>
|
||||
<input type="text" class="form-control form-control-lg" id="productSearchInput"
|
||||
placeholder="Wpisz szukaną frazę..." aria-label="Search..."
|
||||
aria-describedby="basic-addon-search31">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive" style="max-height: 400px; overflow-y: auto;">
|
||||
<table class="table table-hover" id="productSearchTable">
|
||||
<thead class="table-light sticky-top">
|
||||
<tr>
|
||||
<th>Nazwa</th>
|
||||
<th style="width: 100px;">Jednostka</th>
|
||||
<th style="width: 120px;" class="text-end">Cena netto</th>
|
||||
<th style="width: 80px;"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- Mock Data -->
|
||||
<tr>
|
||||
<td>
|
||||
<span class="fw-medium">Usługa programistyczna</span>
|
||||
<small class="text-muted d-block">Kod: O-001</small>
|
||||
</td>
|
||||
<td>godz.</td>
|
||||
<td class="text-end">150,00 zł</td>
|
||||
<td class="text-end">
|
||||
<button class="btn btn-sm btn-primary" data-bs-dismiss="modal">Wybierz</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span class="fw-medium">Hosting WWW - Pakiet Standard</span>
|
||||
<small class="text-muted d-block">Kod: U-002</small>
|
||||
</td>
|
||||
<td>szt.</td>
|
||||
<td class="text-end">300,00 zł</td>
|
||||
<td class="text-end">
|
||||
<button class="btn btn-sm btn-primary" data-bs-dismiss="modal">Wybierz</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span class="fw-medium">Domena .pl (odnowienie)</span>
|
||||
<small class="text-muted d-block">Kod: D-003</small>
|
||||
</td>
|
||||
<td>szt.</td>
|
||||
<td class="text-end">100,00 zł</td>
|
||||
<td class="text-end">
|
||||
<button class="btn btn-sm btn-primary" data-bs-dismiss="modal">Wybierz</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span class="fw-medium">Certyfikat SSL (roczny)</span>
|
||||
<small class="text-muted d-block">Kod: S-004</small>
|
||||
</td>
|
||||
<td>szt.</td>
|
||||
<td class="text-end">150,00 zł</td>
|
||||
<td class="text-end">
|
||||
<button class="btn btn-sm btn-primary" data-bs-dismiss="modal">Wybierz</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span class="fw-medium">Audyt bezpieczeństwa aplikacji</span>
|
||||
<small class="text-muted d-block">Kod: A-005</small>
|
||||
</td>
|
||||
<td>usł.</td>
|
||||
<td class="text-end">2 500,00 zł</td>
|
||||
<td class="text-end">
|
||||
<button class="btn btn-sm btn-primary" data-bs-dismiss="modal">Wybierz</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span class="fw-medium">Konsultacje techniczne</span>
|
||||
<small class="text-muted d-block">Kod: K-006</small>
|
||||
</td>
|
||||
<td>godz.</td>
|
||||
<td class="text-end">200,00 zł</td>
|
||||
<td class="text-end">
|
||||
<button class="btn btn-sm btn-primary" data-bs-dismiss="modal">Wybierz</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span class="fw-medium">Projekt graficzny strony www</span>
|
||||
<small class="text-muted d-block">Kod: P-007</small>
|
||||
</td>
|
||||
<td>usł.</td>
|
||||
<td class="text-end">3 000,00 zł</td>
|
||||
<td class="text-end">
|
||||
<button class="btn btn-sm btn-primary" data-bs-dismiss="modal">Wybierz</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span class="fw-medium">Administracja serwerem (abonament)</span>
|
||||
<small class="text-muted d-block">Kod: M-008</small>
|
||||
</td>
|
||||
<td>m-c</td>
|
||||
<td class="text-end">500,00 zł</td>
|
||||
<td class="text-end">
|
||||
<button class="btn btn-sm btn-primary" data-bs-dismiss="modal">Wybierz</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- <div class="modal-footer">
|
||||
<button type="button" class="btn btn-label-secondary" data-bs-dismiss="modal">Zamknij</button>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// Inicjalizacja Datepickerów
|
||||
if (typeof flatpickr !== 'undefined') {
|
||||
document.querySelectorAll('.date-picker').forEach(picker => {
|
||||
flatpickr(picker, { dateFormat: 'Y-m-d' });
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// Search Filter
|
||||
const searchInput = document.getElementById('productSearchInput');
|
||||
const table = document.getElementById('productSearchTable');
|
||||
const rows = table.getElementsByTagName('tr');
|
||||
|
||||
searchInput.addEventListener('keyup', function () {
|
||||
const filter = searchInput.value.toLowerCase();
|
||||
for (let i = 1; i < rows.length; i++) {
|
||||
const row = rows[i];
|
||||
const cells = row.getElementsByTagName('td');
|
||||
let found = false;
|
||||
if (cells.length > 0) {
|
||||
const name = cells[0].textContent.toLowerCase();
|
||||
if (name.indexOf(filter) > -1) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
row.style.display = found ? '' : 'none';
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
902
prototype/invoice/app-invoice-list.php
Normal file
902
prototype/invoice/app-invoice-list.php
Normal file
@@ -0,0 +1,902 @@
|
||||
<?php
|
||||
$enablePrototypeComments = false;
|
||||
include '../../header-invoice.php';
|
||||
?>
|
||||
|
||||
<div class="container-fluid flex-grow-1 container-p-y">
|
||||
|
||||
<h4 class="py-3 mb-4">
|
||||
<span class="text-muted fw-light">Sprzedaż /</span> Faktury VAT
|
||||
</h4>
|
||||
|
||||
<div class="d-flex mb-3 gap-2 align-items-center flex-nowrap overflow-auto pb-2">
|
||||
<a href="app-invoice-list.php" class="btn btn-label-primary text-nowrap">
|
||||
<i class="bx bx-check-circle me-1"></i> Faktury VAT
|
||||
</a>
|
||||
<a href="app-invoice-list-vat-margin.php" class="btn btn-label-secondary text-nowrap">
|
||||
Faktura VAT marża
|
||||
</a>
|
||||
<a href="#" class="btn btn-label-secondary text-nowrap">
|
||||
Proformy
|
||||
</a>
|
||||
<a href="#" class="btn btn-label-secondary text-nowrap">
|
||||
Zaliczkowe
|
||||
</a>
|
||||
<a href="#" class="btn btn-label-secondary text-nowrap">
|
||||
Korekty
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-lg-9" id="invoice-list-col">
|
||||
<div class="card">
|
||||
<div
|
||||
class="card-header border-bottom d-flex justify-content-between align-items-center flex-wrap gap-2">
|
||||
|
||||
<div class="me-2">
|
||||
<div class="input-group input-group-merge">
|
||||
<span class="input-group-text" id="basic-addon-search31"><i class="bx bx-search"></i></span>
|
||||
<input type="text" class="form-control" placeholder="Wpisz aby wyszukać"
|
||||
aria-label="Search..." aria-describedby="basic-addon-search31">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
|
||||
<div class="dropdown">
|
||||
<button type="button" class="btn btn-label-secondary p-2" data-bs-toggle="dropdown"
|
||||
aria-expanded="false">
|
||||
<i class="bx bx-cog"></i>
|
||||
</button>
|
||||
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li>
|
||||
<h6 class="dropdown-header">Widoczność kolumn</h6>
|
||||
</li>
|
||||
<li>
|
||||
<div class="dropdown-item">
|
||||
<div class="form-check"><input class="form-check-input" type="checkbox" checked>
|
||||
<label class="form-check-label">Numer faktury</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="dropdown-item">
|
||||
<div class="form-check"><input class="form-check-input" type="checkbox" checked>
|
||||
<label class="form-check-label">Kontrahent</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="dropdown-item">
|
||||
<div class="form-check"><input class="form-check-input" type="checkbox" checked>
|
||||
<label class="form-check-label">Kwota Netto</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-label-secondary d-flex align-items-center gap-2"
|
||||
id="filter-toggle-btn">
|
||||
<i class="bx bx-filter-alt"></i> Filtry (2)
|
||||
</button>
|
||||
|
||||
<select class="form-select" style="width: 80px;">
|
||||
<option value="40">40</option>
|
||||
<option value="60">60</option>
|
||||
<option value="100">100</option>
|
||||
</select>
|
||||
|
||||
<a href="app-invoice-add.php" class="btn btn-primary">
|
||||
<i class="bx bx-plus me-1"></i> <span class="d-none d-sm-inline-block">Utwórz fakturę</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive text-nowrap" style="min-height: 400px;">
|
||||
<table class="table table-hover table-striped">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th style="width: 50px;">#</th>
|
||||
<th>Numer faktury</th>
|
||||
<th>Kontrahent</th>
|
||||
<th>Data wyst.</th>
|
||||
<th>Termin</th>
|
||||
<th class="text-end">Netto</th>
|
||||
<th class="text-end">Brutto</th>
|
||||
<th class="text-end">Do zapłaty</th>
|
||||
<th class="text-center">Akcje</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="table-border-bottom-0">
|
||||
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td><a href="app-invoice-preview.php">FV/18/02/2026/MS</a></td>
|
||||
<td>
|
||||
<div class="d-flex justify-content-start align-items-center">
|
||||
<div class="d-flex flex-column">
|
||||
<span class="text-heading text-truncate fw-medium"
|
||||
style="max-width: 200px;">Adam Malicki</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>2026-02-16</td>
|
||||
<td>2026-02-16</td>
|
||||
<td class="text-end">900,00 zł</td>
|
||||
<td class="text-end">1107,00 zł</td>
|
||||
<td class="text-end">0,00 zł</td>
|
||||
<td class="text-center">
|
||||
<div class="d-flex justify-content-center align-items-center gap-1">
|
||||
<span class="badge badge-dot bg-secondary me-1"
|
||||
title="KSeF: Nie wysłano"></span> <a href="#"
|
||||
class="btn btn-icon btn-sm text-success" title="Wyślij e-mail"><i
|
||||
class="bx bx-send"></i></a>
|
||||
<a href="javascript:void(0);" data-bs-toggle="modal"
|
||||
data-bs-target="#invoicePreviewModal"
|
||||
class="btn btn-icon btn-sm text-secondary" title="Podgląd"><i
|
||||
class="bx bx-show"></i></a>
|
||||
<div class="dropdown">
|
||||
<button type="button" class="btn p-0 dropdown-toggle hide-arrow"
|
||||
data-bs-toggle="dropdown">
|
||||
<i class="bx bx-dots-vertical-rounded"></i>
|
||||
</button>
|
||||
<div class="dropdown-menu dropdown-menu-end">
|
||||
|
||||
<a class="dropdown-item" href="app-invoice-edit.php">
|
||||
<i class="bx bx-edit-alt me-1"></i> Edytuj
|
||||
</a>
|
||||
<a class="dropdown-item" href="#">
|
||||
<i class="bx bx-show me-1"></i> Podgląd
|
||||
</a>
|
||||
<a class="dropdown-item" href="#" target="_blank">
|
||||
<i class="bx bx-printer me-1"></i> Drukuj (PDF)
|
||||
</a>
|
||||
|
||||
<div class="dropdown-divider"></div>
|
||||
|
||||
<h6 class="dropdown-header text-uppercase ps-3">Finanse</h6>
|
||||
<a class="dropdown-item" href="#">
|
||||
<i class="bx bx-money me-1"></i> Rozlicz fakturę
|
||||
</a>
|
||||
<a class="dropdown-item" href="#">
|
||||
<i class="bx bx-revision me-1"></i> Wystaw korektę
|
||||
</a>
|
||||
|
||||
<div class="dropdown-divider"></div>
|
||||
|
||||
<h6 class="dropdown-header text-uppercase ps-3">Wysyłka</h6>
|
||||
<a class="dropdown-item d-flex justify-content-between align-items-center"
|
||||
href="#">
|
||||
<span>
|
||||
<i class="bx bx-cloud-upload me-1"></i> Wyślij do KSeF
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<!-- Przykład, kiedy pozycja jest już wysłana -->
|
||||
<a class="dropdown-item d-flex justify-content-between align-items-center"
|
||||
href="#">
|
||||
<span><i class="bx bx-envelope me-1"></i> Wyślij fakturę</span>
|
||||
<span data-bs-toggle="tooltip" data-bs-placement="top"
|
||||
title="Wysłano: 2026-02-16 10:30" class="ms-2">
|
||||
<i class="bx bx-check-circle text-success"></i>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<a class="dropdown-item d-flex justify-content-between align-items-center"
|
||||
href="#">
|
||||
<span>
|
||||
<i class="bx bx-check-shield me-1"></i> Wyślij potwierdzenie
|
||||
</span>
|
||||
<span data-bs-toggle="tooltip" data-bs-placement="top"
|
||||
title="Wysłano: 2026-02-16 10:30" class="ms-2">
|
||||
<i class="bx bx-check-circle text-success"></i>
|
||||
</span>
|
||||
</a>
|
||||
<a class="dropdown-item d-flex justify-content-between align-items-center"
|
||||
href="#">
|
||||
<span>
|
||||
<i class="bx bx-bell me-1 text-warning"></i> Wyślij ponaglenie
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<div class="dropdown-divider"></div>
|
||||
|
||||
<a class="dropdown-item" href="#">
|
||||
<i class="bx bx-duplicate me-1"></i> Duplikuj jako nową
|
||||
</a>
|
||||
<a class="dropdown-item text-danger" href="#">
|
||||
<i class="bx bx-trash me-1"></i> Usuń fakturę
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>2</td>
|
||||
<td><a href="app-invoice-preview.php">FV/17/02/2026/MS</a></td>
|
||||
<td>
|
||||
<span class="text-heading text-truncate fw-medium" style="max-width: 200px;">Gmina
|
||||
Nowa Sarzyna</span>
|
||||
</td>
|
||||
<td>2026-02-14</td>
|
||||
<td><span class="text-danger">2026-03-01</span></td>
|
||||
<td class="text-end">400,00 zł</td>
|
||||
<td class="text-end">492,00 zł</td>
|
||||
<td class="text-end text-danger">492,00 zł</td>
|
||||
<td class="text-center">
|
||||
<div class="d-flex justify-content-center align-items-center gap-1">
|
||||
<span class="badge badge-dot bg-secondary me-1"
|
||||
title="KSeF: Nie wysłano"></span>
|
||||
<a href="#" class="btn btn-icon btn-sm text-secondary" title="Wyślij e-mail"><i
|
||||
class="bx bx-send"></i></a>
|
||||
<a href="javascript:void(0);" data-bs-toggle="modal"
|
||||
data-bs-target="#invoicePreviewModal"
|
||||
class="btn btn-icon btn-sm text-secondary" title="Podgląd"><i
|
||||
class="bx bx-show"></i></a>
|
||||
<div class="dropdown">
|
||||
<button type="button" class="btn btn-sm p-0 dropdown-toggle hide-arrow"
|
||||
data-bs-toggle="dropdown"><i
|
||||
class="bx bx-dots-vertical-rounded"></i></button>
|
||||
<div class="dropdown-menu dropdown-menu-end">
|
||||
<a class="dropdown-item" href="javascript:void(0);"><i
|
||||
class="bx bx-money me-1"></i> Rozlicz</a>
|
||||
<a class="dropdown-item" href="javascript:void(0);"><i
|
||||
class="bx bx-envelope me-1"></i> Wyślij ponaglenie</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>3</td>
|
||||
<td><a href="app-invoice-preview.php">FV/16/02/2026/MS</a></td>
|
||||
<td>
|
||||
<i class="bx bx-note text-warning me-1" title="Adres spoza bazy (custom)"></i>
|
||||
<span class="text-heading text-truncate fw-medium"
|
||||
style="max-width: 200px;">PROFIMED GABINET...</span>
|
||||
</td>
|
||||
<td>2026-02-13</td>
|
||||
<td>2026-02-20</td>
|
||||
<td class="text-end">960,00 zł</td>
|
||||
<td class="text-end">1180,80 zł</td>
|
||||
<td class="text-end text-danger">1180,80 zł</td>
|
||||
<td class="text-center">
|
||||
<div class="d-flex justify-content-center align-items-center gap-1">
|
||||
<span class="badge badge-dot bg-success me-1" title="KSeF: Wysłano"></span>
|
||||
<a href="#" class="btn btn-icon btn-sm text-secondary"><i
|
||||
class="bx bx-send"></i></a>
|
||||
<a href="javascript:void(0);" data-bs-toggle="modal"
|
||||
data-bs-target="#invoicePreviewModal"
|
||||
class="btn btn-icon btn-sm text-secondary"><i class="bx bx-show"></i></a>
|
||||
<div class="dropdown">
|
||||
<button type="button" class="btn btn-sm p-0 dropdown-toggle hide-arrow"
|
||||
data-bs-toggle="dropdown"><i
|
||||
class="bx bx-dots-vertical-rounded"></i></button>
|
||||
<div class="dropdown-menu dropdown-menu-end">
|
||||
<a class="dropdown-item" href="javascript:void(0);"><i
|
||||
class="bx bx-edit-alt me-1"></i> Edytuj</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>4</td>
|
||||
<td><a href="app-invoice-preview.php">FV/15/02/2026/MS</a></td>
|
||||
<td>
|
||||
<div class="d-flex justify-content-start align-items-center">
|
||||
<div class="d-flex flex-column">
|
||||
<span class="text-heading text-truncate fw-medium"
|
||||
style="max-width: 200px;">TechSolutions Sp. z o.o.</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>2026-02-12</td>
|
||||
<td>2026-02-26</td>
|
||||
<td class="text-end">2 500,00 zł</td>
|
||||
<td class="text-end">3 075,00 zł</td>
|
||||
<td class="text-end text-danger">3 075,00 zł</td>
|
||||
<td class="text-center">
|
||||
<div class="d-flex justify-content-center align-items-center gap-1">
|
||||
<span class="badge badge-dot bg-secondary me-1"
|
||||
title="KSeF: Nie wysłano"></span> <a href="#"
|
||||
class="btn btn-icon btn-sm text-success" title="Wyślij e-mail"><i
|
||||
class="bx bx-send"></i></a>
|
||||
<a href="javascript:void(0);" data-bs-toggle="modal"
|
||||
data-bs-target="#invoicePreviewModal"
|
||||
class="btn btn-icon btn-sm text-secondary" title="Podgląd"><i
|
||||
class="bx bx-show"></i></a>
|
||||
<div class="dropdown">
|
||||
<button type="button" class="btn btn-sm p-0 dropdown-toggle hide-arrow"
|
||||
data-bs-toggle="dropdown"><i
|
||||
class="bx bx-dots-vertical-rounded"></i></button>
|
||||
<div class="dropdown-menu dropdown-menu-end">
|
||||
<a class="dropdown-item" href="app-invoice-edit.php"><i
|
||||
class="bx bx-edit-alt me-1"></i> Edytuj</a>
|
||||
<a class="dropdown-item" href="javascript:void(0);"><i
|
||||
class="bx bx-printer me-1"></i> Drukuj</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item text-danger" href="javascript:void(0);"><i
|
||||
class="bx bx-trash me-1"></i> Usuń</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>5</td>
|
||||
<td><a href="app-invoice-preview.php">FV/14/02/2026/MS</a></td>
|
||||
<td>
|
||||
<span class="text-heading text-truncate fw-medium" style="max-width: 200px;">Jan
|
||||
Kowalski Usługi</span>
|
||||
</td>
|
||||
<td>2026-02-10</td>
|
||||
<td>2026-02-24</td>
|
||||
<td class="text-end">150,00 zł</td>
|
||||
<td class="text-end">184,50 zł</td>
|
||||
<td class="text-end">0,00 zł</td>
|
||||
<td class="text-center">
|
||||
<div class="d-flex justify-content-center align-items-center gap-1">
|
||||
<span class="badge badge-dot bg-success me-1" title="KSeF: Wysłano"></span>
|
||||
<a href="#" class="btn btn-icon btn-sm text-secondary" title="Wyślij e-mail"><i
|
||||
class="bx bx-send"></i></a>
|
||||
<a href="javascript:void(0);" data-bs-toggle="modal"
|
||||
data-bs-target="#invoicePreviewModal"
|
||||
class="btn btn-icon btn-sm text-secondary" title="Podgląd"><i
|
||||
class="bx bx-show"></i></a>
|
||||
<div class="dropdown">
|
||||
<button type="button" class="btn btn-sm p-0 dropdown-toggle hide-arrow"
|
||||
data-bs-toggle="dropdown"><i
|
||||
class="bx bx-dots-vertical-rounded"></i></button>
|
||||
<div class="dropdown-menu dropdown-menu-end">
|
||||
<a class="dropdown-item" href="javascript:void(0);"><i
|
||||
class="bx bx-edit-alt me-1"></i> Edytuj</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>6</td>
|
||||
<td><a href="app-invoice-preview.php">FV/12/02/2026/MS</a></td>
|
||||
<td>
|
||||
<span class="text-heading text-truncate fw-medium" style="max-width: 200px;">Global
|
||||
Trans Logistics</span>
|
||||
</td>
|
||||
<td>2026-02-08</td>
|
||||
<td>2026-02-22</td>
|
||||
<td class="text-end">12 000,00 zł</td>
|
||||
<td class="text-end">14 760,00 zł</td>
|
||||
<td class="text-end text-danger">5 000,00 zł</td>
|
||||
<td class="text-center">
|
||||
<div class="d-flex justify-content-center align-items-center gap-1">
|
||||
<span class="badge badge-dot bg-warning me-1"
|
||||
title="KSeF: Przetwarzanie"></span>
|
||||
<a href="#" class="btn btn-icon btn-sm text-secondary"><i
|
||||
class="bx bx-send"></i></a>
|
||||
<a href="javascript:void(0);" data-bs-toggle="modal"
|
||||
data-bs-target="#invoicePreviewModal"
|
||||
class="btn btn-icon btn-sm text-secondary"><i class="bx bx-show"></i></a>
|
||||
<div class="dropdown">
|
||||
<button type="button" class="btn btn-sm p-0 dropdown-toggle hide-arrow"
|
||||
data-bs-toggle="dropdown"><i
|
||||
class="bx bx-dots-vertical-rounded"></i></button>
|
||||
<div class="dropdown-menu dropdown-menu-end">
|
||||
<a class="dropdown-item" href="javascript:void(0);"><i
|
||||
class="bx bx-money me-1"></i> Rozlicz</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>7</td>
|
||||
<td><a href="app-invoice-preview.php">FV/11/02/2026/MS</a></td>
|
||||
<td>
|
||||
<i class="bx bx-store-alt text-info me-1" title="Sklep stacjonarny"></i>
|
||||
<span class="text-heading text-truncate fw-medium"
|
||||
style="max-width: 200px;">Kwiaciarnia "Stokrotka"</span>
|
||||
</td>
|
||||
<td>2026-01-15</td>
|
||||
<td><span class="text-danger">2026-01-29</span></td>
|
||||
<td class="text-end">300,00 zł</td>
|
||||
<td class="text-end">324,00 zł</td>
|
||||
<td class="text-end text-danger">324,00 zł</td>
|
||||
<td class="text-center">
|
||||
<div class="d-flex justify-content-center align-items-center gap-1">
|
||||
<span class="badge badge-dot bg-danger me-1" title="KSeF: Błąd"></span>
|
||||
<a href="#" class="btn btn-icon btn-sm text-secondary"><i
|
||||
class="bx bx-send"></i></a>
|
||||
<a href="javascript:void(0);" data-bs-toggle="modal"
|
||||
data-bs-target="#invoicePreviewModal"
|
||||
class="btn btn-icon btn-sm text-secondary"><i class="bx bx-show"></i></a>
|
||||
<div class="dropdown">
|
||||
<button type="button" class="btn btn-sm p-0 dropdown-toggle hide-arrow"
|
||||
data-bs-toggle="dropdown"><i
|
||||
class="bx bx-dots-vertical-rounded"></i></button>
|
||||
<div class="dropdown-menu dropdown-menu-end">
|
||||
<a class="dropdown-item" href="javascript:void(0);"><i
|
||||
class="bx bx-envelope me-1"></i> Wyślij ponaglenie</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>8</td>
|
||||
<td><a href="app-invoice-preview.php">FV/10/02/2026/MS</a></td>
|
||||
<td>
|
||||
<span class="text-heading text-truncate fw-medium" style="max-width: 200px;">SoftDev
|
||||
Inc.</span>
|
||||
</td>
|
||||
<td>2026-02-01</td>
|
||||
<td>2026-02-15</td>
|
||||
<td class="text-end">5 000,00 zł</td>
|
||||
<td class="text-end">6 150,00 zł</td>
|
||||
<td class="text-end">0,00 zł</td>
|
||||
<td class="text-center">
|
||||
<div class="d-flex justify-content-center align-items-center gap-1">
|
||||
<span class="badge badge-dot bg-success me-1" title="KSeF: Wysłano"></span>
|
||||
<a href="#" class="btn btn-icon btn-sm text-secondary"><i
|
||||
class="bx bx-send"></i></a>
|
||||
<a href="javascript:void(0);" data-bs-toggle="modal"
|
||||
data-bs-target="#invoicePreviewModal"
|
||||
class="btn btn-icon btn-sm text-secondary"><i class="bx bx-show"></i></a>
|
||||
<div class="dropdown">
|
||||
<button type="button" class="btn btn-sm p-0 dropdown-toggle hide-arrow"
|
||||
data-bs-toggle="dropdown"><i
|
||||
class="bx bx-dots-vertical-rounded"></i></button>
|
||||
<div class="dropdown-menu dropdown-menu-end">
|
||||
<a class="dropdown-item" href="javascript:void(0);"><i
|
||||
class="bx bx-download me-1"></i> Pobierz</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="bg-label-secondary">
|
||||
<td colspan="5" class="text-end fw-bold">Suma (PLN):</td>
|
||||
<td class="text-end fw-bold">254 275,93 zł</td>
|
||||
<td class="text-end fw-bold">312 759,36 zł</td>
|
||||
<td class="text-end text-danger">32 958,12 zł</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="card-footer d-flex justify-content-center border-top">
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination pagination-sm mb-0">
|
||||
<li class="page-item prev"><a class="page-link" href="javascript:void(0);"><i
|
||||
class="tf-icon bx bx-chevron-left"></i></a></li>
|
||||
<li class="page-item active"><a class="page-link" href="javascript:void(0);">1</a></li>
|
||||
<li class="page-item"><a class="page-link" href="javascript:void(0);">2</a></li>
|
||||
<li class="page-item"><a class="page-link" href="javascript:void(0);">3</a></li>
|
||||
<li class="page-item"><a class="page-link" href="javascript:void(0);">4</a></li>
|
||||
<li class="page-item next"><a class="page-link" href="javascript:void(0);"><i
|
||||
class="tf-icon bx bx-chevron-right"></i></a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3" id="invoice-filters-col">
|
||||
<div class="card sticky-top" style="top: 20px;">
|
||||
<div class="card-header border-bottom">
|
||||
<h5 class="card-title mb-0">Filtry</h5>
|
||||
</div>
|
||||
<div class="card-body pt-4">
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Kontrahent</label>
|
||||
<select class="select2 form-select" data-allow-clear="true" placeholder="Wybierz kontrahenta">
|
||||
<option value="">Wszyscy</option>
|
||||
<option value="1">MCreo Mateusz Łada</option>
|
||||
<option value="2">"AUTO-CARS" Kołodziej Krzysztof</option>
|
||||
<option value="3">GMINA STALOWA WOLA</option>
|
||||
<option value="4">Majami Mateusz Szczoczarz</option>
|
||||
<option value="5">"GRABOWSKI" PIOTR GRABOWSKI</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Status rozliczenia</label>
|
||||
<div class="d-flex flex-column gap-2">
|
||||
<div class="form-check">
|
||||
<input name="status-radio" class="form-check-input" type="radio" value="" id="statusAll"
|
||||
checked>
|
||||
<label class="form-check-label" for="statusAll"> Wszystkie </label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input name="status-radio" class="form-check-input" type="radio" value=""
|
||||
id="statusUnpaid">
|
||||
<label class="form-check-label" for="statusUnpaid"> Nierozliczone </label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input name="status-radio" class="form-check-input" type="radio" value=""
|
||||
id="statusPaid">
|
||||
<label class="form-check-label" for="statusPaid"> Rozliczone </label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Data utworzenia</label>
|
||||
<input type="text" class="form-control flatpickr-range"
|
||||
placeholder="RRRR-MM-DD do RRRR-MM-DD" />
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Numer faktury</label>
|
||||
<input type="text" class="form-control" placeholder="np. FV/12/2026">
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Termin płatności</label>
|
||||
<div class="d-flex flex-column gap-2">
|
||||
<div class="form-check">
|
||||
<input name="term-radio" class="form-check-input" type="radio" value="" id="termAll"
|
||||
checked>
|
||||
<label class="form-check-label" for="termAll"> Wszystkie </label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input name="term-radio" class="form-check-input" type="radio" value=""
|
||||
id="termOverdue">
|
||||
<label class="form-check-label" for="termOverdue"> Po terminie </label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input name="term-radio" class="form-check-input" type="radio" value="" id="termIntime">
|
||||
<label class="form-check-label" for="termIntime"> W terminie </label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-end gap-2">
|
||||
<button class="btn btn-outline-secondary">Wyczyść filtry</button>
|
||||
<button class="btn btn-primary">Wyszukaj</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-backdrop fade"></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">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header border-bottom py-3 d-flex justify-content-between align-items-center">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<h4 class="modal-title fw-bold mb-0">FV/1/01/2026/KB</h4>
|
||||
<span class="badge bg-label-success fs-6">Opłacona</span>
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
|
||||
<button type="button" class="btn btn-icon btn-label-secondary" data-bs-toggle="tooltip"
|
||||
title="Drukuj PDF">
|
||||
<i class="bx bx-printer"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-icon btn-label-secondary" data-bs-toggle="tooltip"
|
||||
title="Edytuj">
|
||||
<i class="bx bx-edit-alt"></i>
|
||||
</button>
|
||||
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-primary" type="button" id="dropdownInvoiceActions"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
Więcej akcji <i class="bx bx-chevron-down ms-1"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="dropdownInvoiceActions">
|
||||
<h6 class="dropdown-header text-uppercase ps-3">Finanse</h6>
|
||||
<li><button class="dropdown-item"><i class="bx bx-money me-2"></i> Rozlicz fakturę </button>
|
||||
</li>
|
||||
<li><a href="#" class="dropdown-item"><i class="bx bx-revision me-2"></i> Wystaw korektę
|
||||
</a></li>
|
||||
|
||||
<div class="dropdown-divider"></div>
|
||||
<h6 class="dropdown-header text-uppercase ps-3">Wysyłka i KSeF</h6>
|
||||
<li>
|
||||
<a class="dropdown-item d-flex justify-content-between align-items-center" href="#">
|
||||
<span><i class="bx bx-cloud-upload me-2"></i> Wyślij do KSeF </span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<button class="dropdown-item d-flex justify-content-between align-items-center">
|
||||
<span><i class="bx bx-envelope me-2"></i> Wyślij fakturę e-mail</span>
|
||||
<span class="ms-2 text-success" title="Wysłano: 2026-01-30 15:38:32"><i
|
||||
class="bx bx-check-circle"></i></span>
|
||||
</button>
|
||||
</li>
|
||||
<li><button class="dropdown-item"><i class="bx bx-check-shield me-2"></i> Wyślij
|
||||
potwierdzenie </button></li>
|
||||
<li><button class="dropdown-item"><i class="bx bx-bell me-2 text-warning"></i> Wyślij
|
||||
ponaglenie </button></li>
|
||||
|
||||
<div class="dropdown-divider"></div>
|
||||
<h6 class="dropdown-header text-uppercase ps-3">System</h6>
|
||||
<li><button class="dropdown-item"><i class="bx bx-duplicate me-2"></i> Duplikuj jako nową
|
||||
</button></li>
|
||||
<li><button class="dropdown-item text-danger"><i class="bx bx-trash me-2"></i> Usuń fakturę
|
||||
</button></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn-close ms-2" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-body bg-lighter p-4">
|
||||
|
||||
<div class="card shadow-none border border-success mb-4"
|
||||
style="border-left: 5px solid #71dd37 !important;">
|
||||
<div class="card-body p-3 d-flex justify-content-between align-items-center flex-wrap gap-3">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="avatar avatar-sm me-3">
|
||||
<span class="avatar-initial rounded-circle bg-label-success"><i
|
||||
class="bx bx-cloud-check fs-4"></i></span>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="mb-0 text-success fw-bold">Dokument pomyślnie przetworzony w KSeF</h6>
|
||||
<small class="text-muted">Data wysyłki: 2026-01-30 15:36:12</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<div class="text-end me-3">
|
||||
<small class="d-block text-muted mb-0">Numer KSeF</small>
|
||||
<span class="fw-medium user-select-all">1234567890-20260130-1A2B3C4D5E-6F</span>
|
||||
</div>
|
||||
<button class="btn btn-outline-success btn-sm"><i class="bx bx-download me-1"></i> Pobierz
|
||||
UPO</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-4 mb-4">
|
||||
|
||||
<div class="col-lg-4">
|
||||
<div class="card h-100 shadow-sm border-0">
|
||||
<div class="card-body p-4">
|
||||
<h6 class="card-title m-0 mb-3"><i class="bx bx-store me-2"></i> Sprzedawca</h6>
|
||||
<h6 class="mb-1">MARIUSZ BANACZYK "BURGER BAR"</h6>
|
||||
<p class="mb-1 text-muted small">KARCZMA BIESIADA, KULTOWA ZAPIEKANKA</p>
|
||||
<p class="mb-1 mt-2">ul. Ofiar Katynia 2</p>
|
||||
<p class="mb-2">37-450 Stalowa Wola, Polska</p>
|
||||
<span class="badge bg-label-secondary">NIP: 865 000 14 51</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4">
|
||||
<div class="card h-100 shadow-sm border-0">
|
||||
<div class="card-body p-4">
|
||||
<h6 class="card-title m-0 mb-3"><i class="bx bx-user me-2"></i> Kontrahent</h6>
|
||||
<h6 class="mb-1">COCA-COLA HBC POLSKA SP. Z O.O.</h6>
|
||||
<p class="mb-1 mt-2">ul. Żwirki i Wigury 16</p>
|
||||
<p class="mb-2">02-092 Warszawa, Polska</p>
|
||||
<span class="badge bg-label-secondary">NIP: 5242106963</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4">
|
||||
<div class="card h-100 shadow-sm border-0 bg-white">
|
||||
<div class="card-body p-4">
|
||||
<h6 class="card-title m-0 mb-3"><i class="bx bx-info-circle me-2"></i> Szczegóły</h6>
|
||||
<table class="table table-borderless table-sm m-0 px-0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="text-muted ps-0 py-1">Data wystawienia:</td>
|
||||
<td class="fw-medium text-end pe-0 py-1">2026-01-30</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-muted ps-0 py-1">Data dostawy:</td>
|
||||
<td class="fw-medium text-end pe-0 py-1">2026-01-30</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-muted ps-0 py-1">Termin płatności:</td>
|
||||
<td class="fw-bold text-end pe-0 py-1">2026-03-01</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-muted ps-0 py-1">Metoda:</td>
|
||||
<td class="fw-medium text-end pe-0 py-1">Przelew</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-muted ps-0 py-1">Waluta / Język:</td>
|
||||
<td class="fw-medium text-end pe-0 py-1">PLN / Polski</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm border-0 mb-4">
|
||||
<div class="table-responsive text-nowrap">
|
||||
<table class="table table-hover mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th style="width: 50px;">Lp</th>
|
||||
<th>Towar / Usługa</th>
|
||||
<th>J.m.</th>
|
||||
<th class="text-center">Ilość</th>
|
||||
<th class="text-end">Cena netto</th>
|
||||
<th class="text-end">Cena brutto</th>
|
||||
<th class="text-center">VAT</th>
|
||||
<th class="text-end">Wartość netto</th>
|
||||
<th class="text-end">Wartość brutto</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="text-muted">1</td>
|
||||
<td>
|
||||
<div class="d-flex flex-column">
|
||||
<span class="fw-medium">Usługa marketingowa</span>
|
||||
<small class="text-muted">Kod: -</small>
|
||||
</div>
|
||||
</td>
|
||||
<td>szt.</td>
|
||||
<td class="text-center">1</td>
|
||||
<td class="text-end">6 423,61 zł</td>
|
||||
<td class="text-end">7 901,04 zł</td>
|
||||
<td class="text-center"><span class="badge bg-label-secondary">23%</span></td>
|
||||
<td class="text-end fw-medium">6 423,61 zł</td>
|
||||
<td class="text-end fw-bold text-heading">7 901,04 zł</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-4 g-4">
|
||||
<div class="col-md-7">
|
||||
<div class="card shadow-sm border-0 h-100 bg-white p-4">
|
||||
<h6 class="text-uppercase text-muted fw-bold mb-2">Uwagi do dokumentu</h6>
|
||||
<p class="mb-0 text-body">
|
||||
Nota informacyjna nr : 0009131250<br>
|
||||
Nota informacyjna nr : 0009131045
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-5">
|
||||
<div class="card shadow-sm border-0 h-100 bg-white p-4">
|
||||
<h6 class="text-uppercase text-muted fw-bold mb-3 border-bottom pb-2">Suma</h6>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span class="text-muted">Wartość netto:</span>
|
||||
<span class="fw-medium">6 423,61 zł</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-3 border-bottom pb-3">
|
||||
<span class="text-muted">Wartość VAT:</span>
|
||||
<span class="fw-medium">1 477,43 zł</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<span class="fs-5 text-body">Wartość brutto:</span>
|
||||
<span class="fs-4 fw-bold text-primary">7 901,04 zł</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between text-success">
|
||||
<span>Zapłacono:</span>
|
||||
<span class="fw-bold">7 901,04 zł</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between text-muted mt-1 small">
|
||||
<span>Pozostało do zapłaty:</span>
|
||||
<span>0,00 zł</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-header bg-white border-bottom py-3">
|
||||
<h6 class="card-title m-0"><i class="bx bx-history me-2"></i>Historia operacji na dokumencie
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body p-4">
|
||||
<ul class="timeline mb-0">
|
||||
<li class="timeline-item timeline-item-transparent">
|
||||
<span class="timeline-point timeline-point-success"></span>
|
||||
<div class="timeline-event">
|
||||
<div class="timeline-header mb-1">
|
||||
<h6 class="mb-0 fw-bold">Wysłano fakturę</h6>
|
||||
<small class="text-muted">2026-01-30 15:38:32</small>
|
||||
</div>
|
||||
<p class="mb-2 text-muted">Wysłano na email: e-faktura.pl@cchellenic.com</p>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="avatar avatar-xs me-2">
|
||||
<span class="avatar-initial rounded-circle bg-label-primary">GB</span>
|
||||
</div>
|
||||
<span class="small fw-medium">Grażyna Banaczyk</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="timeline-item timeline-item-transparent border-transparent pb-0">
|
||||
<span class="timeline-point timeline-point-info"></span>
|
||||
<div class="timeline-event pb-0">
|
||||
<div class="timeline-header mb-1">
|
||||
<h6 class="mb-0 fw-bold">Utworzono fakturę</h6>
|
||||
<small class="text-muted">2026-01-30 15:35:48</small>
|
||||
</div>
|
||||
<div class="d-flex align-items-center mt-2">
|
||||
<div class="avatar avatar-xs me-2">
|
||||
<span class="avatar-initial rounded-circle bg-label-primary">GB</span>
|
||||
</div>
|
||||
<span class="small fw-medium">Grażyna Banaczyk</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// Inicjalizacja Select2 dla filtrów (jeśli dodasz jQuery w footerze)
|
||||
if ($('.select2').length) {
|
||||
$('.select2').select2({
|
||||
minimumResultsForSearch: 5 // Pokaż szukajkę dopiero przy 5 opcjach
|
||||
});
|
||||
}
|
||||
|
||||
// Inicjalizacja Flatpickr dla dat
|
||||
if (typeof flatpickr !== 'undefined') {
|
||||
document.querySelectorAll('.flatpickr-range').forEach(function (element) {
|
||||
flatpickr(element, {
|
||||
mode: 'range',
|
||||
dateFormat: 'Y-m-d'
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Obsługa przycisku filtrów
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const filterBtn = document.getElementById('filter-toggle-btn');
|
||||
const filtersCol = document.getElementById('invoice-filters-col');
|
||||
const listCol = document.getElementById('invoice-list-col');
|
||||
|
||||
if (filterBtn && filtersCol && listCol) {
|
||||
filterBtn.addEventListener('click', function () {
|
||||
filtersCol.classList.toggle('d-none');
|
||||
|
||||
if (filtersCol.classList.contains('d-none')) {
|
||||
listCol.classList.remove('col-lg-9');
|
||||
listCol.classList.add('col-lg-12');
|
||||
} else {
|
||||
listCol.classList.remove('col-lg-12');
|
||||
listCol.classList.add('col-lg-9');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
462
prototype/invoice/app-products.php
Normal file
462
prototype/invoice/app-products.php
Normal file
@@ -0,0 +1,462 @@
|
||||
<?php
|
||||
$enablePrototypeComments = false;
|
||||
include '../../header-invoice.php';
|
||||
?>
|
||||
|
||||
<div class="container-fluid flex-grow-1 container-p-y">
|
||||
|
||||
<div
|
||||
class="d-flex flex-column flex-md-row justify-content-between align-items-start align-items-md-center mb-4 gap-3">
|
||||
<div class="d-flex flex-column justify-content-center">
|
||||
<h4 class="mb-1 text-body">
|
||||
<span class="text-muted fw-light">Sprzedaż /</span> Towary i Usługi
|
||||
</h4>
|
||||
<p class="text-muted mb-0">Zarządzaj bazą swoich produktów i usług</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-lg-9 transition-width" id="product-list-col">
|
||||
<div class="card">
|
||||
<div
|
||||
class="card-header border-bottom d-flex justify-content-between align-items-center flex-wrap gap-2">
|
||||
|
||||
<div class="me-2 flex-grow-1" style="max-width: 300px;">
|
||||
<div class="input-group input-group-merge">
|
||||
<span class="input-group-text" id="basic-addon-search31"><i class="bx bx-search"></i></span>
|
||||
<input type="text" class="form-control" placeholder="Szukaj nazwy, kodu..."
|
||||
aria-label="Search...">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<button type="button" class="btn btn-label-secondary d-flex align-items-center gap-2"
|
||||
id="filter-toggle-btn">
|
||||
<i class="bx bx-filter-alt"></i> Filtry
|
||||
</button>
|
||||
|
||||
<select class="form-select" style="width: 80px;">
|
||||
<option value="40">40</option>
|
||||
<option value="60">60</option>
|
||||
<option value="100">100</option>
|
||||
</select>
|
||||
|
||||
<div class="dropdown">
|
||||
<button type="button" class="btn btn-icon btn-label-secondary" data-bs-toggle="dropdown"
|
||||
aria-expanded="false">
|
||||
<i class="bx bx-dots-vertical-rounded"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li><a class="dropdown-item" href="javascript:void(0);"><i
|
||||
class="bx bx-import me-2"></i> Importuj z pliku CSV</a></li>
|
||||
<li><a class="dropdown-item" href="javascript:void(0);"><i
|
||||
class="bx bx-export me-2"></i> Eksportuj listę (.csv)</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addProductModal">
|
||||
<i class="bx bx-plus me-1"></i> Dodaj pozycję
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive text-nowrap" style="min-height: 400px;">
|
||||
<table class="table table-hover table-striped align-middle">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th style="width: 50px;">
|
||||
<div class="form-check m-0">
|
||||
<input class="form-check-input" type="checkbox" id="checkAll">
|
||||
</div>
|
||||
</th>
|
||||
<th style="width: 50px;">Typ</th>
|
||||
<th>Nazwa i Kod</th>
|
||||
<th>J.m.</th>
|
||||
<th class="text-end">Cena Netto</th>
|
||||
<th class="text-center">VAT</th>
|
||||
<th class="text-end">Cena Brutto</th>
|
||||
<th class="text-center">Akcje</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="table-border-bottom-0">
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<div class="form-check m-0"><input class="form-check-input" type="checkbox"></div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="avatar avatar-sm" data-bs-toggle="tooltip" title="Usługa">
|
||||
<span class="avatar-initial rounded bg-label-info"><i
|
||||
class="bx bx-briefcase"></i></span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span class="fw-medium text-heading">Konsultacje IT</span>
|
||||
<br><small class="text-muted">Kod: USL-IT-01</small>
|
||||
</td>
|
||||
<td>godz.</td>
|
||||
<td class="text-end">150,00 zł</td>
|
||||
<td class="text-center"><span class="badge bg-label-secondary">23%</span></td>
|
||||
<td class="text-end">184,50 zł</td>
|
||||
<td class="text-center">
|
||||
<div class="d-flex justify-content-center align-items-center gap-1">
|
||||
<button class="btn btn-icon btn-sm btn-text-secondary" data-bs-toggle="tooltip"
|
||||
title="Edytuj"><i class="bx bx-edit-alt"></i></button>
|
||||
<div class="dropdown">
|
||||
<button type="button" class="btn p-0 dropdown-toggle hide-arrow"
|
||||
data-bs-toggle="dropdown"><i
|
||||
class="bx bx-dots-vertical-rounded"></i></button>
|
||||
<div class="dropdown-menu dropdown-menu-end">
|
||||
<a class="dropdown-item" href="javascript:void(0);"><i
|
||||
class="bx bx-duplicate me-1"></i> Duplikuj</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item text-danger" href="javascript:void(0);"><i
|
||||
class="bx bx-trash me-1"></i> Usuń</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<div class="form-check m-0"><input class="form-check-input" type="checkbox"></div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="avatar avatar-sm" data-bs-toggle="tooltip" title="Towar">
|
||||
<span class="avatar-initial rounded bg-label-success"><i
|
||||
class="bx bx-box"></i></span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span class="fw-medium text-heading">Licencja Oprogramowania B</span>
|
||||
<br><small class="text-muted">Kod: LIC-002</small>
|
||||
</td>
|
||||
<td>szt.</td>
|
||||
<td class="text-end">400,00 zł</td>
|
||||
<td class="text-center"><span class="badge bg-label-secondary">23%</span></td>
|
||||
<td class="text-end">492,00 zł</td>
|
||||
<td class="text-center">
|
||||
<div class="d-flex justify-content-center align-items-center gap-1">
|
||||
<button class="btn btn-icon btn-sm btn-text-secondary" data-bs-toggle="tooltip"
|
||||
title="Edytuj"><i class="bx bx-edit-alt"></i></button>
|
||||
<div class="dropdown">
|
||||
<button type="button" class="btn p-0 dropdown-toggle hide-arrow"
|
||||
data-bs-toggle="dropdown"><i
|
||||
class="bx bx-dots-vertical-rounded"></i></button>
|
||||
<div class="dropdown-menu dropdown-menu-end">
|
||||
<a class="dropdown-item" href="javascript:void(0);"><i
|
||||
class="bx bx-duplicate me-1"></i> Duplikuj</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item text-danger" href="javascript:void(0);"><i
|
||||
class="bx bx-trash me-1"></i> Usuń</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<div class="form-check m-0"><input class="form-check-input" type="checkbox"></div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="avatar avatar-sm" data-bs-toggle="tooltip" title="Usługa">
|
||||
<span class="avatar-initial rounded bg-label-info"><i
|
||||
class="bx bx-briefcase"></i></span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span class="fw-medium text-heading">Szkolenie wstępne</span>
|
||||
<br><small class="text-muted">Kod: SZK-01</small>
|
||||
</td>
|
||||
<td>usł.</td>
|
||||
<td class="text-end">1 000,00 zł</td>
|
||||
<td class="text-center"><span class="badge bg-label-secondary">ZW</span></td>
|
||||
<td class="text-end">1 000,00 zł</td>
|
||||
<td class="text-center">
|
||||
<div class="d-flex justify-content-center align-items-center gap-1">
|
||||
<button class="btn btn-icon btn-sm btn-text-secondary" data-bs-toggle="tooltip"
|
||||
title="Edytuj"><i class="bx bx-edit-alt"></i></button>
|
||||
<div class="dropdown">
|
||||
<button type="button" class="btn p-0 dropdown-toggle hide-arrow"
|
||||
data-bs-toggle="dropdown"><i
|
||||
class="bx bx-dots-vertical-rounded"></i></button>
|
||||
<div class="dropdown-menu dropdown-menu-end">
|
||||
<a class="dropdown-item" href="javascript:void(0);"><i
|
||||
class="bx bx-duplicate me-1"></i> Duplikuj</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item text-danger" href="javascript:void(0);"><i
|
||||
class="bx bx-trash me-1"></i> Usuń</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="card-footer d-flex justify-content-center border-top">
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination pagination-sm mb-0">
|
||||
<li class="page-item prev"><a class="page-link" href="javascript:void(0);"><i
|
||||
class="tf-icon bx bx-chevron-left"></i></a></li>
|
||||
<li class="page-item active"><a class="page-link" href="javascript:void(0);">1</a></li>
|
||||
<li class="page-item"><a class="page-link" href="javascript:void(0);">2</a></li>
|
||||
<li class="page-item next"><a class="page-link" href="javascript:void(0);"><i
|
||||
class="tf-icon bx bx-chevron-right"></i></a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3" id="product-filters-col">
|
||||
<div class="card sticky-top" style="top: 20px;">
|
||||
<div class="card-header border-bottom">
|
||||
<h5 class="card-title mb-0">Filtry</h5>
|
||||
</div>
|
||||
<div class="card-body pt-4">
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Typ pozycji</label>
|
||||
<div class="d-flex flex-column gap-2">
|
||||
<div class="form-check">
|
||||
<input name="type-radio" class="form-check-input" type="radio" value="" id="typeAll"
|
||||
checked>
|
||||
<label class="form-check-label" for="typeAll"> Wszystkie </label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input name="type-radio" class="form-check-input" type="radio" value="towar"
|
||||
id="typeProduct">
|
||||
<label class="form-check-label" for="typeProduct"> Tylko towary </label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input name="type-radio" class="form-check-input" type="radio" value="usluga"
|
||||
id="typeService">
|
||||
<label class="form-check-label" for="typeService"> Tylko usługi </label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Stawka VAT</label>
|
||||
<select class="form-select">
|
||||
<option value="">Wszystkie stawki</option>
|
||||
<option value="23">23%</option>
|
||||
<option value="8">8%</option>
|
||||
<option value="5">5%</option>
|
||||
<option value="0">0%</option>
|
||||
<option value="zw">ZW (Zwolnione)</option>
|
||||
<option value="np">NP (Nie podlega)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label class="form-label">Cena Netto</label>
|
||||
<div class="row g-2">
|
||||
<div class="col-6">
|
||||
<input type="number" class="form-control" placeholder="Od">
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<input type="number" class="form-control" placeholder="Do">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-grid gap-2">
|
||||
<button class="btn btn-primary">Filtruj</button>
|
||||
<button class="btn btn-outline-secondary">Wyczyść</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-backdrop fade"></div>
|
||||
|
||||
<div class="modal fade" id="addProductModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header border-bottom">
|
||||
<h5 class="modal-title fs-5">Nowy towar / usługa</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
|
||||
<form id="addProductForm" onsubmit="return false">
|
||||
<div class="modal-body pb-3">
|
||||
|
||||
<div class="mb-4">
|
||||
<label class="form-label d-block mb-2">Rodzaj pozycji</label>
|
||||
<div class="btn-group w-100" role="group">
|
||||
<input type="radio" class="btn-check" name="itemType" id="type_product" autocomplete="off"
|
||||
checked>
|
||||
<label class="btn btn-outline-primary" for="type_product"><i class="bx bx-box me-1"></i>
|
||||
Towar</label>
|
||||
|
||||
<input type="radio" class="btn-check" name="itemType" id="type_service" autocomplete="off">
|
||||
<label class="btn btn-outline-primary" for="type_service"><i
|
||||
class="bx bx-briefcase me-1"></i> Usługa</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-3 mb-3">
|
||||
<div class="col-md-8">
|
||||
<label class="form-label">Nazwa <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" placeholder="np. Konsultacje marketingowe" required>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label">Kod / PKWiU</label>
|
||||
<input type="text" class="form-control" placeholder="np. KM-01">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-label-secondary p-3 rounded mb-3">
|
||||
<div class="row g-3 align-items-end">
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Jednostka</label>
|
||||
<select class="form-select">
|
||||
<option value="szt">szt.</option>
|
||||
<option value="usl">usł.</option>
|
||||
<option value="godz">godz.</option>
|
||||
<option value="km">km</option>
|
||||
<option value="kg">kg</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Cena Netto</label>
|
||||
<div class="input-group input-group-merge bg-white">
|
||||
<input type="number" class="form-control" id="modal_netto" step="0.01"
|
||||
placeholder="0.00">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Stawka VAT</label>
|
||||
<select class="form-select" id="modal_vat_rate">
|
||||
<option value="0.23" selected>23%</option>
|
||||
<option value="0.08">8%</option>
|
||||
<option value="0.05">5%</option>
|
||||
<option value="0">0%</option>
|
||||
<option value="zw">ZW</option>
|
||||
<option value="np">NP</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label fw-bold">Cena Brutto</label>
|
||||
<div class="input-group input-group-merge bg-white">
|
||||
<input type="number" class="form-control fw-bold" id="modal_brutto" step="0.01"
|
||||
placeholder="0.00">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2 text-end">
|
||||
<small class="text-muted"><i class="bx bx-info-circle"></i> Kwoty przeliczają się
|
||||
automatycznie.</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Opis dodatkowy (opcjonalny)</label>
|
||||
<textarea class="form-control" rows="2"
|
||||
placeholder="Ten opis może się drukować pod nazwą na fakturze..."></textarea>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer bg-light">
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Anuluj</button>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bx bx-save me-1"></i> Zapisz do bazy
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
// Tooltipy
|
||||
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
|
||||
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
|
||||
return new bootstrap.Tooltip(tooltipTriggerEl)
|
||||
});
|
||||
|
||||
// Obsługa zwijania filtrów
|
||||
const filterBtn = document.getElementById('filter-toggle-btn');
|
||||
const filtersCol = document.getElementById('product-filters-col');
|
||||
const listCol = document.getElementById('product-list-col');
|
||||
|
||||
if (filterBtn && filtersCol && listCol) {
|
||||
filterBtn.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
filtersCol.classList.toggle('d-none');
|
||||
|
||||
if (filtersCol.classList.contains('d-none')) {
|
||||
listCol.classList.remove('col-lg-9');
|
||||
listCol.classList.add('col-12');
|
||||
} else {
|
||||
listCol.classList.remove('col-12');
|
||||
listCol.classList.add('col-lg-9');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Check All w tabeli
|
||||
const checkAll = document.getElementById('checkAll');
|
||||
if (checkAll) {
|
||||
checkAll.addEventListener('change', function () {
|
||||
const checkboxes = document.querySelectorAll('tbody .form-check-input');
|
||||
checkboxes.forEach(cb => cb.checked = this.checked);
|
||||
});
|
||||
}
|
||||
|
||||
// --- Logika Modala Dodawania (Przeliczanie Netto/Brutto) ---
|
||||
const modNetto = document.getElementById('modal_netto');
|
||||
const modBrutto = document.getElementById('modal_brutto');
|
||||
const modVatRate = document.getElementById('modal_vat_rate');
|
||||
|
||||
function calculateModalValues(source) {
|
||||
let rateVal = modVatRate.value;
|
||||
let rate = parseFloat(rateVal);
|
||||
|
||||
// Jeśli wybrano ZW lub NP, traktujemy stawkę jako 0 do obliczeń matematycznych
|
||||
if (isNaN(rate) || rateVal === 'zw' || rateVal === 'np') rate = 0;
|
||||
|
||||
if (source === 'netto') {
|
||||
let netVal = parseFloat(modNetto.value) || 0;
|
||||
let grossVal = netVal + (netVal * rate);
|
||||
modBrutto.value = grossVal.toFixed(2);
|
||||
}
|
||||
else if (source === 'brutto') {
|
||||
let grossVal = parseFloat(modBrutto.value) || 0;
|
||||
let netVal = grossVal / (1 + rate);
|
||||
modNetto.value = netVal.toFixed(2);
|
||||
}
|
||||
else if (source === 'rate') {
|
||||
// Przy zmianie stawki priorytet ma wpisane Netto
|
||||
if (modNetto.value) calculateModalValues('netto');
|
||||
else if (modBrutto.value) calculateModalValues('brutto');
|
||||
}
|
||||
}
|
||||
|
||||
if (modNetto && modBrutto && modVatRate) {
|
||||
modNetto.addEventListener('input', () => calculateModalValues('netto'));
|
||||
modBrutto.addEventListener('input', () => calculateModalValues('brutto'));
|
||||
modVatRate.addEventListener('change', () => calculateModalValues('rate'));
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
534
prototype/invoice/app-purchase-add.php
Normal file
534
prototype/invoice/app-purchase-add.php
Normal file
@@ -0,0 +1,534 @@
|
||||
<?php
|
||||
$enablePrototypeComments = false;
|
||||
include '../../header-invoice.php';
|
||||
?>
|
||||
|
||||
<div class="container-fluid flex-grow-1 container-p-y">
|
||||
|
||||
<div
|
||||
class="d-flex flex-column flex-md-row justify-content-between align-items-start align-items-md-center mb-4 gap-3">
|
||||
<div class="d-flex flex-column justify-content-center">
|
||||
<h4 class="mb-1 text-body">Nowa Faktura Zakupowa</h4>
|
||||
<p class="text-muted mb-0">Wprowadź koszt firmowy</p>
|
||||
</div>
|
||||
<div class="d-flex align-content-center flex-wrap gap-2">
|
||||
<a href="app-purchase-list.php" class="btn btn-label-secondary">Anuluj</a>
|
||||
<button type="submit" form="invoiceForm" class="btn btn-primary"><i class="bx bx-save me-1"></i> Zapisz
|
||||
fakturę</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form id="invoiceForm" onsubmit="return false">
|
||||
|
||||
<div class="row mb-4">
|
||||
|
||||
<!-- Left Column: Seller & Buyer -->
|
||||
<div class="col-lg-5 col-md-12 mb-3 mb-lg-0">
|
||||
|
||||
<!-- Buyer Card -->
|
||||
<div class="card bg-label-secondary border-0 mb-3">
|
||||
<div class="card-body p-3 d-flex flex-column justify-content-center text-center">
|
||||
<div class="avatar mx-auto mb-2">
|
||||
<span class="avatar-initial rounded bg-white text-secondary"><i
|
||||
class="bx bx-building-house fs-4"></i></span>
|
||||
</div>
|
||||
<h6 class="card-title mb-1 text-nowrap">Nabywca</h6>
|
||||
<small class="d-block fw-bold text-truncate">Magico Software</small>
|
||||
<small class="text-muted text-truncate">NIP: 8652582386</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Seller Card -->
|
||||
<div class="card mb-3">
|
||||
<div class="card-header border-bottom py-3">
|
||||
<h6 class="card-title m-0"><i class="bx bx-store-alt me-2"></i>Sprzedawca</h6>
|
||||
</div>
|
||||
<div class="card-body pt-3">
|
||||
<div class="card shadow-none border mb-3 position-relative">
|
||||
<div class="card-body p-3 d-flex justify-content-between align-items-center"
|
||||
style="min-height: 80px;">
|
||||
<i class="text-muted">Wybierz dostawcę z listy...</i>
|
||||
<button class="btn btn-outline-primary btn-sm position-absolute end-0 top-0 m-2"><i
|
||||
class="bx bx-search"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column gap-2">
|
||||
<label class="form-check form-switch m-0">
|
||||
<input class="form-check-input" type="checkbox" id="descToggle">
|
||||
<span class="form-check-label text-muted">Dodatkowy opis dostawcy</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Right Column: Document Data -->
|
||||
<div class="col-lg-7 col-12">
|
||||
<div class="card h-100">
|
||||
<div class="card-header border-bottom py-3">
|
||||
<h6 class="card-title m-0"><i class="bx bx-file me-2"></i>Dane Dokumentu</h6>
|
||||
</div>
|
||||
<div class="card-body pt-3">
|
||||
|
||||
<!-- OCR Dropzone -->
|
||||
<div class="dropzone p-4 border-dashed border-2 rounded text-center mb-3 d-flex flex-column justify-content-center align-items-center"
|
||||
style="border-color: #d9dee3; background-color: #f8f9fa; cursor: pointer; transition: 0.2s;"
|
||||
onmouseover="this.style.borderColor='#696cff'; this.style.backgroundColor='#f0f2ff';"
|
||||
onmouseout="this.style.borderColor='#d9dee3'; this.style.backgroundColor='#f8f9fa';">
|
||||
<i class="bx bx-cloud-upload fs-2 text-muted mb-2"></i>
|
||||
<span class="text-muted fw-bold">Przeciągnij fakturę tutaj lub kliknij</span>
|
||||
<span class="small text-muted">(PDF, JPG, PNG)</span>
|
||||
</div>
|
||||
<button type="button" class="btn btn-label-primary w-100 mb-4" id="btn-ocr-read-page">
|
||||
<i class="bx bx-scan me-1"></i> Odczytaj dane z pliku (OCR)
|
||||
</button>
|
||||
|
||||
<!-- KSeF Info Block -->
|
||||
<div class="mb-4 p-3 bg-label-secondary rounded border-dashed border-2">
|
||||
<div class="d-flex align-items-center mb-2 justify-content-between">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bx bx-shield-quarter me-2 text-success"></i>
|
||||
<span class="fw-bold small">DANE SYSTEMU KSeF</span>
|
||||
</div>
|
||||
<span class="badge bg-white text-success shadow-sm">ZWERYFIKOWANA</span>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="small text-muted d-block mb-1">Numer identyfikacyjny:</label>
|
||||
<code class="p-2 bg-white border rounded d-block text-dark small fw-bold"
|
||||
style="word-break: break-all;">8652582386-20260120-0C7F00A11237-B1</code>
|
||||
</div>
|
||||
<div class="row align-items-center gx-2">
|
||||
<div class="col-auto">
|
||||
<img src="https://api.qrserver.com/v1/create-qr-code/?size=90x90&data=KSEF_VERIFY_URL"
|
||||
class="border p-1 bg-white rounded" alt="QR KSeF" width="60">
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="d-flex gap-2 mb-2">
|
||||
<button class="btn btn-sm btn-outline-primary w-100"><i
|
||||
class="bx bx-download me-1"></i>PDF</button>
|
||||
<button class="btn btn-sm btn-outline-primary w-100"><i
|
||||
class="bx bx-download me-1"></i>UPO</button>
|
||||
<button class="btn btn-sm btn-outline-secondary w-100"><i
|
||||
class="bx bx-copy me-1"></i>Numer</button>
|
||||
</div>
|
||||
<small class="text-muted d-block" style="font-size: 0.7rem;">Faktura została pobrana
|
||||
z KSeF i zweryfikowana poprawnie.</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-2 mb-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-bold">Numer faktury</label>
|
||||
<input type="text" class="form-control" placeholder="np. FV/2026/02/105">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label small text-uppercase fw-bold text-muted">Data zakupu</label>
|
||||
<input type="text" class="form-control date-picker" value="2026-02-17">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-2 mb-3">
|
||||
<div class="col-6">
|
||||
<label class="form-label small text-uppercase fw-bold text-muted">Data wyst.</label>
|
||||
<input type="text" class="form-control date-picker" value="2026-02-17">
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="form-label small text-uppercase fw-bold text-muted">Termin płat.</label>
|
||||
<input type="text" class="form-control date-picker" value="2026-02-24">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-2 align-items-end">
|
||||
<div class="col-5">
|
||||
<label class="form-label small text-uppercase fw-bold text-muted">Metoda</label>
|
||||
<select class="form-select">
|
||||
<option value="przelew">Przelew</option>
|
||||
<option value="gotowka">Gotówka</option>
|
||||
<option value="karta">Karta</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-7">
|
||||
<label class="form-label fw-bold">Zapłacono</label>
|
||||
<div class="input-group">
|
||||
<input type="number" id="paidInput" class="form-control" value="0.00">
|
||||
<button class="btn btn-outline-primary px-2" type="button" id="payFullBtn"
|
||||
data-bs-toggle="tooltip" title="Przepisz pełną kwotę">
|
||||
Całość
|
||||
</button>
|
||||
<span class="input-group-text">PLN</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card mb-4">
|
||||
<div
|
||||
class="card-header bg-label-primary py-2 d-flex flex-wrap justify-content-between align-items-center gap-3">
|
||||
<span class="fw-bold">Pozycje faktury</span>
|
||||
|
||||
<div class="d-flex align-items-center flex-wrap gap-3">
|
||||
|
||||
<div class="d-flex align-items-center">
|
||||
<label class="text-muted small me-2 text-nowrap d-flex align-items-center">
|
||||
Kategoria kosztu
|
||||
<i class="bx bx-info-circle ms-1 text-primary cursor-pointer" data-bs-toggle="tooltip"
|
||||
title="Listę kategorii możesz zdefiniować w: Ustawienia -> Słowniki"></i>
|
||||
</label>
|
||||
<select class="form-select form-select-sm" style="min-width: 150px;">
|
||||
<option value="towary">Towary handlowe</option>
|
||||
<option value="paliwo">Paliwo i eksploatacja</option>
|
||||
<option value="biuro">Koszty biurowe</option>
|
||||
<option value="uslugi">Usługi obce</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="vr h-100 my-auto text-muted"></div>
|
||||
|
||||
<div class="d-flex align-items-center">
|
||||
<label class="text-muted small me-2 text-nowrap">Licz od:</label>
|
||||
<select class="form-select form-select-sm" style="width: auto;">
|
||||
<option value="brutto">Brutto</option>
|
||||
<option value="netto">Netto</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th style="width: 40px;" class="text-center">Lp</th>
|
||||
<th style="min-width: 250px;">Nazwa kosztu / Towaru</th>
|
||||
<th style="width: 120px;">Kod / PKWiU</th>
|
||||
<th style="width: 90px;">JM</th>
|
||||
<th style="width: 100px;">Ilość</th>
|
||||
<th style="width: 130px;">Cena Netto</th>
|
||||
<th style="width: 100px;">VAT</th>
|
||||
<th style="width: 130px;" class="text-end">Wartość Netto</th>
|
||||
<th style="width: 130px;" class="text-end">Wartość Brutto</th>
|
||||
<th style="width: 50px;"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="align-middle text-center text-muted">1</td>
|
||||
<td class="p-2">
|
||||
<input type="text" class="form-control border-0 shadow-none fw-medium"
|
||||
placeholder="Np. Usługa księgowa, Paliwo...">
|
||||
</td>
|
||||
<td class="p-2">
|
||||
<input type="text" class="form-control border-0 shadow-none text-muted"
|
||||
placeholder="-">
|
||||
</td>
|
||||
<td class="p-2">
|
||||
<select class="form-select border-0 shadow-none px-1">
|
||||
<option value="szt">szt.</option>
|
||||
<option value="usl">usł.</option>
|
||||
<option value="m3">m3</option>
|
||||
<option value="litr">litr</option>
|
||||
</select>
|
||||
</td>
|
||||
<td class="p-2">
|
||||
<input type="number" class="form-control border-0 shadow-none text-center fw-bold"
|
||||
value="1" step="0.01">
|
||||
</td>
|
||||
<td class="p-2">
|
||||
<input type="number" class="form-control border-0 shadow-none text-end" value="0.00"
|
||||
step="0.01">
|
||||
</td>
|
||||
<td class="p-2">
|
||||
<select class="form-select border-0 shadow-none px-1">
|
||||
<option value="23">23%</option>
|
||||
<option value="8">8%</option>
|
||||
<option value="5">5%</option>
|
||||
<option value="0">0%</option>
|
||||
<option value="zw">ZW</option>
|
||||
</select>
|
||||
</td>
|
||||
<td class="align-middle text-end pe-3 bg-lighter">0,00 zł</td>
|
||||
<td class="align-middle text-end pe-3 bg-lighter fw-bold">0,00 zł</td>
|
||||
<td class="align-middle text-center p-2">
|
||||
<button class="btn btn-icon btn-sm btn-label-danger"><i
|
||||
class="bx bx-trash"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="border-top p-3 text-end bg-light">
|
||||
<button class="btn btn-primary btn-sm"><i class="bx bx-plus me-1"></i> Dodaj kolejną
|
||||
pozycję</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-lg-7 mb-4 mb-lg-0">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
|
||||
<label class="form-label">Uwagi do dokumentu (wewnętrzne)</label>
|
||||
<textarea class="form-control bg-lighter" rows="3"
|
||||
placeholder="Wpisz uwagi widoczne tylko dla nas..."></textarea>
|
||||
|
||||
<div class="row g-2 mb-3 mt-3">
|
||||
<div class="col-md-4">
|
||||
<label class="form-label d-flex align-items-center">
|
||||
Waluta dokumentu
|
||||
<i class="bx bx-info-circle ms-1 fs-6 text-muted" data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
title="Waluta w jakiej została wystawiona faktura przez dostawcę.">
|
||||
</i>
|
||||
</label>
|
||||
<select class="form-select">
|
||||
<option value="PLN">PLN</option>
|
||||
<option value="EUR">EUR</option>
|
||||
<option value="USD">USD</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-5">
|
||||
<label class="form-label d-flex align-items-center">
|
||||
Przelicznik (Kurs)
|
||||
<i class="bx bx-info-circle ms-1 fs-6 text-muted" data-bs-toggle="tooltip"
|
||||
data-bs-placement="top"
|
||||
title="Kurs waluty z dnia poprzedzającego wystawienie faktury.">
|
||||
</i>
|
||||
</label>
|
||||
<div class="input-group">
|
||||
<input type="number" id="exchangeRateInput" class="form-control" value="1.0000"
|
||||
disabled>
|
||||
<button class="btn btn-outline-secondary" type="button" id="unlockRateBtn"
|
||||
data-bs-toggle="tooltip" title="Odblokuj edycję kursu">
|
||||
<i class="bx bx-lock-open-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex align-items-center mt-3">
|
||||
<label class="form-check form-switch m-0">
|
||||
<input class="form-check-input" type="checkbox" checked>
|
||||
<span class="form-check-label">Podzielona płatność (MPP)</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-5">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title mb-4">Podsumowanie</h6>
|
||||
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span class="text-muted">Suma Netto:</span>
|
||||
<span class="fw-semibold">0,00 zł</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-3 border-bottom pb-2">
|
||||
<span class="text-muted">Suma VAT:</span>
|
||||
<span class="fw-semibold">0,00 zł</span>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<span class="h5 mb-0">Do zapłaty:</span>
|
||||
<span class="h4 mb-0 text-primary" id="finalTotal">0,00 zł</span>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-warning d-flex align-items-start align-items-sm-center mb-0"
|
||||
role="alert">
|
||||
<i class="bx bx-bell-ring me-2 fs-4 mt-1 mt-sm-0"></i>
|
||||
<div class="small">
|
||||
<strong>Status: Nierozliczona.</strong>
|
||||
Faktura zostanie dodana do kalendarza płatności.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
<div class="content-backdrop fade"></div>
|
||||
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// Inicjalizacja Datepickerów
|
||||
if (typeof flatpickr !== 'undefined') {
|
||||
document.querySelectorAll('.date-picker').forEach(picker => {
|
||||
flatpickr(picker, { dateFormat: 'Y-m-d' });
|
||||
});
|
||||
}
|
||||
|
||||
// Tooltipy
|
||||
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
|
||||
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
|
||||
return new bootstrap.Tooltip(tooltipTriggerEl)
|
||||
});
|
||||
|
||||
// Obsługa odblokowania kursu waluty
|
||||
const unlockBtn = document.getElementById('unlockRateBtn');
|
||||
const rateInput = document.getElementById('exchangeRateInput');
|
||||
if (unlockBtn && rateInput) {
|
||||
unlockBtn.addEventListener('click', function () {
|
||||
rateInput.disabled = !rateInput.disabled;
|
||||
if (!rateInput.disabled) {
|
||||
rateInput.focus();
|
||||
unlockBtn.classList.remove('btn-outline-secondary');
|
||||
unlockBtn.classList.add('btn-primary');
|
||||
unlockBtn.innerHTML = '<i class="bx bx-lock-open-alt"></i>';
|
||||
} else {
|
||||
unlockBtn.classList.add('btn-outline-secondary');
|
||||
unlockBtn.classList.remove('btn-primary');
|
||||
unlockBtn.innerHTML = '<i class="bx bx-lock-alt"></i>';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Obsługa przycisku "Całość"
|
||||
const payFullBtn = document.getElementById('payFullBtn');
|
||||
const paidInput = document.getElementById('paidInput');
|
||||
// Tutaj symulujemy pobranie kwoty z podsumowania (normalnie z logiki JS liczącej tabelę)
|
||||
// Zakładamy, że user klika, a my bierzemy '0.00' lub cokolwiek tam jest
|
||||
if (payFullBtn && paidInput) {
|
||||
payFullBtn.addEventListener('click', function () {
|
||||
// W prawdziwej aplikacji pobrałbyś sumę z obiektu calculateTotal()
|
||||
// Tutaj dla przykładu wpiszemy placeholder, bo tabela jest pusta
|
||||
paidInput.value = "1230.00"; // Przykładowa wartość
|
||||
paidInput.focus();
|
||||
});
|
||||
}
|
||||
|
||||
// --- OCR Simulation Logic for Page ---
|
||||
const ocrBtnPage = document.getElementById('btn-ocr-read-page');
|
||||
if (ocrBtnPage) {
|
||||
ocrBtnPage.addEventListener('click', function () {
|
||||
const btn = this;
|
||||
|
||||
// 1. Loader
|
||||
btn.disabled = true;
|
||||
btn.innerHTML = '<span class="spinner-border spinner-border-sm me-1" role="status" aria-hidden="true"></span> Przetwarzanie obrazu...';
|
||||
|
||||
// 2. Delay
|
||||
setTimeout(() => {
|
||||
// 3. Fill Data
|
||||
|
||||
// Vendor (Find the card body with select placeholder)
|
||||
const vendorCardBody = document.querySelector('.card.shadow-none .card-body');
|
||||
if (vendorCardBody) {
|
||||
vendorCardBody.innerHTML = `
|
||||
<div>
|
||||
<h6 class="mb-0">Tauron Polska Energia S.A.</h6>
|
||||
<small class="text-muted d-block">ul. Ks. Piotra Ściegiennego 3</small>
|
||||
<small class="text-muted d-block">40-114 Katowice</small>
|
||||
<small class="text-muted d-block">NIP: 551-102-12-34</small>
|
||||
</div>
|
||||
<button class="btn btn-outline-secondary btn-sm position-absolute end-0 top-0 m-2"><i class="bx bx-x"></i></button>
|
||||
`;
|
||||
}
|
||||
|
||||
// Invoice Data
|
||||
const invNum = document.querySelector('input[placeholder="np. FV/2026/02/105"]');
|
||||
if (invNum) invNum.value = 'FV/KAT/2026/02/552';
|
||||
|
||||
const dates = document.querySelectorAll('.date-picker');
|
||||
if (dates.length >= 3) {
|
||||
dates[0].value = '2026-02-15'; // Purchase
|
||||
dates[1].value = '2026-02-15'; // Issue
|
||||
dates[2].value = '2026-02-29'; // Payment
|
||||
}
|
||||
|
||||
// Items - Row 1
|
||||
const row1 = document.querySelector('table tbody tr:first-child');
|
||||
if (row1) {
|
||||
const inputs = row1.querySelectorAll('input');
|
||||
if (inputs.length >= 5) { // Name, Code, Qty, Price, VAT (select is not input)
|
||||
inputs[0].value = 'Energia elektryczna - taryfa C11'; // Name
|
||||
inputs[1].value = 'PKW-2026'; // Code
|
||||
// inputs[2] is select in some tables, here it is unit select (col 4, idx 3)
|
||||
// wait, let's look at table structure.
|
||||
// td 2: input name [0]
|
||||
// td 3: input code [1]
|
||||
// td 4: select unit
|
||||
// td 5: input qty [2]
|
||||
// td 6: input price [3]
|
||||
|
||||
// Let's use specific selector for safety
|
||||
}
|
||||
|
||||
const nameInput = row1.querySelector('input[placeholder="Np. Usługa księgowa, Paliwo..."]');
|
||||
if (nameInput) nameInput.value = 'Energia elektryczna - taryfa C11';
|
||||
|
||||
const codeInput = row1.querySelector('input[placeholder="-"]');
|
||||
if (codeInput) codeInput.value = 'PKW-2026';
|
||||
|
||||
const qtyInput = row1.querySelector('td:nth-child(5) input');
|
||||
if (qtyInput) qtyInput.value = '1.00';
|
||||
|
||||
const priceInput = row1.querySelector('td:nth-child(6) input');
|
||||
if (priceInput) priceInput.value = '450.00';
|
||||
|
||||
// Update totals in row (td 8 and 9)
|
||||
const netCell = row1.querySelector('td:nth-child(8)');
|
||||
if (netCell) netCell.innerText = '450,00 zł';
|
||||
|
||||
const grossCell = row1.querySelector('td:nth-child(9)');
|
||||
if (grossCell) grossCell.innerText = '553,50 zł';
|
||||
}
|
||||
|
||||
// Summary
|
||||
const summaries = document.querySelectorAll('.card-body .d-flex.justify-content-between span.fw-semibold');
|
||||
if (summaries.length >= 2) {
|
||||
summaries[0].innerText = '450,00 zł'; // Netto
|
||||
summaries[1].innerText = '103,50 zł'; // VAT
|
||||
}
|
||||
|
||||
const totalEl = document.getElementById('finalTotal');
|
||||
if (totalEl) totalEl.innerText = '553,50 zł';
|
||||
|
||||
// 4. Restore Button
|
||||
btn.disabled = false;
|
||||
btn.innerHTML = '<i class="bx bx-check me-1"></i> Dane odczytane poprawnie';
|
||||
btn.classList.remove('btn-label-primary');
|
||||
btn.classList.add('btn-label-success');
|
||||
|
||||
// Animation
|
||||
const allInputs = document.querySelectorAll('input');
|
||||
allInputs.forEach(input => {
|
||||
if (input.value && input.value !== '0.00' && input.type !== 'text' && input.type !== 'hidden') {
|
||||
// Filter a bit to avoid everything flashing
|
||||
}
|
||||
if (input.value && input.value !== '0.00' && input.type !== 'hidden') {
|
||||
input.classList.add('animate__animated', 'animate__flash');
|
||||
setTimeout(() => input.classList.remove('animate__animated', 'animate__flash'), 1000);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
191
prototype/invoice/app-purchase-calendar.php
Normal file
191
prototype/invoice/app-purchase-calendar.php
Normal file
@@ -0,0 +1,191 @@
|
||||
<?php
|
||||
$enablePrototypeComments = false;
|
||||
include '../../header-invoice.php';
|
||||
?>
|
||||
|
||||
<link rel="stylesheet" href="../../assets/vendor/libs/fullcalendar/fullcalendar.css" />
|
||||
<style>
|
||||
/* Custom darker event colors for white text contrast */
|
||||
.fc-event-dark-success {
|
||||
background-color: #1b5e20 !important;
|
||||
border-color: #1b5e20 !important;
|
||||
color: #ffffff !important;
|
||||
}
|
||||
.fc-event-dark-danger {
|
||||
background-color: #b71c1c !important;
|
||||
border-color: #b71c1c !important;
|
||||
color: #ffffff !important;
|
||||
}
|
||||
.fc-event-dark-warning {
|
||||
background-color: #e65100 !important;
|
||||
border-color: #e65100 !important;
|
||||
color: #ffffff !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container-fluid flex-grow-1 container-p-y">
|
||||
|
||||
<h4 class="py-3 mb-4">
|
||||
<span class="text-muted fw-light">Faktury i sprzedaż /</span> Kalendarz płatności
|
||||
</h4>
|
||||
|
||||
<div class="d-flex mb-3 gap-2 align-items-center flex-nowrap overflow-auto pb-2">
|
||||
<button type="button" class="btn btn-label-primary text-nowrap tab-filter-btn" data-filter="all">
|
||||
Wszystkie
|
||||
</button>
|
||||
<button type="button" class="btn btn-label-secondary text-nowrap tab-filter-btn" data-filter="paid">
|
||||
Zapłacone
|
||||
</button>
|
||||
<button type="button" class="btn btn-label-secondary text-nowrap tab-filter-btn" data-filter="unpaid">
|
||||
Do zapłaty
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="card app-calendar-wrapper">
|
||||
<div class="row g-0">
|
||||
<!-- Calendar Sidebar -->
|
||||
<div class="col app-calendar-sidebar" id="app-calendar-sidebar" style="display:none;">
|
||||
<!-- Hide sidebar/filter for now, we use tabs -->
|
||||
</div>
|
||||
<!-- /Calendar Sidebar -->
|
||||
|
||||
<!-- Calendar & Tabs -->
|
||||
<div class="col app-calendar-content">
|
||||
<div class="card shadow-none border-0">
|
||||
<div class="card-body pb-0">
|
||||
<div id="calendar"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /Calendar & Tabs -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
|
||||
<script src="../../assets/vendor/libs/fullcalendar/fullcalendar.js"></script>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const calendarEl = document.getElementById('calendar');
|
||||
const today = new Date();
|
||||
const y = today.getFullYear();
|
||||
const m = today.getMonth(); // 0-indexed
|
||||
|
||||
// Mock Data
|
||||
// Paid: Green, use payment date
|
||||
// Unpaid: Red/Orange, use due date
|
||||
const allEvents = [
|
||||
// PAID (Past)
|
||||
{
|
||||
id: 1,
|
||||
title: 'FV/2026/01/001 - Comarch',
|
||||
start: new Date(y, m, 5),
|
||||
allDay: true,
|
||||
extendedProps: { status: 'paid', amount: '1230.00 PLN' },
|
||||
className: 'fc-event-dark-success'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: 'FV/2026/01/015 - Google Cloud',
|
||||
start: new Date(y, m, 10),
|
||||
allDay: true,
|
||||
extendedProps: { status: 'paid', amount: '50.00 USD' },
|
||||
className: 'fc-event-dark-success'
|
||||
},
|
||||
|
||||
// UNPAID (Future / Current)
|
||||
{
|
||||
id: 3,
|
||||
title: 'FV/2026/02/105 - Tauron',
|
||||
start: new Date(y, m, 24), // Due date
|
||||
allDay: true,
|
||||
extendedProps: { status: 'unpaid', amount: '553.50 PLN' },
|
||||
className: 'fc-event-dark-danger'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: 'FV/2026/02/110 - Orange',
|
||||
start: new Date(y, m, 28), // Due date
|
||||
allDay: true,
|
||||
extendedProps: { status: 'unpaid', amount: '120.00 PLN' },
|
||||
className: 'fc-event-dark-warning'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
title: 'FV/2026/02/115 - Biurorach',
|
||||
start: new Date(y, m + 1, 5), // Next month
|
||||
allDay: true,
|
||||
extendedProps: { status: 'unpaid', amount: '1500.00 PLN' },
|
||||
className: 'fc-event-dark-warning'
|
||||
}
|
||||
];
|
||||
|
||||
let calendar = new Calendar(calendarEl, {
|
||||
plugins: [dayGridPlugin, interactionPlugin, listPlugin, timegridPlugin],
|
||||
initialView: 'dayGridMonth',
|
||||
headerToolbar: {
|
||||
left: 'prev,next today',
|
||||
center: 'title',
|
||||
right: 'dayGridMonth,listMonth'
|
||||
},
|
||||
buttonText: {
|
||||
today: 'Dzisiaj',
|
||||
month: 'Miesiąc',
|
||||
week: 'Tydzień',
|
||||
day: 'Dzień',
|
||||
list: 'Lista'
|
||||
},
|
||||
events: allEvents,
|
||||
locale: 'pl',
|
||||
firstDay: 1, // Start week on Monday
|
||||
eventDidMount: function (info) {
|
||||
// Add tooltip using Bootstrap
|
||||
if (info.event.extendedProps.amount) {
|
||||
new bootstrap.Tooltip(info.el, {
|
||||
title: info.event.title + ' (' + info.event.extendedProps.amount + ')',
|
||||
placement: 'top',
|
||||
trigger: 'hover',
|
||||
container: 'body'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
calendar.render();
|
||||
|
||||
// Tabs Filtering
|
||||
const tabBtns = document.querySelectorAll('.tab-filter-btn');
|
||||
tabBtns.forEach(btn => {
|
||||
btn.addEventListener('click', function (e) {
|
||||
// Remove active class from all
|
||||
tabBtns.forEach(b => {
|
||||
b.classList.remove('btn-label-primary');
|
||||
b.classList.add('btn-label-secondary');
|
||||
});
|
||||
// Add active class to clicked
|
||||
this.classList.remove('btn-label-secondary');
|
||||
this.classList.add('btn-label-primary');
|
||||
|
||||
const filter = this.getAttribute('data-filter');
|
||||
console.log("Filtering by:", filter);
|
||||
|
||||
// Remove all events first
|
||||
calendar.removeAllEvents();
|
||||
|
||||
// Filter and add back
|
||||
let filteredEvents = [];
|
||||
if (filter === 'all') {
|
||||
filteredEvents = allEvents;
|
||||
} else {
|
||||
filteredEvents = allEvents.filter(ev => ev.extendedProps.status === filter);
|
||||
}
|
||||
|
||||
filteredEvents.forEach(ev => calendar.addEvent(ev));
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
1230
prototype/invoice/app-purchase-list.php
Normal file
1230
prototype/invoice/app-purchase-list.php
Normal file
File diff suppressed because it is too large
Load Diff
349
prototype/invoice/app-report-customers.php
Normal file
349
prototype/invoice/app-report-customers.php
Normal file
@@ -0,0 +1,349 @@
|
||||
<?php
|
||||
$enablePrototypeComments = false;
|
||||
include '../../header-invoice.php';
|
||||
?>
|
||||
|
||||
<div class="container-xxl flex-grow-1 container-p-y">
|
||||
<!-- Vendors CSS dla Select2 i Flatpickr -->
|
||||
<link rel="stylesheet" href="../../assets/vendor/libs/select2/select2.css" />
|
||||
<link rel="stylesheet" href="../../assets/vendor/libs/flatpickr/flatpickr.css" />
|
||||
|
||||
<!-- Nagłówek i przyciski akcji -->
|
||||
<div
|
||||
class="d-flex flex-column flex-md-row justify-content-between align-items-start align-items-md-center mb-4 gap-3">
|
||||
<div>
|
||||
<h4 class="fw-bold mb-1">
|
||||
<span class="text-muted fw-light">Raporty /</span> Ranking klientów
|
||||
</h4>
|
||||
<p class="text-muted mb-0">Zestawienie kontrahentów generujących największy przychód (Top Nabywców).</p>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<button class="btn btn-label-secondary">
|
||||
<i class="bx bx-export me-1"></i> Eksportuj CSV
|
||||
</button>
|
||||
<button class="btn btn-primary">
|
||||
<i class="bx bx-printer me-1"></i> Drukuj raport
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Karta filtrów -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<form class="row g-3">
|
||||
<div class="col-12 col-md-4">
|
||||
<label class="form-label" for="reportDateRange">Zakres dat</label>
|
||||
<div class="input-group input-group-merge">
|
||||
<span class="input-group-text"><i class="bx bx-calendar"></i></span>
|
||||
<input type="text" id="reportDateRange" class="form-control flatpickr-range"
|
||||
placeholder="Wybierz okres (od - do)" value="2026-01-01 do 2026-06-30" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<label class="form-label" for="reportLimit">Zakres danych</label>
|
||||
<select id="reportLimit" class="form-select select2">
|
||||
<option value="10" selected>Top 10</option>
|
||||
<option value="50">Top 50</option>
|
||||
<option value="all">Wszyscy</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-12 col-md-4 d-flex align-items-end">
|
||||
<button type="button" class="btn btn-primary w-100 w-md-auto">
|
||||
<i class="bx bx-refresh me-1"></i> Generuj
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-4">
|
||||
<!-- Wykres - zajmuje prawą stronę na dużym ekranie, bądź górę -->
|
||||
<div class="col-12">
|
||||
<div class="card h-100">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h5 class="card-title m-0">Wykres Top 10 Odbiorców</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="customersReportChart" style="min-height: 400px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tabela -->
|
||||
<div class="col-12">
|
||||
<div class="card h-100">
|
||||
<div class="card-header border-bottom">
|
||||
<h5 class="card-title m-0">Szczegółowe zestawienie</h5>
|
||||
</div>
|
||||
<div class="table-responsive text-nowrap">
|
||||
<table class="table table-hover table-sm align-middle">
|
||||
<thead class="table-light sticky-top">
|
||||
<tr>
|
||||
<th class="text-center" style="width: 50px;">Miejsce</th>
|
||||
<th>Kontrahent</th>
|
||||
<th class="text-center">Dokumenty</th>
|
||||
<th class="text-end">Kwota Netto</th>
|
||||
<th style="width: 120px;">Udział %</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="text-center">
|
||||
<div class="avatar avatar-sm mx-auto">
|
||||
<span
|
||||
class="avatar-initial rounded-circle bg-label-warning fw-bold fs-6">1</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex flex-column">
|
||||
<span class="fw-medium text-heading">TechSolutions Sp. z o.o.</span>
|
||||
<small class="text-muted">NIP: 813-345-67-89</small>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center">24</td>
|
||||
<td class="text-end fw-bold">64 500.00 zł</td>
|
||||
<td>
|
||||
<div class="d-flex justify-content-between align-items-center gap-2">
|
||||
<div class="progress w-100" style="height: 6px;">
|
||||
<div class="progress-bar bg-primary" role="progressbar" style="width: 35.3%"
|
||||
aria-valuenow="35.3" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
<small class="fw-medium">35%</small>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-center">
|
||||
<div class="avatar avatar-sm mx-auto">
|
||||
<span class="avatar-initial rounded-circle bg-label-secondary fw-bold fs-6"
|
||||
style="color:#788393 !important;">2</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex flex-column">
|
||||
<span class="fw-medium text-heading">Gmina Stalowa Wola</span>
|
||||
<small class="text-muted">NIP: 865-123-44-55</small>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center">8</td>
|
||||
<td class="text-end fw-bold">42 800.00 zł</td>
|
||||
<td>
|
||||
<div class="d-flex justify-content-between align-items-center gap-2">
|
||||
<div class="progress w-100" style="height: 6px;">
|
||||
<div class="progress-bar bg-primary" role="progressbar" style="width: 23.4%"
|
||||
aria-valuenow="23.4" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
<small class="fw-medium">23%</small>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-center">
|
||||
<div class="avatar avatar-sm mx-auto">
|
||||
<span class="avatar-initial rounded-circle bg-label-danger fw-bold fs-6"
|
||||
style="color:#ffb400 !important; background-color: #fff2d6 !important;">3</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex flex-column">
|
||||
<span class="fw-medium text-heading">Kwiaciarnia "Róża"</span>
|
||||
<small class="text-muted">NIP: 734-111-22-33</small>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center">45</td>
|
||||
<td class="text-end fw-bold">31 200.00 zł</td>
|
||||
<td>
|
||||
<div class="d-flex justify-content-between align-items-center gap-2">
|
||||
<div class="progress w-100" style="height: 6px;">
|
||||
<div class="progress-bar bg-primary" role="progressbar" style="width: 17.1%"
|
||||
aria-valuenow="17.1" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
<small class="fw-medium">17%</small>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-center"><span class="text-muted fw-bold">4</span></td>
|
||||
<td>
|
||||
<div class="d-flex flex-column">
|
||||
<span class="fw-medium text-heading">F.H.U Jan Kowalski</span>
|
||||
<small class="text-muted">NIP: 555-666-77-88</small>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center">12</td>
|
||||
<td class="text-end fw-bold">18 500.00 zł</td>
|
||||
<td>
|
||||
<div class="d-flex justify-content-between align-items-center gap-2">
|
||||
<div class="progress w-100" style="height: 6px;">
|
||||
<div class="progress-bar bg-primary" role="progressbar" style="width: 10.1%"
|
||||
aria-valuenow="10.1" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
<small class="fw-medium">10%</small>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-center"><span class="text-muted fw-bold">5</span></td>
|
||||
<td>
|
||||
<div class="d-flex flex-column">
|
||||
<span class="fw-medium text-heading">Piekarnia "Złoty Kłos"</span>
|
||||
<small class="text-muted">NIP: 123-456-78-90</small>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center">31</td>
|
||||
<td class="text-end fw-bold">15 400.00 zł</td>
|
||||
<td>
|
||||
<div class="d-flex justify-content-between align-items-center gap-2">
|
||||
<div class="progress w-100" style="height: 6px;">
|
||||
<div class="progress-bar bg-primary" role="progressbar" style="width: 8.4%"
|
||||
aria-valuenow="8.4" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
<small class="fw-medium">8%</small>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-center"><span class="text-muted fw-bold">6</span></td>
|
||||
<td>
|
||||
<div class="d-flex flex-column">
|
||||
<span class="fw-medium text-heading">Sklep Rybny "Posejdon"</span>
|
||||
<small class="text-muted">NIP: 987-654-32-10</small>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center">4</td>
|
||||
<td class="text-end fw-bold">10 150.00 zł</td>
|
||||
<td>
|
||||
<div class="d-flex justify-content-between align-items-center gap-2">
|
||||
<div class="progress w-100" style="height: 6px;">
|
||||
<div class="progress-bar bg-primary" role="progressbar" style="width: 5.6%"
|
||||
aria-valuenow="5.6" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
<small class="fw-medium">6%</small>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot class="table-light fw-bold">
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td class="text-center">124</td>
|
||||
<td class="text-end text-primary">182 550.00 zł</td>
|
||||
<td class="text-center">100%</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
|
||||
<!-- Vendors JS -->
|
||||
<script src="../../assets/vendor/libs/select2/select2.js"></script>
|
||||
<script src="../../assets/vendor/libs/flatpickr/flatpickr.js"></script>
|
||||
|
||||
<!-- ApexCharts scripts and local chart init -->
|
||||
<script src="../../assets/vendor/libs/apex-charts/apexcharts.js"></script>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// 1. Inicjalizacja Flatpickr
|
||||
if (typeof flatpickr !== 'undefined') {
|
||||
const dateRangeEl = document.querySelector('.flatpickr-range');
|
||||
if (dateRangeEl) {
|
||||
flatpickr(dateRangeEl, {
|
||||
mode: 'range',
|
||||
dateFormat: 'Y-m-d',
|
||||
locale: 'pl'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Inicjalizacja Select2
|
||||
if (typeof $ !== 'undefined' && $('.select2').length) {
|
||||
$('.select2').select2({
|
||||
minimumResultsForSearch: Infinity
|
||||
});
|
||||
}
|
||||
|
||||
// 3. Inicjalizacja Wykresu (Horizontal Bar)
|
||||
const chartEl = document.querySelector('#customersReportChart');
|
||||
if (chartEl && typeof ApexCharts !== 'undefined') {
|
||||
const chartConfig = {
|
||||
chart: {
|
||||
type: 'bar',
|
||||
height: 480, // Trochę wyższy by pomieścić wszystkie etykiety
|
||||
parentHeightOffset: 0,
|
||||
toolbar: { show: false }
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
borderRadius: 4,
|
||||
horizontal: true, // Kluczowe by wykres był poziomy
|
||||
barHeight: '50%',
|
||||
startingShape: 'rounded',
|
||||
endingShape: 'rounded'
|
||||
}
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
textAnchor: 'start',
|
||||
style: {
|
||||
colors: ['#fff']
|
||||
},
|
||||
formatter: function (val, opt) {
|
||||
return val.toLocaleString('pl-PL') + " zł";
|
||||
},
|
||||
offsetX: 0,
|
||||
},
|
||||
series: [{
|
||||
name: 'Przychody netto',
|
||||
data: [64500, 42800, 31200, 18500, 15400, 10150]
|
||||
}],
|
||||
xaxis: {
|
||||
categories: [
|
||||
'TechSolutions Sp.', 'Gmina Stalowa Wola',
|
||||
'Kwiaciarnia "Róża"',
|
||||
'F.H.U Jan Kowalski',
|
||||
'Piekarnia Złoty Kłos',
|
||||
'Sklep Rybny Posejdon'
|
||||
],
|
||||
labels: {
|
||||
formatter: function (val) {
|
||||
return (val / 1000) + "k";
|
||||
},
|
||||
style: { colors: '#a1acb8', fontSize: '13px' }
|
||||
},
|
||||
axisBorder: { show: false },
|
||||
},
|
||||
yaxis: {
|
||||
labels: {
|
||||
style: { colors: '#566a7f', fontSize: '13px', fontWeight: 500 }
|
||||
}
|
||||
},
|
||||
colors: ['#696cff'], // Primary color
|
||||
grid: {
|
||||
borderColor: '#e9ecef',
|
||||
strokeDashArray: 4,
|
||||
xaxis: { lines: { show: true } },
|
||||
yaxis: { lines: { show: false } },
|
||||
padding: { top: -20, bottom: -10, left: 10, right: 10 }
|
||||
},
|
||||
tooltip: {
|
||||
y: {
|
||||
formatter: function (val) {
|
||||
return val.toLocaleString('pl-PL') + " zł";
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const customersChart = new ApexCharts(chartEl, chartConfig);
|
||||
customersChart.render();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
330
prototype/invoice/app-report-sales.php
Normal file
330
prototype/invoice/app-report-sales.php
Normal file
@@ -0,0 +1,330 @@
|
||||
<?php
|
||||
$enablePrototypeComments = false;
|
||||
include '../../header-invoice.php';
|
||||
?>
|
||||
|
||||
<div class="container-xxl flex-grow-1 container-p-y">
|
||||
<!-- Vendors CSS dla Select2 i Flatpickr -->
|
||||
<link rel="stylesheet" href="../../assets/vendor/libs/select2/select2.css" />
|
||||
<link rel="stylesheet" href="../../assets/vendor/libs/flatpickr/flatpickr.css" />
|
||||
|
||||
<!-- Nagłówek i przyciski akcji -->
|
||||
<div
|
||||
class="d-flex flex-column flex-md-row justify-content-between align-items-start align-items-md-center mb-4 gap-3">
|
||||
<div>
|
||||
<h4 class="fw-bold mb-1">
|
||||
<span class="text-muted fw-light">Raporty /</span> Raport kwotowy sprzedaży
|
||||
</h4>
|
||||
<p class="text-muted mb-0">Zestawienie wygenerowanych przychodów ze sprzedaży we wskazanym okresie.</p>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<button class="btn btn-label-secondary">
|
||||
<i class="bx bx-export me-1"></i> Eksportuj CSV
|
||||
</button>
|
||||
<button class="btn btn-primary">
|
||||
<i class="bx bx-printer me-1"></i> Drukuj raport
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Karta filtrów -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<form class="row g-3">
|
||||
<div class="col-12 col-md-4">
|
||||
<label class="form-label" for="reportDateRange">Zakres dat</label>
|
||||
<div class="input-group input-group-merge">
|
||||
<span class="input-group-text"><i class="bx bx-calendar"></i></span>
|
||||
<input type="text" id="reportDateRange" class="form-control flatpickr-range"
|
||||
placeholder="Wybierz okres (od - do)" value="2026-01-01 do 2026-06-30" />
|
||||
<button class="btn btn-outline-primary dropdown-toggle" type="button" data-bs-toggle="dropdown"
|
||||
aria-expanded="false">Wybierz</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li><a class="dropdown-item preset-date-range" href="javascript:void(0);"
|
||||
data-range="last-6-months">Ostatnie 6 miesięcy</a></li>
|
||||
<li><a class="dropdown-item preset-date-range" href="javascript:void(0);"
|
||||
data-range="last-12-months">Ostatnie 12 miesięcy</a></li>
|
||||
<li>
|
||||
<hr class="dropdown-divider">
|
||||
</li>
|
||||
<li><a class="dropdown-item preset-date-range" href="javascript:void(0);"
|
||||
data-range="this-month">Ten miesiąc</a></li>
|
||||
<li><a class="dropdown-item preset-date-range" href="javascript:void(0);"
|
||||
data-range="last-month">Poprzedni miesiąc</a></li>
|
||||
<li>
|
||||
<hr class="dropdown-divider">
|
||||
</li>
|
||||
<li><a class="dropdown-item preset-date-range" href="javascript:void(0);"
|
||||
data-range="this-year">Ten rok</a></li>
|
||||
<li><a class="dropdown-item preset-date-range" href="javascript:void(0);"
|
||||
data-range="last-year">Poprzedni rok</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<label class="form-label" for="reportGranularity">Szczegółowość</label>
|
||||
<select id="reportGranularity" class="form-select select2">
|
||||
<option value="days">Dni</option>
|
||||
<option value="months" selected>Miesiące</option>
|
||||
<option value="years">Lata</option>
|
||||
</select>
|
||||
<small id="daysLimitInfo" class="text-muted d-none mt-1 d-block">
|
||||
<i class="bx bx-info-circle fs-6 align-middle me-1"></i>Maksymalny okres dla tej opcji wynosi
|
||||
366 dni.
|
||||
</small>
|
||||
</div>
|
||||
<div class="col-12 col-md-4 d-flex align-items-end">
|
||||
<button type="button" class="btn btn-primary w-100 w-md-auto">
|
||||
<i class="bx bx-refresh me-1"></i> Generuj
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Karta z wykresem -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h5 class="card-title m-0">Przychody netto w czasie</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="salesReportChart" style="min-height: 350px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Karta z tabelą danych -->
|
||||
<div class="card">
|
||||
<div class="card-header border-bottom">
|
||||
<h5 class="card-title m-0">Szczegółowe zestawienie</h5>
|
||||
</div>
|
||||
<div class="table-responsive text-nowrap">
|
||||
<table class="table table-hover">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Okres (Miesiąc)</th>
|
||||
<th class="text-center">Ilość dokumentów</th>
|
||||
<th class="text-end">Suma Kwot Netto</th>
|
||||
<th class="text-end">Suma Kwot VAT</th>
|
||||
<th class="text-end">Suma Kwot Brutto</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="fw-medium">Styczeń 2026</td>
|
||||
<td class="text-center">15</td>
|
||||
<td class="text-end">24 500.00 zł</td>
|
||||
<td class="text-end">5 635.00 zł</td>
|
||||
<td class="text-end fw-bold text-heading">30 135.00 zł</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fw-medium">Luty 2026</td>
|
||||
<td class="text-center">21</td>
|
||||
<td class="text-end">31 200.00 zł</td>
|
||||
<td class="text-end">7 176.00 zł</td>
|
||||
<td class="text-end fw-bold text-heading">38 376.00 zł</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fw-medium">Marzec 2026</td>
|
||||
<td class="text-center">18</td>
|
||||
<td class="text-end">28 450.00 zł</td>
|
||||
<td class="text-end">6 543.50 zł</td>
|
||||
<td class="text-end fw-bold text-heading">34 993.50 zł</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fw-medium">Kwiecień 2026</td>
|
||||
<td class="text-center">24</td>
|
||||
<td class="text-end">36 800.00 zł</td>
|
||||
<td class="text-end">8 464.00 zł</td>
|
||||
<td class="text-end fw-bold text-heading">45 264.00 zł</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fw-medium">Maj 2026</td>
|
||||
<td class="text-center">12</td>
|
||||
<td class="text-end">19 100.00 zł</td>
|
||||
<td class="text-end">4 393.00 zł</td>
|
||||
<td class="text-end fw-bold text-heading">23 493.00 zł</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fw-medium">Czerwiec 2026</td>
|
||||
<td class="text-center">30</td>
|
||||
<td class="text-end">42 500.00 zł</td>
|
||||
<td class="text-end">9 775.00 zł</td>
|
||||
<td class="text-end fw-bold text-heading">52 275.00 zł</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot class="table-light fw-bold">
|
||||
<tr>
|
||||
<td>Podsumowanie całkowite</td>
|
||||
<td class="text-center">120</td>
|
||||
<td class="text-end text-primary">182 550.00 zł</td>
|
||||
<td class="text-end text-primary">41 986.50 zł</td>
|
||||
<td class="text-end text-primary fs-5">224 536.50 zł</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
|
||||
<!-- Vendors JS -->
|
||||
<script src="../../assets/vendor/libs/select2/select2.js"></script>
|
||||
<script src="../../assets/vendor/libs/flatpickr/flatpickr.js"></script>
|
||||
|
||||
<!-- ApexCharts scripts and local chart init -->
|
||||
<script src="../../assets/vendor/libs/apex-charts/apexcharts.js"></script>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// 1. Inicjalizacja Flatpickr dla zakresu dat
|
||||
if (typeof flatpickr !== 'undefined') {
|
||||
const dateRangeEl = document.querySelector('.flatpickr-range');
|
||||
if (dateRangeEl) {
|
||||
const fp = flatpickr(dateRangeEl, {
|
||||
mode: 'range',
|
||||
dateFormat: 'Y-m-d',
|
||||
locale: 'pl'
|
||||
});
|
||||
|
||||
// Obsługa szybkich zakresów dat
|
||||
document.querySelectorAll('.preset-date-range').forEach(item => {
|
||||
item.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
const rangeType = this.getAttribute('data-range');
|
||||
const today = new Date();
|
||||
let startDate = new Date();
|
||||
let endDate = new Date();
|
||||
|
||||
switch (rangeType) {
|
||||
case 'last-6-months':
|
||||
startDate.setMonth(today.getMonth() - 6);
|
||||
break;
|
||||
case 'last-12-months':
|
||||
startDate.setFullYear(today.getFullYear() - 1);
|
||||
break;
|
||||
case 'this-month':
|
||||
startDate = new Date(today.getFullYear(), today.getMonth(), 1);
|
||||
endDate = new Date(today.getFullYear(), today.getMonth() + 1, 0);
|
||||
break;
|
||||
case 'last-month':
|
||||
startDate = new Date(today.getFullYear(), today.getMonth() - 1, 1);
|
||||
endDate = new Date(today.getFullYear(), today.getMonth(), 0);
|
||||
break;
|
||||
case 'this-year':
|
||||
startDate = new Date(today.getFullYear(), 0, 1);
|
||||
endDate = new Date(today.getFullYear(), 11, 31);
|
||||
break;
|
||||
case 'last-year':
|
||||
startDate = new Date(today.getFullYear() - 1, 0, 1);
|
||||
endDate = new Date(today.getFullYear() - 1, 11, 31);
|
||||
break;
|
||||
}
|
||||
|
||||
if (startDate && endDate) {
|
||||
fp.setDate([startDate, endDate]);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Inicjalizacja Select2
|
||||
if (typeof $ !== 'undefined' && $('.select2').length) {
|
||||
$('.select2').select2({
|
||||
minimumResultsForSearch: Infinity // Ukrywamy search jeśli to tylko 3 opcje
|
||||
});
|
||||
|
||||
// Obsługa pojawiania się podpowiedzi po wybraniu z selecta
|
||||
$('#reportGranularity').on('change', function () {
|
||||
const daysInfo = document.getElementById('daysLimitInfo');
|
||||
if (this.value === 'days') {
|
||||
daysInfo.classList.remove('d-none');
|
||||
} else {
|
||||
daysInfo.classList.add('d-none');
|
||||
}
|
||||
});
|
||||
|
||||
// Triggerujemy change dla zainicjowania stanu ukrycia/pokazania podczas ładowania
|
||||
$('#reportGranularity').trigger('change');
|
||||
}
|
||||
|
||||
// 3. Inicjalizacja Wykresu
|
||||
const chartEl = document.querySelector('#salesReportChart');
|
||||
if (chartEl && typeof ApexCharts !== 'undefined') {
|
||||
const chartConfig = {
|
||||
chart: {
|
||||
height: 350,
|
||||
type: 'bar', // lub 'line' / 'area' w zależności od preferencji, bar dobrze działa do zestawień miesięcznych
|
||||
parentHeightOffset: 0,
|
||||
toolbar: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
borderRadius: 4,
|
||||
columnWidth: '40%',
|
||||
startingShape: 'rounded',
|
||||
endingShape: 'rounded'
|
||||
}
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false
|
||||
},
|
||||
series: [{
|
||||
name: 'Przychody netto (PLN)',
|
||||
data: [24500, 31200, 28450, 36800, 19100, 42500]
|
||||
}],
|
||||
xaxis: {
|
||||
categories: ['Styczeń', 'Luty', 'Marzec', 'Kwiecień', 'Maj', 'Czerwiec'],
|
||||
axisBorder: {
|
||||
show: false
|
||||
},
|
||||
axisTicks: {
|
||||
show: false
|
||||
},
|
||||
labels: {
|
||||
style: {
|
||||
colors: '#a1acb8',
|
||||
fontSize: '13px'
|
||||
}
|
||||
}
|
||||
},
|
||||
yaxis: {
|
||||
labels: {
|
||||
formatter: function (val) {
|
||||
return val.toLocaleString('pl-PL') + " zł";
|
||||
},
|
||||
style: {
|
||||
colors: '#a1acb8',
|
||||
fontSize: '13px'
|
||||
}
|
||||
}
|
||||
},
|
||||
colors: ['#696cff'], // Kolor primary bootstrapa z szablonu Sneat
|
||||
grid: {
|
||||
borderColor: '#e9ecef',
|
||||
strokeDashArray: 4,
|
||||
padding: {
|
||||
top: -20,
|
||||
bottom: -10,
|
||||
left: 20,
|
||||
right: 20
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
y: {
|
||||
formatter: function (val) {
|
||||
return val.toLocaleString('pl-PL') + " zł";
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const salesChart = new ApexCharts(chartEl, chartConfig);
|
||||
salesChart.render();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
164
prototype/invoice/app-reports.php
Normal file
164
prototype/invoice/app-reports.php
Normal file
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
$enablePrototypeComments = false;
|
||||
include '../../header-invoice.php';
|
||||
?>
|
||||
|
||||
<div class="container-xxl flex-grow-1 container-p-y">
|
||||
<!-- Header with description -->
|
||||
<div class="card p-0 mb-4">
|
||||
<div class="card-body d-flex flex-column flex-md-row justify-content-between p-0">
|
||||
|
||||
<!-- Left image -->
|
||||
<div class="d-none d-md-flex app-academy-md-25 card-body py-0 pt-3 ps-5 align-items-center">
|
||||
<img src="../../assets/img/illustrations/bulb-light.png" width="90" class="img-fluid" alt="Bulb"
|
||||
data-app-light-img="illustrations/bulb-light.png" data-app-dark-img="illustrations/bulb-dark.png">
|
||||
</div>
|
||||
|
||||
<!-- Center context -->
|
||||
<div class="app-academy-md-50 card-body d-flex align-items-md-center flex-column text-md-center mb-1 py-5">
|
||||
<h4 class="card-title mb-4 px-md-12 lh-base fw-bold">
|
||||
Analizuj i wizualizuj dane finansowe<br>
|
||||
w <span class="text-primary text-nowrap">przejrzystych raportach</span>.
|
||||
</h4>
|
||||
<p class="mb-4 col-md-10 text-muted">
|
||||
Poniżej prezentujemy dostępne raporty, które pomogą Ci śledzić i analizować kondycję finansową
|
||||
Twojej firmy.
|
||||
Monitoruj przychody, koszty oraz rentowność, wybierając odpowiedni typ zestawienia, a następnie
|
||||
dostosuj
|
||||
jego parametry czasowe żeby wygenerować dokument dla pożądanego okresu.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Right image -->
|
||||
<div class="d-none d-md-flex app-academy-md-25 align-items-end justify-content-end pe-4 pb-2">
|
||||
<img src="../../assets/img/illustrations/pencil-rocket.png" alt="pencil rocket" height="150"
|
||||
class="scaleX-n1-rtl">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Reports Gallery -->
|
||||
<div class="card p-4">
|
||||
<div class="row">
|
||||
|
||||
<!-- Raport kwotowy sprzedaży -->
|
||||
<div class="col-sm-6 col-lg-4 mb-4">
|
||||
<div class="card p-2 h-100 shadow-none border">
|
||||
<div class="card-body p-4 pt-2 d-flex flex-column">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<span class="badge bg-label-success">Przychody</span>
|
||||
</div>
|
||||
<a href="javascript:void(0);" class="h5 mb-2 fw-semibold">Raport kwotowy sprzedaży</a>
|
||||
<p class="mt-1 text-muted mb-4 flex-grow-1">
|
||||
Szczegółowe zestawienie wygenerowanych przychodów ze sprzedaży we wskazanym okresie.
|
||||
Pozwala przeanalizować jakie towary i usługi przynoszą największy obrót.
|
||||
</p>
|
||||
<div class="d-flex flex-column flex-md-row gap-4 mt-auto">
|
||||
<a class="w-100 btn btn-label-primary d-flex align-items-center justify-content-center"
|
||||
href="app-report-sales.php">
|
||||
<span class="me-2">Wygeneruj</span>
|
||||
<i class="bx bx-chevron-right icon-sm lh-1 scaleX-n1-rtl"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ranking klientów -->
|
||||
<div class="col-sm-6 col-lg-4 mb-4">
|
||||
<div class="card p-2 h-100 shadow-none border">
|
||||
<div class="card-body p-4 pt-2 d-flex flex-column">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<span class="badge bg-label-success">Przychody</span>
|
||||
</div>
|
||||
<a href="javascript:void(0);" class="h5 mb-2 fw-semibold">Ranking klientów</a>
|
||||
<p class="mt-1 text-muted mb-4 flex-grow-1">
|
||||
Zbiorcze zestawienie wszystkich kontrahentów ułożonych od generujących największy przychód
|
||||
do najmniejszego.
|
||||
Pomaga szybko zidentyfikować kluczowych nabywców.
|
||||
</p>
|
||||
<div class="d-flex flex-column flex-md-row gap-4 mt-auto">
|
||||
<a class="w-100 btn btn-label-primary d-flex align-items-center justify-content-center"
|
||||
href="app-report-customers.php">
|
||||
<span class="me-2">Wygeneruj</span>
|
||||
<i class="bx bx-chevron-right icon-sm lh-1 scaleX-n1-rtl"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Analiza kontrahenta -->
|
||||
<div class="col-sm-6 col-lg-4 mb-4">
|
||||
<div class="card p-2 h-100 shadow-none border">
|
||||
<div class="card-body p-4 pt-2 d-flex flex-column">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<span class="badge bg-label-success">Przychody</span>
|
||||
</div>
|
||||
<a href="javascript:void(0);" class="h5 mb-2 fw-semibold">Historia kontrahenta</a>
|
||||
<p class="mt-1 text-muted mb-4 flex-grow-1">
|
||||
Szczegółowa analiza sprzedaży dla wybranego, pojedynczego klienta.
|
||||
Ukazuje trendy, zestawienie poszczególnych faktur i dokumentów z danym kontrahentem.
|
||||
</p>
|
||||
<div class="d-flex flex-column flex-md-row gap-4 mt-auto">
|
||||
<a class="w-100 btn btn-label-primary d-flex align-items-center justify-content-center"
|
||||
href="javascript:void(0);">
|
||||
<span class="me-2">Wygeneruj</span>
|
||||
<i class="bx bx-chevron-right icon-sm lh-1 scaleX-n1-rtl"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Raport kwotowy kosztów -->
|
||||
<div class="col-sm-6 col-lg-4 mb-4">
|
||||
<div class="card p-2 h-100 shadow-none border">
|
||||
<div class="card-body p-4 pt-2 d-flex flex-column">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<span class="badge bg-label-danger">Koszty i wydatki</span>
|
||||
</div>
|
||||
<a href="javascript:void(0);" class="h5 mb-2 fw-semibold">Raport kwotowy kosztów</a>
|
||||
<p class="mt-1 text-muted mb-4 flex-grow-1">
|
||||
Analiza poniesionych wydatków i kosztów firmowych z podziałem na kategorie oraz sprzedawców,
|
||||
ułatwiająca zlokalizowanie kluczowych obszarów wydatków.
|
||||
</p>
|
||||
<div class="d-flex flex-column flex-md-row gap-4 mt-auto">
|
||||
<a class="w-100 btn btn-label-primary d-flex align-items-center justify-content-center"
|
||||
href="javascript:void(0);">
|
||||
<span class="me-2">Wygeneruj</span>
|
||||
<i class="bx bx-chevron-right icon-sm lh-1 scaleX-n1-rtl"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bilans zysków i strat -->
|
||||
<div class="col-sm-6 col-lg-4 mb-4">
|
||||
<div class="card p-2 h-100 shadow-none border">
|
||||
<div class="card-body p-4 pt-2 d-flex flex-column">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<span class="badge bg-label-info">Podsumowanie całkowite</span>
|
||||
</div>
|
||||
<a href="javascript:void(0);" class="h5 mb-2 fw-semibold">Bilans zysków i strat</a>
|
||||
<p class="mt-1 text-muted mb-4 flex-grow-1">
|
||||
Kompleksowe zestawienie przychodów oraz kosztów. Generuje automatyczne wyliczenia podatków
|
||||
oraz ilustruje całkowitą rentowność i ogólny wynik finansowy w podanym przedziale czasowym.
|
||||
</p>
|
||||
<div class="d-flex flex-column flex-md-row gap-4 mt-auto">
|
||||
<a class="w-100 btn btn-label-primary d-flex align-items-center justify-content-center"
|
||||
href="javascript:void(0);">
|
||||
<span class="me-2">Wygeneruj</span>
|
||||
<i class="bx bx-chevron-right icon-sm lh-1 scaleX-n1-rtl"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
418
prototype/invoice/index.php
Normal file
418
prototype/invoice/index.php
Normal file
@@ -0,0 +1,418 @@
|
||||
<?php
|
||||
$enablePrototypeComments = false;
|
||||
include '../../header-invoice.php';
|
||||
?>
|
||||
|
||||
<div class="container-fluid flex-grow-1 container-p-y">
|
||||
|
||||
<div
|
||||
class="d-flex flex-column flex-md-row justify-content-between align-items-start align-items-md-center mb-4 gap-3">
|
||||
<div class="d-flex flex-column justify-content-center">
|
||||
<h4 class="mb-1 text-body">Witaj w panelu firmy! 👋</h4>
|
||||
<p class="text-muted mb-0">Oto finansowe podsumowanie Twojego biznesu.</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row row-cols-1 row-cols-sm-2 row-cols-md-3 row-cols-xl-5 g-4 mb-4">
|
||||
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-2 pb-1">
|
||||
<div class="avatar me-2">
|
||||
<span class="avatar-initial rounded bg-label-primary"><i
|
||||
class='bx bx-trending-up fs-4'></i></span>
|
||||
</div>
|
||||
<h4 class="ms-1 mb-0 text-nowrap">24 500 zł</h4>
|
||||
</div>
|
||||
<p class="mb-1 fw-medium text-heading">Sprzedaż (Ten miesiąc)</p>
|
||||
<p class="mb-0 text-muted small">
|
||||
<span class="text-success fw-medium"><i class='bx bx-up-arrow-alt'></i> +12.4%</span> vs zeszły
|
||||
m-c
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-2 pb-1">
|
||||
<div class="avatar me-2">
|
||||
<span class="avatar-initial rounded bg-label-secondary"><i
|
||||
class='bx bx-calendar fs-4'></i></span>
|
||||
</div>
|
||||
<h4 class="ms-1 mb-0 text-nowrap">21 800 zł</h4>
|
||||
</div>
|
||||
<p class="mb-1 fw-medium text-heading">Sprzedaż (Poprzedni m-c)</p>
|
||||
<p class="mb-0 text-muted small">Zamknięty okres rozliczeniowy</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-2 pb-1">
|
||||
<div class="avatar me-2">
|
||||
<span class="avatar-initial rounded bg-label-success"><i
|
||||
class='bx bx-wallet fs-4'></i></span>
|
||||
</div>
|
||||
<h4 class="ms-1 mb-0 text-nowrap">15 200 zł</h4>
|
||||
</div>
|
||||
<p class="mb-1 fw-medium text-heading">Należności</p>
|
||||
<p class="mb-0 text-muted small">Niezapłacone faktury (w terminie)</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<div class="card h-100 border border-danger">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-2 pb-1">
|
||||
<div class="avatar me-2">
|
||||
<span class="avatar-initial rounded bg-label-danger"><i
|
||||
class='bx bx-error-circle fs-4'></i></span>
|
||||
</div>
|
||||
<h4 class="ms-1 mb-0 text-danger text-nowrap">4 350 zł</h4>
|
||||
</div>
|
||||
<p class="mb-1 fw-medium text-danger">Po terminie</p>
|
||||
<p class="mb-0 text-muted small">5 dokumentów wymaga uwagi</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-2 pb-1">
|
||||
<div class="avatar me-2">
|
||||
<span class="avatar-initial rounded bg-label-warning"><i
|
||||
class='bx bx-credit-card-front fs-4'></i></span>
|
||||
</div>
|
||||
<h4 class="ms-1 mb-0 text-nowrap">8 100 zł</h4>
|
||||
</div>
|
||||
<p class="mb-1 fw-medium text-heading">Zobowiązania</p>
|
||||
<p class="mb-0 text-muted small">Twoje koszty do opłacenia</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row mb-4 g-4">
|
||||
|
||||
<div class="col-lg-8">
|
||||
<div class="card h-100">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h5 class="card-title mb-0">Sprzedaż netto (Ostatnie 12 miesięcy)</h5>
|
||||
<div class="dropdown">
|
||||
<button class="btn p-0" type="button" data-bs-toggle="dropdown"><i
|
||||
class="bx bx-dots-vertical-rounded"></i></button>
|
||||
<div class="dropdown-menu dropdown-menu-end">
|
||||
<a class="dropdown-item" href="javascript:void(0);">Pobierz jako raport</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="sales12MonthsChart" style="min-height: 300px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h5 class="card-title mb-0">Porównanie Rok do Roku</h5>
|
||||
<select class="form-select form-select-sm w-auto">
|
||||
<option value="3" selected>Ost. 3 lata</option>
|
||||
<option value="5">Ost. 5 lat</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="salesYoYChart" style="min-height: 300px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row g-4">
|
||||
|
||||
<div class="col-lg-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-header border-bottom d-flex justify-content-between align-items-center px-3 py-2">
|
||||
<h5 class="card-title mb-0 pt-1 px-2">Wymaga uwagi</h5>
|
||||
<ul class="nav nav-pills card-header-pills" role="tablist">
|
||||
<li class="nav-item">
|
||||
<button type="button" class="nav-link active btn-sm" data-bs-toggle="tab"
|
||||
data-bs-target="#tab-debtors">Dłużnicy</button>
|
||||
</li>
|
||||
<li class="nav-item ms-2">
|
||||
<button type="button" class="nav-link btn-sm" data-bs-toggle="tab"
|
||||
data-bs-target="#tab-payables">Do zapłaty</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="tab-content p-0">
|
||||
|
||||
<div class="tab-pane fade show active" id="tab-debtors">
|
||||
<div class="table-responsive text-nowrap">
|
||||
<table class="table table-hover table-sm align-middle mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th class="ps-4">Klient</th>
|
||||
<th>Nr Faktury</th>
|
||||
<th class="text-center">Dni zwłoki</th>
|
||||
<th class="text-end pe-4">Kwota</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="table-border-bottom-0">
|
||||
<tr>
|
||||
<td class="ps-4 fw-medium text-heading">Gmina Stalowa Wola</td>
|
||||
<td><a href="#">FV/02/2026</a></td>
|
||||
<td class="text-center"><span class="badge bg-label-danger">14 dni</span>
|
||||
</td>
|
||||
<td class="text-end pe-4 fw-bold">1 250,00 zł</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="ps-4 fw-medium text-heading">TechSolutions Sp. z o.o.</td>
|
||||
<td><a href="#">FV/01/2026</a></td>
|
||||
<td class="text-center"><span class="badge bg-label-warning">5 dni</span>
|
||||
</td>
|
||||
<td class="text-end pe-4 fw-bold">3 100,00 zł</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="p-3 text-center border-top">
|
||||
<a href="app-invoice-list.php" class="btn btn-label-primary btn-sm">Zobacz faktury
|
||||
nierozliczone</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="tab-payables">
|
||||
<div class="table-responsive text-nowrap">
|
||||
<table class="table table-hover table-sm align-middle mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th class="ps-4">Dostawca</th>
|
||||
<th>Termin</th>
|
||||
<th class="text-end pe-4">Kwota</th>
|
||||
<th style="width: 50px;"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="table-border-bottom-0">
|
||||
<tr>
|
||||
<td class="ps-4 fw-medium text-heading">Tauron Polska</td>
|
||||
<td><span class="text-danger fw-bold">Wczoraj</span></td>
|
||||
<td class="text-end pe-4 fw-bold">1 450,20 zł</td>
|
||||
<td><button class="btn btn-sm btn-icon btn-label-success"
|
||||
title="Oznacz jako zapłacone"><i class="bx bx-check"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="ps-4 fw-medium text-heading">Orange S.A.</td>
|
||||
<td>Za 2 dni</td>
|
||||
<td class="text-end pe-4 fw-bold">150,00 zł</td>
|
||||
<td><button class="btn btn-sm btn-icon btn-label-success"
|
||||
title="Oznacz jako zapłacone"><i class="bx bx-check"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="p-3 text-center border-top">
|
||||
<a href="app-purchase-list.php" class="btn btn-label-primary btn-sm">Zobacz wszystkie
|
||||
koszty</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-header border-bottom d-flex justify-content-between align-items-center">
|
||||
<h5 class="card-title mb-0"><i class='bx bx-cloud-download text-primary me-2'></i>Ostatnio pobrane z
|
||||
KSeF</h5>
|
||||
<button class="btn btn-sm btn-label-secondary" title="Sprawdź nowe dokumenty"><i
|
||||
class="bx bx-refresh"></i></button>
|
||||
</div>
|
||||
<div class="table-responsive text-nowrap">
|
||||
<table class="table table-hover table-sm align-middle mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th class="ps-4">Wystawca</th>
|
||||
<th>Numer KSeF</th>
|
||||
<th class="text-end">Kwota Brutto</th>
|
||||
<th class="text-end pe-4">Pobrano</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="table-border-bottom-0">
|
||||
<tr>
|
||||
<td class="ps-4">
|
||||
<span class="fw-medium text-heading">Orlen S.A.</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="text-muted small">...3C4D5E-6F</span>
|
||||
</td>
|
||||
<td class="text-end fw-bold">350,00 zł</td>
|
||||
<td class="text-end pe-4"><span class="badge bg-label-info">15 min temu</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="ps-4">
|
||||
<span class="fw-medium text-heading">PGE Obrót S.A.</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="text-muted small">...A8B9C0-11</span>
|
||||
</td>
|
||||
<td class="text-end fw-bold">1 200,45 zł</td>
|
||||
<td class="text-end pe-4"><span class="badge bg-label-secondary">2 godz. temu</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="ps-4">
|
||||
<span class="fw-medium text-heading">Castorama Polska</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="text-muted small">...F1A2D3-44</span>
|
||||
</td>
|
||||
<td class="text-end fw-bold">840,00 zł</td>
|
||||
<td class="text-end pe-4"><span class="badge bg-label-secondary">Wczoraj</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="ps-4">
|
||||
<span class="fw-medium text-heading">Poczta Polska S.A.</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="text-muted small">...E5F6A7-99</span>
|
||||
</td>
|
||||
<td class="text-end fw-bold">12,50 zł</td>
|
||||
<td class="text-end pe-4"><span class="badge bg-label-secondary">Wczoraj</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="card-footer border-top text-center py-2">
|
||||
<a href="app-purchase-list.php" class="text-primary small fw-medium">Przejdź do listy faktur
|
||||
zakupowych</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="content-backdrop fade"></div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
|
||||
<script src="../../assets/vendor/libs/apex-charts/apexcharts.js"></script>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
// Konfiguracja i kolory ze stylu szablonu
|
||||
let cardColor = '#fff',
|
||||
headingColor = '#566a7f',
|
||||
axisColor = '#a1acb8',
|
||||
borderColor = '#eceef1',
|
||||
primaryColor = '#696cff',
|
||||
infoColor = '#03c3ec';
|
||||
|
||||
// 1. Wykres Słupkowy - 12 Miesięcy (Przychody)
|
||||
const sales12MonthsEl = document.querySelector('#sales12MonthsChart');
|
||||
if (sales12MonthsEl) {
|
||||
const sales12MonthsOptions = {
|
||||
chart: {
|
||||
height: 300,
|
||||
type: 'bar',
|
||||
toolbar: { show: false }
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
borderRadius: 4,
|
||||
columnWidth: '40%',
|
||||
startingShape: 'rounded',
|
||||
endingShape: 'rounded'
|
||||
}
|
||||
},
|
||||
colors: [primaryColor],
|
||||
dataLabels: { enabled: false },
|
||||
series: [{
|
||||
name: 'Sprzedaż Netto (zł)',
|
||||
data: [12000, 15000, 14000, 18000, 22000, 19000, 25000, 21000, 17000, 23000, 21800, 24500]
|
||||
}],
|
||||
xaxis: {
|
||||
categories: ['Kwi', 'Maj', 'Cze', 'Lip', 'Sie', 'Wrz', 'Paź', 'Lis', 'Gru', 'Sty', 'Lut', 'Mar'],
|
||||
axisBorder: { show: false },
|
||||
axisTicks: { show: false },
|
||||
labels: { style: { colors: axisColor } }
|
||||
},
|
||||
yaxis: {
|
||||
labels: { style: { colors: axisColor }, formatter: function (val) { return val / 1000 + "k"; } }
|
||||
},
|
||||
grid: {
|
||||
borderColor: borderColor,
|
||||
strokeDashArray: 4,
|
||||
padding: { top: -20, bottom: -10, left: 10, right: 10 }
|
||||
}
|
||||
};
|
||||
const sales12MonthsChart = new ApexCharts(sales12MonthsEl, sales12MonthsOptions);
|
||||
sales12MonthsChart.render();
|
||||
}
|
||||
|
||||
// 2. Wykres Liniowy - Porównanie Rok do Roku (YoY)
|
||||
const salesYoYEl = document.querySelector('#salesYoYChart');
|
||||
if (salesYoYEl) {
|
||||
const salesYoYOptions = {
|
||||
chart: {
|
||||
height: 300,
|
||||
type: 'line',
|
||||
toolbar: { show: false }
|
||||
},
|
||||
stroke: {
|
||||
width: [2, 2, 2],
|
||||
curve: 'smooth'
|
||||
},
|
||||
colors: [primaryColor, infoColor, '#ffab00'], // Lata 2026, 2025, 2024
|
||||
series: [
|
||||
{ name: '2026', data: [15, 21.8, 24.5, null, null, null, null, null, null, null, null, null] },
|
||||
{ name: '2025', data: [12, 14, 18, 20, 25, 22, 28, 29, 31, 26, 33, 35] },
|
||||
{ name: '2024', data: [10, 11, 13, 14, 17, 16, 20, 21, 23, 22, 25, 28] }
|
||||
],
|
||||
legend: {
|
||||
show: true,
|
||||
position: 'top',
|
||||
horizontalAlign: 'start',
|
||||
labels: { colors: headingColor }
|
||||
},
|
||||
xaxis: {
|
||||
categories: ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', 'XI', 'XII'],
|
||||
axisBorder: { show: false },
|
||||
axisTicks: { show: false },
|
||||
labels: { style: { colors: axisColor } }
|
||||
},
|
||||
yaxis: {
|
||||
show: false // Ukrywamy oś Y by wykres był czystszy (trend jest widoczny z tooltipów)
|
||||
},
|
||||
grid: {
|
||||
borderColor: borderColor,
|
||||
strokeDashArray: 4,
|
||||
padding: { top: 0, bottom: -10, left: 10, right: 10 }
|
||||
}
|
||||
};
|
||||
const salesYoYChart = new ApexCharts(salesYoYEl, salesYoYOptions);
|
||||
salesYoYChart.render();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
184
prototype/invoice/menu.php
Normal file
184
prototype/invoice/menu.php
Normal file
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
$currentPage = basename($_SERVER['PHP_SELF']);
|
||||
?>
|
||||
<aside id="layout-menu" class="layout-menu menu-vertical menu bg-menu-theme" style="padding-top: 10px">
|
||||
<div class="app-brand demo" style="padding-left: .5rem;">
|
||||
<a href="index.php" class="app-brand-link">
|
||||
<svg width="228" height="35" viewBox="0 0 1617 249" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_448_749)">
|
||||
<path d="M405.93 88.56H365.16V64.54H476.18V88.56H435.41V191.94H405.93V88.56Z" fill="#001D4A" />
|
||||
<path
|
||||
d="M548.62 92.56V118.77C546.25 118.59 544.43 118.41 542.25 118.41C526.6 118.41 516.22 126.96 516.22 145.71V191.94H487.83V94.02H514.95V106.94C521.87 97.48 533.51 92.56 548.62 92.56Z"
|
||||
fill="#001D4A" />
|
||||
<path
|
||||
d="M651.641 136.06V191.94H625.071V179.75C619.791 188.67 609.601 193.4 595.221 193.4C572.291 193.4 558.641 180.66 558.641 163.73C558.641 146.8 570.831 134.43 600.681 134.43H623.251C623.251 122.23 615.971 115.14 600.681 115.14C590.311 115.14 579.571 118.6 572.471 124.24L562.281 104.4C573.021 96.76 588.851 92.57 604.501 92.57C634.351 92.57 651.641 106.4 651.641 136.07V136.06ZM623.251 161V150.99H603.781C590.491 150.99 586.311 155.9 586.311 162.46C586.311 169.56 592.321 174.29 602.331 174.29C611.791 174.29 619.981 169.92 623.261 161H623.251Z"
|
||||
fill="#001D4A" />
|
||||
<path d="M772.67 94.02L731.35 191.94H702.05L660.92 94.02H690.22L717.34 160.64L745.37 94.02H772.67Z"
|
||||
fill="#001D4A" />
|
||||
<path
|
||||
d="M876.961 150.99H802.881C805.611 163.18 815.981 170.65 830.911 170.65C841.281 170.65 848.751 167.56 855.481 161.19L870.591 177.57C861.491 187.95 847.841 193.4 830.181 193.4C796.331 193.4 774.301 172.11 774.301 142.98C774.301 113.85 796.691 92.56 826.541 92.56C856.391 92.56 877.501 111.85 877.501 143.34C877.501 145.52 877.141 148.62 876.951 150.98L876.961 150.99ZM802.521 134.43H850.751C848.751 122.05 839.471 114.05 826.731 114.05C813.991 114.05 804.531 121.88 802.521 134.43Z"
|
||||
fill="#001D4A" />
|
||||
<path d="M896.43 56.89H924.82V191.94H896.43V56.89Z" fill="#001D4A" />
|
||||
<path
|
||||
d="M952.26 64.54C952.26 55.62 959.36 48.71 969.91 48.71C980.46 48.71 987.57 55.26 987.57 64C987.57 73.46 980.47 80.38 969.91 80.38C959.35 80.38 952.26 73.46 952.26 64.55V64.54ZM955.72 94.02H984.11V191.94H955.72V94.02Z"
|
||||
fill="#E0740C" />
|
||||
<path
|
||||
d="M1110.6 135.88V191.94H1082.21V140.25C1082.21 124.42 1074.93 117.13 1062.37 117.13C1048.72 117.13 1038.89 125.5 1038.89 143.52V191.93H1010.5V94.01H1037.62V105.48C1045.26 97.11 1056.73 92.56 1070.02 92.56C1093.13 92.56 1110.61 106.03 1110.61 135.88H1110.6Z"
|
||||
fill="#E0740C" />
|
||||
<path
|
||||
d="M1231.64 94.02L1190.33 191.94H1161.03L1119.9 94.02H1149.2L1176.32 160.64L1204.35 94.02H1231.65H1231.64Z"
|
||||
fill="#E0740C" />
|
||||
<path
|
||||
d="M1233.27 142.98C1233.27 113.49 1256.02 92.56 1287.15 92.56C1318.28 92.56 1340.84 113.49 1340.84 142.98C1340.84 172.47 1318.27 193.4 1287.15 193.4C1256.03 193.4 1233.27 172.47 1233.27 142.98ZM1312.08 142.98C1312.08 126.05 1301.34 115.86 1287.15 115.86C1272.96 115.86 1262.03 126.05 1262.03 142.98C1262.03 159.91 1272.95 170.1 1287.15 170.1C1301.35 170.1 1312.08 159.91 1312.08 142.98Z"
|
||||
fill="#E0740C" />
|
||||
<path
|
||||
d="M1356.31 64.54C1356.31 55.62 1363.41 48.71 1373.96 48.71C1384.51 48.71 1391.62 55.26 1391.62 64C1391.62 73.46 1384.52 80.38 1373.96 80.38C1363.4 80.38 1356.31 73.46 1356.31 64.55V64.54ZM1359.76 94.02H1388.15V191.94H1359.76V94.02Z"
|
||||
fill="#E0740C" />
|
||||
<path
|
||||
d="M1407.27 142.98C1407.27 113.49 1430.02 92.56 1461.87 92.56C1482.44 92.56 1498.64 101.48 1505.73 117.5L1483.71 129.33C1478.43 120.05 1470.6 115.86 1461.69 115.86C1447.31 115.86 1436.03 125.87 1436.03 142.98C1436.03 160.09 1447.32 170.1 1461.69 170.1C1470.61 170.1 1478.43 166.1 1483.71 156.63L1505.73 168.64C1498.63 184.29 1482.43 193.39 1461.87 193.39C1430.02 193.39 1407.27 172.46 1407.27 142.97V142.98Z"
|
||||
fill="#E0740C" />
|
||||
<path
|
||||
d="M1616.21 150.99H1542.13C1544.86 163.18 1555.24 170.65 1570.16 170.65C1580.54 170.65 1588 167.56 1594.73 161.19L1609.84 177.57C1600.74 187.95 1587.09 193.4 1569.43 193.4C1535.58 193.4 1513.55 172.11 1513.55 142.98C1513.55 113.85 1535.94 92.56 1565.79 92.56C1595.64 92.56 1616.75 111.85 1616.75 143.34C1616.75 145.52 1616.39 148.62 1616.21 150.98V150.99ZM1541.77 134.43H1590C1588 122.05 1578.71 114.05 1565.97 114.05C1553.23 114.05 1543.76 121.88 1541.76 134.43H1541.77Z"
|
||||
fill="#E0740C" />
|
||||
<path
|
||||
d="M132.02 151.25C120.97 144.9 120.97 128.91 132.02 122.55C135.3 120.66 136.67 116.71 135.27 113.2C132.98 107.47 129.88 102.11 126.05 97.27C123.71 94.31 119.6 93.52 116.34 95.41C105.33 101.78 91.4796 93.82 91.4996 81.06C91.4996 77.27 88.7696 74.11 85.0196 73.57C78.9596 72.7 72.6996 72.7 66.6396 73.57C62.8896 74.11 60.1596 77.27 60.1596 81.06C60.1796 93.8 46.3396 101.79 35.3196 95.41C32.0596 93.52 27.9496 94.3 25.6096 97.27C21.7896 102.11 18.6796 107.47 16.3896 113.2C14.9896 116.71 16.3696 120.67 19.6396 122.55C24.7596 125.49 27.9496 130.99 27.9496 136.9C27.9496 142.81 24.7696 148.31 19.6396 151.25C16.3596 153.13 14.9796 157.09 16.3896 160.6C18.6796 166.32 21.7896 171.69 25.6096 176.53C27.9496 179.49 32.0596 180.27 35.3196 178.38C46.2996 172.03 60.1796 179.93 60.1596 192.73C60.1596 196.52 62.8896 199.68 66.6396 200.22C72.6996 201.09 78.9596 201.1 85.0196 200.22C88.7696 199.68 91.4996 196.52 91.4996 192.73C91.4796 179.98 105.33 172 116.34 178.38C119.61 180.27 123.72 179.48 126.06 176.52C129.88 171.68 132.99 166.32 135.28 160.6C136.68 157.09 135.31 153.13 132.03 151.25H132.02ZM75.8296 159.28C63.4896 159.28 53.4596 149.24 53.4596 136.9C53.4596 124.56 63.4996 114.53 75.8296 114.53C88.1596 114.53 98.2096 124.57 98.2096 136.9C98.2096 149.23 88.1996 159.28 75.8296 159.28Z"
|
||||
fill="url(#paint0_linear_448_749)" />
|
||||
<path
|
||||
d="M121.79 215.99C95.3395 221.5 70.0795 216.46 44.7695 208.22C44.3395 208.08 44.1095 207.62 44.2595 207.18L48.6395 194.41L10.0195 211.36L30.0495 248.5L34.4495 235.73C34.5995 235.31 35.0395 235.08 35.4695 235.22C57.7195 242.32 82.7495 246.67 105.79 240.76C122.58 236.45 136.01 227.29 147.51 214.51L156.57 204.44C144.79 208.98 134.34 213.39 121.8 216L121.79 215.99Z"
|
||||
fill="url(#paint1_linear_448_749)" />
|
||||
<path
|
||||
d="M34.65 59.94C61.05 54.16 86.35 58.94 111.75 66.91C112.18 67.04 112.42 67.5 112.27 67.94L108.02 80.75L146.46 63.4L126.05 26.47L121.78 39.29C121.64 39.72 121.2 39.94 120.77 39.81C98.45 32.94 73.37 28.85 50.39 35C33.64 39.48 20.31 48.78 8.94 61.68L0 71.85C11.73 67.19 22.13 62.68 34.65 59.93V59.94Z"
|
||||
fill="url(#paint2_linear_448_749)" />
|
||||
<path
|
||||
d="M245.04 123.94H148.53C146.79 128.39 143.57 132.28 139.09 134.85C138.31 135.3 137.92 135.99 137.92 136.9C137.92 137.37 138.03 137.77 138.23 138.12H245.04C248.96 138.12 252.13 134.94 252.13 131.03C252.13 127.12 248.95 123.94 245.04 123.94Z"
|
||||
fill="#001D4A" />
|
||||
<path
|
||||
d="M245.04 89.17H137.71C141.12 93.59 144.04 98.34 146.43 103.36H245.04C248.96 103.36 252.13 100.18 252.13 96.27C252.13 92.36 248.95 89.18 245.04 89.18V89.17Z"
|
||||
fill="#001D4A" />
|
||||
<path
|
||||
d="M190.56 42.94H151.36L158.88 56.54C158.98 56.73 159.07 56.93 159.16 57.12H190.56C194.48 57.12 197.65 53.94 197.65 50.03C197.65 46.12 194.47 42.94 190.56 42.94Z"
|
||||
fill="#001D4A" />
|
||||
<path
|
||||
d="M288 46.11C270.79 26.44 264.74 19.76 249.27 4.24C246.58 1.54 242.86 0 239.05 0H130.52C116.93 0 104.86 7.75 97.3096 19.69C102.18 20.47 107.19 21.49 112.34 22.76L112.59 22C114.37 16.66 119.14 12.87 124.75 12.36C125.19 12.32 125.62 12.3 126.05 12.3C128.57 12.3 130.99 12.97 133.11 14.19H224.74V49.69C224.74 61.21 233.02 70.58 243.19 70.58H277.8V194.63C277.8 213.37 265.34 229.21 250.59 229.21H153.06C147.43 234.77 141.53 239.5 135.28 243.4H250.58C273.41 243.4 291.98 221.52 291.98 194.63V56.74C291.98 52.83 290.56 49.05 287.98 46.11H288ZM243.2 56.39C241.23 56.39 238.94 53.46 238.94 49.69V14.19H239.05C239.11 14.19 239.18 14.22 239.22 14.26C254.5 29.58 260.08 35.75 277.32 55.45C277.55 55.72 277.71 56.04 277.77 56.39H243.2Z"
|
||||
fill="#001D4A" />
|
||||
<path
|
||||
d="M89.9397 43.11C89.7597 43.09 89.5896 43.04 89.4196 43.01C89.4196 43.09 89.3996 43.18 89.3896 43.26C89.5696 43.21 89.7497 43.16 89.9397 43.11Z"
|
||||
fill="#001D4A" />
|
||||
<path
|
||||
d="M245.04 157.35H150.01C150.06 160.18 149.57 163.07 148.45 165.87C147.68 167.79 146.83 169.68 145.91 171.54H245.04C248.96 171.54 252.13 168.36 252.13 164.45C252.13 160.54 248.95 157.36 245.04 157.36V157.35Z"
|
||||
fill="#001D4A" />
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_448_749" x1="15.8396" y1="136.91" x2="135.81" y2="136.91"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.4" stop-color="#D26601" />
|
||||
<stop offset="0.94" stop-color="#EC8116" />
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_448_749" x1="21.0018" y1="239.655" x2="150.77" y2="189.399"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.4" stop-color="#D26601" />
|
||||
<stop offset="0.94" stop-color="#EC8116" />
|
||||
</linearGradient>
|
||||
<linearGradient id="paint2_linear_448_749" x1="135.331" y1="35.5783" x2="6.07726" y2="87.1713"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.4" stop-color="#D26601" />
|
||||
<stop offset="0.94" stop-color="#EC8116" />
|
||||
</linearGradient>
|
||||
<clipPath id="clip0_448_749">
|
||||
<rect width="1616.75" height="248.49" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
</a>
|
||||
<a href="javascript:void(0);" class="layout-menu-toggle menu-link text-large ms-auto">
|
||||
<i class="bx bx-chevron-left bx-sm align-middle"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="menu-inner-shadow"></div>
|
||||
|
||||
<ul class="menu-inner py-1">
|
||||
|
||||
<li class="menu-item <?php echo ($currentPage == 'index.php') ? 'active' : ''; ?>">
|
||||
<a href="index.php" class="menu-link">
|
||||
<i class="menu-icon tf-icons bx bx-home-circle"></i>
|
||||
<div class="text-truncate" data-i18n="Kokpit">Kokpit</div>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li
|
||||
class="menu-item <?php echo ($currentPage == 'app-invoice-list.php' || $currentPage == 'app-purchase-list.php' || $currentPage == 'app-purchase-calendar.php' || $currentPage == 'app-products.php') ? 'active open' : ''; ?>">
|
||||
<a href="javascript:void(0);" class="menu-link menu-toggle">
|
||||
<i class="menu-icon tf-icons bx bx-cart-alt"></i>
|
||||
<div class="text-truncate" data-i18n="Faktury i sprzedaż">Faktury i sprzedaż</div>
|
||||
</a>
|
||||
<ul class="menu-sub">
|
||||
<li class="menu-item <?php echo ($currentPage == 'app-invoice-list.php') ? 'active' : ''; ?>">
|
||||
<a href="app-invoice-list.php" class="menu-link">
|
||||
<div class="text-truncate" data-i18n="Faktury sprzedaż">Faktury sprzedaż</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu-item <?php echo ($currentPage == 'app-purchase-list.php') ? 'active' : ''; ?>">
|
||||
<a href="app-purchase-list.php" class="menu-link">
|
||||
<div class="text-truncate" data-i18n="Faktury zakupy">Faktury zakupy</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu-item <?php echo ($currentPage == 'app-purchase-calendar.php') ? 'active' : ''; ?>">
|
||||
<a href="app-purchase-calendar.php" class="menu-link">
|
||||
<div class="text-truncate" data-i18n="Kalendarz płatności">Kalendarz płatności</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu-item <?php echo ($currentPage == 'app-products.php') ? 'active' : ''; ?>">
|
||||
<a href="app-products.php" class="menu-link">
|
||||
<div class="text-truncate" data-i18n="Towary">Towary i usługi</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="menu-item <?php echo ($currentPage == 'app-contractors-list.php') ? 'active' : ''; ?>">
|
||||
<a href="app-contractors-list.php" class="menu-link">
|
||||
<i class="menu-icon tf-icons bx bx-group"></i>
|
||||
<div class="text-truncate" data-i18n="Kontrahenci">Kontrahenci</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu-item <?php echo ($currentPage == 'app-reports.php') ? 'active' : ''; ?>">
|
||||
<a href="app-reports.php" class="menu-link">
|
||||
<i class="menu-icon tf-icons bx bx-bar-chart-alt-2"></i>
|
||||
<div class="text-truncate" data-i18n="Raporty">Raporty</div>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li
|
||||
class="menu-item <?php echo ($currentPage == 'sys-export.php' || $currentPage == 'sys-dictionaries.php' || $currentPage == 'sys-settings.php' || $currentPage == 'sys-logs.php') ? 'active open' : ''; ?>">
|
||||
<a href="javascript:void(0);" class="menu-link menu-toggle">
|
||||
<i class="menu-icon tf-icons bx bx-cog"></i>
|
||||
<div class="text-truncate" data-i18n="System">System</div>
|
||||
</a>
|
||||
<ul class="menu-sub">
|
||||
<li class="menu-item <?php echo ($currentPage == 'sys-export.php') ? 'active' : ''; ?>">
|
||||
<a href="sys-export.php" class="menu-link">
|
||||
<div class="text-truncate" data-i18n="Eksport dokumentów">Eksport dokumentów</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu-item <?php echo ($currentPage == 'sys-dictionaries.php') ? 'active' : ''; ?>">
|
||||
<a href="sys-dictionaries.php" class="menu-link">
|
||||
<div class="text-truncate" data-i18n="Słowniki">Słowniki</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu-item <?php echo ($currentPage == 'sys-settings.php') ? 'active' : ''; ?>">
|
||||
<a href="sys-settings.php" class="menu-link">
|
||||
<div class="text-truncate" data-i18n="Ustawienia">Ustawienia</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="menu-item <?php echo ($currentPage == 'sys-logs.php') ? 'active' : ''; ?>">
|
||||
<a href="sys-logs.php" class="menu-link">
|
||||
<div class="text-truncate" data-i18n="Logi zdarzeń">Logi zdarzeń</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</aside>
|
||||
20
prototype/invoice/sys-dictionaries.php
Normal file
20
prototype/invoice/sys-dictionaries.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
$enablePrototypeComments = false;
|
||||
include '../../header-invoice.php';
|
||||
?>
|
||||
|
||||
<div class="container-xxl flex-grow-1 container-p-y d-flex flex-column justify-content-center">
|
||||
<div class="card p-0 mb-4 h-100 mt-5 border-0 shadow-sm" style="min-height: 400px;">
|
||||
<div class="card-body d-flex flex-column justify-content-center align-items-center p-5 text-center">
|
||||
<h1 class="display-1 text-primary mb-4"><i class="bx bx-book-bookmark"></i></h1>
|
||||
<h3 class="mb-2">Moduł "Słowniki" pojawi się wkrótce!</h3>
|
||||
<p class="text-muted mb-4 fs-5">
|
||||
Obecnie intensywnie pracujemy nad nowymi funkcjonalnościami dla tego modułu.<br>
|
||||
Zaglądaj tu regularnie, aby być na bieżąco z nowościami!
|
||||
</p>
|
||||
<a href="index.php" class="btn btn-primary btn-lg mt-3">Wróć na Kokpit</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
20
prototype/invoice/sys-export.php
Normal file
20
prototype/invoice/sys-export.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
$enablePrototypeComments = false;
|
||||
include '../../header-invoice.php';
|
||||
?>
|
||||
|
||||
<div class="container-xxl flex-grow-1 container-p-y d-flex flex-column justify-content-center">
|
||||
<div class="card p-0 mb-4 h-100 mt-5 border-0 shadow-sm" style="min-height: 400px;">
|
||||
<div class="card-body d-flex flex-column justify-content-center align-items-center p-5 text-center">
|
||||
<h1 class="display-1 text-primary mb-4"><i class="bx bx-export"></i></h1>
|
||||
<h3 class="mb-2">Moduł "Eksport dokumentów" pojawi się wkrótce!</h3>
|
||||
<p class="text-muted mb-4 fs-5">
|
||||
Obecnie intensywnie pracujemy nad nowymi funkcjonalnościami dla tego modułu.<br>
|
||||
Zaglądaj tu regularnie, aby być na bieżąco z nowościami!
|
||||
</p>
|
||||
<a href="index.php" class="btn btn-primary btn-lg mt-3">Wróć na Kokpit</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
20
prototype/invoice/sys-logs.php
Normal file
20
prototype/invoice/sys-logs.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
$enablePrototypeComments = false;
|
||||
include '../../header-invoice.php';
|
||||
?>
|
||||
|
||||
<div class="container-xxl flex-grow-1 container-p-y d-flex flex-column justify-content-center">
|
||||
<div class="card p-0 mb-4 h-100 mt-5 border-0 shadow-sm" style="min-height: 400px;">
|
||||
<div class="card-body d-flex flex-column justify-content-center align-items-center p-5 text-center">
|
||||
<h1 class="display-1 text-primary mb-4"><i class="bx bx-list-ul"></i></h1>
|
||||
<h3 class="mb-2">Moduł "Logi zdarzeń" pojawi się wkrótce!</h3>
|
||||
<p class="text-muted mb-4 fs-5">
|
||||
Obecnie intensywnie pracujemy nad nowymi funkcjonalnościami dla tego modułu.<br>
|
||||
Zaglądaj tu regularnie, aby być na bieżąco z nowościami!
|
||||
</p>
|
||||
<a href="index.php" class="btn btn-primary btn-lg mt-3">Wróć na Kokpit</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
188
prototype/invoice/sys-settings-categories.php
Normal file
188
prototype/invoice/sys-settings-categories.php
Normal file
@@ -0,0 +1,188 @@
|
||||
<?php
|
||||
$enablePrototypeComments = false;
|
||||
include '../../header-invoice.php';
|
||||
?>
|
||||
|
||||
<div class="container-fluid flex-grow-1 container-p-y">
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h4 class="py-3 mb-0">
|
||||
<span class="text-muted fw-light">System / Ustawienia /</span> Kategorie kosztów
|
||||
</h4>
|
||||
<div>
|
||||
<!-- Breadcrumbs or other header actions can go here if needed -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Settings Navigation -->
|
||||
<div class="col-md-3 mb-4 mb-md-0">
|
||||
<div class="card bg-white">
|
||||
<div class="card-body p-2">
|
||||
<ul class="nav nav-pills flex-column">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link w-100 text-start text-body" href="sys-settings.php">Dane firmy</a>
|
||||
</li>
|
||||
<li class="nav-item mt-1">
|
||||
<a class="nav-link w-100 text-start text-body" href="javascript:void(0);">Dokumenty</a>
|
||||
</li>
|
||||
<li class="nav-item mt-1">
|
||||
<a class="nav-link w-100 text-start router-link-active router-link-exact-active btn btn-label-primary"
|
||||
href="sys-settings-categories.php">Kategorie kosztów</a>
|
||||
</li>
|
||||
<li class="nav-item mt-1">
|
||||
<a class="nav-link w-100 text-start text-body" href="javascript:void(0);">Wysyłka e-mail</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Settings Content - Categories List -->
|
||||
<div class="col-md-9">
|
||||
<div class="card">
|
||||
<div class="card-header border-bottom d-flex justify-content-between align-items-center">
|
||||
<h5 class="card-title mb-0">Kategorie kosztów</h5>
|
||||
<button type="button" class="btn btn-primary" data-bs-toggle="modal"
|
||||
data-bs-target="#addCategoryModal">
|
||||
<i class="bx bx-plus me-1"></i> Dodaj
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="card-body pt-4 pb-0">
|
||||
<div class="alert alert-primary alert-dismissible d-flex align-items-center mb-0" role="alert">
|
||||
<span class="alert-icon text-primary me-2">
|
||||
<i class="bx bx-info-circle bx-sm"></i>
|
||||
</span>
|
||||
Kategorie kosztów mają cele statystyczne. Po przypisaniu faktur kosztowych do odpowiedniej
|
||||
kategorii będzie można generować szczegółowe raporty kosztów firmy.
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive text-nowrap mt-3">
|
||||
<table class="table table-hover">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Nazwa kategorii</th>
|
||||
<th>Domyślna</th>
|
||||
<th class="text-end">Akcje</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="table-border-bottom-0">
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Materiały biurowe</strong>
|
||||
</td>
|
||||
<td><span class="badge bg-label-success">TAK</span></td>
|
||||
<td class="text-end">
|
||||
<div class="d-flex justify-content-end align-items-center gap-1">
|
||||
<button type="button" class="btn btn-icon btn-sm text-secondary" title="Edytuj">
|
||||
<i class="bx bx-edit-alt"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-icon btn-sm text-danger" title="Usuń">
|
||||
<i class="bx bx-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Usługi informatyczne</strong>
|
||||
</td>
|
||||
<td><span class="badge bg-label-secondary">NIE</span></td>
|
||||
<td class="text-end">
|
||||
<div class="d-flex justify-content-end align-items-center gap-1">
|
||||
<button type="button" class="btn btn-icon btn-sm text-secondary" title="Edytuj">
|
||||
<i class="bx bx-edit-alt"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-icon btn-sm text-danger" title="Usuń">
|
||||
<i class="bx bx-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Delegacje i podróże</strong>
|
||||
</td>
|
||||
<td><span class="badge bg-label-secondary">NIE</span></td>
|
||||
<td class="text-end">
|
||||
<div class="d-flex justify-content-end align-items-center gap-1">
|
||||
<button type="button" class="btn btn-icon btn-sm text-secondary" title="Edytuj">
|
||||
<i class="bx bx-edit-alt"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-icon btn-sm text-danger" title="Usuń">
|
||||
<i class="bx bx-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Koszty reprezentacji</strong>
|
||||
</td>
|
||||
<td><span class="badge bg-label-secondary">NIE</span></td>
|
||||
<td class="text-end">
|
||||
<div class="d-flex justify-content-end align-items-center gap-1">
|
||||
<button type="button" class="btn btn-icon btn-sm text-secondary" title="Edytuj">
|
||||
<i class="bx bx-edit-alt"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-icon btn-sm text-danger" title="Usuń">
|
||||
<i class="bx bx-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="content-backdrop fade"></div>
|
||||
|
||||
<!-- Add Category Modal -->
|
||||
<div class="modal fade" id="addCategoryModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="addCategoryModalLabel">Dodaj nową kategorię kosztów</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="col mb-3">
|
||||
<label for="categoryName" class="form-label">Nazwa kategorii</label>
|
||||
<input type="text" id="categoryName" class="form-control" placeholder="Wprowadź nazwę..." />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col mb-0">
|
||||
<div class="form-check form-switch mt-2">
|
||||
<input class="form-check-input" type="checkbox" id="isDefaultCategory">
|
||||
<label class="form-check-label" for="isDefaultCategory">Ustaw jako domyślną
|
||||
kategorię</label>
|
||||
<div class="form-text mt-1">Jeśli zaznaczysz tę opcję, poprzednia kategoria domyślna
|
||||
zostanie nadpisana i straci ten status (tylko jedna kategoria może być domyślna).</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Anuluj</button>
|
||||
<button type="button" class="btn btn-primary">Dodaj</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
187
prototype/invoice/sys-settings.php
Normal file
187
prototype/invoice/sys-settings.php
Normal file
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
$enablePrototypeComments = false;
|
||||
include '../../header-invoice.php';
|
||||
?>
|
||||
|
||||
<div class="container-fluid flex-grow-1 container-p-y">
|
||||
|
||||
<h4 class="py-3 mb-4">
|
||||
<span class="text-muted fw-light">System /</span> Ustawienia
|
||||
</h4>
|
||||
|
||||
<div class="row">
|
||||
<!-- Settings Navigation -->
|
||||
<div class="col-md-3 mb-4 mb-md-0">
|
||||
<div class="card bg-white">
|
||||
<div class="card-body p-2">
|
||||
<ul class="nav nav-pills flex-column">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link w-100 text-start router-link-active router-link-exact-active btn btn-label-primary"
|
||||
href="javascript:void(0);">Dane
|
||||
firmy</a>
|
||||
</li>
|
||||
<li class="nav-item mt-1">
|
||||
<a class="nav-link w-100 text-start text-body" href="javascript:void(0);">Dokumenty</a>
|
||||
</li>
|
||||
<li class="nav-item mt-1">
|
||||
<a class="nav-link w-100 text-start text-body" href="sys-settings-categories.php">Kategorie
|
||||
kosztów</a>
|
||||
</li>
|
||||
<li class="nav-item mt-1">
|
||||
<a class="nav-link w-100 text-start text-body" href="javascript:void(0);">Wysyłka e-mail</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Settings Content -->
|
||||
<div class="col-md-9">
|
||||
<div class="card mb-4">
|
||||
<div class="row m-0 mb-3 p-2">
|
||||
<div class="col-md-6 px-0">
|
||||
<h5 class="mb-3 border-bottom p-3 pb-2">Dane</h5>
|
||||
<div class="pt-2 px-3">
|
||||
<div class="mb-3"><label for="input446" class="form-label d-flex align-items-center">Nazwa
|
||||
firmy</label>
|
||||
<div class="input-group"><input type="text" class="form-control" id="input446"
|
||||
value="Magico Software sp. z o.o."><!----><!----><!----></div>
|
||||
</div>
|
||||
<div class="mb-3"><label for="input446"
|
||||
class="form-label d-flex align-items-center">nip</label>
|
||||
<div class="input-group"><input type="text" class="form-control" id="input446"
|
||||
value="PL 865 258 23 86"><!----><!----><!----></div>
|
||||
</div>
|
||||
<div class="mb-3"><label for="input446"
|
||||
class="form-label d-flex align-items-center">regon</label>
|
||||
<div class="input-group"><input type="text" class="form-control" id="input446"
|
||||
value="524220457"><!----><!----><!----></div>
|
||||
</div>
|
||||
<div class="mb-3"><label for="input446" class="form-label d-flex align-items-center">Nazwa
|
||||
banku</label>
|
||||
<div class="input-group"><input type="text" class="form-control" id="input446"
|
||||
value="mBank (SWIFT BREXPLPWMBK)"><!----><!----><!----></div>
|
||||
</div>
|
||||
<div class="mb-3"><label for="input446" class="form-label d-flex align-items-center">Numer
|
||||
konta</label>
|
||||
<div class="input-group"><input type="text" class="form-control" id="input446"
|
||||
value="24 1140 2004 0000 3502 8330 0117"><!----><!----><!----></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="px-3">
|
||||
<div class="mb-3"><label for="input446"
|
||||
class="form-label d-flex align-items-center">telefon</label>
|
||||
<div class="input-group"><input type="text" class="form-control" id="input446"
|
||||
value="+48 726 322 202"><!----><!----><!----></div>
|
||||
</div>
|
||||
<div class="mb-3"><label for="input446"
|
||||
class="form-label d-flex align-items-center">email</label>
|
||||
<div class="input-group"><input type="text" class="form-control" id="input446"
|
||||
value="kontakt@magico.pl"><!----><!----><!----></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 px-0">
|
||||
<h5 class="mb-3 border-bottom p-3 pb-2">Adres firmy</h5>
|
||||
<div class="py-2 px-3">
|
||||
<div class="mb-3"><label for="input446"
|
||||
class="form-label d-flex align-items-center">Ulica</label>
|
||||
<div class="input-group"><input type="text" class="form-control" id="input446"
|
||||
value="Przemysłowa"><!----><!----><!----></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<div class="mb-3"><label for="input446"
|
||||
class="form-label d-flex align-items-center">Numer budynku</label>
|
||||
<div class="input-group"><input type="text" class="form-control" id="input446"
|
||||
value="11"><!----><!----><!----></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="mb-3"><label for="input446"
|
||||
class="form-label d-flex align-items-center">Numer lokalu</label>
|
||||
<div class="input-group"><input type="text" class="form-control" id="input446"
|
||||
value=""><!----><!----><!----></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<div class="mb-3"><label for="input446"
|
||||
class="form-label d-flex align-items-center">Kod pocztowy</label>
|
||||
<div class="input-group"><input type="text" class="form-control" id="input446"
|
||||
value="37-450"><!----><!----><!----></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="mb-3"><label for="input446"
|
||||
class="form-label d-flex align-items-center">Miasto</label>
|
||||
<div class="input-group"><input type="text" class="form-control" id="input446"
|
||||
value="Stalowa Wola"><!----><!----><!----></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3"><label for="input446"
|
||||
class="form-label d-flex align-items-center">Gmina</label>
|
||||
<div class="input-group"><input type="text" class="form-control" id="input446"
|
||||
value="Stalowa Wola"><!----><!----><!----></div>
|
||||
</div>
|
||||
<div class="mb-3"><label for="input446"
|
||||
class="form-label d-flex align-items-center">Powiat</label>
|
||||
<div class="input-group"><input type="text" class="form-control" id="input446"
|
||||
value="Stalowowolski"><!----><!----><!----></div>
|
||||
</div>
|
||||
<div class="mb-3"><label for="input446"
|
||||
class="form-label d-flex align-items-center">Województwo</label>
|
||||
<div class="input-group"><input type="text" class="form-control" id="input446"
|
||||
value="Podkarpackie"><!----><!----><!----></div>
|
||||
</div>
|
||||
<div class="mb-3"><label for="input446"
|
||||
class="form-label d-flex align-items-center">Kraj</label>
|
||||
<div class="input-group"><input type="text" class="form-control" id="input446"
|
||||
value="Polska"><!----><!----><!----></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header border-bottom">
|
||||
<h5 class="card-title mb-0">Logo na dokumentach</h5>
|
||||
</div>
|
||||
<div class="card-body pt-4">
|
||||
<div class="d-flex align-items-start align-items-sm-center gap-4">
|
||||
<!-- Placeholder na logo, jeśli jest jakaś ścieżka ogólna to można zmienić, tutaj dałem szary kwadrat -->
|
||||
<div class="bg-label-secondary rounded d-flex align-items-center justify-content-center"
|
||||
style="width: 100px; height: 100px;">
|
||||
<i class="bx bx-image fs-1 text-secondary"></i>
|
||||
</div>
|
||||
<div class="button-wrapper">
|
||||
<label for="upload" class="btn btn-primary me-2 mb-4" tabindex="0">
|
||||
<span class="d-none d-sm-block">Wgraj nowe logo</span>
|
||||
<i class="bx bx-upload d-block d-sm-none"></i>
|
||||
<input type="file" id="upload" class="account-file-input" hidden
|
||||
accept="image/png, image/jpeg" />
|
||||
</label>
|
||||
<button type="button" class="btn btn-outline-secondary account-image-reset mb-4">
|
||||
<i class="bx bx-reset d-block d-sm-none"></i>
|
||||
<span class="d-none d-sm-block">Resetuj</span>
|
||||
</button>
|
||||
<p class="text-muted mb-0">Dozwolone formaty: JPG, PNG. Maksymalny rozmiar: 800 KB.
|
||||
Rekomentowany wymiar: 300x150 px</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="content-backdrop fade"></div>
|
||||
|
||||
<?php include '../../footer.php'; ?>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php include '../../header-sneat.php'; ?>
|
||||
<?php
|
||||
$enablePrototypeComments = true;
|
||||
include '../../header-sneat.php';
|
||||
?>
|
||||
|
||||
<style>
|
||||
.bg-light {
|
||||
@@ -39,7 +42,7 @@
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-2 mb-4 overflow-auto pb-2" id="inquiryTabs" role="tablist">
|
||||
<button class="btn btn-primary btn-sm d-flex align-items-center text-nowrap"
|
||||
<button class="btn btn-primary btn-sm d-flex align-items-center text-nowrap active"
|
||||
id="tab-general-btn" data-bs-toggle="tab" data-bs-target="#tab-general" type="button"
|
||||
role="tab" aria-selected="true">
|
||||
<i class="bi bi-info-circle me-2"></i> Ogólne
|
||||
@@ -66,8 +69,9 @@
|
||||
<div class="tab-pane fade show active" id="tab-general" role="tabpanel">
|
||||
|
||||
<div class="mb-4">
|
||||
<h5 class="d-flex align-items-center gap-1 text-primary mb-3" style="cursor: pointer;"
|
||||
data-bs-toggle="collapse" data-bs-target="#descCollapse" aria-expanded="true">
|
||||
<h5 class="d-flex align-items-center gap-1 text-primary mb-3"
|
||||
style="cursor: pointer;" data-bs-toggle="collapse"
|
||||
data-bs-target="#descCollapse" aria-expanded="true">
|
||||
<i class="bi bi-chevron-down fs-5"></i> Opis oferty
|
||||
</h5>
|
||||
<div class="collapse show" id="descCollapse">
|
||||
@@ -82,141 +86,137 @@
|
||||
<hr class="my-4">
|
||||
|
||||
<div>
|
||||
<h5 class="d-flex align-items-center gap-1 text-primary mb-4" style="cursor: pointer;"
|
||||
data-bs-toggle="collapse" data-bs-target="#timelineCollapse" aria-expanded="true">
|
||||
<h5 class="d-flex align-items-center gap-1 text-primary mb-4"
|
||||
style="cursor: pointer;" data-bs-toggle="collapse"
|
||||
data-bs-target="#timelineCollapse" aria-expanded="true">
|
||||
<i class="bi bi-chevron-down fs-5"></i> Historia operacji
|
||||
</h5>
|
||||
|
||||
<div class="collapse show" id="timelineCollapse">
|
||||
<ul class="timeline timeline-outline mb-0 pb-0">
|
||||
|
||||
<div id="timeline-initial">
|
||||
|
||||
<!-- Item 1: Komentarz -->
|
||||
<li class="timeline-item timeline-item-transparent pb-3 border-left-dashed">
|
||||
<span class="timeline-point timeline-point-warning"></span>
|
||||
<div class="timeline-event">
|
||||
<div class="timeline-header mb-1">
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<div class="avatar avatar-xs">
|
||||
<span
|
||||
class="avatar-initial rounded-circle bg-label-primary">MT</span>
|
||||
</div>
|
||||
<h6 class="mb-0">Mateusz Travel dodał komentarz</h6>
|
||||
<!-- Item 1: Komentarz -->
|
||||
<li class="timeline-item timeline-item-transparent pb-3 border-left-dashed">
|
||||
<span class="timeline-point timeline-point-warning"></span>
|
||||
<div class="timeline-event">
|
||||
<div class="timeline-header mb-1">
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<div class="avatar avatar-xs">
|
||||
<span
|
||||
class="avatar-initial rounded-circle bg-label-primary">MT</span>
|
||||
</div>
|
||||
<small class="text-muted">15 min temu</small>
|
||||
<h6 class="mb-0">Mateusz Travel dodał komentarz</h6>
|
||||
</div>
|
||||
<div class="bg-lighter p-2 rounded ms-1">
|
||||
<p class="mb-0 small fst-italic">"Klient prosi o zmianę
|
||||
terminu na
|
||||
czerwiec. Do weryfikacji dostępność hoteli."</p>
|
||||
<small class="text-muted">15 min temu</small>
|
||||
</div>
|
||||
<div class="bg-lighter p-2 rounded ms-1">
|
||||
<p class="mb-0 small fst-italic">"Klient prosi o zmianę
|
||||
terminu na
|
||||
czerwiec. Do weryfikacji dostępność hoteli."</p>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<!-- Item 2: Błąd SMS -->
|
||||
<li class="timeline-item timeline-item-transparent pb-3 border-left-dashed">
|
||||
<span class="timeline-point timeline-point-danger"></span>
|
||||
<div class="timeline-event">
|
||||
<div class="timeline-header mb-1">
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<div class="avatar avatar-xs">
|
||||
<span
|
||||
class="avatar-initial rounded-circle bg-label-secondary">SY</span>
|
||||
</div>
|
||||
<h6 class="mb-0 text-danger">Błąd wysyłki SMS (System)
|
||||
</h6>
|
||||
</div>
|
||||
<small class="text-muted">Dziś, 12:21</small>
|
||||
</div>
|
||||
<p class="mb-0 text-danger small ms-1">Limit środków wyczerpany.
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<!-- Item 3: Email -->
|
||||
<li class="timeline-item timeline-item-transparent pb-3 border-left-dashed">
|
||||
<span class="timeline-point timeline-point-secondary"></span>
|
||||
<div class="timeline-event">
|
||||
<div
|
||||
class="timeline-header mb-1 d-flex justify-content-between align-items-center">
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<div class="avatar avatar-xs">
|
||||
<img src="https://demos.themeselection.com/sneat-bootstrap-html-admin-template/assets/img/avatars/1.png"
|
||||
alt="Avatar" class="rounded-circle" />
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="mb-0">Wysłano e-mail (Automat)</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<small class="text-muted">Dziś, 12:20</small>
|
||||
<button class="btn btn-xs btn-label-secondary p-1 px-2"
|
||||
type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#emailContent1" aria-expanded="false">
|
||||
<i class="bi bi-eye"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<!-- Item 2: Błąd SMS -->
|
||||
<li class="timeline-item timeline-item-transparent pb-3 border-left-dashed">
|
||||
<span class="timeline-point timeline-point-danger"></span>
|
||||
<div class="timeline-event">
|
||||
<div class="timeline-header mb-1">
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<div class="avatar avatar-xs">
|
||||
<span
|
||||
class="avatar-initial rounded-circle bg-label-secondary">SY</span>
|
||||
</div>
|
||||
<h6 class="mb-0 text-danger">Błąd wysyłki SMS (System)
|
||||
</h6>
|
||||
</div>
|
||||
<small class="text-muted">Dziś, 12:21</small>
|
||||
</div>
|
||||
<p class="mb-0 text-danger small ms-1">Limit środków wyczerpany.
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
<div class="ms-1">
|
||||
<p class="mb-1 small">Temat: <strong>Propozycja wycieczki w
|
||||
Tatry</strong> <span class="text-muted mx-1">|</span>
|
||||
do:
|
||||
jan@jan.pl</p>
|
||||
|
||||
<!-- Item 3: Email -->
|
||||
<li class="timeline-item timeline-item-transparent pb-3 border-left-dashed">
|
||||
<span class="timeline-point timeline-point-secondary"></span>
|
||||
<div class="timeline-event">
|
||||
<div
|
||||
class="timeline-header mb-1 d-flex justify-content-between align-items-center">
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<div class="avatar avatar-xs">
|
||||
<img src="https://demos.themeselection.com/sneat-bootstrap-html-admin-template/assets/img/avatars/1.png"
|
||||
alt="Avatar" class="rounded-circle" />
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="mb-0">Wysłano e-mail (Automat)</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<small class="text-muted">Dziś, 12:20</small>
|
||||
<button class="btn btn-xs btn-label-secondary p-1 px-2"
|
||||
type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#emailContent1" aria-expanded="false">
|
||||
<i class="bi bi-eye"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ms-1">
|
||||
<p class="mb-1 small">Temat: <strong>Propozycja wycieczki w
|
||||
Tatry</strong> <span class="text-muted mx-1">|</span>
|
||||
do:
|
||||
jan@jan.pl</p>
|
||||
|
||||
<div class="collapse mt-1" id="emailContent1">
|
||||
<div
|
||||
class="bg-lighter p-2 rounded border small text-muted">
|
||||
<p class="mb-1">Dzień dobry,</p>
|
||||
<p class="mb-1">W załączeniu przesyłam wstępną
|
||||
ofertę
|
||||
wyjazdu w
|
||||
Tatry dla grupy szkolnej. Proszę o zapoznanie
|
||||
się z
|
||||
programem.</p>
|
||||
<p class="mb-0">Pozdrawiam, Zespół Mateusz Travel
|
||||
</p>
|
||||
</div>
|
||||
<div class="collapse mt-1" id="emailContent1">
|
||||
<div class="bg-lighter p-2 rounded border small text-muted">
|
||||
<p class="mb-1">Dzień dobry,</p>
|
||||
<p class="mb-1">W załączeniu przesyłam wstępną
|
||||
ofertę
|
||||
wyjazdu w
|
||||
Tatry dla grupy szkolnej. Proszę o zapoznanie
|
||||
się z
|
||||
programem.</p>
|
||||
<p class="mb-0">Pozdrawiam, Zespół Mateusz Travel
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<!-- Item 4: Załączniki -->
|
||||
<li class="timeline-item timeline-item-transparent pb-3 border-left-dashed">
|
||||
<span class="timeline-point timeline-point-dark"></span>
|
||||
<div class="timeline-event">
|
||||
<div class="timeline-header mb-1">
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<div class="avatar avatar-xs">
|
||||
<span
|
||||
class="avatar-initial rounded-circle bg-label-primary">MT</span>
|
||||
</div>
|
||||
<h6 class="mb-0">Mateusz Travel wgrał załączniki</h6>
|
||||
<!-- Item 4: Załączniki -->
|
||||
<li class="timeline-item timeline-item-transparent pb-3 border-left-dashed">
|
||||
<span class="timeline-point timeline-point-dark"></span>
|
||||
<div class="timeline-event">
|
||||
<div class="timeline-header mb-1">
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<div class="avatar avatar-xs">
|
||||
<span
|
||||
class="avatar-initial rounded-circle bg-label-primary">MT</span>
|
||||
</div>
|
||||
<small class="text-muted">Dziś, 12:15</small>
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-2 ms-1">
|
||||
<i class="bi bi-file-earmark-pdf text-danger"></i>
|
||||
<span class="small">Oferta_Wstepna_v1.pdf</span>
|
||||
<h6 class="mb-0">Mateusz Travel wgrał załączniki</h6>
|
||||
</div>
|
||||
<small class="text-muted">Dziś, 12:15</small>
|
||||
</div>
|
||||
</li>
|
||||
<div class="d-flex align-items-center gap-2 ms-1">
|
||||
<i class="bi bi-file-earmark-pdf text-danger"></i>
|
||||
<span class="small">Oferta_Wstepna_v1.pdf</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<!-- Item 5: Zadanie -->
|
||||
<li class="timeline-item timeline-item-transparent pb-3 border-left-dashed">
|
||||
<span class="timeline-point timeline-point-warning"></span>
|
||||
<div class="timeline-event">
|
||||
<div class="timeline-header mb-1">
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<div class="avatar avatar-xs">
|
||||
<span
|
||||
class="avatar-initial rounded-circle bg-label-primary">MT</span>
|
||||
</div>
|
||||
<h6 class="mb-0">Utworzono zadanie</h6>
|
||||
<!-- Item 5: Zadanie -->
|
||||
<li class="timeline-item timeline-item-transparent pb-3 border-left-dashed">
|
||||
<span class="timeline-point timeline-point-warning"></span>
|
||||
<div class="timeline-event">
|
||||
<div class="timeline-header mb-1">
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<div class="avatar avatar-xs">
|
||||
<span
|
||||
class="avatar-initial rounded-circle bg-label-primary">MT</span>
|
||||
</div>
|
||||
<small class="text-muted">Dziś, 11:00</small>
|
||||
<h6 class="mb-0">Utworzono zadanie</h6>
|
||||
</div>
|
||||
<div
|
||||
class="bg-label-warning rounded p-1 px-2 d-inline-block ms-1">
|
||||
@@ -225,24 +225,29 @@
|
||||
kalkulację</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div id="load-more-container" class="text-center py-2 border-left-dashed"
|
||||
style="margin-left: 14px; border-left: 1px dashed #d9dee3;">
|
||||
<button id="btn-load-more"
|
||||
class="btn btn-xs btn-outline-primary rounded-pill">
|
||||
<span class="spinner-border spinner-border-sm me-1 d-none"
|
||||
role="status" aria-hidden="true"></span>
|
||||
<i class="bi bi-arrow-down-circle me-1"></i> Wczytaj wcześniejsze
|
||||
(2)
|
||||
</button>
|
||||
</div>
|
||||
<!-- Load More Action -->
|
||||
<div id="load-more-container" class="text-center py-2 border-left-dashed"
|
||||
style="margin-left: 14px; border-left: 1px dashed #d9dee3;">
|
||||
<button id="btn-load-more"
|
||||
class="btn btn-xs btn-outline-primary rounded-pill">
|
||||
<span class="spinner-border spinner-border-sm me-1 d-none" role="status"
|
||||
aria-hidden="true"></span>
|
||||
<i class="bi bi-arrow-down-circle me-1"></i> Wczytaj wcześniejsze
|
||||
(2)
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="timeline-extra" class="d-none">
|
||||
<!-- Extra items (initially hidden) -->
|
||||
<div id="timeline-extra" class="d-none">
|
||||
<ul class="timeline timeline-outline mb-0 pb-0 pt-0">
|
||||
|
||||
<!-- Item 6: Zmiana danych -->
|
||||
<li class="timeline-item timeline-item-transparent pb-3 border-left-dashed">
|
||||
<li
|
||||
class="timeline-item timeline-item-transparent pb-3 border-left-dashed">
|
||||
<span class="timeline-point timeline-point-info"></span>
|
||||
<div class="timeline-event">
|
||||
<div class="timeline-header mb-1">
|
||||
@@ -279,39 +284,190 @@
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</div>
|
||||
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Tap Pane: Komentarze -->
|
||||
<div class="tab-pane fade" id="tab-comments" role="tabpanel">
|
||||
<div class="text-center py-5 text-muted">
|
||||
<i class="bi bi-chat-left-text fs-1 d-block mb-3"></i>
|
||||
<h5 class="mb-1">Brak komentarzy</h5>
|
||||
<p class="mb-0 small">Komentarze pojawią się w tym miejscu.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tap Pane: Zadania -->
|
||||
<div class="tab-pane fade" id="tab-tasks" role="tabpanel">
|
||||
<div class="text-center py-5 text-muted">
|
||||
<i class="bi bi-check2-circle fs-1 d-block mb-3"></i>
|
||||
<h5 class="mb-1">Brak zadań</h5>
|
||||
<p class="mb-0 small">Zadania przypisane do tego zapytania pojawią się tutaj.</p>
|
||||
<i class="bi bi-chat-left-text fs-1 d-block mb-3"></i>
|
||||
<h5 class="mb-1">Brak komentarzy</h5>
|
||||
<p class="mb-0 small">Komentarze pojawią się w tym miejscu.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tap Pane: Inne zapytania -->
|
||||
<div class="tab-pane fade" id="tab-other" role="tabpanel">
|
||||
<div class="text-center py-5 text-muted">
|
||||
<i class="bi bi-briefcase fs-1 d-block mb-3"></i>
|
||||
<h5 class="mb-1">Brak powiązanych zapytań</h5>
|
||||
<p class="mb-0 small">Inne zapytania tego klienta pojawią się tutaj.</p>
|
||||
<!-- Tap Pane: Zadania -->
|
||||
<div class="tab-pane fade" id="tab-tasks" role="tabpanel">
|
||||
<div class="text-center py-5 text-muted">
|
||||
<i class="bi bi-check2-circle fs-1 d-block mb-3"></i>
|
||||
<h5 class="mb-1">Brak zadań</h5>
|
||||
<p class="mb-0 small">Zadania przypisane do tego zapytania pojawią się tutaj.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tap Pane: Inne zapytania -->
|
||||
<div class="tab-pane fade" id="tab-other" role="tabpanel">
|
||||
<div class="text-center py-5 text-muted">
|
||||
<i class="bi bi-briefcase fs-1 d-block mb-3"></i>
|
||||
<h5 class="mb-1">Brak powiązanych zapytań</h5>
|
||||
<p class="mb-0 small">Inne zapytania tej Organizacji pojawią się tutaj.</p>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
lub
|
||||
<hr>
|
||||
|
||||
<div class="p-3">
|
||||
<div class="alert alert-primary d-flex align-items-center p-3 mb-4" role="alert">
|
||||
<i class="bi bi-info-circle-fill me-2 fs-5"></i>
|
||||
<div class="small">
|
||||
Poniżej znajdują się inne zapytania powiązane z tym klientem (Jan Jan) lub
|
||||
organizacją.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive text-nowrap border rounded mb-3">
|
||||
<table class="table table-sm table-hover mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th style="width: 40px;" class="text-center">
|
||||
<input class="form-check-input" type="checkbox" id="chkAll">
|
||||
</th>
|
||||
<th>Zapytanie / Data</th>
|
||||
<th>Opiekun</th>
|
||||
<th class="text-center">Status</th>
|
||||
<th style="width: 50px;"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="table-border-bottom-0">
|
||||
|
||||
<tr>
|
||||
<td class="text-center align-middle">
|
||||
<input class="form-check-input inquiry-chk" type="checkbox">
|
||||
</td>
|
||||
<td class="align-middle">
|
||||
<div class="d-flex flex-column" style="max-width: 280px;">
|
||||
<a href="#" class="fw-semibold text-truncate text-body"
|
||||
title="#135 - Wycieczka Bieszczady">#135 - Wycieczka
|
||||
Bieszczady</a>
|
||||
<small class="text-muted"
|
||||
style="font-size: 0.75rem;">12.02.2026</small>
|
||||
</div>
|
||||
</td>
|
||||
<td class="align-middle">
|
||||
<div class="d-flex align-items-center" data-bs-toggle="tooltip"
|
||||
title="Mateusz Travel">
|
||||
<div class="avatar avatar-xs me-2">
|
||||
<span
|
||||
class="avatar-initial rounded-circle bg-label-primary"
|
||||
style="font-size: 0.65rem;">MT</span>
|
||||
</div>
|
||||
<small class="text-muted">M. Travel</small>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center align-middle">
|
||||
<span class="badge bg-label-info"
|
||||
style="font-size: 0.7rem; padding: 4px 8px;">Nowa</span>
|
||||
</td>
|
||||
<td class="align-middle text-center">
|
||||
<a href="#"
|
||||
class="btn btn-sm btn-icon btn-label-secondary rounded-circle"
|
||||
data-bs-toggle="tooltip" title="Przejdź do zapytania">
|
||||
<i class="bi bi-arrow-right-short fs-4"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="text-center align-middle">
|
||||
<input class="form-check-input inquiry-chk" type="checkbox">
|
||||
</td>
|
||||
<td class="align-middle">
|
||||
<div class="d-flex flex-column" style="max-width: 280px;">
|
||||
<a href="#" class="fw-semibold text-truncate text-body">#120
|
||||
- Zapytanie ogólne</a>
|
||||
<small class="text-muted"
|
||||
style="font-size: 0.75rem;">28.01.2026</small>
|
||||
</div>
|
||||
</td>
|
||||
<td class="align-middle">
|
||||
<div class="d-flex align-items-center" data-bs-toggle="tooltip"
|
||||
title="Adam Admin">
|
||||
<div class="avatar avatar-xs me-2">
|
||||
<span
|
||||
class="avatar-initial rounded-circle bg-label-secondary"
|
||||
style="font-size: 0.65rem;">AD</span>
|
||||
</div>
|
||||
<small class="text-muted">A. Admin</small>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center align-middle">
|
||||
<span class="badge bg-label-secondary"
|
||||
style="font-size: 0.7rem; padding: 4px 8px;">Nie
|
||||
zainter.</span>
|
||||
</td>
|
||||
<td class="align-middle text-center">
|
||||
<a href="#"
|
||||
class="btn btn-sm btn-icon btn-label-secondary rounded-circle"
|
||||
data-bs-toggle="tooltip" title="Przejdź do zapytania">
|
||||
<i class="bi bi-arrow-right-short fs-4"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="text-center align-middle">
|
||||
<input class="form-check-input inquiry-chk" type="checkbox">
|
||||
</td>
|
||||
<td class="align-middle">
|
||||
<div class="d-flex flex-column" style="max-width: 280px;">
|
||||
<a href="#" class="fw-semibold text-truncate text-body">#115
|
||||
- Kolonie Lato 2026</a>
|
||||
<small class="text-muted"
|
||||
style="font-size: 0.75rem;">15.01.2026</small>
|
||||
</div>
|
||||
</td>
|
||||
<td class="align-middle">
|
||||
<div class="d-flex align-items-center" data-bs-toggle="tooltip"
|
||||
title="Kasia Kowalska">
|
||||
<div class="avatar avatar-xs me-2">
|
||||
<img src="https://demos.themeselection.com/sneat-bootstrap-html-admin-template/assets/img/avatars/5.png"
|
||||
alt="Avatar" class="rounded-circle">
|
||||
</div>
|
||||
<small class="text-muted">K. Kowalska</small>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center align-middle">
|
||||
<span class="badge bg-label-success"
|
||||
style="font-size: 0.7rem; padding: 4px 8px;">Wysłana</span>
|
||||
</td>
|
||||
<td class="align-middle text-center">
|
||||
<a href="#"
|
||||
class="btn btn-sm btn-icon btn-label-secondary rounded-circle"
|
||||
data-bs-toggle="tooltip" title="Przejdź do zapytania">
|
||||
<i class="bi bi-arrow-right-short fs-4"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<small class="text-muted">Wybrano: <strong id="merge-count">0</strong></small>
|
||||
<button class="btn btn-sm btn-primary disabled" id="btn-merge-selection">
|
||||
<i class="bi bi-intersect me-1"></i> Scal zaznaczone
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -744,4 +900,49 @@
|
||||
}, 0);
|
||||
});
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 6. TABS: AKTUALIZACJA STYLI PRZYCISKÓW
|
||||
// ==========================================
|
||||
const tabButtons = document.querySelectorAll('#inquiryTabs button[data-bs-toggle="tab"]');
|
||||
|
||||
tabButtons.forEach(btn => {
|
||||
btn.addEventListener('shown.bs.tab', function (event) {
|
||||
// Reset styli dla wszystkich przycisków w tej grupie
|
||||
tabButtons.forEach(b => {
|
||||
b.classList.remove('btn-primary');
|
||||
b.classList.add('btn-outline-secondary');
|
||||
});
|
||||
|
||||
// Aktywacja klikniętego przycisku
|
||||
event.target.classList.remove('btn-outline-secondary');
|
||||
event.target.classList.add('btn-primary');
|
||||
});
|
||||
});
|
||||
|
||||
(function () {
|
||||
const checkboxes = document.querySelectorAll('.inquiry-checkbox');
|
||||
const btnMerge = document.getElementById('btnMergeInquiries');
|
||||
const countSpan = document.getElementById('selectedCount');
|
||||
const selectAll = document.getElementById('selectAllInquiries');
|
||||
|
||||
function updateState() {
|
||||
const count = Array.from(checkboxes).filter(c => c.checked).length;
|
||||
countSpan.textContent = count;
|
||||
if (count > 0) {
|
||||
btnMerge.removeAttribute('disabled');
|
||||
} else {
|
||||
btnMerge.setAttribute('disabled', 'true');
|
||||
}
|
||||
}
|
||||
|
||||
checkboxes.forEach(cb => cb.addEventListener('change', updateState));
|
||||
|
||||
if (selectAll) {
|
||||
selectAll.addEventListener('change', function () {
|
||||
checkboxes.forEach(cb => cb.checked = this.checked);
|
||||
updateState();
|
||||
});
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
Reference in New Issue
Block a user