Bandmakers · design pass two

Walked every
screen. Fixed
what was there.

The first pass was read off the code. This one was done with the app running on a phone, opening one screen at a time — which is the only way most of this could have been found.

These are written comparisons, not screenshots. Every change below was made and then checked on the running simulator; the panels describe what was on screen before and after. Colours and spacing on this page come from the app's own theme.ts.
Screens walked
48
Fixes landed
31
Shared components
6
One-tap destructive
0

The three that mattered most

Everything else on this page is tidying. These three were doing real damage across the whole app, and all three were invisible until it was running.

Every tab opened 62pt too low

Home · Bookings · Progress · Profile · all five staff tabs

Was

Inside the native tab bar, iOS adds the top safe area to a scroll view by itself — and every screen was also padding by it. The same 62pt was counted twice, so Home's greeting started 135pt down instead of 70. A tenth of the first screenful, on every tab, spent on nothing.

Now

Counted once. One shared hook owns the top of every scrolling screen, and the content container is made a pixel taller than the window so the rule iOS applies is the same on a short screen and a long one.

Measure before tuning. The obvious fix — contentInsetAdjustmentBehavior="never" — does nothing here; it is not reaching the native view at all. Both values were tried on the device and neither moved a pixel. That is written down in the code so nobody spends the hour again.

"Academy staff sign in" did nothing

Profile → the staff switch

Was

The row pushed the staff sign-in, the route guard saw a parent standing on an auth screen and replaced it on the next frame. The screen flashed and the app was back on Home. A row that looks like a destination and is a no-op — the entire staff side was unreachable from inside the app.

Now

The one auth screen a signed-in parent is allowed to reach. Staff are a separate account with separate tokens, so signing into one has nothing to do with being signed into the other, and the only way in is from a screen you reach while already signed in as a parent.

"Step 6 of 5" on the screen before payment

Booking → review

Was

Review was numbered as a sixth step in a five-step flow. Underneath it, the button read "Payment — not built yet" — a developer's note sitting on a customer's screen — and when the quote failed the screen was a dead end with no way back to the choices that caused it.

Now

Review is outside the count and shows its own kicker instead. The button says Pay; the foot note carries the truth that card payment is not open yet. A failed quote offers Pick another time.

This is the last screen before a parent decides whether this academy is careful with their child and their card. It was the screen with the arithmetic error on it.

One shape per pattern

The rule you gave me after the two profile headers. Nobody decided to have four kinds of list — it accumulated one screen at a time. Six shared components now cover what was written out by hand between eleven and fifty-nine times each.

A card per record became one card with hairlines

Staff Desk · Timetable · Branches · Teachers · Books · Stock · Codes · Bundles · Accounts · Family · Payments · Progress · Trial · Careers

Was
Complaints & notes
Home tutoring requests
Music tour requests

Identical rounded cards repeated down the page, with a target-sized dead zone between every pair of tappable rows.

Now
Complaints & notesWhat parents have told us3
Home tutoringWaiting for a teacher1
Music tourWaiting for a teacher0

One card, 1px separators, and a hand-drawn glyph on every row so the list can be scanned rather than read.

Columns of solid black buttons

Branches (7) · Concerts (17) · Teachers (3) · Stock (2 per row)

Was
Mivida
Show code
KODE
Show code

A full-width filled button inside every card. On Concerts that was seventeen black slabs; on Branches, seven — for something you do standing at a printer a few times a year.

Now
MividaNew Cairo · 1 room
KODENew Cairo · 1 room

The row itself opens the thing. Where an action has to stay visible it is a quiet chip that sizes to its own words.

At most one primary per screen — and a control repeated once per row is never the one thing the screen is for.

Buttons named after states

Discount codes · Bundles · Staff accounts

Was

Codes and bundles carried a bordered button reading Switch on / Switch off — the opposite of the current state, spelled out. Staff rows were worse: each offered the two states the person was not in, so "Demo Teacher A · Suspended · Left" looked like a description of them.

Now

Codes and bundles use a real switch — the same control the Instruments screen two rows away was already using. Account status is a three-way segmented control that shows the state and offers the change in one object.

