Add studio-defined account-registration questions
CI / Tests (PHP 8.2) (pull_request) Successful in 44s
CI / Tests (PHP 8.1) (pull_request) Successful in 45s
CI / No Debug Code (pull_request) Successful in 2s
CI / Coding Standards (pull_request) Successful in 2m46s
CI / PHPStan (pull_request) Successful in 2m58s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m41s
CI / Build Plugin Zip (pull_request) Skipped
CI / Tests (PHP 8.2) (pull_request) Successful in 44s
CI / Tests (PHP 8.1) (pull_request) Successful in 45s
CI / No Debug Code (pull_request) Successful in 2s
CI / Coding Standards (pull_request) Successful in 2m46s
CI / PHPStan (pull_request) Successful in 2m58s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m41s
CI / Build Plugin Zip (pull_request) Skipped
Studio admins can now define registration questions that every new student answers as a required second step during signup, with each student's answers shown under a "Registration Information" section in the admin. Extends the existing Registration domain: us_questions gains a scope column (offering | account) and a nullable offering_id, and account answers reuse us_question_answers with registration_type = 'account'. Authoring reuses the Offerings -> Questions page via an "Account signup" scope (studio-admin only). The registration form becomes two steps (progressive enhancement via assets/js/register.js; works without JS); required answers are validated before the account is created and apply to all signup paths (invite, group link, self-approval). StudentHistory::registrationInfo() powers the admin section. Bumps the plugin version to 1.1.0 so dbDelta runs the schema migration. Closes #90 Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
@@ -11,6 +11,7 @@ use Unsupervised\Schedular\Policy\PolicyRepository;
|
||||
use Unsupervised\Schedular\Policy\PolicyVersionRepository;
|
||||
use Unsupervised\Schedular\Registration\Answer;
|
||||
use Unsupervised\Schedular\Registration\AnswerRepository;
|
||||
use Unsupervised\Schedular\Registration\Question;
|
||||
use Unsupervised\Schedular\Registration\QuestionRepository;
|
||||
|
||||
/**
|
||||
@@ -51,22 +52,58 @@ class StudentHistory {
|
||||
}
|
||||
|
||||
/**
|
||||
* Every intake answer the student has submitted, newest registration first.
|
||||
* Booking/enrolment intake answers the student has submitted, newest first.
|
||||
* Account-signup answers are excluded — those are shown on their own under
|
||||
* {@see registrationInfo()}.
|
||||
*
|
||||
* @return list<array{question: string, answer: string, context: string}>
|
||||
*/
|
||||
public function intakeAnswers( int $studentId ): array {
|
||||
$bookingAnswers = array_filter(
|
||||
$this->answers->findByStudent( $studentId ),
|
||||
static fn( Answer $answer ): bool => Answer::REG_ACCOUNT !== $answer->registrationType
|
||||
);
|
||||
|
||||
return array_values(
|
||||
array_map(
|
||||
function ( Answer $answer ): array {
|
||||
$question = $this->questions->findById( $answer->questionId );
|
||||
|
||||
return [
|
||||
'question' => $question ? $question->label : sprintf( '#%d', $answer->questionId ),
|
||||
'answer' => $answer->answerValue ?? '—',
|
||||
'context' => $this->contextLabel( $answer->registrationType, $answer->registrationId ),
|
||||
];
|
||||
},
|
||||
$bookingAnswers
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The student's answers to the studio-wide account-signup questions: every
|
||||
* configured account question paired with the student's answer ("—" when
|
||||
* unanswered, e.g. a question added after they registered).
|
||||
*
|
||||
* @return list<array{question: string, answer: string, required: bool}>
|
||||
*/
|
||||
public function registrationInfo( int $studentId ): array {
|
||||
$byQuestion = [];
|
||||
foreach ( $this->answers->findByRegistration( Answer::REG_ACCOUNT, $studentId ) as $answer ) {
|
||||
$byQuestion[ $answer->questionId ] = $answer->answerValue ?? '';
|
||||
}
|
||||
|
||||
return array_map(
|
||||
function ( Answer $answer ): array {
|
||||
$question = $this->questions->findById( $answer->questionId );
|
||||
static function ( Question $question ) use ( $byQuestion ): array {
|
||||
$value = $byQuestion[ (int) $question->id ] ?? '';
|
||||
|
||||
return [
|
||||
'question' => $question ? $question->label : sprintf( '#%d', $answer->questionId ),
|
||||
'answer' => $answer->answerValue ?? '—',
|
||||
'context' => $this->contextLabel( $answer->registrationType, $answer->registrationId ),
|
||||
'question' => $question->label,
|
||||
'answer' => '' === $value ? '—' : $value,
|
||||
'required' => $question->isRequired,
|
||||
];
|
||||
},
|
||||
$this->answers->findByStudent( $studentId )
|
||||
$this->questions->findByScope( Question::SCOPE_ACCOUNT )
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user