poprawki cd
This commit is contained in:
@@ -5349,3 +5349,355 @@ body:not(.sorting-active) .drag-handle {
|
||||
margin-bottom: .65rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========== /expenses mobile fixes: separate range pickers + better wrapping ========== */
|
||||
.endpoint-expenses .expenses-range-toolbar {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.endpoint-expenses .expenses-range-group {
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.endpoint-expenses .expenses-range-group > .btn {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.endpoint-expenses .expenses-date-range {
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
.endpoint-expenses .expenses-range-toolbar {
|
||||
justify-content: stretch !important;
|
||||
overflow: visible;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.endpoint-expenses .expenses-range-group {
|
||||
display: grid !important;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 0.55rem;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.endpoint-expenses .expenses-table-toolbar .expenses-range-group {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.endpoint-expenses .expenses-range-group > .btn {
|
||||
flex: initial !important;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
padding-inline: 0.55rem;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.endpoint-expenses .expenses-date-range {
|
||||
display: grid !important;
|
||||
grid-template-columns: 52px minmax(0, 1fr);
|
||||
gap: 0.55rem;
|
||||
width: 100%;
|
||||
max-width: 100% !important;
|
||||
flex-wrap: wrap !important;
|
||||
}
|
||||
|
||||
.endpoint-expenses .expenses-date-range > .input-group-text,
|
||||
.endpoint-expenses .expenses-date-range > .form-control,
|
||||
.endpoint-expenses .expenses-date-range > .btn {
|
||||
width: 100% !important;
|
||||
min-width: 0 !important;
|
||||
flex: initial !important;
|
||||
border-radius: 0.85rem !important;
|
||||
}
|
||||
|
||||
.endpoint-expenses .expenses-date-range > .btn {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* /share expense entry card aligned with product card */
|
||||
.endpoint-list .shopping-entry-card--expense,
|
||||
.endpoint-list_share .shopping-entry-card--expense,
|
||||
.endpoint-shared_list .shopping-entry-card--expense,
|
||||
.endpoint-view_list .shopping-entry-card--expense {
|
||||
background: linear-gradient(180deg, rgba(13, 110, 253, 0.16), rgba(13, 17, 23, 0.92));
|
||||
border-color: rgba(13, 110, 253, 0.42);
|
||||
}
|
||||
|
||||
.endpoint-list .shopping-entry-card--expense .shopping-entry-card__label,
|
||||
.endpoint-list_share .shopping-entry-card--expense .shopping-entry-card__label,
|
||||
.endpoint-shared_list .shopping-entry-card--expense .shopping-entry-card__label,
|
||||
.endpoint-view_list .shopping-entry-card--expense .shopping-entry-card__label {
|
||||
color: #d7e9ff;
|
||||
}
|
||||
|
||||
.endpoint-list .shopping-entry-card--expense .shopping-expense-input-group,
|
||||
.endpoint-list_share .shopping-entry-card--expense .shopping-expense-input-group,
|
||||
.endpoint-shared_list .shopping-entry-card--expense .shopping-expense-input-group,
|
||||
.endpoint-view_list .shopping-entry-card--expense .shopping-expense-input-group {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.endpoint-list .shopping-entry-card--expense .shopping-expense-input-group > .form-control,
|
||||
.endpoint-list_share .shopping-entry-card--expense .shopping-expense-input-group > .form-control,
|
||||
.endpoint-shared_list .shopping-entry-card--expense .shopping-expense-input-group > .form-control,
|
||||
.endpoint-view_list .shopping-entry-card--expense .shopping-expense-input-group > .form-control {
|
||||
border-color: rgba(13, 110, 253, 0.55) !important;
|
||||
background: rgba(17, 24, 39, 0.95) !important;
|
||||
}
|
||||
|
||||
.endpoint-list .shopping-entry-card--expense .shopping-expense-input-group > .form-control::placeholder,
|
||||
.endpoint-list_share .shopping-entry-card--expense .shopping-expense-input-group > .form-control::placeholder,
|
||||
.endpoint-shared_list .shopping-entry-card--expense .shopping-expense-input-group > .form-control::placeholder,
|
||||
.endpoint-view_list .shopping-entry-card--expense .shopping-expense-input-group > .form-control::placeholder {
|
||||
color: rgba(255, 255, 255, 0.62);
|
||||
}
|
||||
|
||||
.endpoint-list .shopping-entry-card--expense .shopping-expense-input-group > .shopping-expense-amount-input:focus,
|
||||
.endpoint-list_share .shopping-entry-card--expense .shopping-expense-input-group > .shopping-expense-amount-input:focus,
|
||||
.endpoint-shared_list .shopping-entry-card--expense .shopping-expense-input-group > .shopping-expense-amount-input:focus,
|
||||
.endpoint-view_list .shopping-entry-card--expense .shopping-expense-input-group > .shopping-expense-amount-input:focus {
|
||||
box-shadow: inset 0 0 0 1px rgba(13, 110, 253, 0.25), 0 0 0 .2rem rgba(13, 110, 253, 0.18);
|
||||
}
|
||||
|
||||
.endpoint-list .share-submit-btn--expense,
|
||||
.endpoint-list_share .share-submit-btn--expense,
|
||||
.endpoint-shared_list .share-submit-btn--expense,
|
||||
.endpoint-view_list .share-submit-btn--expense {
|
||||
color: #8ec5ff;
|
||||
border-color: rgba(13, 110, 253, 0.72) !important;
|
||||
background: rgba(13, 110, 253, 0.12);
|
||||
}
|
||||
|
||||
.endpoint-list .share-submit-btn--expense:hover,
|
||||
.endpoint-list_share .share-submit-btn--expense:hover,
|
||||
.endpoint-shared_list .share-submit-btn--expense:hover,
|
||||
.endpoint-view_list .share-submit-btn--expense:hover,
|
||||
.endpoint-list .share-submit-btn--expense:focus,
|
||||
.endpoint-list_share .share-submit-btn--expense:focus,
|
||||
.endpoint-shared_list .share-submit-btn--expense:focus,
|
||||
.endpoint-view_list .share-submit-btn--expense:focus {
|
||||
color: #fff;
|
||||
border-color: rgba(13, 110, 253, 0.9) !important;
|
||||
background: rgba(13, 110, 253, 0.22);
|
||||
box-shadow: 0 0 0 .2rem rgba(13, 110, 253, 0.16);
|
||||
}
|
||||
|
||||
/* UX polish 2026-03-19: list quick actions card */
|
||||
.list-quick-actions {
|
||||
display: grid;
|
||||
gap: .9rem;
|
||||
padding: 1rem;
|
||||
border: 1px solid rgba(255,255,255,.08);
|
||||
border-radius: 1rem;
|
||||
background: linear-gradient(180deg, rgba(255,255,255,.04), rgba(255,255,255,.02));
|
||||
box-shadow: 0 .5rem 1.25rem rgba(0,0,0,.14);
|
||||
}
|
||||
|
||||
.list-quick-actions__header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: .75rem;
|
||||
}
|
||||
|
||||
.list-quick-actions__eyebrow {
|
||||
font-size: .72rem;
|
||||
letter-spacing: .08em;
|
||||
text-transform: uppercase;
|
||||
color: rgba(255,255,255,.58);
|
||||
margin-bottom: .15rem;
|
||||
}
|
||||
|
||||
.list-quick-actions__title {
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.list-quick-actions__hint {
|
||||
font-size: .82rem;
|
||||
color: rgba(255,255,255,.62);
|
||||
text-align: right;
|
||||
max-width: 18rem;
|
||||
}
|
||||
|
||||
.list-quick-actions__grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: .75rem;
|
||||
}
|
||||
|
||||
.list-quick-actions__form {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.list-quick-actions__action.btn {
|
||||
width: 100%;
|
||||
min-height: 78px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: .75rem;
|
||||
padding: .9rem 1rem;
|
||||
border-radius: .95rem;
|
||||
text-align: left;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.list-quick-actions__action--primary.btn {
|
||||
border-color: rgba(255,255,255,.2);
|
||||
background: rgba(255,255,255,.03);
|
||||
}
|
||||
|
||||
.list-quick-actions__action--secondary.btn {
|
||||
border-color: rgba(13,110,253,.5);
|
||||
background: rgba(13,110,253,.08);
|
||||
}
|
||||
|
||||
.list-quick-actions__icon {
|
||||
flex: 0 0 auto;
|
||||
font-size: 1.05rem;
|
||||
line-height: 1;
|
||||
margin-top: .1rem;
|
||||
}
|
||||
|
||||
.list-quick-actions__content {
|
||||
display: grid;
|
||||
gap: .2rem;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.list-quick-actions__label {
|
||||
font-size: .95rem;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.list-quick-actions__desc {
|
||||
font-size: .81rem;
|
||||
color: rgba(255,255,255,.66);
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
.list-quick-actions {
|
||||
padding: .9rem;
|
||||
gap: .75rem;
|
||||
}
|
||||
|
||||
.list-quick-actions__header {
|
||||
flex-direction: column;
|
||||
gap: .35rem;
|
||||
}
|
||||
|
||||
.list-quick-actions__hint {
|
||||
max-width: none;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.list-quick-actions__grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.list-quick-actions__action.btn {
|
||||
min-height: 72px;
|
||||
padding: .85rem .9rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* mobile user chip 2026-03-19 */
|
||||
.app-navbar__meta--mobile {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.app-user-chip--mobile {
|
||||
max-width: min(46vw, 15rem);
|
||||
min-width: 0;
|
||||
padding-left: .6rem;
|
||||
padding-right: .4rem;
|
||||
}
|
||||
|
||||
.app-user-chip--mobile .badge {
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@media (max-width: 991.98px) {
|
||||
.app-navbar__meta--mobile {
|
||||
display: flex !important;
|
||||
width: auto;
|
||||
justify-content: flex-end;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.app-user-chip--mobile {
|
||||
display: inline-flex;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 575.98px) {
|
||||
.app-brand__icon {
|
||||
width: 2.25rem;
|
||||
height: 2.25rem;
|
||||
}
|
||||
|
||||
.app-user-chip--mobile {
|
||||
gap: .35rem;
|
||||
padding: .34rem .38rem .34rem .5rem;
|
||||
}
|
||||
|
||||
.app-user-chip--mobile .app-user-chip__label {
|
||||
font-size: .62rem;
|
||||
letter-spacing: .05em;
|
||||
}
|
||||
|
||||
.app-user-chip--mobile .badge {
|
||||
font-size: .72rem;
|
||||
max-width: 5.9rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* mobile navbar layout fix 2026-03-19 */
|
||||
@media (max-width: 991.98px) {
|
||||
.app-navbar .container-xxl {
|
||||
grid-template-columns: minmax(0, 1fr) auto auto;
|
||||
}
|
||||
|
||||
.app-navbar__meta--mobile {
|
||||
grid-column: 2;
|
||||
justify-self: end;
|
||||
min-width: 0;
|
||||
max-width: min(42vw, 12rem);
|
||||
}
|
||||
|
||||
.app-mobile-menu {
|
||||
grid-column: 3;
|
||||
justify-self: end;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 430px) {
|
||||
.app-navbar .container-xxl {
|
||||
grid-template-columns: minmax(0, 1fr) auto auto;
|
||||
gap: .45rem;
|
||||
}
|
||||
|
||||
.app-user-chip--mobile {
|
||||
max-width: min(38vw, 8.5rem);
|
||||
}
|
||||
|
||||
.app-user-chip--mobile .app-user-chip__label {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
}
|
||||
|
||||
// porzucenie zakresu
|
||||
document.querySelectorAll("#chartTab .range-btn").forEach(b => b.classList.remove("active"));
|
||||
document.querySelectorAll("#chartTab .chart-range-btn").forEach(b => b.classList.remove("active"));
|
||||
reloadRespectingSplit();
|
||||
});
|
||||
|
||||
@@ -90,9 +90,9 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
});
|
||||
|
||||
// ——— Predefiniowane zakresy pod wykresem ———
|
||||
document.querySelectorAll("#chartTab .range-btn").forEach((btn) => {
|
||||
document.querySelectorAll("#chartTab .chart-range-btn").forEach((btn) => {
|
||||
btn.addEventListener("click", function () {
|
||||
document.querySelectorAll("#chartTab .range-btn").forEach((b) => b.classList.remove("active"));
|
||||
document.querySelectorAll("#chartTab .chart-range-btn").forEach((b) => b.classList.remove("active"));
|
||||
this.classList.add("active");
|
||||
const r = this.getAttribute("data-range"); // last30days/currentmonth/monthly/quarterly/halfyearly/yearly
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const checkboxes = document.querySelectorAll('.list-checkbox');
|
||||
const totalEl = document.getElementById('listsTotal');
|
||||
const filterButtons = document.querySelectorAll('.range-btn');
|
||||
const filterButtons = document.querySelectorAll('#listsTab .table-range-btn');
|
||||
const rows = document.querySelectorAll('#listsTableBody tr');
|
||||
const categoryButtons = document.querySelectorAll('.category-filter');
|
||||
const applyCustomBtn = document.getElementById('applyCustomRange');
|
||||
@@ -136,7 +136,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
if (initialLoad) {
|
||||
filterByLast30Days();
|
||||
} else {
|
||||
const activeRange = document.querySelector('.range-btn.active');
|
||||
const activeRange = document.querySelector('#listsTab .table-range-btn.active');
|
||||
if (activeRange) filterByRange(activeRange.dataset.range);
|
||||
}
|
||||
applyExpenseFilter();
|
||||
@@ -158,7 +158,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
return;
|
||||
}
|
||||
initialLoad = false;
|
||||
document.querySelectorAll('.range-btn').forEach(b => b.classList.remove('active'));
|
||||
document.querySelectorAll('#listsTab .table-range-btn').forEach(b => b.classList.remove('active'));
|
||||
filterByCustomRange(startStr, endStr);
|
||||
applyExpenseFilter();
|
||||
applyCategoryFilter();
|
||||
|
||||
@@ -58,7 +58,23 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="dropdown d-lg-none app-mobile-menu ms-auto">
|
||||
<div class="d-lg-none app-navbar__meta app-navbar__meta--mobile ms-auto">
|
||||
{% if has_authorized_cookie and not is_blocked %}
|
||||
{% if current_user.is_authenticated %}
|
||||
<div class="app-user-chip app-user-chip--mobile">
|
||||
<span class="app-user-chip__label">Zalogowany</span>
|
||||
<span class="badge rounded-pill text-bg-success">{{ current_user.username }}</span>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="app-user-chip app-user-chip--guest app-user-chip--mobile">
|
||||
<span class="app-user-chip__label">Tryb</span>
|
||||
<span class="badge rounded-pill text-bg-info">gość</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="dropdown d-lg-none app-mobile-menu">
|
||||
<button class="btn app-navbar-toggler app-mobile-menu__toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false" aria-label="Otwórz menu">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
@@ -61,18 +61,18 @@
|
||||
<div class="tab-pane fade show active" id="listsTab" role="tabpanel">
|
||||
<div class="card bg-dark text-white mb-4">
|
||||
<div class="card-body">
|
||||
<div class="d-flex flex-wrap gap-2 mb-3 justify-content-center">
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
<button class="btn btn-outline-light range-btn" data-range="day">🗓️ Dzień</button>
|
||||
<button class="btn btn-outline-light range-btn" data-range="week">📆 Tydzień</button>
|
||||
<button class="btn btn-outline-light range-btn active" data-range="month">📅 Miesiąc</button>
|
||||
<button class="btn btn-outline-light range-btn" data-range="year">📈 Rok</button>
|
||||
<button class="btn btn-outline-light range-btn" data-range="all">🌐 Wszystko</button>
|
||||
<div class="d-flex flex-wrap gap-2 mb-3 justify-content-center expenses-range-toolbar expenses-table-toolbar">
|
||||
<div class="btn-group btn-group-sm expenses-range-group" role="group">
|
||||
<button class="btn btn-outline-light range-btn table-range-btn" data-range="day">🗓️ Dzień</button>
|
||||
<button class="btn btn-outline-light range-btn table-range-btn" data-range="week">📆 Tydzień</button>
|
||||
<button class="btn btn-outline-light range-btn table-range-btn active" data-range="month">📅 Miesiąc</button>
|
||||
<button class="btn btn-outline-light range-btn table-range-btn" data-range="year">📈 Rok</button>
|
||||
<button class="btn btn-outline-light range-btn table-range-btn" data-range="all">🌐 Wszystko</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-center mb-3">
|
||||
<div class="input-group input-group-sm w-100" style="max-width: 570px;">
|
||||
<div class="input-group input-group-sm w-100 expenses-date-range" style="max-width: 570px;">
|
||||
<span class="input-group-text bg-secondary text-white border-secondary">Od</span>
|
||||
<input type="date" class="form-control bg-dark text-white border-secondary flex-grow-1"
|
||||
id="customStart">
|
||||
@@ -169,20 +169,20 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-wrap gap-2 mb-3 justify-content-center">
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
<button class="btn btn-outline-light range-btn" data-range="last30days">🗓️ Ostatnie 30
|
||||
<div class="d-flex flex-wrap gap-2 mb-3 justify-content-center expenses-range-toolbar expenses-chart-toolbar">
|
||||
<div class="btn-group btn-group-sm expenses-range-group" role="group">
|
||||
<button class="btn btn-outline-light range-btn chart-range-btn" data-range="last30days">🗓️ Ostatnie 30
|
||||
dni</button>
|
||||
<button class="btn btn-outline-light range-btn" data-range="currentmonth">📅 Bieżący miesiąc</button>
|
||||
<button class="btn btn-outline-light range-btn" data-range="monthly">📆 Miesięczne</button>
|
||||
<button class="btn btn-outline-light range-btn" data-range="quarterly">📊 Kwartalne</button>
|
||||
<button class="btn btn-outline-light range-btn" data-range="halfyearly">🗓️ Półroczne</button>
|
||||
<button class="btn btn-outline-light range-btn" data-range="yearly">📈 Roczne</button>
|
||||
<button class="btn btn-outline-light range-btn chart-range-btn" data-range="currentmonth">📅 Bieżący miesiąc</button>
|
||||
<button class="btn btn-outline-light range-btn chart-range-btn" data-range="monthly">📆 Miesięczne</button>
|
||||
<button class="btn btn-outline-light range-btn chart-range-btn" data-range="quarterly">📊 Kwartalne</button>
|
||||
<button class="btn btn-outline-light range-btn chart-range-btn" data-range="halfyearly">🗓️ Półroczne</button>
|
||||
<button class="btn btn-outline-light range-btn chart-range-btn" data-range="yearly">📈 Roczne</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-center mb-4">
|
||||
<div class="input-group input-group-sm w-100" style="max-width: 570px;">
|
||||
<div class="input-group input-group-sm w-100 expenses-date-range" style="max-width: 570px;">
|
||||
<span class="input-group-text bg-secondary text-white border-secondary">Od</span>
|
||||
<input type="date" class="form-control bg-dark text-white border-secondary flex-grow-1" id="startDate">
|
||||
<span class="input-group-text bg-secondary text-white border-secondary">Do</span>
|
||||
|
||||
@@ -185,16 +185,6 @@
|
||||
</div>
|
||||
|
||||
{% if not list.is_archived %}
|
||||
<div class="list-action-block mb-3">
|
||||
<div class="list-action-row mb-2">
|
||||
<button class="btn btn-outline-light btn-sm list-action-row__btn" data-bs-toggle="modal" data-bs-target="#massAddModal">
|
||||
Dodaj produkty masowo
|
||||
</button>
|
||||
<form method="post" action="{{ url_for('create_template_from_user_list', list_id=list.id) }}" class="list-action-row__form">
|
||||
<input type="hidden" name="template_name" value="{{ list.title }} - szablon">
|
||||
<button type="submit" class="btn btn-outline-primary btn-sm list-action-row__btn">🧩 Zapisz jako szablon</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="shopping-entry-card mb-3" aria-label="Sekcja dodawania produktu">
|
||||
<div class="shopping-entry-card__label">➕ Dodaj produkt</div>
|
||||
@@ -216,6 +206,37 @@
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="list-quick-actions mb-3" aria-label="Szybkie akcje listy">
|
||||
<div class="list-quick-actions__header">
|
||||
<div>
|
||||
<div class="list-quick-actions__eyebrow">Szybkie akcje</div>
|
||||
<div class="list-quick-actions__title">Dodawanie i zapis listy</div>
|
||||
</div>
|
||||
<div class="list-quick-actions__hint">Najczęściej używane akcje pod ręką.</div>
|
||||
</div>
|
||||
|
||||
<div class="list-quick-actions__grid">
|
||||
<button class="btn btn-outline-light list-quick-actions__action list-quick-actions__action--primary" data-bs-toggle="modal" data-bs-target="#massAddModal" type="button">
|
||||
<span class="list-quick-actions__icon" aria-hidden="true">➕</span>
|
||||
<span class="list-quick-actions__content">
|
||||
<span class="list-quick-actions__label">Dodaj produkty masowo</span>
|
||||
<span class="list-quick-actions__desc">Wklej kilka pozycji naraz i uzupełnij listę szybciej.</span>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<form method="post" action="{{ url_for('create_template_from_user_list', list_id=list.id) }}" class="list-quick-actions__form">
|
||||
<input type="hidden" name="template_name" value="{{ list.title }} - szablon">
|
||||
<button type="submit" class="btn btn-outline-primary list-quick-actions__action list-quick-actions__action--secondary">
|
||||
<span class="list-quick-actions__icon" aria-hidden="true">🧩</span>
|
||||
<span class="list-quick-actions__content">
|
||||
<span class="list-quick-actions__label">Zapisz jako szablon</span>
|
||||
<span class="list-quick-actions__desc">Zachowaj układ tej listy i użyj go ponownie.</span>
|
||||
</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if activity_logs %}
|
||||
@@ -225,7 +246,7 @@
|
||||
<h5 class="mb-0">🕘 Historia zmian listy</h5>
|
||||
<button class="btn btn-sm btn-outline-light" type="button" data-bs-toggle="collapse" data-bs-target="#activityHistory" aria-expanded="false" aria-controls="activityHistory">Pokaż / ukryj</button>
|
||||
</div>
|
||||
<div class="small text-secondary mb-3">Domyślnie ukryte. Zdarzeń: {{ activity_logs|length }}</div>
|
||||
<div class="small text-secondary mb-3">Rozwiń aby zobaczyć | Zdarzeń: {{ activity_logs|length }}</div>
|
||||
<div class="collapse" id="activityHistory">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-dark table-sm align-middle">
|
||||
@@ -248,23 +269,56 @@
|
||||
{% endif %}
|
||||
|
||||
{% set receipt_pattern = 'list_' ~ list.id %}
|
||||
<hr>
|
||||
<h5 class="mt-4">📸 Paragony dodane do tej listy</h5>
|
||||
|
||||
<div class="row g-3 mt-2" id="receiptGallery">
|
||||
{% if receipts %}
|
||||
{% for r in receipts %}
|
||||
<div class="col-6 col-md-4 col-lg-3 text-center">
|
||||
<a href="{{ url_for('uploaded_file', filename=r.filename) }}?v={{ r.version_token or '0' }}" class="glightbox"
|
||||
data-gallery="receipt-gallery">
|
||||
<img src="{{ url_for('uploaded_file', filename=r.filename) }}?v={{ r.version_token or '0' }}"
|
||||
class="img-fluid rounded shadow-sm border border-secondary" style="max-height: 200px; object-fit: cover;">
|
||||
</a>
|
||||
<div class="card bg-dark text-white border-secondary shadow-sm mt-4">
|
||||
<div class="card-body">
|
||||
<div class="d-flex flex-column flex-lg-row align-items-lg-center justify-content-between gap-2 mb-3">
|
||||
<div>
|
||||
<h5 class="mb-1">📄 Paragony dodane do tej listy</h5>
|
||||
<p class="text-secondary small mb-0">
|
||||
Tutaj możesz wygodnie przejrzeć wszystkie paragony przypisane do tej listy.
|
||||
</p>
|
||||
</div>
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<span class="badge rounded-pill bg-secondary">{{ receipts|length }} plik{% if receipts|length != 1 %}i{% endif %}</span>
|
||||
<span class="badge rounded-pill bg-info text-dark">Tylko podgląd</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border border-secondary rounded-3 p-3">
|
||||
<div class="d-flex justify-content-between align-items-center flex-wrap gap-2 mb-3">
|
||||
<h6 class="mb-0">📸 Galeria paragonów</h6>
|
||||
{% if receipts %}
|
||||
<span class="text-secondary small">Kliknij miniaturę, aby otworzyć podgląd</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="row g-3" id="receiptGallery">
|
||||
{% if receipts %}
|
||||
{% for r in receipts %}
|
||||
<div class="col-6 col-md-4 col-xl-3">
|
||||
<a href="{{ url_for('uploaded_file', filename=r.filename) }}?v={{ r.version_token or '0' }}" class="glightbox text-decoration-none"
|
||||
data-gallery="receipt-gallery">
|
||||
<div class="card bg-black border-secondary h-100 overflow-hidden shadow-sm">
|
||||
<img src="{{ url_for('uploaded_file', filename=r.filename) }}?v={{ r.version_token or '0' }}"
|
||||
class="card-img-top img-fluid" style="height: 180px; object-fit: cover;" alt="Paragon {{ loop.index }}">
|
||||
<div class="card-body p-2">
|
||||
<div class="small text-truncate text-secondary">Paragon {{ loop.index }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="col-12">
|
||||
<div class="alert alert-info text-center mb-0" role="alert">
|
||||
ℹ️ Brak wgranych paragonów do tej listy
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="alert alert-info text-center w-100" role="alert">ℹ️ Brak wgranych paragonów do tej listy</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- MODAL: KATEGORIA (pojedynczy wybór) -->
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
</li>
|
||||
{% else %}
|
||||
<li id="empty-placeholder" class="list-group-item bg-dark text-secondary text-center w-100">
|
||||
Brak produktów w tej liście.
|
||||
Brak produktów w tej liście.
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
@@ -109,14 +109,34 @@
|
||||
{% endif %}
|
||||
|
||||
{% if not list.is_archived %}
|
||||
<hr>
|
||||
<h5>💰 Dodaj wydatek</h5>
|
||||
<div class="input-group mb-2 shopping-compact-input-group shopping-expense-input-group">
|
||||
<input id="expenseAmount" type="number" step="0.01" min="0" class="form-control bg-dark text-white border-secondary shopping-expense-amount-input"
|
||||
placeholder="Kwota (PLN)">
|
||||
<button onclick="submitExpense({{ list.id }})" class="btn btn-outline-primary share-submit-btn shopping-compact-submit"><span class="shopping-btn-icon" aria-hidden="true">💾</span><span class="shopping-btn-label">Zapisz</span></button>
|
||||
</div>{% endif %}
|
||||
<p id="total-expense2"><b>💸 Łącznie wydano:</b> {{ '%.2f'|format(total_expense) }} PLN</p>
|
||||
<div class="shopping-entry-card shopping-entry-card--expense mb-3" aria-label="Sekcja dodawania wydatku">
|
||||
<div class="shopping-entry-card__label d-flex justify-content-between align-items-center">
|
||||
<span>💰 Dodaj wydatek</span>
|
||||
|
||||
<span class="badge rounded-pill bg-success" id="total-expense2">
|
||||
💸 Łączna suma: {{ '%.2f'|format(total_expense) }} PLN
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="shopping-entry-card__hint">Wpisz kwotę wydatku i kliknij Zapisz.</div>
|
||||
|
||||
<div class="input-group mb-0 shopping-compact-input-group shopping-expense-input-group">
|
||||
<input id="expenseAmount" type="number" step="0.01" min="0"
|
||||
class="form-control bg-dark text-white border-secondary shopping-expense-amount-input"
|
||||
placeholder="Kwota (PLN)">
|
||||
|
||||
<button onclick="submitExpense({{ list.id }})"
|
||||
class="btn btn-outline-primary share-submit-btn share-submit-btn--expense shopping-compact-submit">
|
||||
<span class="shopping-btn-icon" aria-hidden="true">💾</span>
|
||||
<span class="shopping-btn-label">Zapisz</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<p id="total-expense2" style="display: none;">
|
||||
<b>💸 Łącznie wydano:</b> {{ '%.2f'|format(total_expense) }} PLN
|
||||
</p>
|
||||
|
||||
<button id="toggleReceiptBtn" class="btn btn-outline-light mb-3 w-100 w-md-auto d-block mx-auto" type="button"
|
||||
data-bs-toggle="collapse" data-bs-target="#receiptSection" aria-expanded="false" aria-controls="receiptSection">
|
||||
@@ -126,82 +146,143 @@
|
||||
<div class="collapse px-2 px-md-4" id="receiptSection">
|
||||
{% set receipt_pattern = 'list_' ~ list.id %}
|
||||
|
||||
<div class="mt-3 p-3 border border-secondary rounded bg-dark text-white
|
||||
{% if not receipts %}
|
||||
d-none
|
||||
{% endif %}" id="receiptAnalysisBlock">
|
||||
<div class="receipt-section-stack d-flex flex-column gap-3 mt-3">
|
||||
<div class="card bg-dark text-white border-secondary shadow-sm">
|
||||
<div class="card-body">
|
||||
<div class="d-flex flex-column flex-lg-row align-items-lg-center justify-content-between gap-2 mb-3">
|
||||
<div>
|
||||
<h5 class="mb-1">📄 Paragony</h5>
|
||||
<p class="text-secondary small mb-0">
|
||||
Przeglądaj dodane paragony, wrzucaj nowe i rozliczaj je przez OCR.
|
||||
</p>
|
||||
</div>
|
||||
<div class="d-flex flex-wrap gap-2">
|
||||
<span class="badge rounded-pill bg-secondary">{{ receipts|length }} plik{% if receipts|length != 1 %}i{% endif %}</span>
|
||||
{% if list.is_archived %}
|
||||
<span class="badge rounded-pill bg-secondary">Lista archiwalna</span>
|
||||
{% elif current_user.is_authenticated %}
|
||||
<span class="badge rounded-pill bg-success">Możesz dodawać</span>
|
||||
{% else %}
|
||||
<span class="badge rounded-pill bg-warning text-dark">Tylko podgląd</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5>🔍 Analiza paragonów (OCR)</h5>
|
||||
<p class="text-small">System spróbuje automatycznie rozpoznać kwoty z dodanych paragonów.<br>
|
||||
Dokonaj korekty jeśli źle rozpozna kwote i kliknij w "Dodaj" aby dodać wydatek.
|
||||
</p>
|
||||
<div class="row g-3 align-items-stretch">
|
||||
<div class="col-12 col-xl-7">
|
||||
<div class="border border-secondary rounded-3 p-3 h-100">
|
||||
<div class="d-flex justify-content-between align-items-center flex-wrap gap-2 mb-3">
|
||||
<h6 class="mb-0">📸 Dodane paragony</h6>
|
||||
{% if receipts %}
|
||||
<span class="text-secondary small">Kliknij miniaturę, aby otworzyć podgląd</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if current_user.is_authenticated %}
|
||||
<button id="analyzeBtn" class="btn btn-sm btn-outline-light mb-3">
|
||||
🔍 Zleć analizę OCR
|
||||
</button>
|
||||
{% else %}
|
||||
<div class="alert alert-warning text-centerg">
|
||||
⚠️ Tylko zalogowani użytkownicy mogą zlecać analizę OCR.
|
||||
<div class="row g-3" id="receiptGallery">
|
||||
{% if receipts %}
|
||||
{% for r in receipts %}
|
||||
<div class="col-6 col-md-4 text-center">
|
||||
<a href="{{ url_for('uploaded_file', filename=r.filename) }}?v={{ r.version_token or '0' }}" class="glightbox text-decoration-none"
|
||||
data-gallery="receipt-gallery">
|
||||
<div class="card bg-black border-secondary h-100 overflow-hidden shadow-sm">
|
||||
<img src="{{ url_for('uploaded_file', filename=r.filename) }}?v={{ r.version_token or '0' }}"
|
||||
class="card-img-top img-fluid" style="height: 180px; object-fit: cover;" alt="Paragon {{ loop.index }}">
|
||||
<div class="card-body p-2">
|
||||
<div class="small text-truncate text-secondary">Paragon {{ loop.index }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="col-12">
|
||||
<div class="alert alert-info text-center mb-0" role="alert">
|
||||
ℹ️ Brak wgranych paragonów do tej listy
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-xl-5">
|
||||
<div class="d-flex flex-column gap-3 h-100">
|
||||
<div class="border border-secondary rounded-3 p-3 bg-black bg-opacity-25 {% if not receipts %}d-none{% endif %}" id="receiptAnalysisBlock">
|
||||
<div class="d-flex justify-content-between align-items-start gap-2 flex-wrap mb-2">
|
||||
<div>
|
||||
<h6 class="mb-1">🔍 Analiza paragonów (OCR)</h6>
|
||||
<p class="text-small text-secondary mb-0">
|
||||
System spróbuje automatycznie rozpoznać kwoty. Sprawdź wynik i kliknij „Dodaj”, aby dopisać wydatek.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if current_user.is_authenticated %}
|
||||
<button id="analyzeBtn" class="btn btn-sm btn-outline-light mb-3 w-100 w-sm-auto">
|
||||
🔍 Zleć analizę OCR
|
||||
</button>
|
||||
{% else %}
|
||||
<div class="alert alert-warning mb-3">
|
||||
⚠️ Tylko zalogowani użytkownicy mogą zlecać analizę OCR.
|
||||
</div>
|
||||
{% endif %}
|
||||
<div id="analysisResults" class="mt-2"></div>
|
||||
</div>
|
||||
|
||||
{% if not list.is_archived and current_user.is_authenticated %}
|
||||
<div class="border border-secondary rounded-3 p-3 h-100">
|
||||
<h6 class="mb-1">📤 Dodaj nowy paragon</h6>
|
||||
<p class="text-secondary small mb-3">Możesz dodać zdjęcie z aparatu, z galerii albo plik PDF.</p>
|
||||
|
||||
<form id="receiptForm" action="{{ url_for('upload_receipt', list_id=list.id) }}" method="post"
|
||||
enctype="multipart/form-data" class="text-center">
|
||||
|
||||
<div class="d-grid gap-2">
|
||||
<label for="cameraInput" id="cameraBtn"
|
||||
class="btn btn-outline-light w-100 py-2 d-flex align-items-center justify-content-center gap-2">
|
||||
<i class="bi bi-camera"></i> 📸 Zrób zdjęcie
|
||||
</label>
|
||||
<input type="file" name="receipt" accept="image/*" capture="environment" class="d-none" id="cameraInput">
|
||||
|
||||
<label for="galleryInput" id="galleryBtn"
|
||||
class="btn btn-outline-light w-100 py-2 d-flex align-items-center justify-content-center gap-2">
|
||||
<i class="bi bi-image"></i> <span id="galleryBtnText">🖼️ Z galerii</span>
|
||||
</label>
|
||||
<input type="file" name="receipt" accept="image/*" class="d-none" id="galleryInput">
|
||||
|
||||
<label for="pdfInput" id="pdfBtn"
|
||||
class="btn btn-outline-light w-100 py-2 d-flex align-items-center justify-content-center gap-2">
|
||||
📄 Dodaj PDF
|
||||
</label>
|
||||
<input type="file" name="receipt" accept="application/pdf" class="d-none" id="pdfInput">
|
||||
</div>
|
||||
|
||||
<div id="progressContainer" class="progress progress-dark rounded-3 overflow-hidden shadow-sm mt-3"
|
||||
style="height: 20px; display: none;">
|
||||
<div id="progressBar" class="progress-bar bg-success fw-bold text-white text-center" role="progressbar"
|
||||
style="width: 0%;">0%</div>
|
||||
</div>
|
||||
|
||||
<div id="receiptUploadFeedback" class="mt-3"></div>
|
||||
</form>
|
||||
</div>
|
||||
{% elif list.is_archived %}
|
||||
<div class="border border-secondary rounded-3 p-3 bg-black bg-opacity-25">
|
||||
<h6 class="mb-1">📤 Dodawanie zablokowane</h6>
|
||||
<p class="text-secondary small mb-0">Ta lista jest archiwalna, więc nie można już dodawać nowych paragonów.</p>
|
||||
</div>
|
||||
{% elif not current_user.is_authenticated %}
|
||||
<div class="border border-secondary rounded-3 p-3 bg-black bg-opacity-25">
|
||||
<h6 class="mb-1">🔐 Dodawanie wymaga logowania</h6>
|
||||
<p class="text-secondary small mb-0">Zaloguj się, aby dodawać paragony i uruchamiać analizę OCR.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div id="analysisResults" class="mt-2"></div>
|
||||
</div>
|
||||
|
||||
<h5 class="mt-4">📸 Paragony dodane do tej listy</h5>
|
||||
<div class="row g-3 mt-2" id="receiptGallery">
|
||||
{% if receipts %}
|
||||
{% for r in receipts %}
|
||||
<div class="col-6 col-md-4 col-lg-3 text-center">
|
||||
<a href="{{ url_for('uploaded_file', filename=r.filename) }}?v={{ r.version_token or '0' }}" class="glightbox"
|
||||
data-gallery="receipt-gallery">
|
||||
<img src="{{ url_for('uploaded_file', filename=r.filename) }}?v={{ r.version_token or '0' }}"
|
||||
class="img-fluid rounded shadow-sm border border-secondary" style="max-height: 200px; object-fit: cover;">
|
||||
</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="alert alert-info text-center w-100" role="alert">
|
||||
ℹ️ Brak wgranych paragonów do tej listy
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if not list.is_archived and current_user.is_authenticated %}
|
||||
<hr>
|
||||
<h5>📤 Dodaj zdjęcie paragonu</h5>
|
||||
<form id="receiptForm" action="{{ url_for('upload_receipt', list_id=list.id) }}" method="post"
|
||||
enctype="multipart/form-data" class="text-center">
|
||||
|
||||
<!-- Zrób zdjęcie (tylko mobile) -->
|
||||
<label for="cameraInput" id="cameraBtn"
|
||||
class="btn btn-outline-light w-100 py-2 mb-2 d-flex align-items-center justify-content-center gap-2">
|
||||
<i class="bi bi-camera"></i> 📸 Zrób zdjęcie
|
||||
</label>
|
||||
<input type="file" name="receipt" accept="image/*" capture="environment" class="d-none" id="cameraInput">
|
||||
|
||||
<!-- Z galerii / Dodaj paragon -->
|
||||
<label for="galleryInput" id="galleryBtn"
|
||||
class="btn btn-outline-light w-100 py-2 mb-2 d-flex align-items-center justify-content-center gap-2">
|
||||
<i class="bi bi-image"></i> <span id="galleryBtnText">🖼️ Z galerii</span>
|
||||
</label>
|
||||
<input type="file" name="receipt" accept="image/*" class="d-none" id="galleryInput">
|
||||
|
||||
<label for="pdfInput" id="pdfBtn"
|
||||
class="btn btn-outline-light w-100 py-2 mb-2 d-flex align-items-center justify-content-center gap-2">
|
||||
📄 Dodaj PDF
|
||||
</label>
|
||||
<input type="file" name="receipt" accept="application/pdf" class="d-none" id="pdfInput">
|
||||
|
||||
<div id="progressContainer" class="progress progress-dark rounded-3 overflow-hidden shadow-sm"
|
||||
style="height: 20px; display: none;">
|
||||
<div id="progressBar" class="progress-bar bg-success fw-bold text-white text-center" role="progressbar"
|
||||
style="width: 0%;">0%</div>
|
||||
</div>
|
||||
|
||||
<div id="receiptGallery" class="mt-3"></div>
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Modal notatki -->
|
||||
|
||||
Reference in New Issue
Block a user