Files
unsupervised-scheduler/templates/admin/availability.php
T
Kydoimosandanthropic/claude-opus-4-8 12765d8f13
CI / Coding Standards (pull_request) Successful in 27s
CI / Tests (PHP 8.1) (pull_request) Successful in 37s
CI / No Debug Code (pull_request) Successful in 9s
CI / Tests (PHP 8.3) (pull_request) Successful in 36s
CI / Tests (PHP 8.5) (pull_request) Successful in 40s
CI / Tests (PHP 8.2) (pull_request) Successful in 42s
CI / Static Analysis (pull_request) Successful in 48s
CI / Build Plugin Zip (pull_request) Skipped
Notify instructors on new bookings and enrolments
Add an opt-in, per-instructor email notice sent when someone books one of
their lessons or enrols in one of their group classes. Off by default and
set from My Availability → Notifications; covers both the student/guardian
REST flows and the studio's wp-admin "book/add for a student" forms.

The opt-in check lives in InstructorNotificationMailer so no booking path
can drift on who is mailed; lessons fire from LessonBooker::settle (the one
step both booking paths reach), enrolments from EnrollmentEndpoint::enroll
and GroupClassController::addDirect. The notice is a courtesy and never
fails a booking or enrolment that otherwise succeeded.

Co-authored-by: anthropic/claude-opus-4-8
2026-09-18 16:18:43 -03:00

