Implement dues reminder system with monthly payment cycle
Some checks failed
Build And Push Image / docker (push) Failing after 1m10s

- Add API endpoint and email templates for dues reminders
- Change due date calculation from yearly to monthly billing
- Add visual status indicators for overdue and due-soon members
- Enhance member cards with status stripes and styling
This commit is contained in:
2025-08-15 14:39:22 +02:00
parent 7784fab23f
commit 888059a612
7 changed files with 523 additions and 6 deletions

View File

@@ -254,10 +254,10 @@ watch(duesPaid, (newValue) => {
} else {
form.value['Membership Date Paid'] = '';
if (!form.value['Payment Due Date']) {
// Set due date to one year from member since date or today
// Set due date to one month from member since date or today
const memberSince = form.value['Member Since'] || new Date().toISOString().split('T')[0];
const dueDate = new Date(memberSince);
dueDate.setFullYear(dueDate.getFullYear() + 1);
dueDate.setMonth(dueDate.getMonth() + 1);
form.value['Payment Due Date'] = dueDate.toISOString().split('T')[0];
}
}

View File

@@ -415,10 +415,10 @@ watch(duesPaid, (newValue) => {
} else {
form.value.membership_date_paid = '';
if (!form.value.payment_due_date) {
// Set due date to one year from member since date or today
// Set due date to one month from member since date or today
const memberSince = form.value.member_since || new Date().toISOString().split('T')[0];
const dueDate = new Date(memberSince);
dueDate.setFullYear(dueDate.getFullYear() + 1);
dueDate.setMonth(dueDate.getMonth() + 1);
form.value.payment_due_date = dueDate.toISOString().split('T')[0];
}
}

View File

@@ -1,10 +1,23 @@
<template>
<v-card
class="member-card"
:class="{ 'member-card--inactive': !isActive }"
:class="{
'member-card--inactive': !isActive,
'member-card--overdue': isOverdue,
'member-card--due-soon': isDuesComingDue
}"
elevation="2"
@click="$emit('view', member)"
>
<!-- Status Stripe -->
<div
v-if="isOverdue || isDuesComingDue"
class="status-stripe"
:class="{
'status-stripe--overdue': isOverdue,
'status-stripe--due-soon': isDuesComingDue
}"
/>
<!-- Member Status Badge -->
<div class="member-status-badge">
<v-chip
@@ -547,4 +560,33 @@ const formatDate = (dateString: string): string => {
.text-error {
color: rgb(var(--v-theme-error)) !important;
}
/* Status Stripe Styles */
.status-stripe {
position: absolute;
top: 0;
left: 0;
width: 4px;
height: 100%;
z-index: 2;
border-radius: 12px 0 0 12px;
}
.status-stripe--overdue {
background: linear-gradient(180deg, #f44336 0%, #d32f2f 100%);
box-shadow: 2px 0 8px rgba(244, 67, 54, 0.3);
}
.status-stripe--due-soon {
background: linear-gradient(180deg, #ff9800 0%, #f57c00 100%);
box-shadow: 2px 0 8px rgba(255, 152, 0, 0.3);
}
.member-card--overdue {
border-left: 4px solid #f44336;
}
.member-card--due-soon {
border-left: 4px solid #ff9800;
}
</style>