fix(display): cadence-aware contribution suffix across UI + admin dashboard

Add formatContribution helper in app/config/contributions.js and route
all member-facing and admin contribution displays through cadence-aware
expressions so annual members see /yr instead of /mo. Normalize annual
amounts to monthly equivalents in the admin dashboard revenue
aggregate now that contributionAmount is stored in cadence units.
This commit is contained in:
Jennie Robinson Faber 2026-05-23 15:47:10 +01:00
parent 5023fb14ad
commit 0dd68ff1aa
6 changed files with 29 additions and 12 deletions

View file

@ -54,7 +54,7 @@
</select>
</div>
<div class="field">
<label>Contribution ($/mo)</label>
<label>Contribution ({{ member.billingCadence === 'annual' ? '$/yr' : '$/mo' }})</label>
<input v-model.number="form.contributionAmount" type="number" min="0" step="1">
<p class="field-hint field-hint--warn">
Writes to our database only. If the member is on a paid plan, also update <code>recurringAmount</code> in the Helcim dashboard this form does not sync.

View file

@ -111,7 +111,7 @@
<td>
<CircleBadge :circle="member.circle" />
</td>
<td class="col-mono">${{ member.contributionAmount ?? 0 }}/mo</td>
<td class="col-mono">${{ member.contributionAmount ?? 0 }}{{ member.billingCadence === 'annual' ? '/yr' : '/mo' }}</td>
<td>
<span class="badge status" :class="`status-${member.status || 'pending_payment'}`">{{ statusLabel(member.status) }}</span>
</td>
@ -192,7 +192,7 @@
</select>
</div>
<div class="field">
<label>Contribution ($/mo)</label>
<label>Contribution ({{ newMember.billingCadence === 'annual' ? '$/yr' : '$/mo' }})</label>
<input v-model.number="newMember.contributionAmount" type="number" min="0" step="1">
</div>
<div class="modal-actions">
@ -286,7 +286,7 @@
<td>{{ row.name }}</td>
<td class="col-email">{{ row.email }}</td>
<td>{{ row.circle }}</td>
<td>${{ row.contributionAmount }}/mo</td>
<td>${{ row.contributionAmount }}{{ row.billingCadence === 'annual' ? '/yr' : '/mo' }}</td>
</tr>
</tbody>
</table>
@ -366,7 +366,7 @@
</select>
</div>
<div class="field">
<label>Contribution ($/mo)</label>
<label>Contribution ({{ editingMember.billingCadence === 'annual' ? '$/yr' : '$/mo' }})</label>
<input v-model.number="editingMember.contributionAmount" type="number" min="0" step="1">
</div>
<div class="field">
@ -860,6 +860,7 @@ const editingMember = reactive({
email: "",
circle: "community",
contributionAmount: 0,
billingCadence: "monthly",
status: "pending_payment",
});
@ -870,6 +871,7 @@ const editMember = (member) => {
email: member.email,
circle: member.circle,
contributionAmount: member.contributionAmount ?? 0,
billingCadence: member.billingCadence || "monthly",
status: member.status || "pending_payment",
});
showEditModal.value = true;

View file

@ -32,7 +32,7 @@
<DashedBox :hoverable="false">
<div class="section-label">Contribution</div>
<div class="info-value">
${{ memberData?.contributionAmount ?? 0 }} CAD/month
{{ formatContribution(memberData?.contributionAmount ?? 0, memberData?.billingCadence) }} CAD
</div>
</DashedBox>
</div>
@ -308,7 +308,7 @@
<script setup>
import { reactive, ref, computed, onMounted, onUnmounted } from "vue";
import { getCircleOptions } from "~/config/circles";
import { requiresPayment } from "~/config/contributions";
import { requiresPayment, formatContribution } from "~/config/contributions";
useSiteMeta({
title: "Join",

View file

@ -36,7 +36,7 @@
<PageHeader :title="welcomeTitle">
<div class="dashboard-meta">
<CircleBadge :circle="memberData?.circle || 'community'" />
<span>${{ memberData?.contributionAmount ?? 0 }} CAD/mo</span>
<span>{{ formatContribution(memberData?.contributionAmount ?? 0, memberData?.billingCadence) }} CAD</span>
</div>
<p v-if="showSlackComingNote" class="slack-coming-note">
Slack workspace access is part of your membership. Invitations are
@ -171,7 +171,7 @@
<div class="membership-row">
<span class="key">Contribution</span>
<span class="val"
>${{ memberData?.contributionAmount ?? 0 }} CAD/month</span
>{{ formatContribution(memberData?.contributionAmount ?? 0, memberData?.billingCadence) }} CAD</span
>
</div>
<div class="membership-row">
@ -220,6 +220,8 @@
</template>
<script setup>
import { formatContribution } from '~/config/contributions';
useSiteMeta({ title: 'Dashboard', noindex: true });
const { memberData, checkMemberStatus } = useAuth();