This is a design mockup. All data, member names, and monetary values are illustrative only and not connected to the live system.
Problem & Goals

Dashboard & Pricing Redesign

The current dashboard dedicates ~75% of the viewport to a single action queue list. Financial visibility — renewal values, status breakdown — is absent. The office manager and CEO need at-a-glance financial health alongside staff triage.

The redesign restructures the dashboard as a card grid: KPI strip at top for quick reads, workflow-specific cards below, and a more prominent renewals chart showing status and value. A companion Pricing Management screen provides staff with control over the membership price schedule, modifiers, and per-member special rates.

Goals

  • Add renewal value as a KPI visible to office manager and CEO
  • Make the renewals chart more prominent with status breakdown and clickable bars
  • Separate action types into workflow-specific cards (renewals, signups, data issues)
  • Make the layout flexible for future dashboard cards
  • Activity feed fills available space with pagination
  • New pricing management screen for price bands, modifiers, and special rates
  • Special rate toggle on member records for individually negotiated pricing

1 Layout — Card Grid

Three-column layout with a full-width KPI strip across the top. Each dashboard widget is a card placed into the grid. New cards can be added without changing the existing layout.

KPI STRIP — full width (Active · Pending · Renewals · Value · Quick Find) CARD GRID Renewals Chart cols 1–2 · stacked bars · clickable · values Activity Feed col 3 · spans all rows fills height · paginated Renewal Actions col 1 · overdue + due + upcoming New Signups col 2 · pending review Data Issues col 1 · missing email/address
Card grid layout — three columns, activity feed spanning all rows
Technical notes
  • CSS grid: grid-template-columns: 1fr 1fr 320px
  • Chart card: grid-column: 1 / 3
  • Activity feed: grid-column: 3; grid-row: 1 / 4
  • New cards slot into the grid by adding a grid item — no layout restructuring needed

2 KPI Strip

Four metric tiles plus a quick-find search, spanning the full width above the card grid.

287 Active Members
2 Pending
Awaiting approval
14 June Renewals
1 overdue
£4,280 June Value
Renewal revenue this month
  • Large numeral with small uppercase label — same pattern as current dashboard
  • Active, Pending and Renewals counts use existing data already shown on the current dashboard
  • June Value is a new capability — see Renewal Value
  • Quick Find searches by organisation name or account number
Technical notes
  • Active, Pending, Renewals: existing useKpiCounts hook
  • Quick Find: existing useQuickFind hook — ilike on name and account_number, limit 6
  • June Value: new useRenewalValue hook — sums price_excl_vat_gbp + premium_supplement_excl_vat_gbp for current month (see Renewal Value)

3 Renewal Value New

A new KPI tile showing the total monetary value of the current month's renewals. This is the key new financial metric requested by the office manager and CEO.

Pricing data comes from a new Pricing Management screen where price bands, modifiers, and special rates are maintained. The per-member price is fixed at renewal time based on the current schedule — see the Pricing Management sections below for detail.

Technical notes
  • Value computed from price_excl_vat_gbp + premium_supplement_excl_vat_gbp for each org renewing in the current month
  • New hook: useRenewalValue — aggregates billing totals for orgs where renewal_month = currentMonth

4 Renewals Chart

A much larger renewals chart spanning two columns of the dashboard. The current month breaks down into status segments; every bar is clickable and shows the monetary value.

Renewals by Month

2026 · showing count and value
Renewed / Paid
Pending / Due
Overdue

Features

  • Much larger than the current sidebar chart — takes a prominent position on the dashboard
  • Current month stacked by status: renewed/paid, pending/due, overdue
  • Clickable bars — navigates to Members list filtered by that month
  • Per-month £ value shown below each bar
  • Past months in neutral grey; future months as outlined placeholders
Technical notes
  • Spans grid-column: 1 / 3 — two of three grid columns
  • Current month stacked via CSS flex with column-reverse direction
  • Bar click navigates to /members?renewal_month=N
  • Renewal counts: existing useRenewalCounts hook, extended with status breakdown
  • Value data: shares useRenewalValue hook with KPI strip — sums price_excl_vat_gbp + premium_supplement_excl_vat_gbp per month

5 Action Cards

Three separate cards, one per workflow: renewal management, signup review, and data cleanup. Each card shows top items with overflow linking to the Members list.

Renewal Actions

