feat: implement local payment QR codes and update AI co-authoring rules
QR codes are now generated locally using the 'qrcode' library for better privacy and reliability. Updated .agent/rules.md with co-author details and Conventional Commits preference. Co-authored-by: Antigravity <antigravity@google.com>
This commit is contained in:
@@ -138,6 +138,28 @@
|
||||
|
||||
.cell-unpaid {
|
||||
color: #ff3333;
|
||||
background-color: rgba(255, 51, 51, 0.05);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.pay-btn {
|
||||
display: none;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background: #ff3333;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
padding: 2px 6px;
|
||||
font-size: 10px;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.member-row:hover .pay-btn {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.cell-empty {
|
||||
@@ -360,6 +382,42 @@
|
||||
margin-top: 5px;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
/* QR Modal styles */
|
||||
#qrModal .modal-content {
|
||||
max-width: 400px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.qr-image {
|
||||
background: white;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
margin: 20px 0;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.qr-image img {
|
||||
display: block;
|
||||
width: 250px;
|
||||
height: 250px;
|
||||
}
|
||||
|
||||
.qr-details {
|
||||
text-align: left;
|
||||
margin-top: 15px;
|
||||
font-size: 14px;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.qr-details div {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.qr-details span {
|
||||
color: #00ff00;
|
||||
font-family: monospace;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
@@ -403,8 +461,12 @@
|
||||
</td>
|
||||
{% for cell in row.months %}
|
||||
<td
|
||||
class="{% if cell == '-' %}cell-empty{% elif 'UNPAID' in cell %}cell-unpaid{% elif cell == 'OK' %}cell-ok{% endif %}">
|
||||
{{ cell }}
|
||||
class="{% if cell.status == 'empty' %}cell-empty{% elif cell.status == 'unpaid' or cell.status == 'partial' %}cell-unpaid{% elif cell.status == 'ok' %}cell-ok{% endif %}">
|
||||
{{ cell.text }}
|
||||
{% if cell.status == 'unpaid' or cell.status == 'partial' %}
|
||||
<button class="pay-btn"
|
||||
onclick="showPayQR('{{ row.name|e }}', {{ cell.amount }}, '{{ cell.month|e }}')">Pay</button>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
<td class="{% if row.balance > 0 %}balance-pos{% elif row.balance < 0 %}balance-neg{% endif %}">
|
||||
@@ -460,6 +522,25 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- QR Code Modal -->
|
||||
<div id="qrModal" class="modal"
|
||||
style="display:none; position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background-color: rgba(0, 0, 0, 0.9); z-index: 9999; justify-content: center; align-items: center;">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title" id="qrTitle">Payment for ...</div>
|
||||
<div class="close-btn" onclick="closeModal('qrModal')">[close]</div>
|
||||
</div>
|
||||
<div class="qr-image">
|
||||
<img id="qrImg" src="" alt="Payment QR Code">
|
||||
</div>
|
||||
<div class="qr-details">
|
||||
<div>Account: <span id="qrAccount"></span></div>
|
||||
<div>Amount: <span id="qrAmount"></span> CZK</div>
|
||||
<div>Message: <span id="qrMessage"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="memberModal">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
@@ -620,8 +701,15 @@
|
||||
document.getElementById('memberModal').classList.add('active');
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
document.getElementById('memberModal').classList.remove('active');
|
||||
function closeModal(id) {
|
||||
if (id) {
|
||||
document.getElementById(id).style.display = 'none';
|
||||
if (id === 'qrModal') {
|
||||
document.getElementById(id).style.display = 'none';
|
||||
}
|
||||
} else {
|
||||
document.getElementById('memberModal').classList.remove('active');
|
||||
}
|
||||
}
|
||||
|
||||
// Existing filter script
|
||||
@@ -644,6 +732,33 @@
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (e.key === 'Escape') closeModal();
|
||||
});
|
||||
function showPayQR(name, amount, month) {
|
||||
const account = "{{ bank_account }}";
|
||||
const message = `${name} / ${month}`;
|
||||
const qrTitle = document.getElementById('qrTitle');
|
||||
const qrImg = document.getElementById('qrImg');
|
||||
const qrAccount = document.getElementById('qrAccount');
|
||||
const qrAmount = document.getElementById('qrAmount');
|
||||
const qrMessage = document.getElementById('qrMessage');
|
||||
|
||||
qrTitle.innerText = `Payment for ${month}`;
|
||||
qrAccount.innerText = account;
|
||||
qrAmount.innerText = amount;
|
||||
qrMessage.innerText = message;
|
||||
|
||||
const encodedMessage = encodeURIComponent(message);
|
||||
const qrUrl = `/qr?account=${encodeURIComponent(account)}&amount=${amount}&message=${encodedMessage}`;
|
||||
|
||||
qrImg.src = qrUrl;
|
||||
document.getElementById('qrModal').style.display = 'block';
|
||||
}
|
||||
|
||||
// Close modal when clicking outside
|
||||
window.onclick = function (event) {
|
||||
if (event.target.className === 'modal') {
|
||||
event.target.style.display = 'none';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user