/* global wp */ (function () { 'use strict'; const { registerBlockType } = wp.blocks; const { createElement: el, useState, useEffect } = wp.element; const { useBlockProps, InspectorControls } = wp.blockEditor; const { PanelBody, SelectControl, ToggleControl, TextareaControl } = wp.components; const { useSelect } = wp.data; const apiFetch = wp.apiFetch; const ServerSideRender = wp.serverSideRender; const { __ } = wp.i18n; /** * Dropdown of published pages with a leading "default" choice. * Values are page IDs; 0 means the default behaviour. */ function PageSelect(props) { const pages = useSelect( (select) => select('core').getEntityRecords('postType', 'page', { per_page: -1, orderby: 'title', order: 'asc', status: 'publish', _fields: 'id,title', }), [] ); const options = [{ label: props.defaultLabel, value: '0' }].concat( (pages || []).map((page) => ({ label: (page.title && page.title.rendered) || __('(no title)', 'unsupervised-schedular'), value: String(page.id), })) ); return el(SelectControl, { label: props.label, help: props.help, value: String(props.value || 0), options: options, onChange: (value) => props.onChange(parseInt(value, 10) || 0), }); } /** * Dropdown of active group classes fetched from the plugin's public * offerings endpoint. Values are offering IDs; 0 means all classes. */ function GroupClassSelect(props) { const [offerings, setOfferings] = useState(null); useEffect(() => { apiFetch({ path: '/us-scheduler/v1/offerings?kind=group_class' }) .then(setOfferings) .catch(() => setOfferings([])); }, []); const options = [{ label: __('All classes', 'unsupervised-schedular'), value: '0' }].concat( (offerings || []).map((o) => ({ label: o.title || __('(no title)', 'unsupervised-schedular'), value: String(o.id), })) ); // A previously chosen class that is no longer offered (deleted or // deactivated) keeps its stored id visible instead of silently // pretending "All classes" is selected. const value = String(props.value || 0); if (offerings !== null && !options.some((opt) => opt.value === value)) { options.push({ label: __('Unavailable class #', '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', title: __('Lesson Booking', 'unsupervised-schedular'), description: __('Lets students browse availability and book lessons. Shows a styled preview in the editor.', 'unsupervised-schedular'), icon: 'calendar-alt', keywords: ['booking', 'lesson', 'schedule'], shortcode: 'us_booking', attributes: { loginPageId: { type: 'number', default: 0 }, autoRedirect: { type: 'boolean', default: false }, }, 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 }), }) ), }, { name: 'us-scheduler/student-login', title: __('Student Login', 'unsupervised-schedular'), description: __('The front-end login form for students.', 'unsupervised-schedular'), icon: 'admin-users', keywords: ['login', 'student', 'sign in'], shortcode: 'us_student_login', attributes: { bookingPageId: { type: 'number', default: 0 }, autoRedirect: { type: 'boolean', default: false }, }, inspector: (attributes, setAttributes) => el( PanelBody, { title: __('Logged-in visitors', 'unsupervised-schedular') }, el(PageSelect, { label: __('Booking page', 'unsupervised-schedular'), help: __('Where students are sent after logging in, and where the link shown to already-logged-in visitors points.', 'unsupervised-schedular'), defaultLabel: __('This page', 'unsupervised-schedular'), value: attributes.bookingPageId, onChange: (bookingPageId) => setAttributes({ bookingPageId }), }), el(ToggleControl, { label: __('Redirect automatically', 'unsupervised-schedular'), help: __('Send logged-in visitors straight to the booking page instead of showing a link. Requires a booking page to be chosen.', 'unsupervised-schedular'), checked: !!attributes.autoRedirect, onChange: (autoRedirect) => setAttributes({ autoRedirect }), }) ), }, { name: 'us-scheduler/student-register', title: __('Student Registration', 'unsupervised-schedular'), description: __('The invite-only student registration form.', 'unsupervised-schedular'), icon: 'welcome-add-page', keywords: ['register', 'student', 'invite'], shortcode: 'us_student_register', attributes: { loginPageId: { type: 'number', default: 0 }, inviteOnlyMessage: { type: 'string', default: '' }, }, inspector: (attributes, setAttributes) => [ el( PanelBody, { title: __('After email confirmation', 'unsupervised-schedular'), key: 'confirmation' }, el(PageSelect, { label: __('Sign-in page', 'unsupervised-schedular'), help: __('Where the sign-in link shown after a student confirms their email address sends them.', 'unsupervised-schedular'), defaultLabel: __('WordPress login screen', 'unsupervised-schedular'), value: attributes.loginPageId, onChange: (loginPageId) => setAttributes({ loginPageId }), }) ), el( PanelBody, { title: __('Invitation-only notice', 'unsupervised-schedular'), key: 'invite-only' }, el(TextareaControl, { label: __('Message', 'unsupervised-schedular'), help: __('Shown when registration is invite-only and the visitor has no valid invite link. Leave blank to use the default wording.', 'unsupervised-schedular'), value: attributes.inviteOnlyMessage, onChange: (inviteOnlyMessage) => setAttributes({ inviteOnlyMessage }), }) ), ], }, { name: 'us-scheduler/group-classes', title: __('Group Classes', 'unsupervised-schedular'), description: __('Lets students browse and enrol in group classes. Shows a styled preview in the editor.', 'unsupervised-schedular'), icon: 'groups', keywords: ['group', 'class', 'enrol'], shortcode: 'us_group_classes', attributes: { offeringId: { type: 'number', default: 0 }, }, inspector: (attributes, setAttributes) => el( PanelBody, { title: __('Classes shown', 'unsupervised-schedular') }, el(GroupClassSelect, { label: __('Class', 'unsupervised-schedular'), help: __('Show only one group class, for embedding on a page dedicated to it.', 'unsupervised-schedular'), value: attributes.offeringId, onChange: (offeringId) => setAttributes({ offeringId }), }) ), }, ]; blocks.forEach((def) => { registerBlockType(def.name, { apiVersion: 3, title: def.title, description: def.description, icon: def.icon, category: 'widgets', keywords: def.keywords, supports: { html: false, multiple: false }, attributes: def.attributes || {}, example: {}, edit: function Edit(props) { const inspector = def.inspector ? el(InspectorControls, {}, def.inspector(props.attributes, props.setAttributes)) : null; return el( 'div', useBlockProps(), inspector, el(ServerSideRender, { block: def.name, attributes: props.attributes }) ); }, save: () => null, transforms: { from: [{ type: 'shortcode', tag: def.shortcode }], }, }); }); }());