11 members
Overdue 1
Renewal Overdue
Skye Smokery Ltd
April renewal — 18 days overdue
Due This Month 6
Renewal Due
Ben Nevis Outdoor Gear
WHC-00094 · Not yet contacted
Renewal Due
Fort William Bakehouse
WHC-00076 · Not yet contacted
Renewal Due
Caledonian Cycles
WHC-00087 · Chasing
Upcoming 4
Upcoming Renewal
Morvern Community Woodland
WHC-00038 · Renewal month: July
Upcoming Renewal
Arisaig Marine
WHC-00072 · Renewal month: July

Features

  • One card per workflow: renewal management, signup review, data cleanup
  • Renewal Actions has three collapsible tiers: overdue, due this month, upcoming
  • Whole item row is clickable — navigates to org record
  • Overflow links to Members list with the relevant filter pre-applied
  • Signups show sector, region and size band metadata for quick context
  • Data issues identify the specific problem (missing email vs missing address)
Technical notes
  • Renewal Actions: existing useActionQueue hook — overdue, due, upcoming tiers
  • New Signups: membership_status = 'new' from same hook
  • Data Issues: orgs missing primary email or contact address, from same hook
  • Overflow links require URL-driven filters on Members page (see Navigation Pattern)

6 Activity Feed

A timeline of recent membership activity shown in plain language. This is what staff see — a friendly narrative of what's happening, separate from the technical event log.

Recent Activity

New signup received
Highland Horizons B&B submitted a membership application
2 hours ago
Membership approved
Oban Print Workshop approved by Claire — Xero contact created
Yesterday 11:32
New signup received
Glencoe Outdoor Co. submitted a membership application
Yesterday 09:14
Webhook delivered
membership_approved → xero-contact-sync · 200 OK
Yesterday 11:33
Renewal paid
Ben Nevis Outdoor Gear — £320 received via Xero
Yesterday 09:50
Membership approved
Loch Lomond Activities approved by Claire
13 Jun · 14:07
Renewal paid
Caledonian Cycles — £280 received via Xero
11 Jun · 14:40

Features

  • Fills available space in the right column — shows as many events as will fit
  • Same event types as the current dashboard, displayed in a friendlier format
  • Load more appends the next page of events below — the feed grows, button moves down
  • Coloured dots by event type; connector lines between entries
Technical notes
  • Existing useRecentEvents hook, current limit of 10 removed
  • Pagination: offset-based, fetches next page on "Load more" click
  • Grid placement: grid-column: 3; grid-row: 1 / 4 — fills all rows
  • Not the admin /events page — same event types, friendlier display

8 URL-Driven Member Filters New

The Members page needs to support opening with filters already applied from a link. Today, filters reset every time you visit the page — there's no way to link someone to a filtered view.

Links to the Members list — from the dashboard, from emails, from bookmarks — will open with the right filters already applied. For example, a colleague can share a link to "all overdue renewals" and it just works.

Technical notes

This is a prerequisite for the dashboard overflow links and chart bar clicks. Without it, those links would land on an unfiltered Members page.

  • Replace local useState filter state with useSearchParams
  • Seed filters from URL on mount; update URL when filters change
  • Param mapping: renewal_status=due|upcoming|overdue, renewal_month=N, issue=missing_data, status=active|new
  • Existing filter UI unchanged — just wired to the URL

9 Clickable Items

Action items are clickable as a whole row — the entire item navigates to the member record, not just the explicit Open/Review button.

The button remains as a visible affordance, but the click target is the full item. This is a change from the current dashboard where only the button is clickable.

Change from current behaviour. Try clicking any item in the mockups above — the whole row responds, not just the button.

10 Price Bands New

A new settings screen for managing the membership price schedule. Price bands are keyed to employee size — the same size_band values already stored on each member record.

Prices are applied at next renewal. Typically updated on 1 April. Already-processed renewals are not affected — the per-member price is fixed in place at renewal time.

Price Bands

Excl. VAT
Size Band Annual Price
Sole Trader £120.00
1–5 employees £180.00
6–20 employees £280.00
21–50 employees £420.00
51+ employees £580.00

Features

  • One row per size_band — matches the existing enum on the organisation table
  • Inline edit: click Edit to change a price, Save to persist, Cancel to discard
  • Prices are excl. VAT — consistent with the existing price_excl_vat_gbp field
  • Changes take effect at next renewal — no retrospective impact on existing members
