CI / Tests (PHP 8.1) (pull_request) Successful in 45s
CI / No Debug Code (pull_request) Successful in 2s
CI / Tests (PHP 8.2) (pull_request) Successful in 55s
CI / PHPStan (pull_request) Successful in 2m57s
CI / Coding Standards (pull_request) Successful in 3m3s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m42s
CI / Build Plugin Zip (pull_request) Skipped
The Profile block is headed "Your profile", but the one person on it you could not change was yourself: your name, your birth year, and whether you take lessons yourself were fixed at whatever signup recorded, and correcting any of them meant asking a studio admin. A "Your details" section now opens the page, saved through the same nonce-checked template_redirect post/redirect/get path the child rows use: - Your name, written to display_name and nickname together, for the reason updateChild() does — UserName reads the nickname first, and leaving it behind would put the account's email address back on every screen that names a person. - "I take lessons myself", the positive of us_guardian_only. This makes good on the claim already in bookableStudents() and the feature doc that a guardian-only account can put itself right from the profile page. - Your birth year, held to the same normaliseBirthYear() rule as every other student. The email is shown but not editable: it is the account's user_login as well as its address, so changing it stays a studio-side job. The birth-year field deliberately carries no `required` attribute. It is asked of a student only, and this page loads no JavaScript, so a browser-enforced `required` would leave a guardian who books solely for other people unable to submit the form at all; handleSelf() enforces it against the checkbox instead. Unticking the box does not clear a stored birth year — it says who books, not "forget what is on file". Closes #165 Co-Authored-By: Claude Opus 5 <[email protected]>
160 lines
9.4 KiB
PHP
160 lines
9.4 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
use Unsupervised\Schedular\Registration\QuestionField;
|
|
|
|
if (! defined('ABSPATH')) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* @var array{name: string, email: string, birth_year: string, is_student: bool} $self The account holder's own details.
|
|
* @var list<array{id: int, name: string, birth_year: string, relationship: string}> $children
|
|
* @var list<\Unsupervised\Schedular\Registration\Question> $questions Account-scope questions, asked once per child.
|
|
* @var string $error Validation error from the last submission, if any.
|
|
* @var string $notice Confirmation of a completed add/edit/remove, if any.
|
|
* @var int $editingId Child whose row is open for editing; 0 for none.
|
|
*/
|
|
?>
|
|
<div class="us-family">
|
|
<h3><?php esc_html_e('Your profile', 'unsupervised-schedular'); ?></h3>
|
|
|
|
<?php if ($notice !== '') : ?>
|
|
<p class="us-success"><?php echo esc_html($notice); ?></p>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($error !== '') : ?>
|
|
<p class="us-error" role="alert"><?php echo esc_html($error); ?></p>
|
|
<?php endif; ?>
|
|
|
|
<form method="post" action="" class="us-family-self">
|
|
<?php wp_nonce_field('us_family'); ?>
|
|
<input type="hidden" name="us_family_action" value="self">
|
|
|
|
<h4><?php esc_html_e('Your details', 'unsupervised-schedular'); ?></h4>
|
|
|
|
<?php if ($self['email'] !== '') : ?>
|
|
<?php /* Shown, not editable: the address is the account's login, and changing it is a studio-side job. */ ?>
|
|
<p class="us-family-self-email">
|
|
<?php esc_html_e('Email', 'unsupervised-schedular'); ?>
|
|
<span><?php echo esc_html($self['email']); ?></span>
|
|
</p>
|
|
<?php endif; ?>
|
|
|
|
<p>
|
|
<label for="us-own-name"><?php esc_html_e('Your name', 'unsupervised-schedular'); ?> <span class="us-required" aria-hidden="true">*</span></label>
|
|
<input type="text" name="own_name" id="us-own-name" autocomplete="name" required value="<?php echo esc_attr($self['name']); ?>">
|
|
</p>
|
|
<p>
|
|
<label>
|
|
<input type="checkbox" name="is_student" value="1"<?php checked($self['is_student']); ?>>
|
|
<?php esc_html_e('I take lessons myself', 'unsupervised-schedular'); ?>
|
|
</label>
|
|
<span class="us-field-hint"><?php esc_html_e('Leave this unticked if you only book for the students below — you will not be offered as a student yourself.', 'unsupervised-schedular'); ?></span>
|
|
</p>
|
|
<?php
|
|
/*
|
|
* Asked of a student only, so `required` is deliberately absent: the box
|
|
* above is what decides, and the browser cannot be told to enforce a
|
|
* field conditionally without JavaScript this page does not load.
|
|
* `handleSelf()` enforces it on the server either way.
|
|
*/
|
|
?>
|
|
<p>
|
|
<label for="us-own-birth-year"><?php esc_html_e('Your birth year', 'unsupervised-schedular'); ?></label>
|
|
<input type="number" name="own_birth_year" id="us-own-birth-year" value="<?php echo esc_attr($self['birth_year']); ?>" min="1900" max="<?php echo esc_attr(current_time('Y')); ?>" step="1" inputmode="numeric" autocomplete="bday-year" placeholder="<?php esc_attr_e('YYYY', 'unsupervised-schedular'); ?>" aria-describedby="us-own-birth-year-hint">
|
|
<span class="us-field-hint" id="us-own-birth-year-hint"><?php esc_html_e('Needed only if you take lessons yourself.', 'unsupervised-schedular'); ?></span>
|
|
</p>
|
|
|
|
<p>
|
|
<button type="submit"><?php esc_html_e('Save my details', 'unsupervised-schedular'); ?></button>
|
|
</p>
|
|
</form>
|
|
|
|
<h4><?php esc_html_e('Your students', 'unsupervised-schedular'); ?></h4>
|
|
|
|
<?php if (empty($children)) : ?>
|
|
<p><?php esc_html_e('You have not added any students yet. Add one below to start booking lessons for them.', 'unsupervised-schedular'); ?></p>
|
|
<?php else : ?>
|
|
<ul class="us-family-list">
|
|
<?php foreach ($children as $child) : ?>
|
|
<li class="us-family-child">
|
|
<?php if ($editingId === $child['id']) : ?>
|
|
<form method="post" action="" class="us-family-edit">
|
|
<?php wp_nonce_field('us_family'); ?>
|
|
<input type="hidden" name="us_family_action" value="edit">
|
|
<input type="hidden" name="child_id" value="<?php echo esc_attr((string) $child['id']); ?>">
|
|
<p>
|
|
<label for="us-edit-name-<?php echo esc_attr((string) $child['id']); ?>"><?php esc_html_e('Name', 'unsupervised-schedular'); ?> <span class="us-required" aria-hidden="true">*</span></label>
|
|
<input type="text" name="child_name" id="us-edit-name-<?php echo esc_attr((string) $child['id']); ?>" value="<?php echo esc_attr($child['name']); ?>" required>
|
|
</p>
|
|
<p>
|
|
<label for="us-edit-birth-year-<?php echo esc_attr((string) $child['id']); ?>"><?php esc_html_e('Birth year', 'unsupervised-schedular'); ?> <span class="us-required" aria-hidden="true">*</span></label>
|
|
<input type="number" name="child_birth_year" required id="us-edit-birth-year-<?php echo esc_attr((string) $child['id']); ?>" value="<?php echo esc_attr($child['birth_year']); ?>" min="1900" max="<?php echo esc_attr(current_time('Y')); ?>" step="1" inputmode="numeric" placeholder="<?php esc_attr_e('YYYY', 'unsupervised-schedular'); ?>">
|
|
</p>
|
|
<p>
|
|
<button type="submit"><?php esc_html_e('Save', 'unsupervised-schedular'); ?></button>
|
|
<a href="<?php echo esc_url((string) get_permalink()); ?>"><?php esc_html_e('Cancel', 'unsupervised-schedular'); ?></a>
|
|
</p>
|
|
</form>
|
|
<?php else : ?>
|
|
<span class="us-family-child-name"><?php echo esc_html($child['name']); ?></span>
|
|
<?php if ($child['birth_year'] !== '') : ?>
|
|
<span class="us-family-child-birth-year"><?php echo esc_html($child['birth_year']); ?></span>
|
|
<?php endif; ?>
|
|
<span class="us-family-child-actions">
|
|
<a href="<?php echo esc_url(add_query_arg('us_edit_child', $child['id'], (string) get_permalink())); ?>"><?php esc_html_e('Edit', 'unsupervised-schedular'); ?></a>
|
|
<form method="post" action="" class="us-family-remove">
|
|
<?php wp_nonce_field('us_family'); ?>
|
|
<input type="hidden" name="us_family_action" value="remove">
|
|
<input type="hidden" name="child_id" value="<?php echo esc_attr((string) $child['id']); ?>">
|
|
<button type="submit"><?php esc_html_e('Remove', 'unsupervised-schedular'); ?></button>
|
|
</form>
|
|
</span>
|
|
<?php endif; ?>
|
|
</li>
|
|
<?php endforeach; ?>
|
|
</ul>
|
|
<?php endif; ?>
|
|
|
|
<form method="post" action="" class="us-family-add">
|
|
<?php wp_nonce_field('us_family'); ?>
|
|
<input type="hidden" name="us_family_action" value="add">
|
|
|
|
<h4><?php esc_html_e('Add a student', 'unsupervised-schedular'); ?></h4>
|
|
<p>
|
|
<label for="us-child-name"><?php esc_html_e('Name', 'unsupervised-schedular'); ?> <span class="us-required" aria-hidden="true">*</span></label>
|
|
<input type="text" name="child_name" id="us-child-name" required>
|
|
</p>
|
|
<p>
|
|
<label for="us-child-birth-year"><?php esc_html_e('Birth year', 'unsupervised-schedular'); ?> <span class="us-required" aria-hidden="true">*</span></label>
|
|
<input type="number" name="child_birth_year" id="us-child-birth-year" required min="1900" max="<?php echo esc_attr(current_time('Y')); ?>" step="1" inputmode="numeric" placeholder="<?php esc_attr_e('YYYY', 'unsupervised-schedular'); ?>">
|
|
</p>
|
|
<p>
|
|
<label for="us-child-relationship"><?php esc_html_e('Your relationship to them', 'unsupervised-schedular'); ?></label>
|
|
<input type="text" name="child_relationship" id="us-child-relationship" placeholder="<?php esc_attr_e('Parent', 'unsupervised-schedular'); ?>">
|
|
</p>
|
|
|
|
<?php if (! empty($questions)) : ?>
|
|
<fieldset class="us-reg-questions">
|
|
<legend><?php esc_html_e('About this student', 'unsupervised-schedular'); ?></legend>
|
|
<?php foreach ($questions as $question) : ?>
|
|
<?php
|
|
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- QuestionField::render() escapes every interpolated value.
|
|
echo QuestionField::render(
|
|
$question,
|
|
'us_answers[' . (int) $question->id . ']',
|
|
'us-family-q-' . (int) $question->id,
|
|
isRequired: $question->isRequiredForChild()
|
|
);
|
|
?>
|
|
<?php endforeach; ?>
|
|
</fieldset>
|
|
<?php endif; ?>
|
|
|
|
<p>
|
|
<button type="submit"><?php esc_html_e('Add student', 'unsupervised-schedular'); ?></button>
|
|
</p>
|
|
</form>
|
|
</div>
|