Let parents register once and book for their children
CI / Tests (PHP 8.2) (pull_request) Successful in 42s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m45s
CI / Build Plugin Zip (pull_request) Skipped
CI / Tests (PHP 8.1) (pull_request) Failing after 52s
CI / No Debug Code (pull_request) Successful in 2s
CI / PHPStan (pull_request) Successful in 2m52s
CI / Coding Standards (pull_request) Successful in 2m57s
CI / Tests (PHP 8.2) (pull_request) Successful in 42s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m45s
CI / Build Plugin Zip (pull_request) Skipped
CI / Tests (PHP 8.1) (pull_request) Failing after 52s
CI / No Debug Code (pull_request) Successful in 2s
CI / PHPStan (pull_request) Successful in 2m52s
CI / Coding Standards (pull_request) Successful in 2m57s
A parent registers once and manages lessons for one or more children, who need no login of their own. A child is a real wp_users row with the student role but no usable login — so student_id keeps meaning "a WordPress user" on every table, and booking, credits, policies and enrolments work unchanged. A us_guardians link table maps guardian to child. The signup form gains a parent/guardian tick that reveals a block per child, with the account-signup questions asked per child rather than per guardian — they describe the student, not the account holder. Signup policies are recorded once per child with the guardian as the acceptor, which is the record that actually means something. A family that half-creates is rolled back entirely rather than leaving a guardian who cannot re-register. The booking and enrolment forms gain a "Who is this for?" picker listing children first, so the default selection is never the parent — booking for the wrong child is correctable, quietly billing a parent for their kid's lesson is not. POST /bookings and POST /enrollments take an optional student_id honoured only for that child's guardian; anything else is a 403. That check is the authorisation boundary of the feature. Payments and credits gain a payer: the charge names the child it was for and the guardian who owes it, so per-child reporting is unchanged while notices, receipts and the payment step reach the parent. Credit is held by the payer, so one child's cancellation can settle a sibling's charge, and the daily billing scan sends a guardian one notice covering every child. Closes #132 Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -388,6 +388,108 @@
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* "Who is this for?" picker — booking and enrolment. Present only on an account
|
||||
* that books for more than one person, so it is styled as a normal field rather
|
||||
* than a callout.
|
||||
*/
|
||||
.us-student-picker select {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* Whose lesson a row in the upcoming panel is — only shown on a family account. */
|
||||
.us-my-lesson-who {
|
||||
font-weight: normal;
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
/* Parent/guardian signup: the child blocks revealed by the checkbox. */
|
||||
.us-guardian {
|
||||
margin: 16px 0;
|
||||
padding: 12px 14px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.us-guardian legend {
|
||||
padding: 0 6px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.us-children-intro {
|
||||
margin-top: 0;
|
||||
font-size: 0.9em;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/*
|
||||
* Each child is a bordered group so a family of three does not read as one long
|
||||
* undifferentiated column of fields.
|
||||
*/
|
||||
.us-child {
|
||||
margin-bottom: 12px;
|
||||
padding: 10px 12px;
|
||||
border-left: 3px solid #ddd;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.us-child > p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* The guardian's manage-children screen ([us_family]). */
|
||||
.us-family-list {
|
||||
margin: 0 0 20px;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.us-family-child {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px 12px;
|
||||
align-items: baseline;
|
||||
padding: 10px 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.us-family-child-name {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.us-family-child-dob {
|
||||
font-size: 0.9em;
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
/*
|
||||
* The actions sit at the far end of the row. Remove is its own form (it posts),
|
||||
* so it is forced inline rather than taking a block of its own.
|
||||
*/
|
||||
.us-family-child-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: baseline;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.us-family-remove {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/* The editing row replaces the child's line, so it spans the whole width. */
|
||||
.us-family-edit {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
/* A name, a date and two actions do not fit one narrow line. */
|
||||
.us-family-child-actions {
|
||||
margin-left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* Shown only in block-editor previews (see BlockPreview). */
|
||||
.us-editor-note {
|
||||
font-size: 0.85em;
|
||||
|
||||
Reference in New Issue
Block a user