232 lines
12 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
if (! defined('ABSPATH')) {
exit;
}
/**
* @var list<\Unsupervised\Schedular\Availability\AvailabilitySlot> $slots
* @var list<\Unsupervised\Schedular\Offering\Offering> $offeringChoices
* @var 'list'|'week' $view
* @var string $weekStart
* @var list<array{date: string, slots: list<\Unsupervised\Schedular\Availability\AvailabilitySlot>}> $weekDays
* @var string $prevWeek
* @var string $nextWeek
* @var string $notice Success message from the submitted action; empty when none.
* @var string $error Failure message from the submitted action; empty when none.
* @var bool $notifyOnBooking Whether the instructor is emailed on new bookings/enrolments.
*/
use Unsupervised\Schedular\Availability\AvailabilitySlot;
$baseUrl = admin_url('admin.php?page=us-availability');
$deleteForm = static function (\Unsupervised\Schedular\Availability\AvailabilitySlot $slot): void {
?>
<form method="post" style="display:inline;">
<?php wp_nonce_field('usc_availability_action'); ?>
<input type="hidden" name="usc_action" value="delete">
<input type="hidden" name="slot_id" value="<?php echo esc_attr((string) $slot->id); ?>">
<button type="submit" class="button button-small button-link-delete">
<?php esc_html_e('Delete', 'unsupervised-schedular'); ?>
</button>
</form>
<?php
};
?>
<div class="wrap">
<h1><?php esc_html_e('My Availability', 'unsupervised-schedular'); ?></h1>
<?php if ('' !== $notice) : ?>
<div class="notice notice-success is-dismissible"><p><?php echo esc_html($notice); ?></p></div>
<?php endif; ?>
<?php if ('' !== $error) : ?>
<div class="notice notice-error is-dismissible"><p><?php echo esc_html($error); ?></p></div>
<?php endif; ?>
<h2><?php esc_html_e('Notifications', 'unsupervised-schedular'); ?></h2>
<form method="post">
<?php wp_nonce_field('usc_availability_action'); ?>
<input type="hidden" name="usc_action" value="save_notify">
<table class="form-table">
<tr>
<th scope="row"><?php esc_html_e('Booking emails', 'unsupervised-schedular'); ?></th>
<td>
<label>
<input type="checkbox" name="notify_on_booking" value="1" <?php checked($notifyOnBooking); ?>>
<?php esc_html_e('Email me when someone books a lesson or enrols in one of my group classes', 'unsupervised-schedular'); ?>
</label>
<p class="description"><?php esc_html_e('Off by default. Covers both your private lessons and your group classes, whether the student booked themselves or the studio booked for them.', 'unsupervised-schedular'); ?></p>
</td>
</tr>
</table>
<?php submit_button(esc_html__('Save Notification Preference', 'unsupervised-schedular')); ?>
</form>
<h2><?php esc_html_e('Add Availability', 'unsupervised-schedular'); ?></h2>
<p><?php esc_html_e('The window must start and end on the same day. It is split into bookable slots of the chosen lesson length — for example, 9:00 AM4:00 PM with 60-minute lessons creates seven slots.', 'unsupervised-schedular'); ?></p>
<form method="post" id="usc-add-availability">
<?php wp_nonce_field('usc_availability_action'); ?>
<input type="hidden" name="usc_action" value="add">
<table class="form-table">
<tr>
<th><label for="start_dt"><?php esc_html_e('Start', 'unsupervised-schedular'); ?></label></th>
<td><input type="datetime-local" name="start_dt" id="start_dt" required></td>
</tr>
<tr>
<th><label for="end_dt"><?php esc_html_e('End', 'unsupervised-schedular'); ?></label></th>
<td><input type="datetime-local" name="end_dt" id="end_dt" required></td>
</tr>
<tr>
<th><label for="duration_minutes"><?php esc_html_e('Lesson length (minutes)', 'unsupervised-schedular'); ?></label></th>
<td>
<select name="duration_minutes" id="duration_minutes">
<?php foreach (AvailabilitySlot::DURATION_CHOICES as $choice) : ?>
<option value="<?php echo esc_attr((string) $choice); ?>" <?php selected($choice, AvailabilitySlot::DEFAULT_DURATION_MINUTES); ?>>
<?php echo esc_html((string) $choice); ?>
</option>
<?php endforeach; ?>
</select>
<?php
// Filled and revealed by availability-admin.js when the entered
// window is too short for every lesson length. The wording lives
// here so it stays translatable.
?>
<p class="description usc-duration-warning" id="usc-duration-warning" hidden>
<?php esc_html_e('This window is too short for any lesson length. Lengthen the window or it cannot be saved.', 'unsupervised-schedular'); ?>
</p>
</td>
</tr>
<tr>
<th><label for="offering_id"><?php esc_html_e('Offering', 'unsupervised-schedular'); ?></label></th>
<td>
<select name="offering_id" id="offering_id">
<option value="0"><?php esc_html_e('— Any private lesson —', 'unsupervised-schedular'); ?></option>
<?php foreach ($offeringChoices as $offering) : ?>
<option value="<?php echo esc_attr((string) $offering->id); ?>"><?php echo esc_html($offering->title); ?></option>
<?php endforeach; ?>
</select>
</td>
</tr>
<tr>
<th><?php esc_html_e('Repeat', 'unsupervised-schedular'); ?></th>
<td>
<label><input type="radio" name="recurrence" value="single" checked> <?php esc_html_e('One-off', 'unsupervised-schedular'); ?></label>
&nbsp;
<label><input type="radio" name="recurrence" value="weekly"> <?php esc_html_e('Weekly for', 'unsupervised-schedular'); ?></label>
<input type="number" name="weeks" min="1" max="<?php echo esc_attr((string) AvailabilitySlot::MAX_WEEKLY_OCCURRENCES); ?>" value="12" style="width:5em;"> <?php esc_html_e('weeks', 'unsupervised-schedular'); ?>
</td>
</tr>
</table>
<?php submit_button(esc_html__('Add Availability', 'unsupervised-schedular')); ?>
</form>
<h2><?php esc_html_e('Current Slots', 'unsupervised-schedular'); ?></h2>
<ul class="subsubsub" style="margin-bottom:12px;">
<li>
<a href="<?php echo esc_url($baseUrl); ?>" <?php echo 'week' === $view ? 'class="current"' : ''; ?>><?php esc_html_e('Week', 'unsupervised-schedular'); ?></a> |
</li>
<li>
<a href="<?php echo esc_url(add_query_arg('usc_view', 'list', $baseUrl)); ?>" <?php echo 'list' === $view ? 'class="current"' : ''; ?>><?php esc_html_e('List', 'unsupervised-schedular'); ?></a>
</li>
</ul>
<div class="clear"></div>
<?php if ('week' === $view) : ?>
<p>
<a class="button" href="<?php echo esc_url(add_query_arg('usc_week', $prevWeek, $baseUrl)); ?>">&lsaquo; <?php esc_html_e('Previous week', 'unsupervised-schedular'); ?></a>
<strong style="margin:0 12px;">
<?php
/* translators: %s: date of the first day of the displayed week */
echo esc_html(sprintf(__('Week of %s', 'unsupervised-schedular'), (string) mysql2date('M j, Y', $weekStart)));
?>
</strong>
<a class="button" href="<?php echo esc_url(add_query_arg('usc_week', $nextWeek, $baseUrl)); ?>"><?php esc_html_e('Next week', 'unsupervised-schedular'); ?> &rsaquo;</a>
</p>
<table class="wp-list-table widefat fixed">
<thead>
<tr>
<?php foreach ($weekDays as $day) : ?>
<th><?php echo esc_html((string) mysql2date('D M j', $day['date'])); ?></th>
<?php endforeach; ?>
</tr>
</thead>
<tbody>
<tr>
<?php foreach ($weekDays as $day) : ?>
<td style="vertical-align:top;">
<?php if (empty($day['slots'])) : ?>
<span aria-hidden="true">—</span>
<?php endif; ?>
<?php foreach ($day['slots'] as $slot) : ?>
<p style="margin:0 0 8px;">
<?php echo esc_html((string) mysql2date('g:i A', $slot->startDt) . '' . (string) mysql2date('g:i A', $slot->endDt)); ?><br>
<?php if ($slot->isBooked) : ?>
<em><?php esc_html_e('Booked', 'unsupervised-schedular'); ?></em>
<?php else : ?>
<?php $deleteForm($slot); ?>
<?php endif; ?>
</p>
<?php endforeach; ?>
</td>
<?php endforeach; ?>
</tr>
</tbody>
</table>
<?php elseif (empty($slots)) : ?>
<p><?php esc_html_e('No availability slots configured.', 'unsupervised-schedular'); ?></p>
<?php else : ?>
<?php
// Bulk-delete form. The row checkboxes live inside the table and are
// associated via the HTML form attribute, because the table also
// contains the per-row delete forms and forms cannot nest.
?>
<form method="post" id="usc-bulk-delete-form" onsubmit="return confirm('<?php echo esc_js(__('Delete the selected slots?', 'unsupervised-schedular')); ?>');">
<?php wp_nonce_field('usc_availability_action'); ?>
<input type="hidden" name="usc_action" value="bulk_delete">
</form>
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<td class="manage-column column-cb check-column">
<input type="checkbox" id="cb-select-all-1">
<label for="cb-select-all-1"><span class="screen-reader-text"><?php esc_html_e('Select all', 'unsupervised-schedular'); ?></span></label>
</td>
<th><?php esc_html_e('Start', 'unsupervised-schedular'); ?></th>
<th><?php esc_html_e('End', 'unsupervised-schedular'); ?></th>
<th><?php esc_html_e('Length', 'unsupervised-schedular'); ?></th>
<th><?php esc_html_e('Status', 'unsupervised-schedular'); ?></th>
<th><?php esc_html_e('Actions', 'unsupervised-schedular'); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($slots as $slot) : ?>
<tr>
<th scope="row" class="check-column">
<?php if (! $slot->isBooked) : ?>
<input type="checkbox" name="slot_ids[]" form="usc-bulk-delete-form" value="<?php echo esc_attr((string) $slot->id); ?>">
<?php endif; ?>
</th>
<td><?php echo esc_html((string) mysql2date('M j, Y g:i A', $slot->startDt)); ?></td>
<td><?php echo esc_html((string) mysql2date('M j, Y g:i A', $slot->endDt)); ?></td>
<td><?php echo esc_html((string) $slot->durationMinutes . ' min'); ?></td>
<td><?php echo $slot->isBooked ? esc_html__('Booked', 'unsupervised-schedular') : esc_html__('Available', 'unsupervised-schedular'); ?></td>
<td>
<?php if (! $slot->isBooked) : ?>
<?php $deleteForm($slot); ?>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<p>
<button type="submit" class="button" form="usc-bulk-delete-form">
<?php esc_html_e('Delete selected', 'unsupervised-schedular'); ?>
</button>
</p>
<?php endif; ?>
</div>