Updated functionalities 2

This commit is contained in:
2026-04-25 12:41:24 -04:00
parent a515df6a02
commit 111ec5c740
11 changed files with 280 additions and 11 deletions
+13
View File
@@ -43,6 +43,19 @@
.notif-body { font-size: 0.78rem; color: #555; white-space: normal; }
.notif-time { font-size: 0.7rem; color: #999; }
.notif-empty { padding: 24px; text-align: center; color: #aaa; font-size: 0.85rem; }
/* ── Active nav tab ── */
.navbar-dark .navbar-nav .nav-link.active {
background-color: rgba(255, 255, 255, 0.18);
color: #ffffff !important;
border-radius: 6px;
font-weight: 600;
box-shadow: inset 0 -2px 0 rgba(255,255,255,0.6);
}
.navbar-dark .navbar-nav .nav-link:not(.active):hover {
background-color: rgba(255, 255, 255, 0.08);
border-radius: 6px;
}
</style>
</head>
<body>
+29
View File
@@ -18,6 +18,35 @@
</div>
{% if customers %}
{% if expired_invitations %}
<div class="alert alert-warning d-flex align-items-start gap-3 mb-3" role="alert">
<i class="bi bi-exclamation-triangle-fill fs-5 mt-1 flex-shrink-0"></i>
<div>
<strong>{{ expired_invitations|length }} invitation{{ 's' if expired_invitations|length != 1 else '' }} expired</strong>
— the following customer{{ 's' if expired_invitations|length != 1 else '' }} never completed account setup
and {{ 'their' if expired_invitations|length != 1 else 'their' }} link has expired:
<ul class="mb-2 mt-1">
{% for c in expired_invitations %}
<li>
<strong>{{ c.display_name }}</strong> ({{ c.email }}) —
expired {{ c.set_password_token_expires.strftime('%Y-%m-%d %H:%M') }}
&nbsp;
<form method="POST" action="{{ url_for('customers.resend_invite', customer_id=c.id) }}"
class="d-inline">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<button type="submit" class="btn btn-sm btn-warning py-0 px-2"
style="font-size:.75rem;">
<i class="bi bi-send me-1"></i>Resend
</button>
</form>
</li>
{% endfor %}
</ul>
<span class="text-muted small">Resend a fresh 72-hour invitation link or delete the account if it is no longer needed.</span>
</div>
</div>
{% endif %}
<div class="card shadow-sm">
<div class="card-body p-0">
<div class="table-responsive">
@@ -21,6 +21,20 @@
<form method="post">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
{# ── Pause all emails banner ── #}
{% set any_email_on = prefs_map.values() | selectattr('email_enabled') | list | length > 0
or prefs_map | length == 0 %}
<div class="alert alert-light border d-flex align-items-center justify-content-between py-2 mb-3">
<div>
<i class="bi bi-pause-circle me-2 text-secondary"></i>
<strong>Pause all email notifications</strong>
<span class="text-muted ms-2" style="font-size:.85rem;">— in-app notifications are unaffected</span>
</div>
<button type="button" id="pauseAllBtn" class="btn btn-sm btn-outline-secondary">
<i class="bi bi-pause-fill me-1"></i>Pause All Emails
</button>
</div>
<div class="card shadow-sm">
<div class="card-header bg-light">
<div class="row fw-semibold text-muted" style="font-size:.8rem;">
@@ -292,6 +306,42 @@
badge.textContent = 'Live';
}
}
// ── Pause all emails button ──────────────────────────────────────────────
var pauseBtn = document.getElementById('pauseAllBtn');
if (pauseBtn) {
pauseBtn.addEventListener('click', function () {
var allEmailToggles = document.querySelectorAll('.email-toggle');
var anyOn = Array.from(allEmailToggles).some(function (c) { return c.checked; });
allEmailToggles.forEach(function (emailChk) {
var event = emailChk.dataset.event;
var digestChk = document.getElementById('digest_' + event);
var freqSelect = document.getElementById('freq_' + event);
var badge = document.getElementById('badge-' + event);
if (anyOn) {
// Pause: turn everything off
emailChk.checked = false;
digestChk.checked = false;
digestChk.disabled = true;
freqSelect.disabled = true;
updateBadge(badge, false, false);
} else {
// Resume: re-enable email (digest stays off until user opts back in)
emailChk.checked = true;
digestChk.disabled = false;
updateBadge(badge, true, false);
}
});
// Update button label to reflect new state
var nowPaused = !anyOn ? false : true;
pauseBtn.innerHTML = nowPaused
? '<i class="bi bi-play-fill me-1"></i>Resume All Emails'
: '<i class="bi bi-pause-fill me-1"></i>Pause All Emails';
});
}
})();
</script>
{% endblock %}