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
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:
+57
-16
@@ -34,47 +34,72 @@
|
|||||||
margin-top: 8px;
|
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;
|
margin-bottom: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.us-my-lesson {
|
#us-booking-app .us-my-lesson {
|
||||||
|
box-sizing: border-box;
|
||||||
|
max-width: 100%;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 12px 16px;
|
padding: 12px 16px;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
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;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 2px;
|
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;
|
font-size: 1.05em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.us-my-lesson-duration {
|
#us-booking-app .us-my-lesson-duration {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
color: #666;
|
color: #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
.us-my-lesson-when {
|
#us-booking-app .us-my-lesson-when {
|
||||||
color: #555;
|
color: #555;
|
||||||
}
|
}
|
||||||
|
|
||||||
.us-my-lesson-actions {
|
#us-booking-app .us-my-lesson-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 12px;
|
flex-wrap: wrap;
|
||||||
|
gap: 8px 12px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.us-show-all-lessons {
|
#us-booking-app .us-show-all-lessons {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -82,11 +107,11 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.us-show-all-lessons:hover {
|
#us-booking-app .us-show-all-lessons:hover {
|
||||||
border-color: #888;
|
border-color: #888;
|
||||||
}
|
}
|
||||||
|
|
||||||
.us-cancel-lesson {
|
#us-booking-app .us-cancel-lesson {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -95,24 +120,26 @@
|
|||||||
color: #c00;
|
color: #c00;
|
||||||
}
|
}
|
||||||
|
|
||||||
.us-cancel-lesson:hover {
|
#us-booking-app .us-cancel-lesson:hover {
|
||||||
border-color: #c00;
|
border-color: #c00;
|
||||||
}
|
}
|
||||||
|
|
||||||
.us-lesson-status {
|
#us-booking-app .us-lesson-status {
|
||||||
|
display: inline-block;
|
||||||
font-size: 0.85em;
|
font-size: 0.85em;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
padding: 2px 10px;
|
padding: 2px 10px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
background: #eee;
|
background: #eee;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.us-lesson-status-confirmed {
|
#us-booking-app .us-lesson-status-confirmed {
|
||||||
background: #e2f5e5;
|
background: #e2f5e5;
|
||||||
color: #1a7d2e;
|
color: #1a7d2e;
|
||||||
}
|
}
|
||||||
|
|
||||||
.us-lesson-status-pending {
|
#us-booking-app .us-lesson-status-pending {
|
||||||
background: #fdf3d7;
|
background: #fdf3d7;
|
||||||
color: #8a6d1a;
|
color: #8a6d1a;
|
||||||
}
|
}
|
||||||
@@ -345,6 +372,20 @@
|
|||||||
.us-week-day {
|
.us-week-day {
|
||||||
min-height: 0;
|
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). */
|
/* Shown only in block-editor previews (see BlockPreview). */
|
||||||
|
|||||||
@@ -582,16 +582,19 @@
|
|||||||
function lessonRowHtml(l) {
|
function lessonRowHtml(l) {
|
||||||
const title = l.offering_title ? escHtml(String(l.offering_title)) : 'Lesson';
|
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>` : '';
|
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 `
|
return `
|
||||||
<div class="us-my-lesson">
|
<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>
|
<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 class="us-my-lesson-when">${escHtml(dayLabel(dayKey(l.start_dt)))} · ${escHtml(timeOf(l.start_dt))}–${escHtml(timeOf(l.end_dt))}</span>
|
||||||
</span>
|
</div>
|
||||||
<span class="us-my-lesson-actions">
|
<div class="us-my-lesson-actions">
|
||||||
<span class="us-lesson-status us-lesson-status-${escHtml(String(l.status))}">${escHtml(lessonStatusLabel(String(l.status)))}</span>
|
<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>
|
<button type="button" class="us-cancel-lesson" data-lesson-id="${l.id}">Cancel</button>
|
||||||
</span>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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`
|
- 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`
|
- REST endpoint: `Unsupervised\Schedular\Booking\BookingEndpoint`
|
||||||
- Frontend: `Unsupervised\Schedular\Booking\BookingPage`, `Unsupervised\Schedular\Auth\LoginPage`
|
- 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 seam:** a priced booking is created with `status = pending` and its
|
||||||
> payment linked via `payment_id`; the lesson is confirmed when the payment is
|
> 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.
|
> Unpriced bookings skip the seam entirely and are confirmed at creation.
|
||||||
> `GET /policies?scope=booking` returns just the booking-gate policies the form
|
> `GET /policies?scope=booking` returns just the booking-gate policies the form
|
||||||
> must collect.
|
> 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
|
||||||
- `tests/Unit/Booking/BookingRepositoryTest.php`
|
- `tests/Unit/Booking/BookingRepositoryTest.php`
|
||||||
|
|||||||
@@ -86,13 +86,13 @@ class BlockPreview {
|
|||||||
private static function upcomingLessons(): string {
|
private static function upcomingLessons(): string {
|
||||||
return sprintf(
|
return sprintf(
|
||||||
'<div class="us-my-lessons"><h3>%s</h3>'
|
'<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>'
|
. '<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-when">%s</span></div>'
|
||||||
. '<span class="us-my-lesson-actions">'
|
. '<div class="us-my-lesson-actions">'
|
||||||
. '<span class="us-lesson-status us-lesson-status-confirmed">%s</span>'
|
. '<span class="us-lesson-status us-lesson-status-confirmed">%s</span>'
|
||||||
. '<button type="button" class="us-cancel-lesson" disabled>%s</button>'
|
. '<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__( 'Your upcoming lessons', 'unsupervised-schedular' ),
|
||||||
esc_html__( 'Piano Lesson', 'unsupervised-schedular' ),
|
esc_html__( 'Piano Lesson', 'unsupervised-schedular' ),
|
||||||
esc_html__( 'Monday · 4:00 PM–4:30 PM', 'unsupervised-schedular' ),
|
esc_html__( 'Monday · 4:00 PM–4:30 PM', 'unsupervised-schedular' ),
|
||||||
|
|||||||
Reference in New Issue
Block a user