Add per-embed lesson-type and section options to the booking block
CI / Tests (PHP 8.1) (pull_request) Successful in 47s
CI / Tests (PHP 8.2) (pull_request) Successful in 54s
CI / No Debug Code (pull_request) Successful in 2s
CI / PHPStan (pull_request) Successful in 2m51s
CI / Coding Standards (pull_request) Successful in 2m56s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m42s
CI / Build Plugin Zip (pull_request) Skipped
CI / Tests (PHP 8.1) (pull_request) Successful in 47s
CI / Tests (PHP 8.2) (pull_request) Successful in 54s
CI / No Debug Code (pull_request) Successful in 2s
CI / PHPStan (pull_request) Successful in 2m51s
CI / Coding Standards (pull_request) Successful in 2m56s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m42s
CI / Build Plugin Zip (pull_request) Skipped
Three sidebar options on the Lesson Booking block, all mirrored as shortcode attributes and carried to the front end as data attributes on #us-booking-app (or as omitted containers): - Lesson type (lessonTypeId / lesson_type) pins the calendar to a single private-lesson type: only the times bookable as it are listed, and it is the only type bookable there, auto-selected on the registration form. A pinned type that is no longer offered says so instead of showing an empty calendar. - Show the lesson-type filter (showTypeFilter / show_filter) drops the "Show Only" control for studios that do not want it. - Sections (displayMode / show) embeds one half of the page — the booking calendar or the student's upcoming lessons — so the two can live on different pages. The script skips the work belonging to a missing half: no availability or catalog request for an upcoming-only embed, no bookings request for a booking-only one. An unrecognised value renders the whole page. The editor preview follows the same setting. Also fixes the expanded filter's first lesson type sharing a line with the "Lesson type" heading — the choices now sit in their own row beneath it. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
+94
-17
@@ -83,6 +83,47 @@
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Dropdown of active private-lesson types fetched from the plugin's public
|
||||
* offerings endpoint. Values are offering IDs; 0 means every type.
|
||||
*/
|
||||
function LessonTypeSelect(props) {
|
||||
const [offerings, setOfferings] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
apiFetch({ path: '/us-scheduler/v1/offerings?kind=private_lesson' })
|
||||
.then(setOfferings)
|
||||
.catch(() => setOfferings([]));
|
||||
}, []);
|
||||
|
||||
const options = [{ label: __('All lesson types', 'unsupervised-schedular'), value: '0' }].concat(
|
||||
(offerings || []).map((o) => ({
|
||||
label: o.duration_minutes
|
||||
? `${o.title} (${o.duration_minutes} min)`
|
||||
: (o.title || __('(no title)', 'unsupervised-schedular')),
|
||||
value: String(o.id),
|
||||
}))
|
||||
);
|
||||
|
||||
// A previously chosen type that is no longer offered keeps its stored
|
||||
// id visible instead of silently pretending "All lesson types" is set.
|
||||
const value = String(props.value || 0);
|
||||
if (offerings !== null && !options.some((opt) => opt.value === value)) {
|
||||
options.push({
|
||||
label: __('Unavailable lesson type #', 'unsupervised-schedular') + value,
|
||||
value: value,
|
||||
});
|
||||
}
|
||||
|
||||
return el(SelectControl, {
|
||||
label: props.label,
|
||||
help: props.help,
|
||||
value: value,
|
||||
options: options,
|
||||
onChange: (newValue) => props.onChange(parseInt(newValue, 10) || 0),
|
||||
});
|
||||
}
|
||||
|
||||
const blocks = [
|
||||
{
|
||||
name: 'us-scheduler/booking',
|
||||
@@ -94,24 +135,60 @@
|
||||
attributes: {
|
||||
loginPageId: { type: 'number', default: 0 },
|
||||
autoRedirect: { type: 'boolean', default: false },
|
||||
lessonTypeId: { type: 'number', default: 0 },
|
||||
showTypeFilter: { type: 'boolean', default: true },
|
||||
displayMode: { type: 'string', default: 'both' },
|
||||
},
|
||||
inspector: (attributes, setAttributes) => el(
|
||||
PanelBody,
|
||||
{ title: __('Logged-out visitors', 'unsupervised-schedular') },
|
||||
el(PageSelect, {
|
||||
label: __('Login page', 'unsupervised-schedular'),
|
||||
help: __('Where the log-in link sends visitors who are not logged in.', 'unsupervised-schedular'),
|
||||
defaultLabel: __('WordPress login screen', 'unsupervised-schedular'),
|
||||
value: attributes.loginPageId,
|
||||
onChange: (loginPageId) => setAttributes({ loginPageId }),
|
||||
}),
|
||||
el(ToggleControl, {
|
||||
label: __('Redirect automatically', 'unsupervised-schedular'),
|
||||
help: __('Send logged-out visitors straight to the login page instead of showing a link.', 'unsupervised-schedular'),
|
||||
checked: !!attributes.autoRedirect,
|
||||
onChange: (autoRedirect) => setAttributes({ autoRedirect }),
|
||||
})
|
||||
),
|
||||
inspector: (attributes, setAttributes) => [
|
||||
el(
|
||||
PanelBody,
|
||||
{ title: __('What to show', 'unsupervised-schedular'), key: 'display' },
|
||||
el(SelectControl, {
|
||||
label: __('Sections', 'unsupervised-schedular'),
|
||||
help: __('Split the page in two: a booking calendar here, the student’s upcoming lessons somewhere else.', 'unsupervised-schedular'),
|
||||
value: attributes.displayMode || 'both',
|
||||
options: [
|
||||
{ label: __('Booking and upcoming lessons', 'unsupervised-schedular'), value: 'both' },
|
||||
{ label: __('Booking only', 'unsupervised-schedular'), value: 'booking' },
|
||||
{ label: __('Upcoming lessons only', 'unsupervised-schedular'), value: 'upcoming' },
|
||||
],
|
||||
onChange: (displayMode) => setAttributes({ displayMode }),
|
||||
})
|
||||
),
|
||||
el(
|
||||
PanelBody,
|
||||
{ title: __('Lesson types', 'unsupervised-schedular'), key: 'lesson-types' },
|
||||
el(LessonTypeSelect, {
|
||||
label: __('Lesson type', 'unsupervised-schedular'),
|
||||
help: __('Show only the times bookable as one lesson type, for embedding on a page dedicated to it. That type is then the only one students can book here.', 'unsupervised-schedular'),
|
||||
value: attributes.lessonTypeId,
|
||||
onChange: (lessonTypeId) => setAttributes({ lessonTypeId }),
|
||||
}),
|
||||
el(ToggleControl, {
|
||||
label: __('Show the lesson-type filter', 'unsupervised-schedular'),
|
||||
help: __('Offer students the “Show Only” button that narrows the calendar to chosen lesson types. Not used when a single lesson type is set above.', 'unsupervised-schedular'),
|
||||
checked: attributes.showTypeFilter !== false,
|
||||
onChange: (showTypeFilter) => setAttributes({ showTypeFilter }),
|
||||
})
|
||||
),
|
||||
el(
|
||||
PanelBody,
|
||||
{ title: __('Logged-out visitors', 'unsupervised-schedular'), key: 'logged-out' },
|
||||
el(PageSelect, {
|
||||
label: __('Login page', 'unsupervised-schedular'),
|
||||
help: __('Where the log-in link sends visitors who are not logged in.', 'unsupervised-schedular'),
|
||||
defaultLabel: __('WordPress login screen', 'unsupervised-schedular'),
|
||||
value: attributes.loginPageId,
|
||||
onChange: (loginPageId) => setAttributes({ loginPageId }),
|
||||
}),
|
||||
el(ToggleControl, {
|
||||
label: __('Redirect automatically', 'unsupervised-schedular'),
|
||||
help: __('Send logged-out visitors straight to the login page instead of showing a link.', 'unsupervised-schedular'),
|
||||
checked: !!attributes.autoRedirect,
|
||||
onChange: (autoRedirect) => setAttributes({ autoRedirect }),
|
||||
})
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'us-scheduler/student-login',
|
||||
|
||||
Reference in New Issue
Block a user