Ask who the signup is for, and ask each student the studio's questions #159

Merged
thatguygriff merged 2 commits from feature/145-registering-for-choice into main 2026-07-30 02:24:53 +00:00
Owner

Closes #145 and #146. Bumps the plugin to 1.4.0 as requested.

Two commits, and they are much better read in order — #146 only makes sense once #145 has established what "both" means.

1. The three-way choice (#145)

Replaces the single "I'm registering as a parent or guardian" tick with Just myself / On behalf of one or more students / Both.

Radios, not checkboxes. The feedback said "three checkboxes", but the three answers are mutually exclusive — "both" only means anything as a third choice alongside the other two. Flagging it since it differs from the literal wording.

This turned out to be more than a UI change. The old checkbox could only say whether there were children to add. It could not say whether the account holder was a student, so bookableStudents() always appended them and every guardian was offered their own name in the Who is this for? picker — an invitation to book a lesson nobody meant to sell. "On behalf of" now records us_guardian_only and leaves them out.

The flag is stored as the negative deliberately: every account predating this choice is a bookable student, and absence has to keep meaning exactly that, or the picker would silently stop offering people themselves on upgrade. setGuardianOnly() clears the key rather than writing 0, so "not set" stays the single spelling of "yes, a student".

One guard: a guardian-only account with nobody linked is still offered itself — an empty picker is no way to book at all, and they can correct the account from the profile page.

An unrecognised or absent value reads as "just myself" — the choice that collects and grants the least. A form posted without the radio must never be read as "register these children"; there is a test for exactly that.

2. The questions follow from it (#146)

Choice Student blocks Account holder bookable Answers the studio's questions
Just myself no yes for themselves
On behalf of students yes no per student only
Both yes yes per student and for themselves

That last column is the whole of #146. The account-scope questions describe a student — instrument, level, school — so they are asked of everyone being registered as one. Under both the account holder was previously skipped entirely: never asked, never stored, despite being able to book lessons. Now their answers are recorded against their own user id.

Two details:

  • Recorded after the children, so a rollback that deletes the account cannot leave answers pointing at a user that no longer exists.
  • Validation is two passes, not one. With a single pass, "both" had to blame "each student" for the account holder's own blank field. Now the message says whose answers are missing.

In the form these turn out to be two independent questions — are student blocks in play, and does the account holder answer for themselves — so sync() tracks them separately. "Both" is the case that needs its own answer to each, and it is why step two comes back into play there.

Verification

composer test 822 (up from 814), composer lint, composer cs all pass.

New server-side tests: the guardian-only flag set for students and cleared for self/both; "both" still requiring a student; the unknown-value fallback creating no students; "both" recording the account holder's answer against their own id alongside each student's; "both" rejecting the account holder's blank required answer with a message that does not say "for each student"; and students ignoring anything posted as the account holder's answers.

The form logic is JS, so I drove it in a headless browser — 21 checks across all three choices covering which blocks show, which fields carry required, whether the account holder's question panel is enabled, which submit is offered, and that switching back to "just myself" leaves no hidden required field blocking submit.

Note on the shared test base

checked() and selected() are now stubbed in tests/Unit/TestCase.php. The template needed checked(), and they are pure output helpers with no behaviour worth faking differently per test — the same reasoning as the translation and escape stubs already there.

Closes #145 and #146. **Bumps the plugin to 1.4.0** as requested. Two commits, and they are much better read in order — #146 only makes sense once #145 has established what "both" means. ## 1. The three-way choice (#145) Replaces the single "I'm registering as a parent or guardian" tick with **Just myself** / **On behalf of one or more students** / **Both**. **Radios, not checkboxes.** The feedback said "three checkboxes", but the three answers are mutually exclusive — "both" only means anything as a third choice alongside the other two. Flagging it since it differs from the literal wording. **This turned out to be more than a UI change.** The old checkbox could only say *whether there were children to add*. It could not say whether the **account holder** was a student, so `bookableStudents()` always appended them and every guardian was offered their own name in the **Who is this for?** picker — an invitation to book a lesson nobody meant to sell. "On behalf of" now records `us_guardian_only` and leaves them out. The flag is stored as the **negative** deliberately: every account predating this choice is a bookable student, and absence has to keep meaning exactly that, or the picker would silently stop offering people themselves on upgrade. `setGuardianOnly()` clears the key rather than writing `0`, so "not set" stays the single spelling of "yes, a student". **One guard:** a guardian-only account with nobody linked is still offered itself — an empty picker is no way to book at all, and they can correct the account from the profile page. **An unrecognised or absent value reads as "just myself"** — the choice that collects and grants the least. A form posted without the radio must never be read as "register these children"; there is a test for exactly that. ## 2. The questions follow from it (#146) | Choice | Student blocks | Account holder bookable | Answers the studio's questions | |---|---|---|---| | Just myself | no | yes | for themselves | | On behalf of students | yes | **no** | per student only | | Both | yes | yes | **per student *and* for themselves** | That last column is the whole of #146. The account-scope questions describe a *student* — instrument, level, school — so they are asked of everyone being registered as one. Under **both** the account holder was previously skipped entirely: never asked, never stored, despite being able to book lessons. Now their answers are recorded against their own user id. Two details: - **Recorded after the children**, so a rollback that deletes the account cannot leave answers pointing at a user that no longer exists. - **Validation is two passes, not one.** With a single pass, "both" had to blame "each student" for the account holder's own blank field. Now the message says whose answers are missing. In the form these turn out to be two independent questions — are student blocks in play, and does the account holder answer for themselves — so `sync()` tracks them separately. "Both" is the case that needs its own answer to each, and it is why step two comes back into play there. ## Verification `composer test` 822 (up from 814), `composer lint`, `composer cs` all pass. New server-side tests: the guardian-only flag set for `students` and cleared for `self`/`both`; "both" still requiring a student; the unknown-value fallback creating no students; "both" recording the account holder's answer against **their own** id alongside each student's; "both" rejecting the account holder's blank required answer with a message that does *not* say "for each student"; and `students` ignoring anything posted as the account holder's answers. The form logic is JS, so I drove it in a headless browser — 21 checks across all three choices covering which blocks show, which fields carry `required`, whether the account holder's question panel is enabled, which submit is offered, and that switching back to "just myself" leaves no hidden required field blocking submit. ## Note on the shared test base `checked()` and `selected()` are now stubbed in `tests/Unit/TestCase.php`. The template needed `checked()`, and they are pure output helpers with no behaviour worth faking differently per test — the same reasoning as the translation and escape stubs already there.
thatguygriff added 1 commit 2026-07-30 02:10:20 +00:00
Ask who the signup is for as a three-way choice
CI / Tests (PHP 8.2) (pull_request) Successful in 50s
CI / PHPStan (pull_request) Successful in 2m53s
CI / Coding Standards (pull_request) Successful in 2m57s
CI / Tests (PHP 8.1) (pull_request) Successful in 45s
CI / No Debug Code (pull_request) Successful in 2s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m40s
CI / Build Plugin Zip (pull_request) Skipped
4e5382e259
Replaces the single "I'm registering as a parent or guardian" tick with
"Just myself" / "On behalf of one or more students" / "Both".

Radios, not checkboxes as the feedback put it: the three answers are
mutually exclusive, and "both" only means anything as a third choice
alongside the other two.

The tick could only ever say whether there were children to add. It could
not say whether the account holder was a student, so bookableStudents()
always offered them their own name and any guardian could book themselves a
lesson nobody meant to sell. "On behalf of" now records us_guardian_only and
leaves them out of the picker.

That flag is stored as the negative on purpose. Every account predating this
choice is a bookable student, and absence has to keep meaning exactly that,
or the picker would quietly stop offering people themselves on upgrade.
setGuardianOnly() clears the key rather than writing 0, so "not set" stays
the single spelling of "yes, a student". A guardian-only account with nobody
linked to it is still offered itself — an empty picker is no way to book at
all, and they can put the account right from the profile page.

An unrecognised or absent value reads as "just myself": the choice that
collects the least and grants the least. A missing radio must never be taken
as "register these children".

Bumps to 1.4.0.

The account holder's own questions stay out of play whenever students are
being added, "both" included — asking them there is #146.

Verified the form in a headless browser across all three choices: which
blocks show, which fields carry `required`, whether the account holder's
question panel is disabled, which submit is offered, and that switching back
to "just myself" leaves no hidden required field blocking submit.

Closes #145

Co-Authored-By: Claude Opus 5 <[email protected]>
thatguygriff added 1 commit 2026-07-30 02:15:49 +00:00
Ask the account holder the studio's questions when they are a student too
CI / Tests (PHP 8.2) (pull_request) Successful in 43s
CI / Tests (PHP 8.1) (pull_request) Successful in 52s
CI / No Debug Code (pull_request) Successful in 2s
CI / PHPStan (pull_request) Successful in 2m50s
CI / Coding Standards (pull_request) Successful in 3m19s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m47s
CI / Build Plugin Zip (pull_request) Skipped
69179b75c9
Under "both" the questions were collected per student only, so someone
registering themselves alongside their children was never asked their own
instrument, level or anything else — despite being able to book lessons. The
account-scope questions describe a student, and under "both" the account
holder is one.

Their answers are recorded against their own user id, not shared with a
child's, and recorded after the children so a rollback that deletes the
account cannot leave answers pointing at a user that no longer exists. A
pure guardian is unchanged: they are not a student, so anything posted for
them is still ignored.

Validation became two passes rather than one so the message can say whose
answers are missing — with one pass, "both" had to blame "each student" for
the account holder's own blank field.

In the form, the two questions turn out to be independent: whether student
blocks are in play, and whether the account holder answers for themselves.
"Both" is the case that needs its own answer to each, so sync() now tracks
them separately, and step two comes back into play under "both".

Verified in a headless browser: 21 checks across all three choices, now
including that "both" enables the account holder's own question panel and
offers Next rather than the early submit.

Closes #146

Co-Authored-By: Claude Opus 5 <[email protected]>
thatguygriff changed title from Ask who the signup is for as a three-way choice to Ask who the signup is for, and ask each student the studio's questions 2026-07-30 02:16:25 +00:00
thatguygriff merged commit 969d864106 into main 2026-07-30 02:24:53 +00:00
thatguygriff deleted branch feature/145-registering-for-choice 2026-07-30 02:24:53 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Unsupervised/unsupervised-scheduler#159