From 1f50c2adb7fffa95c363590a7ae9f8ad09cfa64a Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 15 Aug 2025 15:02:56 +0200 Subject: [PATCH] fixes --- components/DuesPaymentBanner.vue | 116 ++++++++++++++++++++----------- 1 file changed, 76 insertions(+), 40 deletions(-) diff --git a/components/DuesPaymentBanner.vue b/components/DuesPaymentBanner.vue index de54959..770b0cb 100644 --- a/components/DuesPaymentBanner.vue +++ b/components/DuesPaymentBanner.vue @@ -209,38 +209,75 @@ const isPaymentOverOneYear = computed(() => { }); /** - * Check if dues are coming due within 30 days + * Calculate next dues date (1 year from when they last paid or joined) + */ +const nextDuesDate = computed(() => { + if (!memberData.value) return null; + + // If dues are paid, calculate 1 year from payment date + if (memberData.value.current_year_dues_paid === 'true' && memberData.value.membership_date_paid) { + const lastPaidDate = new Date(memberData.value.membership_date_paid); + const nextDue = new Date(lastPaidDate); + nextDue.setFullYear(nextDue.getFullYear() + 1); + return nextDue; + } + + // If not paid but has a due date, use that + if (memberData.value.payment_due_date) { + return new Date(memberData.value.payment_due_date); + } + + // Fallback: 1 year from member since date + if (memberData.value.member_since) { + const memberSince = new Date(memberData.value.member_since); + const nextDue = new Date(memberSince); + nextDue.setFullYear(nextDue.getFullYear() + 1); + return nextDue; + } + + return null; +}); + +/** + * Check if dues are coming due within 30 days (for paid members) */ const isDueSoon = computed(() => { - if (!memberData.value?.payment_due_date) return false; + if (!memberData.value || !nextDuesDate.value) return false; - try { - const dueDate = new Date(memberData.value.payment_due_date); - const today = new Date(); - const diffTime = dueDate.getTime() - today.getTime(); - const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); - - // Show banner if due within 30 days (including overdue) - return diffDays <= 30; - } catch { - return false; - } + // Only show warning if dues are currently paid + if (memberData.value.current_year_dues_paid !== 'true') return false; + + const today = new Date(); + const thirtyDaysFromNow = new Date(); + thirtyDaysFromNow.setDate(thirtyDaysFromNow.getDate() + 30); + + // Show banner if due date is within the next 30 days + return nextDuesDate.value <= thirtyDaysFromNow && nextDuesDate.value > today; +}); + +/** + * Check if dues are overdue + */ +const isDuesOverdue = computed(() => { + if (!memberData.value) return false; + + // If dues are current, not overdue + const duesCurrentlyPaid = memberData.value.current_year_dues_paid === 'true'; + const paymentTooOld = isPaymentOverOneYear.value; + const gracePeriod = isInGracePeriod.value; + + // Member is overdue if payment is too old OR (dues not paid AND not in grace period) + return paymentTooOld || (!duesCurrentlyPaid && !gracePeriod); }); /** * Check if dues need to be paid (either coming due soon or overdue) - * Banner should show when payment is needed within 30 days */ const needsPayment = computed(() => { if (!memberData.value) return false; - const duesCurrentlyPaid = memberData.value.current_year_dues_paid === 'true'; - const paymentTooOld = isPaymentOverOneYear.value; - - // Show banner if: - // 1. Dues are coming due within 30 days AND not currently paid - // 2. OR payment is over 1 year old (even if marked as paid) - return (isDueSoon.value && !duesCurrentlyPaid) || paymentTooOld; + // Show banner if dues are coming due soon OR overdue + return isDueSoon.value || isDuesOverdue.value; }); // Computed properties @@ -253,9 +290,9 @@ const shouldShowBanner = computed(() => { }); const daysRemaining = computed(() => { - if (!memberData.value?.payment_due_date) return 0; + if (!nextDuesDate.value) return 0; - const dueDate = new Date(memberData.value.payment_due_date); + const dueDate = nextDuesDate.value; const today = new Date(); const diffTime = dueDate.getTime() - today.getTime(); const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); @@ -264,19 +301,22 @@ const daysRemaining = computed(() => { }); const isOverdue = computed(() => { - return daysRemaining.value < 0; + return isDuesOverdue.value; }); const paymentMessage = computed(() => { - if (isOverdue.value) { + if (isDuesOverdue.value) { const overdueDays = Math.abs(daysRemaining.value); - return `Your annual membership dues of €${config.value.membershipFee} are ${overdueDays} day${overdueDays !== 1 ? 's' : ''} overdue. Immediate payment is required to avoid account suspension.`; - } else if (daysRemaining.value <= 7) { - return `Your annual membership dues of €${config.value.membershipFee} are due in ${daysRemaining.value} days. Please pay immediately to avoid late fees.`; - } else if (daysRemaining.value <= 30) { - return `Your annual membership dues of €${config.value.membershipFee} are due in ${daysRemaining.value} days. Please pay soon to avoid account suspension.`; + return `Your annual membership dues of €${config.value.membershipFee} are ${overdueDays > 0 ? overdueDays + ' day' + (overdueDays !== 1 ? 's' : '') + ' ' : ''}overdue. Immediate payment is required to avoid account suspension.`; + } else if (isDueSoon.value) { + const dueDays = daysRemaining.value; + if (dueDays <= 7) { + return `Your annual membership dues of €${config.value.membershipFee} are due in ${dueDays} day${dueDays !== 1 ? 's' : ''}. Please pay immediately to avoid late fees.`; + } else { + return `Your annual membership dues of €${config.value.membershipFee} are due in ${dueDays} day${dueDays !== 1 ? 's' : ''}. Please pay soon to avoid account suspension.`; + } } else { - return `Your annual membership dues of €${config.value.membershipFee} are due in ${daysRemaining.value} days.`; + return `Your annual membership dues of €${config.value.membershipFee} require attention.`; } }); @@ -338,18 +378,14 @@ async function markDuesAsPaid() { } } -// Load member data for the current user +// Load member data for the current user from session async function loadMemberData() { - if (!user.value?.email) return; + if (!user.value) return; try { - const response = await $fetch('/api/members') as any; - const members = response?.data || response?.list || []; - - // Find member by email - const member = members.find((m: any) => m.email === user.value?.email); - if (member) { - memberData.value = member; + const response = await $fetch('/api/auth/session') as any; + if (response?.success && response?.member) { + memberData.value = response.member; } } catch (error) { console.warn('Failed to load member data:', error);