feat(member): pending_payment retains access, soften status copy

pending_payment now grants the same RSVP/peer-support capabilities as active,
and status banner/label copy is rewritten to be non-threatening ("Setting up
payment", "Paused", "Closed"). Aligns member-facing copy across the account
page with the capability model.
This commit is contained in:
Jennie Robinson Faber 2026-04-18 17:06:22 +01:00
parent 15329e3e84
commit 37a58cb0eb
3 changed files with 43 additions and 43 deletions

View file

@ -61,11 +61,11 @@ describe("MEMBER_STATUS_CONFIG", () => {
expect(cfg.canPeerSupport).toBe(true);
});
it("pending_payment can access members but not RSVP or peer support", () => {
it("pending_payment has full permissions (payment is decoupled from access)", () => {
const cfg = MEMBER_STATUS_CONFIG.pending_payment;
expect(cfg.canRSVP).toBe(false);
expect(cfg.canRSVP).toBe(true);
expect(cfg.canAccessMembers).toBe(true);
expect(cfg.canPeerSupport).toBe(false);
expect(cfg.canPeerSupport).toBe(true);
});
it("suspended has all permissions false", () => {
@ -122,10 +122,10 @@ describe("useMemberStatus composable", () => {
expect(canRSVP.value).toBe(true);
});
it("canRSVP is false when pending_payment", () => {
it("canRSVP is true when pending_payment (decoupled from payment)", () => {
memberData.value = { status: "pending_payment" };
const { canRSVP } = useMemberStatus();
expect(canRSVP.value).toBe(false);
expect(canRSVP.value).toBe(true);
});
it("canAccessMembers is true for active and pending_payment", () => {
@ -182,22 +182,22 @@ describe("useMemberStatus composable", () => {
});
describe("getBannerMessage", () => {
it("returns payment message for pending_payment", () => {
it("returns payment-setup message for pending_payment", () => {
memberData.value = { status: "pending_payment" };
const { getBannerMessage } = useMemberStatus();
expect(getBannerMessage()).toContain("pending payment");
expect(getBannerMessage()).toContain("payment setup");
});
it("returns suspended message for suspended", () => {
it("returns paused message for suspended", () => {
memberData.value = { status: "suspended" };
const { getBannerMessage } = useMemberStatus();
expect(getBannerMessage()).toContain("suspended");
expect(getBannerMessage()).toContain("paused");
});
it("returns cancelled message for cancelled", () => {
it("returns closed message for cancelled", () => {
memberData.value = { status: "cancelled" };
const { getBannerMessage } = useMemberStatus();
expect(getBannerMessage()).toContain("cancelled");
expect(getBannerMessage()).toContain("closed");
});
it("returns null for active", () => {
@ -208,22 +208,22 @@ describe("useMemberStatus composable", () => {
});
describe("getRSVPMessage", () => {
it("returns payment message for pending_payment", () => {
it("returns null for pending_payment (decoupled from RSVP)", () => {
memberData.value = { status: "pending_payment" };
const { getRSVPMessage } = useMemberStatus();
expect(getRSVPMessage()).toContain("payment");
expect(getRSVPMessage()).toBeNull();
});
it("returns restriction message for suspended", () => {
it("returns inactive-account message for suspended", () => {
memberData.value = { status: "suspended" };
const { getRSVPMessage } = useMemberStatus();
expect(getRSVPMessage()).toContain("reactivate");
expect(getRSVPMessage()).toContain("isn't active");
});
it("returns restriction message for cancelled", () => {
it("returns inactive-account message for cancelled", () => {
memberData.value = { status: "cancelled" };
const { getRSVPMessage } = useMemberStatus();
expect(getRSVPMessage()).toContain("reactivate");
expect(getRSVPMessage()).toContain("isn't active");
});
it("returns null for active", () => {