Technical notes
  • New table: membership_price_bandsize_band (PK, references the enum), annual_price_excl_vat_gbp (numeric(10,2))
  • Seeded via migration with initial values matching the current spreadsheet
  • CRUD via new /settings/pricing route in admin UI
  • At renewal time: look up band price by org's size_band, apply modifiers, stamp onto price_excl_vat_gbp

11 Modifiers New

Two modifiers adjust the band price at renewal: a flat premium supplement and a percentage charity discount. Both are system-wide values managed alongside the price bands.

Premium Supplement
£150.00
Added to band price · excl. VAT
Charity Discount
50%
Applied after band + supplement

How modifiers are applied

  • Premium supplement — a flat amount added to the band price when is_premium = true. Example: 6–20 band (£280) + premium (£150) = £430
  • Charity discount — a percentage applied after band + supplement when is_charity = true. Example: sole trader (£120) at 50% = £60
  • Both flags already exist on the organisation record and are toggled via the member's billing section
  • Modifiers are applied at renewal time only — changes don't affect already-processed renewals
Technical notes
  • New table: membership_modifierkey (text PK: 'premium_supplement' | 'charity_discount'), value_numeric (numeric(10,2)), value_type ('flat' | 'percent')
  • Renewal price calculation: band_price + (is_premium ? supplement : 0), then × (is_charity ? (1 - discount/100) : 1)
  • Result stamped onto price_excl_vat_gbp and premium_supplement_excl_vat_gbp
  • Existing is_premium / is_charity booleans on the org row are unchanged

12 Special Rates New

Some members have individually negotiated pricing — a fixed rate that doesn't follow the band schedule at renewal. The pricing management screen shows a read-only summary of all members with special rates.

Special Rates

Managed on each member’s record
Member Override Price Note
Fergusons Transport £350.00 3-year fixed rate, agreed 2025
SSE Transmissions £500.00 Corporate agreement

Features

  • Read-only on the pricing page — special rates are set up on the individual member's record
  • Shows the override price and the reason/note explaining the arrangement
  • "View" links navigate directly to the member record where the rate can be edited
  • At renewal, members with a special rate keep their override price — the band schedule is not applied
Technical notes
  • Derived from orgs where has_special_rate = true — see Special Pricing on a Member
  • Query: select name, price_excl_vat_gbp, special_rate_note from organisation where has_special_rate = true
  • No inline editing — View link navigates to /orgs/{id}

13 Special Pricing on a Member New

The billing section on a member's record gains a "Special Rate" toggle. When enabled, the member's price is manually set and won't be overwritten by the band schedule at renewal.

This is how staff set up negotiated rates, corporate agreements, or any other pricing that doesn't follow the standard bands.

Try it below. Click the Special Rate toggle to see how the billing section changes between standard and override pricing.

Billing

Ben Nevis Outdoor Gear · WHC-00094
Membership Type
Standard
Size Band
6–20 employees
Renewal Month
June
Annual Fee
£280.00
Special Rate
Shown on the Pricing Management summary
Standard band price would be: £280.00 (6–20 employees)
Annual Total (excl. VAT) £280.00

How it works

  • The Special Rate toggle appears in the billing section of every member record
  • When off (default): the member gets their price from the band schedule at next renewal
  • When on: an override price and reason field appear. This price is fixed and the band schedule is skipped at renewal
  • The standard band price is shown for reference so staff can see what the member would pay
  • The reason/note is displayed on the Special Rates summary on the pricing page

What happens when a special rate is set

  • The override price and reason are saved to the member's billing record
  • A note is automatically added to the organisation's notes recording the special rate, the reason, and who set it — providing a visible audit trail on the member record itself
  • An event is created and appears in the activity feed on the dashboard, e.g. "Special rate set for Fergusons Transport — £350.00 (3-year fixed rate, agreed 2025)"
  • The member appears on the Special Rates summary on the pricing management page
Technical notes
  • New columns on organisation: has_special_rate (boolean, default false), special_rate_note (text, nullable)
  • When has_special_rate = true: renewal processing skips band lookup, keeps existing price_excl_vat_gbp
  • When has_special_rate = false: renewal processing applies band price + modifiers and stamps onto price_excl_vat_gbp
  • On toggle-on: append a timestamped note to organisation.notes and insert a special_rate_set event into the events table
  • On toggle-off: append a note recording the removal and insert a special_rate_removed event
  • UI: toggle added to the existing Billing section in OrgForm.tsx, field-level save pattern consistent with other billing fields
  • Affiliate constraint unchanged — affiliates inherit billing from parent and cannot have their own special rate