CI / Tests (PHP 8.1) (pull_request) Successful in 49s
CI / Tests (PHP 8.2) (pull_request) Successful in 51s
CI / No Debug Code (pull_request) Successful in 2s
CI / Coding Standards (pull_request) Successful in 2m51s
CI / PHPStan (pull_request) Successful in 2m59s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m37s
CI / Build Plugin Zip (pull_request) Skipped
Not every open time can be booked as every private-lesson type: a slot tied to an offering takes that offering only, and a generic slot only takes types whose length fits. Students had no way to see that before clicking a time. The booking calendar now carries a lesson-type filter — a checkbox per active private-lesson type, fetched once from GET /offerings?kind=private_lesson. Ticking types narrows the calendar to the times bookable as one of them and re-anchors the week view on the earliest match. The registration form's Lesson type picker is narrowed the same way, and a lone remaining type is pre-selected with its intake questions loaded. Bookability is decided by offeringFitsSlot(), the client-side mirror of the rule POST /bookings enforces; the filter is a browsing aid and the server still validates every booking. No ticks means no filter, and the whole control is hidden when the studio offers fewer than two private-lesson types. Closes #117 Co-Authored-By: Claude Opus 5 <[email protected]>
233 lines
3.7 KiB
CSS
233 lines
3.7 KiB
CSS
.us-login-form label {
|
|
display: block;
|
|
margin-bottom: 4px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.us-login-form input[type="text"],
|
|
.us-login-form input[type="password"] {
|
|
width: 100%;
|
|
max-width: 340px;
|
|
padding: 8px;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.us-error {
|
|
color: #c00;
|
|
border-left: 4px solid #c00;
|
|
padding-left: 8px;
|
|
}
|
|
|
|
#us-booking-app .us-slot {
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
padding: 12px 16px;
|
|
margin-bottom: 8px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
#us-booking-error {
|
|
color: #c00;
|
|
margin-top: 8px;
|
|
}
|
|
|
|
.us-my-lessons {
|
|
margin-bottom: 24px;
|
|
}
|
|
|
|
.us-my-lesson {
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
padding: 12px 16px;
|
|
margin-bottom: 8px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
gap: 12px;
|
|
}
|
|
|
|
.us-my-lesson-info {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 2px;
|
|
}
|
|
|
|
.us-my-lesson-title {
|
|
font-size: 1.05em;
|
|
}
|
|
|
|
.us-my-lesson-duration {
|
|
font-weight: normal;
|
|
color: #666;
|
|
}
|
|
|
|
.us-my-lesson-when {
|
|
color: #555;
|
|
}
|
|
|
|
.us-my-lesson-actions {
|
|
display: flex;
|
|
gap: 12px;
|
|
align-items: center;
|
|
}
|
|
|
|
.us-show-all-lessons {
|
|
background: transparent;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
padding: 6px 14px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.us-show-all-lessons:hover {
|
|
border-color: #888;
|
|
}
|
|
|
|
.us-cancel-lesson {
|
|
background: transparent;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
padding: 4px 12px;
|
|
cursor: pointer;
|
|
color: #c00;
|
|
}
|
|
|
|
.us-cancel-lesson:hover {
|
|
border-color: #c00;
|
|
}
|
|
|
|
.us-lesson-status {
|
|
font-size: 0.85em;
|
|
font-weight: 600;
|
|
padding: 2px 10px;
|
|
border-radius: 10px;
|
|
background: #eee;
|
|
}
|
|
|
|
.us-lesson-status-confirmed {
|
|
background: #e2f5e5;
|
|
color: #1a7d2e;
|
|
}
|
|
|
|
.us-lesson-status-pending {
|
|
background: #fdf3d7;
|
|
color: #8a6d1a;
|
|
}
|
|
|
|
.us-type-filter {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: 8px 16px;
|
|
margin-bottom: 12px;
|
|
padding: 8px 12px;
|
|
border: 1px solid #eee;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.us-type-filter-heading {
|
|
font-weight: 600;
|
|
}
|
|
|
|
.us-type-filter-choice {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
}
|
|
|
|
.us-type-filter-clear {
|
|
margin-left: auto;
|
|
padding: 4px 12px;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
background: transparent;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.us-view-toggle {
|
|
display: flex;
|
|
gap: 8px;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.us-view-toggle button {
|
|
padding: 6px 16px;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
background: transparent;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.us-view-toggle button.us-active {
|
|
background: #333;
|
|
border-color: #333;
|
|
color: #fff;
|
|
}
|
|
|
|
.us-week-nav {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
gap: 8px;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.us-week-nav button {
|
|
padding: 6px 12px;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
background: transparent;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.us-week-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(7, 1fr);
|
|
gap: 8px;
|
|
}
|
|
|
|
.us-week-day {
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
padding: 8px;
|
|
min-height: 90px;
|
|
}
|
|
|
|
.us-week-day-heading {
|
|
margin: 0 0 8px;
|
|
font-size: 0.85em;
|
|
text-align: center;
|
|
}
|
|
|
|
.us-week-slot {
|
|
display: block;
|
|
width: 100%;
|
|
margin-bottom: 6px;
|
|
}
|
|
|
|
.us-week-empty {
|
|
display: block;
|
|
text-align: center;
|
|
opacity: 0.4;
|
|
}
|
|
|
|
@media (max-width: 640px) {
|
|
.us-week-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.us-week-day {
|
|
min-height: 0;
|
|
}
|
|
}
|
|
|
|
/* Shown only in block-editor previews (see BlockPreview). */
|
|
.us-editor-note {
|
|
font-size: 0.85em;
|
|
font-style: italic;
|
|
opacity: 0.7;
|
|
}
|