Merge pull request 'Stop the upcoming-lessons row collapsing onto itself' (#135) from fix/upcoming-lessons-row-layout into main
CI / Tests (PHP 8.1) (push) Successful in 55s
CI / Tests (PHP 8.2) (push) Successful in 46s
CI / No Debug Code (push) Successful in 2s
CI / PHPStan (push) Successful in 2m56s
CI / Coding Standards (push) Successful in 2m59s
CI / Tests (PHP 8.3) (push) Successful in 2m46s
CI / Build Plugin Zip (push) Successful in 2m53s

Reviewed-on: #135
This commit was merged in pull request #135.
This commit is contained in:
2026-07-29 02:02:10 +00:00
4 changed files with 77 additions and 24 deletions
+57 -16
View File
@@ -34,47 +34,72 @@
margin-top: 8px;
}
.us-my-lessons {
/*
* The upcoming-lessons panel. Every rule here is scoped under #us-booking-app —
* the same id-level specificity .us-slot above uses — because these rows sit in
* whatever layout the theme provides and carry more content than a calendar
* cell. Bare class selectors lost to theme rules on div/span/strong, which
* collapsed the flex layout and piled the details on top of the actions.
*/
#us-booking-app .us-my-lessons {
margin-bottom: 24px;
}
.us-my-lesson {
#us-booking-app .us-my-lesson {
box-sizing: border-box;
max-width: 100%;
border: 1px solid #ddd;
border-radius: 4px;
padding: 12px 16px;
margin-bottom: 8px;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
gap: 12px;
gap: 8px 12px;
}
.us-my-lesson-info {
/*
* `min-width: 0` lets the title column shrink below its content width — without
* it a long offering title cannot compress and shoves the status pill and
* Cancel button out of the row. The flex-basis keeps the details and the
* actions on one line while there is room, and wraps them once there is not.
*/
#us-booking-app .us-my-lesson-info {
display: flex;
flex-direction: column;
gap: 2px;
flex: 1 1 14em;
min-width: 0;
}
.us-my-lesson-title {
#us-booking-app .us-my-lesson-title,
#us-booking-app .us-my-lesson-when {
overflow-wrap: break-word;
word-break: break-word;
}
#us-booking-app .us-my-lesson-title {
font-size: 1.05em;
}
.us-my-lesson-duration {
#us-booking-app .us-my-lesson-duration {
font-weight: normal;
color: #666;
}
.us-my-lesson-when {
#us-booking-app .us-my-lesson-when {
color: #555;
}
.us-my-lesson-actions {
#us-booking-app .us-my-lesson-actions {
display: flex;
gap: 12px;
flex-wrap: wrap;
gap: 8px 12px;
align-items: center;
}
.us-show-all-lessons {
#us-booking-app .us-show-all-lessons {
background: transparent;
border: 1px solid #ccc;
border-radius: 4px;
@@ -82,11 +107,11 @@
cursor: pointer;
}
.us-show-all-lessons:hover {
#us-booking-app .us-show-all-lessons:hover {
border-color: #888;
}
.us-cancel-lesson {
#us-booking-app .us-cancel-lesson {
background: transparent;
border: 1px solid #ccc;
border-radius: 4px;
@@ -95,24 +120,26 @@
color: #c00;
}
.us-cancel-lesson:hover {
#us-booking-app .us-cancel-lesson:hover {
border-color: #c00;
}
.us-lesson-status {
#us-booking-app .us-lesson-status {
display: inline-block;
font-size: 0.85em;
font-weight: 600;
padding: 2px 10px;
border-radius: 10px;
background: #eee;
white-space: nowrap;
}
.us-lesson-status-confirmed {
#us-booking-app .us-lesson-status-confirmed {
background: #e2f5e5;
color: #1a7d2e;
}
.us-lesson-status-pending {
#us-booking-app .us-lesson-status-pending {
background: #fdf3d7;
color: #8a6d1a;
}
@@ -345,6 +372,20 @@
.us-week-day {
min-height: 0;
}
/*
* A lesson row carries a title, a date/time, a status pill and a button —
* more than fits one narrow line, so stack the details above the actions
* rather than letting them wrap into each other.
*/
#us-booking-app .us-my-lesson {
flex-direction: column;
align-items: stretch;
}
#us-booking-app .us-my-lesson-info {
flex: 0 0 auto;
}
}
/* Shown only in block-editor previews (see BlockPreview). */
+7 -4
View File
@@ -582,16 +582,19 @@
function lessonRowHtml(l) {
const title = l.offering_title ? escHtml(String(l.offering_title)) : 'Lesson';
const duration = l.duration_minutes ? ` <span class="us-my-lesson-duration">(${escHtml(String(l.duration_minutes))} min)</span>` : '';
// The two columns are divs, not spans: as spans the layout only held up
// while the stylesheet's display:flex won, and a theme rule on span
// collapsed the row onto itself.
return `
<div class="us-my-lesson">
<span class="us-my-lesson-info">
<div class="us-my-lesson-info">
<strong class="us-my-lesson-title">${title}${duration}</strong>
<span class="us-my-lesson-when">${escHtml(dayLabel(dayKey(l.start_dt)))} · ${escHtml(timeOf(l.start_dt))}${escHtml(timeOf(l.end_dt))}</span>
</span>
<span class="us-my-lesson-actions">
</div>
<div class="us-my-lesson-actions">
<span class="us-lesson-status us-lesson-status-${escHtml(String(l.status))}">${escHtml(lessonStatusLabel(String(l.status)))}</span>
<button type="button" class="us-cancel-lesson" data-lesson-id="${l.id}">Cancel</button>
</span>
</div>
</div>`;
}
+9
View File
@@ -154,6 +154,7 @@ instructor may only open their own lessons; the studio **Scheduler** may open an
- Admin lesson detail presenter: `Unsupervised\Schedular\Booking\LessonDetail` (per-lesson intake answers + policy acceptances), template `templates/admin/lesson-detail.php`
- REST endpoint: `Unsupervised\Schedular\Booking\BookingEndpoint`
- Frontend: `Unsupervised\Schedular\Booking\BookingPage`, `Unsupervised\Schedular\Auth\LoginPage`
- Upcoming-lessons panel: rendered client-side into `#us-my-lessons` by `assets/js/booking.js` (`lessonRowHtml`/`renderMyLessons`), mirrored for the editor by `BlockPreview::upcomingLessons()` — keep the two markup shapes in step.
> **Payment seam:** a priced booking is created with `status = pending` and its
> payment linked via `payment_id`; the lesson is confirmed when the payment is
@@ -161,6 +162,14 @@ instructor may only open their own lessons; the studio **Scheduler** may open an
> Unpriced bookings skip the seam entirely and are confirmed at creation.
> `GET /policies?scope=booking` returns just the booking-gate policies the form
> must collect.
>
> **Frontend CSS scoping:** every rule for the booking page's own markup is
> written under `#us-booking-app` (`assets/css/frontend.css`). These panels sit
> inside whatever layout the active theme provides, and bare class selectors lose
> to theme rules on `div`/`span`/`strong` — which flattens the flex layout and
> renders the lesson details on top of the actions. The row's two columns are
> `div`s for the same reason: the layout must not depend on overriding the
> inline default. New booking-page rules should follow both conventions.
## Tests
- `tests/Unit/Booking/BookingRepositoryTest.php`
+4 -4
View File
@@ -86,13 +86,13 @@ class BlockPreview {
private static function upcomingLessons(): string {
return sprintf(
'<div class="us-my-lessons"><h3>%s</h3>'
. '<div class="us-my-lesson"><span class="us-my-lesson-info">'
. '<div class="us-my-lesson"><div class="us-my-lesson-info">'
. '<strong class="us-my-lesson-title">%s <span class="us-my-lesson-duration">(30 min)</span></strong>'
. '<span class="us-my-lesson-when">%s</span></span>'
. '<span class="us-my-lesson-actions">'
. '<span class="us-my-lesson-when">%s</span></div>'
. '<div class="us-my-lesson-actions">'
. '<span class="us-lesson-status us-lesson-status-confirmed">%s</span>'
. '<button type="button" class="us-cancel-lesson" disabled>%s</button>'
. '</span></div></div>',
. '</div></div></div>',
esc_html__( 'Your upcoming lessons', 'unsupervised-schedular' ),
esc_html__( 'Piano Lesson', 'unsupervised-schedular' ),
esc_html__( 'Monday · 4:00 PM4:30 PM', 'unsupervised-schedular' ),