nordabiz/templates/membership/review_changes.html
Maciej Pienczyn c0d60481f0
Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions
refactor(rbac): Migrate legacy is_admin checks to role-based has_role()/set_role()
Replace ~20 remaining is_admin references across backend, templates and scripts
with proper SystemRole checks. Column is_admin stays as deprecated (synced by
set_role()) until DB migration removes it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-05 21:06:22 +01:00

1080 lines
31 KiB
HTML

{% extends "base.html" %}
{% block title %}Przegląd proponowanych zmian - Norda Biznes Partner{% endblock %}
{% block extra_css %}
<style>
.review-container {
max-width: 800px;
margin: 0 auto;
}
.review-header {
margin-bottom: var(--spacing-2xl);
}
.review-header h1 {
font-size: var(--font-size-2xl);
color: var(--text-primary);
margin: 0 0 var(--spacing-sm) 0;
}
.review-header p {
color: var(--text-secondary);
margin: 0;
}
.review-card {
background: var(--surface);
border-radius: var(--radius-lg);
box-shadow: var(--shadow);
overflow: hidden;
}
.review-card-header {
background: linear-gradient(135deg, #0ea5e9 0%, #0284c7 100%);
color: white;
padding: var(--spacing-xl);
}
.review-card-header h2 {
margin: 0 0 var(--spacing-sm) 0;
font-size: var(--font-size-lg);
}
.review-card-header .company-info {
opacity: 0.9;
font-size: var(--font-size-sm);
}
.review-card-body {
padding: var(--spacing-xl);
}
.info-box {
background: rgba(14, 165, 233, 0.1);
border: 1px solid rgba(14, 165, 233, 0.3);
border-radius: var(--radius);
padding: var(--spacing-lg);
margin-bottom: var(--spacing-xl);
}
.info-box p {
margin: 0;
color: var(--text-primary);
font-size: var(--font-size-sm);
}
.info-box strong {
color: #0ea5e9;
}
.changes-list {
margin-bottom: var(--spacing-xl);
}
.change-item {
background: var(--background);
border-radius: var(--radius);
padding: var(--spacing-lg);
margin-bottom: var(--spacing-md);
border-left: 4px solid var(--primary);
}
.change-label {
font-weight: 600;
color: var(--text-primary);
margin-bottom: var(--spacing-sm);
display: flex;
align-items: center;
gap: var(--spacing-sm);
}
.change-label svg {
color: var(--primary);
}
.change-values {
display: grid;
grid-template-columns: 1fr 40px 1fr;
align-items: center;
gap: var(--spacing-md);
margin-top: var(--spacing-md);
}
.old-value, .new-value {
padding: var(--spacing-md);
border-radius: var(--radius);
font-size: var(--font-size-sm);
}
.old-value {
background: rgba(239, 68, 68, 0.1);
border: 1px dashed rgba(239, 68, 68, 0.3);
color: var(--text-secondary);
text-decoration: line-through;
}
.new-value {
background: rgba(34, 197, 94, 0.1);
border: 1px solid rgba(34, 197, 94, 0.3);
color: var(--text-primary);
font-weight: 500;
}
.arrow-icon {
color: var(--text-secondary);
text-align: center;
}
.value-empty {
color: var(--text-secondary);
font-style: italic;
}
.admin-comment {
background: var(--background);
border-radius: var(--radius);
padding: var(--spacing-lg);
margin-bottom: var(--spacing-xl);
}
.admin-comment-header {
display: flex;
align-items: center;
gap: var(--spacing-sm);
margin-bottom: var(--spacing-sm);
font-size: var(--font-size-sm);
color: var(--text-secondary);
}
.admin-comment p {
margin: 0;
color: var(--text-primary);
}
.reviewer-role {
font-size: var(--font-size-xs);
color: var(--text-secondary);
background: var(--background);
padding: 2px 8px;
border-radius: var(--radius);
margin-left: var(--spacing-sm);
}
.actions-section {
border-top: 1px solid var(--border);
padding-top: var(--spacing-xl);
}
.actions-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--spacing-lg);
}
.action-card {
padding: var(--spacing-xl);
border-radius: var(--radius-lg);
text-align: center;
}
.action-card.accept {
background: rgba(34, 197, 94, 0.1);
border: 2px solid rgba(34, 197, 94, 0.3);
}
.action-card.reject {
background: rgba(239, 68, 68, 0.05);
border: 2px solid rgba(239, 68, 68, 0.2);
}
.action-card h3 {
margin: 0 0 var(--spacing-sm) 0;
font-size: var(--font-size-lg);
}
.action-card.accept h3 {
color: #16a34a;
}
.action-card.reject h3 {
color: #dc2626;
}
.action-card p {
margin: 0 0 var(--spacing-lg) 0;
font-size: var(--font-size-sm);
color: var(--text-secondary);
}
.btn-action {
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--spacing-sm);
padding: var(--spacing-md) var(--spacing-xl);
border: none;
border-radius: var(--radius);
font-weight: 600;
cursor: pointer;
transition: var(--transition);
width: 100%;
}
.btn-accept {
background: #16a34a;
color: white;
}
.btn-accept:hover {
background: #15803d;
}
.btn-reject {
background: transparent;
color: #dc2626;
border: 2px solid #dc2626;
}
.btn-reject:hover {
background: rgba(239, 68, 68, 0.1);
}
.reject-comment {
margin-top: var(--spacing-md);
display: none;
}
.reject-comment.show {
display: block;
}
.reject-comment textarea {
width: 100%;
padding: var(--spacing-md);
border: 1px solid var(--border);
border-radius: var(--radius);
resize: vertical;
min-height: 80px;
font-size: var(--font-size-sm);
}
.reject-comment textarea:focus {
outline: none;
border-color: var(--primary);
}
/* Modal potwierdzenia */
.confirm-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: none;
align-items: center;
justify-content: center;
z-index: 1001;
backdrop-filter: blur(4px);
}
.confirm-modal.show {
display: flex;
}
.confirm-modal-content {
background: var(--surface);
padding: var(--spacing-2xl);
border-radius: var(--radius-lg);
max-width: 400px;
width: 90%;
text-align: center;
box-shadow: var(--shadow-lg);
animation: modalSlideIn 0.2s ease-out;
}
@keyframes modalSlideIn {
from {
opacity: 0;
transform: scale(0.95) translateY(-10px);
}
to {
opacity: 1;
transform: scale(1) translateY(0);
}
}
.confirm-modal-icon {
margin-bottom: var(--spacing-lg);
}
.confirm-modal-icon.accept svg {
color: #16a34a;
}
.confirm-modal-icon.reject svg {
color: #dc2626;
}
.confirm-modal-icon.info svg {
color: #0ea5e9;
}
.confirm-modal-content h3 {
margin: 0 0 var(--spacing-sm) 0;
font-size: var(--font-size-lg);
color: var(--text-primary);
}
.confirm-modal-content p {
margin: 0 0 var(--spacing-xl) 0;
color: var(--text-secondary);
font-size: var(--font-size-sm);
}
.confirm-modal-buttons {
display: flex;
gap: var(--spacing-md);
justify-content: center;
}
.btn-modal {
padding: var(--spacing-sm) var(--spacing-xl);
border-radius: var(--radius);
font-weight: 600;
cursor: pointer;
transition: var(--transition);
min-width: 100px;
}
.btn-modal-cancel {
background: var(--surface);
border: 1px solid var(--border);
color: var(--text-primary);
}
.btn-modal-cancel:hover {
background: var(--background);
}
.btn-modal-confirm {
border: none;
color: white;
}
.btn-modal-confirm.accept {
background: #16a34a;
}
.btn-modal-confirm.accept:hover {
background: #15803d;
}
.btn-modal-confirm.reject {
background: #dc2626;
}
.btn-modal-confirm.reject:hover {
background: #b91c1c;
}
.loading-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: none;
align-items: center;
justify-content: center;
z-index: 1000;
}
.loading-overlay.show {
display: flex;
}
.loading-box {
background: var(--surface);
padding: var(--spacing-2xl);
border-radius: var(--radius-lg);
text-align: center;
}
.loading-spinner {
width: 40px;
height: 40px;
border: 3px solid var(--border);
border-top-color: var(--primary);
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 0 auto var(--spacing-md);
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* Ekran sukcesu */
.success-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: var(--background);
display: none;
align-items: center;
justify-content: center;
z-index: 1002;
}
.success-overlay.show {
display: flex;
}
.success-box {
background: var(--surface);
padding: var(--spacing-2xl) var(--spacing-3xl);
border-radius: var(--radius-lg);
text-align: center;
max-width: 600px;
width: 90%;
box-shadow: var(--shadow-lg);
animation: successSlideIn 0.4s ease-out;
}
@keyframes successSlideIn {
from {
opacity: 0;
transform: translateY(-20px) scale(0.95);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
.success-icon {
margin-bottom: var(--spacing-lg);
}
.success-icon.accept svg {
color: #16a34a;
}
.success-icon.reject svg {
color: #f59e0b;
}
.success-box h2 {
margin: 0 0 var(--spacing-sm) 0;
font-size: var(--font-size-xl);
color: var(--text-primary);
}
.success-box > p {
margin: 0 0 var(--spacing-2xl) 0;
color: var(--text-secondary);
}
.success-progress {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: var(--spacing-2xl);
padding: var(--spacing-lg);
background: var(--background);
border-radius: var(--radius);
}
.progress-step {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--spacing-xs);
}
.step-icon {
width: 32px;
height: 32px;
border-radius: 50%;
background: var(--border);
color: var(--text-secondary);
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
font-size: var(--font-size-sm);
}
.progress-step.completed .step-icon {
background: #16a34a;
color: white;
}
.progress-step.current .step-icon {
background: #0ea5e9;
color: white;
box-shadow: 0 0 0 4px rgba(14, 165, 233, 0.2);
}
.step-label {
font-size: var(--font-size-xs);
color: var(--text-secondary);
white-space: nowrap;
}
.progress-step.completed .step-label,
.progress-step.current .step-label {
color: var(--text-primary);
font-weight: 500;
}
.progress-line {
width: 40px;
height: 3px;
background: var(--border);
margin: 0 var(--spacing-xs);
margin-bottom: 20px;
}
.progress-line.completed {
background: #16a34a;
}
/* Sub-workflow (propozycja zmian) */
.progress-sub-flow {
display: flex;
flex-direction: column;
align-items: center;
margin: 0 var(--spacing-xs);
position: relative;
}
.sub-flow-container {
display: flex;
flex-direction: column;
align-items: center;
background: rgba(14, 165, 233, 0.05);
border: 1px dashed rgba(14, 165, 233, 0.3);
border-radius: var(--radius);
padding: var(--spacing-sm) var(--spacing-md);
margin: var(--spacing-xs) 0;
}
.sub-flow-arrow {
color: #0ea5e9;
font-size: 12px;
margin: 2px 0;
}
.sub-flow-step {
display: flex;
align-items: center;
gap: var(--spacing-xs);
font-size: var(--font-size-xs);
color: var(--text-secondary);
white-space: nowrap;
}
.sub-flow-step.completed {
color: #16a34a;
}
.sub-flow-step svg {
width: 14px;
height: 14px;
}
.sub-flow-label {
font-size: 10px;
color: var(--text-secondary);
text-align: center;
margin-top: 2px;
}
.btn-success-action {
display: inline-flex;
align-items: center;
gap: var(--spacing-sm);
padding: var(--spacing-md) var(--spacing-xl);
background: var(--primary);
color: white;
text-decoration: none;
border-radius: var(--radius);
font-weight: 600;
transition: var(--transition);
}
.btn-success-action:hover {
opacity: 0.9;
}
.success-comment {
background: var(--background);
border-radius: var(--radius);
padding: var(--spacing-md) var(--spacing-lg);
margin-bottom: var(--spacing-xl);
text-align: left;
max-width: 400px;
margin-left: auto;
margin-right: auto;
}
.success-comment-header {
font-size: var(--font-size-sm);
color: var(--text-secondary);
margin-bottom: var(--spacing-xs);
}
.success-comment p {
margin: 0;
color: var(--text-primary);
font-size: var(--font-size-sm);
}
@media (max-width: 600px) {
.success-progress {
flex-wrap: wrap;
gap: var(--spacing-sm);
}
.progress-line {
display: none;
}
}
@media (max-width: 600px) {
.actions-grid {
grid-template-columns: 1fr;
}
.change-values {
grid-template-columns: 1fr;
}
.arrow-icon {
transform: rotate(90deg);
}
}
</style>
{% endblock %}
{% block content %}
<div class="review-container">
<div class="review-header">
<h1>Przegląd proponowanych zmian</h1>
<p>Administrator zaproponował aktualizację danych Twojej deklaracji na podstawie rejestru KRS/CEIDG</p>
</div>
<div class="review-card">
<div class="review-card-header">
<h2>{{ application.company_name }}</h2>
<div class="company-info">
NIP: {{ application.nip }}
{% if application.krs_number %}| KRS: {{ application.krs_number }}{% endif %}
</div>
</div>
<div class="review-card-body">
<div class="info-box">
<p>
<strong>{{ reviewer.name if reviewer else 'Biuro Izby NORDA' }}</strong>
{% if reviewer and reviewer.can_access_admin_panel() %}<span class="reviewer-role">Biuro Izby NORDA</span>{% endif %}
zaproponował(a) aktualizację danych na podstawie oficjalnych danych z
{% if application.registry_source == 'KRS' %}
Krajowego Rejestru Sądowego (KRS).
{% elif application.registry_source == 'CEIDG' %}
Centralnej Ewidencji i Informacji o Działalności Gospodarczej (CEIDG).
{% else %}
rejestru publicznego.
{% endif %}
Przejrzyj poniższe zmiany i zdecyduj, czy chcesz je zaakceptować.
</p>
</div>
{% if application.proposed_changes %}
<div class="changes-list">
<h3 style="margin-bottom: var(--spacing-lg); font-size: var(--font-size-base);">Proponowane zmiany:</h3>
{% for field_name, change in application.proposed_changes.items() %}
<div class="change-item">
<div class="change-label">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
</svg>
{{ change.label }}
</div>
<div class="change-values">
<div class="old-value">
{% if change.old %}{{ change.old }}{% else %}<span class="value-empty">(brak danych)</span>{% endif %}
</div>
<div class="arrow-icon"></div>
<div class="new-value">
{{ change.new }}
</div>
</div>
</div>
{% endfor %}
</div>
{% endif %}
{% if application.proposed_changes_comment %}
<div class="admin-comment">
<div class="admin-comment-header">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/>
</svg>
Komentarz od: <strong>{{ reviewer.name if reviewer else 'Biuro Izby NORDA' }}</strong>
{% if reviewer and reviewer.can_access_admin_panel() %}<span class="reviewer-role">Biuro Izby NORDA</span>{% endif %}
</div>
<p>{{ application.proposed_changes_comment }}</p>
</div>
{% endif %}
<div class="actions-section">
<div class="actions-grid">
<div class="action-card accept">
<h3>Akceptuję zmiany</h3>
<p>Dane zostaną zaktualizowane zgodnie z rejestrem. Deklaracja wróci do rozpatrzenia.</p>
<button type="button" class="btn-action btn-accept" onclick="acceptChanges()">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="20 6 9 17 4 12"/>
</svg>
Zaakceptuj zmiany
</button>
</div>
<div class="action-card reject">
<h3>Odrzucam zmiany</h3>
<p>Dane pozostaną bez zmian. Deklaracja wróci do rozpatrzenia z oryginalnymi danymi.</p>
<button type="button" class="btn-action btn-reject" onclick="showRejectForm()">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="18" y1="6" x2="6" y2="18"/>
<line x1="6" y1="6" x2="18" y2="18"/>
</svg>
Odrzuć zmiany
</button>
<div class="reject-comment" id="rejectComment">
<textarea id="rejectReason" placeholder="Opcjonalnie: podaj powód odrzucenia zmian..."></textarea>
<button type="button" class="btn-action btn-reject" style="margin-top: var(--spacing-sm);" onclick="rejectChanges()">
Potwierdź odrzucenie
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="loading-overlay" id="loadingOverlay">
<div class="loading-box">
<div class="loading-spinner"></div>
<p>Przetwarzanie...</p>
</div>
</div>
<!-- Ekran sukcesu -->
<div class="success-overlay" id="successOverlay">
<div class="success-box">
<div class="success-icon" id="successIcon">
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"/>
<polyline points="9 12 12 15 16 10"/>
</svg>
</div>
<h2 id="successTitle">Zmiany zaakceptowane!</h2>
<p id="successMessage">Twoja deklaracja wróciła do rozpatrzenia przez administratora.</p>
<div class="success-progress" id="successProgress">
<div class="progress-step completed">
<div class="step-icon">1</div>
<div class="step-label">Złożono deklarację</div>
</div>
<div class="progress-line completed"></div>
<div class="progress-step completed">
<div class="step-icon">2</div>
<div class="step-label">Weryfikacja danych</div>
</div>
<!-- Sub-workflow: propozycja zmian -->
<div class="progress-sub-flow">
<div class="sub-flow-container">
<div class="sub-flow-step completed">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="20 6 9 17 4 12"/>
</svg>
<span>Propozycja zmian</span>
</div>
<div class="sub-flow-arrow"></div>
<div class="sub-flow-step completed">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="20 6 9 17 4 12"/>
</svg>
<span id="userActionLabel">Twoja akceptacja</span>
</div>
<div class="sub-flow-arrow"></div>
</div>
<div class="sub-flow-label">Powrót do rozpatrzenia</div>
</div>
<div class="progress-line completed"></div>
<div class="progress-step current">
<div class="step-icon">3</div>
<div class="step-label">Rozpatrzenie</div>
</div>
<div class="progress-line"></div>
<div class="progress-step">
<div class="step-icon">4</div>
<div class="step-label">Decyzja</div>
</div>
</div>
<!-- Komentarz w ekranie sukcesu -->
{% if application.proposed_changes_comment %}
<div class="success-comment" id="successComment">
<div class="success-comment-header">
Komentarz od: <strong>{{ reviewer.name if reviewer else 'Biuro Izby NORDA' }}</strong>
</div>
<p>{{ application.proposed_changes_comment }}</p>
</div>
{% endif %}
<a href="{{ url_for('membership.status') }}" class="btn-success-action">
Zobacz status deklaracji →
</a>
</div>
</div>
<!-- Modal potwierdzenia -->
<div class="confirm-modal" id="confirmModal">
<div class="confirm-modal-content">
<div class="confirm-modal-icon" id="confirmModalIcon">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"/>
<path d="M12 8v4"/>
<path d="M12 16h.01"/>
</svg>
</div>
<h3 id="confirmModalTitle">Potwierdź akcję</h3>
<p id="confirmModalMessage">Czy na pewno chcesz kontynuować?</p>
<div class="confirm-modal-buttons">
<button type="button" class="btn-modal btn-modal-cancel" onclick="closeConfirmModal()">Anuluj</button>
<button type="button" class="btn-modal btn-modal-confirm" id="confirmModalButton" onclick="confirmModalAction()">Potwierdź</button>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content || '';
const appId = {{ application.id }};
let pendingAction = null;
function showLoading() {
document.getElementById('loadingOverlay').classList.add('show');
}
function hideLoading() {
document.getElementById('loadingOverlay').classList.remove('show');
}
function showRejectForm() {
document.getElementById('rejectComment').classList.toggle('show');
}
// Ładne powiadomienia zamiast alert()
function showNotification(message, type = 'info') {
let container = document.querySelector('.flash-messages');
if (!container) {
container = document.createElement('div');
container.className = 'flash-messages';
container.setAttribute('role', 'alert');
container.setAttribute('aria-live', 'polite');
document.body.appendChild(container);
}
const flash = document.createElement('div');
flash.className = `flash flash-${type}`;
flash.innerHTML = `
<span>${message}</span>
<button class="flash-close" onclick="this.parentElement.remove()" aria-label="Zamknij">&times;</button>
`;
container.appendChild(flash);
setTimeout(() => {
flash.style.animation = 'slideOut 0.3s ease-out';
setTimeout(() => flash.remove(), 300);
}, 5000);
}
// Modal potwierdzenia zamiast confirm()
function showConfirmModal(title, message, type, onConfirm) {
const modal = document.getElementById('confirmModal');
const icon = document.getElementById('confirmModalIcon');
const titleEl = document.getElementById('confirmModalTitle');
const messageEl = document.getElementById('confirmModalMessage');
const button = document.getElementById('confirmModalButton');
titleEl.textContent = title;
messageEl.textContent = message;
icon.className = 'confirm-modal-icon ' + type;
button.className = 'btn-modal btn-modal-confirm ' + type;
if (type === 'accept') {
button.textContent = 'Tak, akceptuję';
icon.innerHTML = '<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="9 12 12 15 16 10"/></svg>';
} else if (type === 'reject') {
button.textContent = 'Tak, odrzucam';
icon.innerHTML = '<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>';
}
pendingAction = onConfirm;
modal.classList.add('show');
}
function closeConfirmModal() {
document.getElementById('confirmModal').classList.remove('show');
pendingAction = null;
}
function confirmModalAction() {
const action = pendingAction; // Zapisz przed zamknięciem (closeConfirmModal zeruje pendingAction)
closeConfirmModal();
if (action) {
action();
}
}
function acceptChanges() {
showConfirmModal(
'Akceptujesz zmiany?',
'Dane firmy zostaną zaktualizowane zgodnie z rejestrem. Deklaracja wróci do rozpatrzenia przez administratora.',
'accept',
doAcceptChanges
);
}
async function doAcceptChanges() {
showLoading();
try {
const response = await fetch(`/membership/review-changes/${appId}/accept`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify({})
});
const data = await response.json();
hideLoading();
if (data.success) {
showSuccessScreen(
'accept',
'Zmiany zaakceptowane!',
'Twoja deklaracja wróciła do rozpatrzenia przez administratora. Otrzymasz powiadomienie o decyzji.'
);
} else {
showNotification(data.error || 'Wystąpił błąd', 'error');
}
} catch (error) {
hideLoading();
showNotification('Wystąpił błąd połączenia. Spróbuj ponownie.', 'error');
}
}
function rejectChanges() {
showConfirmModal(
'Odrzucasz zmiany?',
'Dane firmy pozostaną bez zmian. Deklaracja wróci do rozpatrzenia z oryginalnymi danymi.',
'reject',
doRejectChanges
);
}
async function doRejectChanges() {
showLoading();
const comment = document.getElementById('rejectReason').value.trim();
try {
const response = await fetch(`/membership/review-changes/${appId}/reject`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
},
body: JSON.stringify({ comment: comment })
});
const data = await response.json();
hideLoading();
if (data.success) {
showSuccessScreen(
'reject',
'Propozycja odrzucona',
'Twoja deklaracja zachowuje oryginalne dane i wróciła do rozpatrzenia przez administratora.'
);
} else {
showNotification(data.error || 'Wystąpił błąd', 'error');
}
} catch (error) {
console.error('Error:', error);
hideLoading();
showNotification('Wystąpił błąd połączenia. Spróbuj ponownie.', 'error');
}
}
function showSuccessScreen(type, title, message) {
const overlay = document.getElementById('successOverlay');
const icon = document.getElementById('successIcon');
const titleEl = document.getElementById('successTitle');
const messageEl = document.getElementById('successMessage');
const userActionLabel = document.getElementById('userActionLabel');
if (!overlay) {
// Fallback - jeśli element nie istnieje, pokaż powiadomienie i przekieruj
showNotification('Zmiany zapisane pomyślnie! Przekierowuję...', 'success');
setTimeout(() => {
window.location.href = '{{ url_for("membership.status") }}';
}, 2000);
return;
}
titleEl.textContent = title;
messageEl.textContent = message;
icon.className = 'success-icon ' + type;
if (type === 'accept') {
icon.innerHTML = '<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="9 12 12 15 16 10"/></svg>';
if (userActionLabel) userActionLabel.textContent = 'Twoja akceptacja';
} else {
icon.innerHTML = '<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 8v4"/><path d="M12 16h.01"/></svg>';
if (userActionLabel) userActionLabel.textContent = 'Twoje odrzucenie';
}
overlay.classList.add('show');
}
// Zamknij modal klikając poza nim
document.getElementById('confirmModal').addEventListener('click', function(e) {
if (e.target === this) {
closeConfirmModal();
}
});
// Zamknij modal klawiszem Escape
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
closeConfirmModal();
}
});
{% endblock %}