Things that were not true

Copy that said something the system did not mean. These are the ones a parent or a front-desk person would have acted on.

"6 instruments cannot be booked" — three of them could

Lesson prices, and the Academy row that leads to it

Was

The headline counted every instrument missing any tier and called them all unbookable. Drums with no Expert price books perfectly well with a Core teacher. Meanwhile the Academy hub counted only the ones with no price at all — so two screens showed different numbers for what looked like the same fact.

Now

3 instruments cannot be booked, and a second line saying three more are missing a price at one rate only. The hub and the screen agree.

Never round a partial problem up into a total one. The staff member who fixes the wrong three loses an afternoon.

A rejected password stayed on screen while you retyped

Both sign-in screens

Was

"Email or password is incorrect" cleared only on the next submit. After a sign-out it was still sitting in red above two empty boxes, telling a parent their blank password was wrong — and it pushed the Sign in button down as it appeared.

Now

Editing either box clears it, because the thing the message describes is no longer what is in the box.

An expired code still offered to switch itself on

Discount codes

Was

A code that ended in January and one that had used its single use both showed a working Switch on. The server refuses them at checkout either way — a control that does nothing is worse than no control.

Now

They read Expired and Used up, and dates print as "ended 1 January 2026" rather than 2026-01-01.

Nothing destroys on the first tap

Four controls removed something real, immediately, with no undo anywhere in the app — and three of them were the loudest thing on their screen.

Retire · Remove · Replace this code · Mark as left

Timetable · Closed days · Branches · Staff accounts

Was

A red bordered button on every row, firing on the first tap. Retiring a slot stops parents booking it. Removing a closure puts a holiday back on sale. Replacing a branch code invalidates the printed sign on the door — and it sat next to the button you press to read that sign.

Now

A quiet red word, and a confirmation that names the exact thing: "Sunday 11:00 stops being bookable. Lessons already booked into it keep their place."

Confirmations only for the genuinely irreversible — use them anywhere else and people learn to tap through them. Suspending a staff account still passes straight through; marking someone as left does not.

Forms that fit on the screen

The staff "add a weekly time" form asked four questions and every one was a fully expanded list: 2 teachers, 7 branches, 7 instruments, 7 days. Twenty-three rows to answer four questions, so the only thing you actually type sat two screens below the fold.

Long lists collapse onto the answer

Timetable · Day minimums · Closed days · Prices · Cash · Place a make-up · Books

Was

Four walls of rows in a row. The weekday was a seven-row list — while a one-row day strip was already sitting in the same component file, used elsewhere.

Now
MividaNew CairoChange

Once a choice is made the list shows the answer and a Change. The whole form is now four rows and a text box. It only ever collapses onto a real answer — with nothing chosen the list stays open, because a collapsed empty row is a question the form is hiding from you.

The instrument field said "optional" and gave you seven instruments with no way to say any — so it could never be finished, so it never collapsed. "Optional" has to be a choice you can make.

Smaller things, same reasons

Twelve more

Across both sides

Was

· "This time is already taken." printed in full on eight consecutive rows
· core / legacy / cash / accessory printed raw from the database
· "Zamalek · Zamalek", "Sahel · Sahel"
· Space Mono caps under every bar on Reports
· "2026-08" as a cohort label
· A lone "1" floated 350pt from its section heading
· A key glyph drawn as a magnifying glass; a book drawn as the pause symbol
· A section headed "Concerts" containing one row called "Concerts"
· "Closures." on a screen reached from a row called "Closed days"
· Three names for one search box
· "Move to Open to everyone"
· "Events  17"

Now

· A Taken tag, and the 45 minutes every slot shares stated once in the foot note instead of eight times
· One shared place turns a column value into something a person reads
· A subtitle only when it adds something
· The display face on section headings and nowhere else
· "August 2026"
· The count rides with the label
· Both redrawn, and a globe added for Language
· Folded into "Schedule & events"
· The screen takes the row's wording
· One
· "Open to everyone" — a button says what happens when you press it
· "Events (17)"

Still open

Not design problems. These need the academy or a decision from you.