merge: catch up with feature/helcim-plan-consolidation base
# Conflicts: # server/api/auth/member.get.js # server/api/members/update-contribution.post.js # tests/server/api/update-contribution.test.js
This commit is contained in:
commit
7704557f16
10 changed files with 160 additions and 9 deletions
|
|
@ -59,6 +59,10 @@
|
|||
<span class="membership-k">Contribution</span>
|
||||
<span class="membership-v">{{ currentContributionLabel }}</span>
|
||||
</div>
|
||||
<div v-if="nextPaymentDate" class="membership-row">
|
||||
<span class="membership-k">Next payment</span>
|
||||
<span class="membership-v">{{ formatNextPaymentDate(nextPaymentDate) }}</span>
|
||||
</div>
|
||||
<div class="membership-row">
|
||||
<span class="membership-k">Member since</span>
|
||||
<span class="membership-v">{{
|
||||
|
|
@ -333,6 +337,18 @@ const paymentHistoryLoading = ref(false);
|
|||
const paymentHistoryError = ref(false);
|
||||
const paymentHistoryLoaded = ref(false);
|
||||
|
||||
// Next payment (refreshed lazily from Helcim when cached date is stale)
|
||||
const refreshedNextBillingDate = ref(null);
|
||||
const nextBillingRefreshed = ref(false);
|
||||
|
||||
const nextPaymentDate = computed(() => {
|
||||
const m = memberData.value;
|
||||
if (!m) return null;
|
||||
if (m.status !== 'active') return null;
|
||||
if (!Number(m.contributionAmount)) return null;
|
||||
return refreshedNextBillingDate.value || m.nextBillingDate || null;
|
||||
});
|
||||
|
||||
// Change-card state
|
||||
const isChangingCard = ref(false);
|
||||
const changeCardButtonLabel = ref("Change card");
|
||||
|
|
@ -403,6 +419,44 @@ const formatMemberSince = (dateStr) => {
|
|||
});
|
||||
};
|
||||
|
||||
const formatNextPaymentDate = (dateStr) => {
|
||||
if (!dateStr) return "";
|
||||
const d = new Date(dateStr);
|
||||
if (Number.isNaN(d.getTime())) return "";
|
||||
return d.toLocaleDateString("en-US", {
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
});
|
||||
};
|
||||
|
||||
const STALE_WINDOW_MS = 24 * 60 * 60 * 1000;
|
||||
|
||||
const isNextBillingStale = (dateStr) => {
|
||||
if (!dateStr) return true;
|
||||
const d = new Date(dateStr);
|
||||
if (Number.isNaN(d.getTime())) return true;
|
||||
return d.getTime() - Date.now() < STALE_WINDOW_MS;
|
||||
};
|
||||
|
||||
const refreshNextBillingIfStale = async () => {
|
||||
if (nextBillingRefreshed.value) return;
|
||||
const m = memberData.value;
|
||||
if (!m) return;
|
||||
if (m.status !== 'active') return;
|
||||
if (!Number(m.contributionAmount)) return;
|
||||
if (!isNextBillingStale(m.nextBillingDate)) return;
|
||||
|
||||
nextBillingRefreshed.value = true;
|
||||
try {
|
||||
const response = await $fetch("/api/helcim/subscription");
|
||||
const fresh = response?.subscription?.nextBillingDate;
|
||||
if (fresh) refreshedNextBillingDate.value = fresh;
|
||||
} catch (err) {
|
||||
// Silent — fall back to cached value (if any)
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpdateTier = async () => {
|
||||
isUpdating.value = true;
|
||||
try {
|
||||
|
|
@ -514,6 +568,7 @@ onMounted(() => {
|
|||
if (memberData.value?.helcimCustomerId) {
|
||||
loadPaymentHistory();
|
||||
}
|
||||
refreshNextBillingIfStale();
|
||||
});
|
||||
|
||||
watch(
|
||||
|
|
@ -525,6 +580,13 @@ watch(
|
|||
},
|
||||
);
|
||||
|
||||
watch(
|
||||
() => memberData.value?.status,
|
||||
() => {
|
||||
refreshNextBillingIfStale();
|
||||
},
|
||||
);
|
||||
|
||||
const formatTxnDate = (iso) => {
|
||||
if (!iso) return "—";
|
||||
const d = new Date(iso);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue