PageSourceSearch

https://www.principals.org/wp-content/plugins/personify/pfyPageRegister/pfyPageRegister.js?ver=1786109190

js principals.org collected 2026-10-09 21:30:45 UTC 48,324 bytes, 2,056 lines download raw bytes

1new Vue({
2
3	name: 'pfy-register',
4
5	el: '#pfy-register',
6
7	data: {
8
9		// SSO
10		loggedIn:                  Portal.getData('pfySSOLoggedIn'),
11
12		// Reference
13		pfyServerURL:              Portal.getData('pfyServerURL'),
14		loginURL:                  pfyRegisterData.loginURL,
15		forgotPasswordURL:         pfyRegisterData.forgotPasswordURL,
16		accountURL:                pfyRegisterData.accountURL,
17		returnURL:                 pfyRegisterData.returnURL,
18		vendorID:                  pfyRegisterData.vendorID,
19		siteContext:               pfyRegisterData.siteContext,
20		studentRelationshipEntity: pfyRegisterData.studentRelationshipEntity,
21		studentJobFunctionCode:    pfyRegisterData.studentJobFunctionCode,
22		studentJoinLink:           pfyRegisterData.studentJoinLink,
23		programNoun:               pfyRegisterData.programNoun,
24		jobFunctions:              [],
25		relationshipTypes:         [],
26		addressTypes:              [],
27		countries:                 [],
28		states:                    [],
29		graduationYears:           [],
30		genders:				   [],
31		ethnicities: 			   [],
32
33		// Role
34		primaryRole:     null,
35		studentInducted: null,
36
37		// Email
38		emailForm: {
39			email: '',
40			emailConfirm: '',
41		},
42
43		emailSelected:    false,
44		emailAlertExists: false,
45
46		// Password
47		passwordForm: {
48			// password: pfyRegisterData.defaultPassword,
49			password: '',
50		},
51
52		// Personal information
53		personalForm: {
54			firstName: '',
55			lastName: '',
56			phone: '',
57			birthDate: '',
58			gender: null,
59			ethnicity: null,
60		},
61
62		// School
63		schoolForm: {
64			relationshipType: null,
65			jobFunction:      null,
66			graduationYear:   null,
67		},
68
69		// Address Search
70		addressSearchForm: {
71			method:      'search',
72			name:        '',
73			city:        '',
74			state:       null,
75			country:     'USA',
76			schoolID:    null,
77		},
78
79		addressSearchResults:  {},
80		addressSearchSelected: null,
81
82		// Address Manual Entry
83		addressManualForm: {
84			type:          null,
85			line1:         '',
86			line2:         '',
87			line3:         '',
88			city:          '',
89			state:         null,
90			country:       'USA',
91			zip:           '',
92			startDate:     '',
93			endDate:       '',
94			doNotValidate: false,
95		},
96
97		addressAlertUnvalidated:   false,
98		addressAlertUndeliverable: false,
99
100		consentForm: {
101			consent: false,
102		},
103
104		// API responses
105		password:           '',
106
107		// UI
108		step: 1
109
110	},
111
112	computed: {
113
114		primaryRoleIsValid() {
115			return Boolean(
116				this.primaryRole === 'employee'
117				||
118				this.primaryRole === 'student' && this.studentInducted === 'yes'
119				||
120				this.primaryRole === 'other'
121			);
122		},
123
124		isStudentProgram() {
125			return Boolean( this.siteContext !== 'nassp' );
126		},
127
128		isStudent() {
129			return Boolean( this.primaryRole && this.primaryRole === 'student' );
130		},
131
132		isEmployee() {
133			return Boolean( this.primaryRole && this.primaryRole === 'employee' );
134		},
135
136		isOther() {
137			return Boolean( this.primaryRole && this.primaryRole === 'other' );
138		},
139
140		birthDateRequiresCOPPA() {
141
142			if ( !this.personalForm.birthDate.length ) return false;
143
144			var dateNow = new Date();
145			dateNow.setHours( 0, 0, 0, 0 );
146
147			var dateBirth = new Date( this.personalForm.birthDate );
148			dateBirth.setHours( 0, 0, 0, 0 );
149
150			var diff = dateNow - dateBirth;
151			var age  = Math.floor( diff / 3.154e+10 );
152
153			return ( age < 2 );
154
155		},
156
157		phoneDigits() {
158
159			if ( this.$v.personalForm.phone.$anyError ) return false;
160
161			return this.personalForm.phone.replace( /\D/g, '');
162
163		},
164
165		phoneAreaCode() {
166
167			if ( !this.phoneDigits ) return '';
168
169			return this.phoneDigits.substr(0,3);
170
171		},
172
173		phoneBody() {
174
175			if ( !this.phoneDigits ) return '';
176
177			return this.phoneDigits.substr(3,7);
178
179		},
180
181		phoneExtension() {
182
183			if ( !this.phoneDigits ) return '';
184
185			return this.phoneDigits.substr(10);
186
187		},
188
189		phonePreview() {
190
191			if ( !this.phoneDigits ) return '';
192
193			let areaCode  = this.phoneAreaCode,
194			    body1     = this.phoneDigits.substr(3,3),
195				body2     = this.phoneDigits.substr(6,4),
196				extension = this.phoneExtension;
197
198			var phonePreview = '(' + areaCode + ') ' + body1 + '-' + body2;
199
200			if ( extension.length ) phonePreview += ' x' + extension;
201
202			return phonePreview;
203
204		},
205
206		addressSearchResultsList() {
207
208			var addressSearchResultsList = [];
209
210			var addressIDs = Object.keys( this.addressSearchResults );
211
212			for (let i = 0; i < addressIDs.length; i++) {
213				var id      = addressIDs[i];
214				var address = this.addressSearchResults[ id ];
215				addressSearchResultsList.push( address );
216			}
217
218			addressSearchResultsList = addressSearchResultsList.sort( (a,b) => {
219				return String( this.getAddressName(a) ).localeCompare( String( this.getAddressName(b) ) );
220			});
221
222			return addressSearchResultsList;
223
224		},
225
226		addressSearchHasResults() {
227
228			return ( this.addressSearchResultsList.length > 0 );
229
230		},
231
232		derivedAddressType() {
233
234			switch ( this.primaryRole ) {
235				case 'student':
236				case 'employee':
237					return 'SCHOOL';
238				case 'other':
239				default:
240					return this.addressManualForm.type;
241			}
242
243		},
244
245		employeeJobFunctionCodes() {
246
247			const whitelist = [
248				'AA',
249				'ASSTHEADMAST',
250				'ASSTHEADMIST',
251				'ASSTPR',
252				'ASSTSUPER',
253				'ASSOCPRIN',
254				'ADMIN',
255				'COUNSELOR',
256				'CURRCOOR',
257				'DEAN',
258				'DEPTHEAD',
259				'DEPSUPER',
260				'DIRECTOR',
261				'DISTST',
262				'EDUC',
263				'HEADSCHOOL',
264				'HEADMASTER',
265				'HEADMISTRESS',
266				'PRESIDENT',
267				'PRIN',
268				'PROFESSOR',
269				'SUPER',
270				'SUPERVISOR',
271				'TEACHER',
272				'VICEPRIN',
273			];
274
275			let employeeJobFunctionCodes = structuredClone( this.jobFunctions ).filter( type => {
276				return whitelist.indexOf( type.Code ) !== -1;
277			});
278
279			return employeeJobFunctionCodes;
280
281		},
282
283		otherJobFunctionCodes() {
284
285			const employeeJobFunctionCodesList = this.employeeJobFunctionCodes.map( type => type.Code );
286
287			let otherJobFunctionCodes = structuredClone( this.jobFunctions ).filter( type => {
288
289				return (
290					employeeJobFunctionCodesList.indexOf( type.Code ) === -1
291					&&
292					type.Code !== 'STUDENT'
293				);
294
295			});
296
297			return otherJobFunctionCodes;
298
299		},
300
301		availableJobFunctionCodes() {
302			switch ( this.primaryRole ) {
303				case 'employee':
304					return this.employeeJobFunctionCodes;
305				case 'other':
306					return this.otherJobFunctionCodes;
307				default:
308					return [];
309			}
310		},
311
312		derivedRelationshipType() {
313			if ( this.isStudent ) {
314				return this.studentRelationshipEntity; // FULL ENTITY
315			} else {
316				return this.schoolForm.relationshipType;
317			}
318		},
319
320		derivedJobFunctionCode() {
321			if ( this.isStudent ) {
322				return this.studentJobFunctionCode;
323			} else {
324				return this.schoolForm.jobFunction;
325			}
326		},
327
328	},
329
330	/*html*/
331	template: `<section id="pfy-register" class="pfy-register multi-step-form">
332
333		<div class="progressBar">
334			<div class="stepItemContainer">
335				<div class="stepCircleContainer">
336					<div class="stepCircle" :class="[{ active: step >= 1 }, { done: step >= 2 }]" data-id="account-info">
337						<svg width="19" height="15" viewBox="0 0 19 15" fill="none" xmlns="http://www.w3.org/2000/svg">
338							<path d="M6.14645 13.5202L6.5 13.8738L6.85355 13.5202L17.4369 2.93691L17.7904 2.58335L17.4369 2.2298L16.2702 1.06313L15.9167 0.70958L15.5631 1.06313L6.5 10.1262L3.27022 6.89647L2.91667 6.54291L2.56311 6.89647L1.39645 8.06313L1.04289 8.41669L1.39645 8.77024L6.14645 13.5202Z" fill="white" stroke="white"/>
339						</svg>
340					</div>
341					<div class="stepLabel account" :class="{ active: step === 1 }" >Account info</div>
342				</div>
343			</div>
344			<div class="stepItemContainer">
345				<div class="stepLine" :class="{ active: step >= 2 }" data-id="your-info"></div>
346				<div class="stepCircleContainer">
347					<div class="stepCircle" :class="[{ active: step >= 2 }, { done: step >= 3 }]" data-id="your-info">
348						<svg width="19" height="15" viewBox="0 0 19 15" fill="none" xmlns="http://www.w3.org/2000/svg">
349							<path d="M6.14645 13.5202L6.5 13.8738L6.85355 13.5202L17.4369 2.93691L17.7904 2.58335L17.4369 2.2298L16.2702 1.06313L15.9167 0.70958L15.5631 1.06313L6.5 10.1262L3.27022 6.89647L2.91667 6.54291L2.56311 6.89647L1.39645 8.06313L1.04289 8.41669L1.39645 8.77024L6.14645 13.5202Z" fill="white" stroke="white"/>
350						</svg>
351					</div>
352					<div class="stepLabel" :class="{ active: step === 2 }">Your Info</div>
353				</div>
354			</div>
355			<div class="stepItemContainer">
356				<div class="stepLine" :class="{ active: step >= 3 }" data-id="school-info"></div>
357				<div class="stepCircleContainer">
358					<div class="stepCircle" :class="{ active: step >= 3 }" data-id="school-info"></div>
359					<div class="stepLabel school" :class="{ active: step === 3 }">School Info</div>
360				</div>
361			</div>
362		</div>
363
364		<div class="stepContainer" v-show="step === 1">
365  
366			<h1>Create an Account</h1>
367
368			<p>Follow the instructions below to create a username and password.</p>
369
370			<p><small>Already a member looking to renew your membership? <a :href="loginURL">Click here.</a></small></p>
371
372			<h2 class="mt-5">Role</h2>
373
374			<b-row id="pfy-register-primary-role">
375
376				<b-col md="6">
377
378					<b-button
379						class="mt-1"
380						block
381						:variant="primaryRole === 'student' ? 'primary' : 'outline-primary'"
382						v-if="isStudentProgram"
383						@click.prevent="setPrimaryRole('student')">
384						Current Student
385					</b-button>
386
387					<b-button
388						class="mt-1"
389						block
390						:variant="primaryRole === 'employee' ? 'primary' : 'outline-primary'"
391						@click.prevent="setPrimaryRole('employee')">
392						Current School Leader
393					</b-button>
394
395					<b-button
396						class="mt-1"
397						block
398						:variant="primaryRole === 'other' ? 'primary' : 'outline-primary'"
399						@click.prevent="setPrimaryRole('other')">
400						Other
401					</b-button>
402
403				</b-col>
404
405			</b-row>
406
407			<p
408				class="small text-danger"
409				v-if="$v.primaryRole.$dirty && $v.primaryRole.$anyError">
410				Please choose your primary role.
411			</p>
412
413			<b-form-group
414				v-if="primaryRole === 'student'"
415				:label="'Are you a current member of your ' + programNoun + '?'"
416				label-for="pfy-register-student-inducted"
417				:state="validateField('studentInducted')"
418				class="mt-5">
419
420				<!-- RADIO_BUTTON -->
421				<b-form-radio-group
422					id="pfy-register-student-inducted"
423					v-model="$v.studentInducted.$model"
424					:state="validateField('studentInducted')"
425					size="sm">
426
427					<b-form-radio
428						value="yes">
429						Yes
430					</b-form-radio>
431
432					<b-form-radio
433						value="no">
434						No
435					</b-form-radio>
436
437				</b-form-radio-group>
438
439			</b-form-group>
440			
441			<b-modal
442				ref="modalStudentNotInducted"
443				id="pfy-register-student-not-inducted">
444
445				<p>You must be a current member of your {{ programNoun }} to continue.</p>
446
447				<template v-slot:modal-footer>
448					<b-button
449						variant="primary"
450						:href="studentJoinLink.url">
451						{{ studentJoinLink.title }}
452					</b-button>
453				</template>
454
455			</b-modal>
456
457			<b-form
458				id="pfy-register-email-form"
459				:class="getFormClass( 'pfy-register-email-form', primaryRoleIsValid )"
460				@submit.stop.prevent="submitEmail">
461
462				<h2 class="mt-5">Email</h2>
463
464				<b-row>
465
466					<b-col md="6">
467
468						<b-form-group
469							label="Email Address"
470							label-for="pfy-register-email">
471
472							<b-form-input
473								id="pfy-register-email"
474								v-model="$v.emailForm.email.$model"
475								type="email"
476								:state="validateFormField('emailForm', 'email')"
477								:disabled="emailSelected">
478							</b-form-input>
479
480							<b-form-invalid-feedback>Please enter a valid email address.</b-form-invalid-feedback>
481
482							<b-form-text v-if="!emailSelected">
483								Use a non-school email address.<br>
484							</b-form-text>
485
486						</b-form-group>
487
488					</b-col>
489
490					<b-col md="6">
491
492						<b-form-group
493							label="Confirm Email Address"
494							label-for="pfy-register-email-confirm">
495
496							<b-form-input
497								id="pfy-register-email-confirm"
498								v-model="$v.emailForm.emailConfirm.$model"
499								type="email"
500								:state="validateFormField('emailForm', 'emailConfirm')"
501								:disabled="emailSelected">
502							</b-form-input>
503
504							<b-form-invalid-feedback>The email addresses must match.</b-form-invalid-feedback>
505
506						</b-form-group>
507
508					</b-col>
509
510				</b-row>
511
512				<b-alert v-model="emailAlertExists" variant="danger" class="mt-3">
513					An account already exists with this email address. Would you like to <a :href="loginURL">log in</a> or <a :href="forgotPasswordURL">reset your password</a>?
514				</b-alert>
515
516			</b-form>
517
518			<b-form
519				id="pfy-register-password-form"
520				:class="getFormClass( 'pfy-register-password-form', primaryRoleIsValid )">
521
522				<b-row>
523
524					<b-col md="6">
525
526						<b-form-group
527							label="Password"
528							label-for="pfy-register-password"
529							class="mt-3">
530
531							<b-form-input
532								id="pfy-register-password"
533								v-model="$v.passwordForm.password.$model"
534								type="password"
535								:state="validateFormField('passwordForm', 'password')">
536							</b-form-input>
537
538							<b-form-invalid-feedback>Your password must be at least 6 characters long.</b-form-invalid-feedback>
539
540							<b-form-text v-if="!emailSelected">
541								Make sure to save your account password in a secure location.<br>
542							</b-form-text>
543
544						</b-form-group>
545
546					</b-col>
547
548				</b-row>
549
550				<div :class="getFormClass( 'progress-footer', primaryRoleIsValid )">
551					<div class="button-container">
552						<button id="next-step" type="submit" class="btn mt-1 btn-primary" @click.prevent="submitEmail">
553							Next
554						</button>
555					</div>
556				</div>
557
558			</b-form>
559
560		</div>
561
562		<div class="stepContainer" v-show="step === 2">
563
564			<b-form
565				id="pfy-register-personal-form"
566				class="pfy-register-personal-form">
567
568				<h2 class="mt-5">Tell us about yourself</h2>
569
570				<b-row>
571
572					<b-col md="6">
573
574						<!-- FIRST NAME -->
575						<b-form-group
576							label="First Name"
577							label-for="pfy-register-first-name">
578
579							<b-form-input
580								id="pfy-register-first-name"
581								v-model="$v.personalForm.firstName.$model"
582								:state="validateFormField('personalForm', 'firstName')">
583							</b-form-input>
584
585							<b-form-invalid-feedback>This field is required.</b-form-invalid-feedback>
586
587						</b-form-group>
588
589					</b-col>
590
591					<b-col md="6">
592
593						<!-- LAST NAME -->
594						<b-form-group
595							label="Last Name"
596							label-for="pfy-register-last-name">
597
598							<b-form-input
599								id="pfy-register-last-name"
600								v-model="$v.personalForm.lastName.$model"
601								:state="validateFormField('personalForm', 'lastName')">
602							</b-form-input>
603
604							<b-form-invalid-feedback>This field is required.</b-form-invalid-feedback>
605
606						</b-form-group>
607
608					</b-col>
609
610					<b-col md="6">
611
612						<!-- BIRTH DATE -->
613						<b-form-group
614							label="Date of Birth"
615							label-for="pfy-register-birthdate">
616
617							<b-form-input
618								id="pfy-register-birthdate"
619								v-model="$v.personalForm.birthDate.$model"
620								type="date"
621								:state="validateFormField('personalForm', 'birthDate')">
622							</b-form-input>
623
624							<b-form-invalid-feedback>Please enter your date of birth.</b-form-invalid-feedback>
625
626						</b-form-group>
627
628						<transition name="fade">
629						<b-alert :show="birthDateRequiresCOPPA" variant="danger" class="mt-3">
630
631							<p>Please ensure that your date of birth is correct.</p>
632
633							<!--
634							<b-button
635								class="mb-2"
636								variant="primary"
637								href="/create-an-account/coppa-parental-consent-form/"
638								target="_blank">
639								<i class="fas fa-file-pdf"></i>&nbsp;COPPA Parental Consent Form
640							</b-button>
641
642							<b-button
643								class="mb-2"
644								variant="outline-secondary"
645								href="/create-an-account/faq/"
646								target="_blank">
647								Learn more&nbsp;<i class="fas fa-angle-right"></i>
648							</b-button>
649							-->
650
651						</b-alert>
652						</transition>
653
654					</b-col>
655
656					<b-col md="6">
657
658						<!-- PHONE NUMBER -->
659						<b-form-group
660							label="Phone"
661							label-for="pfy-register-phone"
662							:class="getFormClass( 'pfy-register-phone', primaryRoleIsValid && !birthDateRequiresCOPPA )">
663
664							<b-form-input
665								id="pfy-register-phone"
666								type="tel"
667								v-model="$v.personalForm.phone.$model"
668								:state="validateFormField('personalForm', 'phone')">
669							</b-form-input>
670
671							<b-form-invalid-feedback>Please enter at least 10 digits.</b-form-invalid-feedback>
672
673							<b-form-valid-feedback>{{ phonePreview }}</b-form-valid-feedback>
674
675						</b-form-group>
676
677					</b-col>
678
679					<b-col md="6">
680
681						<!-- GENDER -->
682						<b-form-group
683							label="Gender"
684							label-for="pfy-demographics-gender">
685
686							<b-form-select
687							id="pfy-demographics-gender"
688							v-model="$v.personalForm.gender.$model"
689							:state="validateFormField('personalForm', 'gender')">
690
691								<b-form-select-option
692									v-for="gender in genders"
693									:key="gender.Code"
694									:value="gender.Code">
695									{{ gender.Description }}
696								</b-form-select-option>
697
698							</b-form-select>
699
700							<b-form-invalid-feedback>Please select an option.</b-form-invalid-feedback>
701
702						</b-form-group>
703
704					</b-col>
705
706					<b-col md="6">
707
708						<!-- ETHNICITY -->
709						<b-form-group
710							label="Ethnicity"
711							label-for="pfy-register-ethnicity">
712
713							<b-form-select
714							id="pfy-register-ethnicity"
715							v-model="$v.personalForm.ethnicity.$model"
716							:state="validateFormField('personalForm', 'ethnicity')">
717
718								<b-form-select-option
719									v-for="ethnicity in ethnicities"
720									:key="ethnicity.Code"
721									:value="ethnicity.Code">
722									{{ ethnicity.Description }}
723								</b-form-select-option>
724
725							</b-form-select>
726
727							<b-form-invalid-feedback>Please select an option.</b-form-invalid-feedback>
728
729						</b-form-group>
730
731					</b-col>
732
733				</b-row>
734
735				<div class="progress-footer">
736					
737					<div class="button-container">
738						<button id="next-step" type="submit" class="btn mt-1 btn-outline-primary" @click.prevent="unsubmitEmail">
739							Back
740						</button>
741					</div>
742					<div class="button-container">
743						<button id="next-step" type="submit" class="btn mt-1 btn-primary" @click.prevent="submitPersonal">
744							Next
745						</button>
746					</div>
747				</div>
748
749			</b-form>
750
751		</div>
752
753		<div class="stepContainer" v-show="step === 3">
754
755			<b-form
756				id="pfy-register-school-role-form"
757				:class="getFormClass( 'pfy-register-school-role-form', primaryRoleIsValid && !birthDateRequiresCOPPA && !emailAlertExists )">
758
759				<h2 class="mt-5">School</h2>
760
761				<b-row>
762
763					<b-col md="6" v-if="isEmployee">
764
765						<!-- SCHOOL ROLE -->
766						<transition name="fade">
767						<b-form-group
768							:label="'What is your role ' + ( isStudentProgram ? 'in the ' + programNoun : 'at your school' ) + '?'"
769							label-for="pfy-register-school-role">
770
771							<b-form-select
772							id="pfy-register-school-role"
773							v-model="$v.schoolForm.relationshipType.$model"
774							:state="validateFormField( 'schoolForm', 'relationshipType' )">
775
776								<b-form-select-option
777									v-for="relationshipType in relationshipTypes"
778									:key="relationshipType.RelationshipCode"
779									:value="relationshipType">
780									{{ relationshipType.RelationshipCodeDescription }}
781								</b-form-select-option>
782
783							</b-form-select>
784
785							<b-form-invalid-feedback>This field is required.</b-form-invalid-feedback>
786
787						</b-form-group>
788						</transition>
789
790					</b-col>
791
792					<b-col md="6" v-if="isEmployee || isOther">
793
794						<!-- JOB FUNCTION -->
795						<b-form-group
796							label="Job Description"
797							label-for="pfy-register-job-function"
798							:class="getFormClass( 'pfy-register-job-function', primaryRoleIsValid && !birthDateRequiresCOPPA )">
799
800							<b-form-select
801							id="pfy-register-job-function"
802							v-model="$v.schoolForm.jobFunction.$model"
803							:state="validateFormField( 'schoolForm', 'jobFunction' )">
804
805								<b-form-select-option
806									v-for="jobFunction in availableJobFunctionCodes"
807									:key="jobFunction.Code"
808									:value="jobFunction.Code">
809									{{ jobFunction.Description }}
810								</b-form-select-option>
811
812							</b-form-select>
813
814							<b-form-invalid-feedback>This field is required.</b-form-invalid-feedback>
815
816						</b-form-group>
817
818					</b-col>
819
820					<b-col md="6" v-if="isStudent">
821
822						<!-- GRADUATION YEAR -->
823						<b-form-group
824							label="Anticipated High School Graduation Year"
825							label-for="pfy-register-graduation-year">
826
827							<b-form-select
828								id="pfy-register-graduation-year"
829								v-model="$v.schoolForm.graduationYear.$model"
830								:state="validateFormField( 'schoolForm', 'graduationYear' )">
831
832								<b-form-select-option
833									v-for="graduationYear in graduationYears"
834									:key="graduationYear.Subcode"
835									:value="graduationYear.Subcode">
836									{{ graduationYear.Description }}
837								</b-form-select-option>
838
839							</b-form-select>
840
841						</b-form-group>
842
843					</b-col>
844
845				</b-row>
846
847			</b-form>
848
849			<!-- SEARCH -->
850			<transition name="fade">
851			<b-form
852				id="pfy-register-address-search-form"
853				:class="getFormClass( 'pfy-register-address-search-form', primaryRoleIsValid && !birthDateRequiresCOPPA && !emailAlertExists )"
854				v-show="isStudent || isEmployee"
855				@submit.stop.prevent="submitAddressSearch">
856
857				<h3 class="mt-5">Find your school</h3>
858
859				<!-- METHOD -->
860				<b-form-group v-if="!addressSearchSelected">
861
862					<b-form-radio-group
863						id="pfy-register-address-search-method"
864						name="pfy-register-address-search-method"
865						v-model="$v.addressSearchForm.method.$model">
866						
867						<b-form-radio
868							value="search"
869							plain>
870							<i class="fas fa-search"></i>&nbsp;Search for your school
871						</b-form-radio>
872						
873						<b-form-radio
874							value="id"
875							plain>
876							<i class="fas fa-hashtag"></i>&nbsp;Enter School ID Number
877						</b-form-radio>
878
879					</b-form-radio-group>
880
881				</b-form-group>
882
883				<!-- BY SCHOOL ID -->
884				<template v-if="addressSearchForm.method == 'id' && !addressSearchSelected">
885
886					<b-row>
887
888						<b-col md="6">
889
890							<!-- SCHOOL ID -->
891							<b-form-group
892								label="School ID Number"
893								label-for="pfy-register-address-search-school-id">
894
895								<b-form-input
896									id="pfy-register-address-search-name"
897									v-model="$v.addressSearchForm.schoolID.$model"
898									:state="validateFormField('addressSearchForm', 'schoolID')">
899								</b-form-input>
900
901								<b-form-invalid-feedback>This field is required.</b-form-invalid-feedback>
902
903							</b-form-group>
904
905						</b-col>
906
907					</b-row>
908
909				</template>
910
911				<!-- BY NAME -->
912				<template v-if="addressSearchForm.method == 'search' && !addressSearchSelected">
913
914					<b-row>
915
916						<b-col md="6">
917
918							<!-- CITY -->
919							<b-form-group
920								label="City"
921								label-for="pfy-register-address-search-city">
922
923								<b-form-input
924									id="pfy-register-address-search-city"
925									v-model="$v.addressSearchForm.city.$model">
926								</b-form-input>
927
928							</b-form-group>
929
930						</b-col>
931
932						<b-col md="6">
933
934							<!-- STATE -->
935							<b-form-group
936								label="State"
937								label-for="pfy-register-address-search-state"
938								v-if="addressSearchForm.country == 'USA'">
939
940								<b-form-select
941								id="pfy-register-address-search-state"
942								v-model="$v.addressSearchForm.state.$model"
943								:state="validateFormField( 'addressSearchForm', 'state' )">
944
945									<b-form-select-option
946										v-for="state in states"
947										:key="state.StateCode"
948										:value="state.StateCode">
949										{{ state.StateDescription }}
950									</b-form-select-option>
951
952								</b-form-select>
953
954								<b-form-invalid-feedback>This field is required.</b-form-invalid-feedback>
955
956							</b-form-group>
957
958						</b-col>
959
960						<b-col md="6">
961
962							<!-- COUNTRY -->
963							<b-form-group
964								label="Country"
965								label-for="pfy-register-address-search-country">
966
967								<b-form-select
968									id="pfy-register-address-search-country"
969									v-model="$v.addressSearchForm.country.$model"
970									:state="validateFormField( 'addressSearchForm', 'country' )">
971
972									<b-form-select-option
973										v-for="country in countries"
974										:key="country.CountryCode"
975										:value="country.CountryCode">
976										{{ country.CountryDescription }}
977									</b-form-select-option>
978
979								</b-form-select>
980
981								<b-form-invalid-feedback>This field is required.</b-form-invalid-feedback>
982
983							</b-form-group>
984
985						</b-col>
986
987					</b-row>
988
989				</template>
990
991				<b-card
992					v-if="addressSearchSelected"
993					class="my-3">
994
995					<b-card-text>
996						<b>{{ getAddressName( addressSearchSelected ) }}</b><br>
997						<span v-html="formatHTML( addressSearchSelected.Address )"></span><br>
998						<small><span class="text-muted">School ID Number: #{{ addressSearchSelected.SchoolID }}</span></small>
999					</b-card-text>
1000
1001				</b-card>
1002
1003				<b-button
1004					v-if="!addressSearchSelected"
1005					type="submit"
1006					variant="primary"
1007					@click.prevent="submitAddressSearch">
1008					Search for school
1009				</b-button>
1010
1011				<b-button
1012					v-if="addressSearchSelected"
1013					variant="outline-secondary"
1014					@click.prevent="resetSearch">
1015					Change school
1016				</b-button>
1017
1018				<b-button
1019					v-if="!addressSearchSelected"
1020					variant="outline-secondary"
1021					@click.prevent="endSearch">
1022					I can’t find my school
1023				</b-button>
1024
1025			</b-form>
1026			</transition>
1027
1028			<!-- SEARCH RESULTS -->
1029			<b-modal
1030				ref="modalAddressSearchResults"
1031				id="pfy-register-address-search-results"
1032				title="Search Results"
1033				ok-disabled
1034				cancel-disabled>
1035
1036				<b-card
1037					v-for="schoolAddress in addressSearchResultsList"
1038					:key="schoolAddress.CustomerAddressId"
1039					class="my-3">
1040
1041					<b-card-text>
1042
1043						<b-form-checkbox
1044							v-model="addressSearchSelected"
1045							:value="schoolAddress">
1046							<b>{{ getAddressName( schoolAddress ) }}</b>
1047						</b-form-checkbox>
1048
1049						<span v-html="formatHTML( schoolAddress.Address )"></span><br>
1050						<small><span class="text-muted">School ID Number: #{{ schoolAddress.SchoolID }}</span></small>
1051					</b-card-text>
1052
1053				</b-card>
1054
1055				<template v-if="!addressSearchHasResults">
1056
1057					<h3 class="text-danger">No Search Results</h3>
1058
1059					<p>Your search did not match any schools. Try searching again with different information. If you are unable to find your school, you may also continue by entering a home or business address.</p>
1060
1061				</template>
1062
1063				<template v-slot:modal-footer>
1064
1065					<b-button
1066						variant="primary"
1067						@click.prevent="resetSearch"
1068						v-if="!addressSearchHasResults">
1069						Search again
1070					</b-button>
1071
1072					<b-button
1073						variant="outline-secondary"
1074						@click="endSearch">
1075						I can’t find my school
1076					</b-button>
1077
1078				</template>
1079
1080			</b-modal>
1081
1082			<b-modal
1083				ref="modalAddressSearchUnsuccessful"
1084				id="pfy-register-address-search-unsuccessful"
1085				ok-only>
1086
1087				<p>Current student and employee accounts must be affiliated with your school. If you are unable to find your school online, please contact <a href="mailto:[email protected]">NASSP Customer Care</a> with your school information to activate your account.</p>
1088
1089			</b-modal>
1090
1091			<!-- MANUAL ADDRESS FORM -->
1092			<b-form
1093				id="pfy-register-address-manual-form"
1094				:class="getFormClass( 'pfy-register-address-manual-form', primaryRoleIsValid && !birthDateRequiresCOPPA && !emailAlertExists )"
1095				v-show="isOther">
1096
1097				<h2 class="mt-5">Address</h2>
1098
1099				<b-alert
1100					v-model="addressAlertUnvalidated"
1101					variant="danger">
1102					We could not validate the address you submitted. Please make sure the information you have entered is correct.
1103				</b-alert>
1104
1105				<b-alert
1106					v-model="addressAlertUndeliverable"
1107					variant="danger">
1108					The address you submitted is not valid. Please try another address.
1109				</b-alert>
1110
1111				<b-form-checkbox
1112					id="pfy-register-address-manual-novalidate"
1113					v-model="$v.addressManualForm.doNotValidate.$model"
1114					v-if="addressAlertUnvalidated"
1115					:value="true"
1116					:unchecked-value="false"
1117					class="mb-3">
1118					Continue without validating my address.
1119				</b-form-checkbox>
1120
1121				<b-row>
1122
1123					<b-col md="6">
1124
1125						<b-form-group
1126							label="Address Type"
1127							label-for="pfy-register-address-manual-type">
1128
1129							<b-form-select
1130							id="pfy-register-address-manual-type"
1131							v-model="$v.addressManualForm.type.$model"
1132							:state="validateFormField( 'addressManualForm', 'type' )">
1133
1134								<b-form-select-option
1135									v-for="addressType in addressTypes"
1136									v-if="addressType.Code != 'SCHOOL'"
1137									:key="addressType.Code"
1138									:value="addressType.Code">
1139									{{ addressType.Description }}
1140								</b-form-select-option>
1141
1142							</b-form-select>
1143
1144							<b-form-invalid-feedback>This field is required.</b-form-invalid-feedback>
1145
1146						</b-form-group>
1147
1148					</b-col>
1149
1150					<b-col md="6">
1151
1152						<!-- LINE 1 -->
1153						<b-form-group
1154							label="Address Line 1"
1155							label-for="pfy-register-address-manual-line1"
1156							required>
1157
1158							<b-form-input
1159								id="pfy-register-address-manual-line1"
1160								v-model="$v.addressManualForm.line1.$model"
1161								:state="validateFormField( 'addressManualForm', 'line1' )">
1162							</b-form-input>
1163
1164							<b-form-invalid-feedback>This field is required.</b-form-invalid-feedback>
1165
1166						</b-form-group>
1167
1168					</b-col>
1169
1170					<b-col md="6">
1171
1172						<!-- LINE 2 -->
1173						<b-form-group
1174							label="Address Line 2"
1175							label-for="pfy-register-address-manual-line2">
1176
1177							<b-form-input
1178								id="pfy-register-address-manual-line2"
1179								v-model="$v.addressManualForm.line2.$model"
1180								:state="validateFormField( 'addressManualForm', 'line2' )">
1181							</b-form-input>
1182
1183						</b-form-group>
1184
1185					</b-col>
1186
1187					<b-col md="6">
1188
1189						<!-- LINE 3 -->
1190						<b-form-group
1191							label="Address Line 3"
1192							label-for="pfy-register-address-manual-line3">
1193
1194							<b-form-input
1195								id="pfy-register-address-manual-line3"
1196								v-model="$v.addressManualForm.line3.$model"
1197								:state="validateFormField( 'addressManualForm', 'line3' )">
1198							</b-form-input>
1199
1200						</b-form-group>
1201
1202					</b-col>
1203
1204					<b-col md="6">
1205
1206						<!-- CITY -->
1207						<b-form-group
1208							label="City"
1209							label-for="pfy-register-address-manual-city">
1210
1211							<b-form-input
1212								id="pfy-register-address-manual-city"
1213								v-model="$v.addressManualForm.city.$model"
1214								:state="validateFormField( 'addressManualForm', 'city' )">
1215							</b-form-input>
1216
1217						</b-form-group>
1218
1219					</b-col>
1220
1221					<b-col md="6">
1222
1223						<!-- STATE -->
1224						<b-form-group
1225							label="State"
1226							label-for=""
1227							v-if="addressManualForm.country == 'USA'">
1228
1229							<b-form-select
1230							id="pfy-register-address-manual-state"
1231							v-model="$v.addressManualForm.state.$model"
1232							:state="validateFormField( 'addressManualForm', 'state' )">
1233
1234								<b-form-select-option
1235									v-for="state in states"
1236									:key="state.StateCode"
1237									:value="state.StateCode">
1238									{{ state.StateDescription }}
1239								</b-form-select-option>
1240
1241							</b-form-select>
1242
1243							<b-form-invalid-feedback>This field is required.</b-form-invalid-feedback>
1244
1245						</b-form-group>
1246
1247					</b-col>
1248
1249					<b-col md="6">
1250
1251						<!-- ZIP CODE -->
1252						<b-form-group
1253							:label="addressManualForm.country == 'USA' ? 'ZIP Code' : 'Postal Code'"
1254							label-for="pfy-register-address-manual-zip">
1255
1256							<b-form-input
1257								id="pfy-register-address-manual-zip"
1258								v-model="$v.addressManualForm.zip.$model"
1259								:state="validateFormField( 'addressManualForm', 'zip' )">
1260							</b-form-input>
1261
1262							<b-form-invalid-feedback>This field is required.</b-form-invalid-feedback>
1263
1264						</b-form-group>
1265
1266					</b-col>
1267
1268					<b-col md="6">
1269
1270						<!-- COUNTRY -->
1271						<b-form-group
1272							label="Country"
1273							label-for="pfy-register-address-manual-country">
1274
1275							<b-form-select
1276								id="pfy-register-address-manual-country"
1277								v-model="$v.addressManualForm.country.$model"
1278								:state="validateFormField( 'addressManualForm', 'country' )">
1279
1280								<b-form-select-option
1281									v-for="country in countries"
1282									:key="country.CountryCode"
1283									:value="country.CountryCode">
1284									{{ country.CountryDescription }}
1285								</b-form-select-option>
1286
1287							</b-form-select>
1288
1289							<b-form-invalid-feedback>This field is required.</b-form-invalid-feedback>
1290
1291						</b-form-group>
1292
1293					</b-col>
1294
1295					<b-col md="6">
1296
1297						<!-- START DATE -->
1298						<b-form-group
1299							label="Start Date"
1300							label-for="pfy-register-start-date"
1301							v-if="derivedAddressType == 'SEASONAL'">
1302
1303							<b-form-input
1304								id="pfy-register-start-date"
1305								v-model="$v.addressManualForm.startDate.$model"
1306								type="date"
1307								:state="validateFormField('addressManualForm', 'startDate')">
1308							</b-form-input>
1309
1310							<b-form-invalid-feedback>This field is required for seasonal addresses.</b-form-invalid-feedback>
1311
1312						</b-form-group>
1313
1314					</b-col>
1315
1316					<b-col md="6">
1317
1318						<!-- END DATE -->
1319						<b-form-group
1320							label="End Date"
1321							label-for="pfy-register-end-date"
1322							v-if="derivedAddressType == 'SEASONAL'">
1323
1324							<b-form-input
1325								id="pfy-register-end-date"
1326								v-model="$v.addressManualForm.endDate.$model"
1327								type="date"
1328								:state="validateFormField('addressManualForm', 'endDate')">
1329							</b-form-input>
1330
1331							<b-form-invalid-feedback>This field is required for seasonal addresses.</b-form-invalid-feedback>
1332
1333						</b-form-group>
1334
1335					</b-col>
1336
1337				</b-row>
1338
1339			</b-form>
1340
1341			<b-form
1342				id="pfy-register-consent-form"
1343				:class="getFormClass( 'pfy-register-consent-form', primaryRoleIsValid && !birthDateRequiresCOPPA && !emailAlertExists )"
1344				@submit.stop.prevent="submit">
1345
1346				<h2 class="mt-5">Terms and Conditions</h2>
1347
1348				<p>By creating an account, you will have access to additional information, content, and resources concerning NASSP’s programs and activities, including information pertaining to the National Honor Society, National Junior Honor Society, National Elementary Honor Society, and National Association of Student Councils.</p>
1349
1350				<b-form-checkbox-group>
1351
1352					<b-form-checkbox
1353						id="pfy-register-consent"
1354						v-model="$v.consentForm.consent.$model"
1355						:value="true"
1356						:unchecked-value="null">
1357						I certify that I have read and understand the website <a href="/privacy-policy" target="_blank">Privacy Policy</a> and <a href="/terms-of-use" target="_blank">Terms and Conditions</a>.
1358					</b-form-checkbox>
1359
1360					<b-form-invalid-feedback
1361						:state="validateFormField('consentForm', 'consent')">
1362						You must accept the terms and conditions to create an account.
1363					</b-form-invalid-feedback>
1364
1365				</b-form-checkbox-group>
1366
1367				<div class="progress-footer">
1368					<div class="button-container">
1369						<button id="next-step" type="submit" class="btn mt-1 btn-primary" @click.prevent="submit">
1370							Create my account
1371						</button>
1372					</div>
1373					<div class="button-container">
1374						<button id="next-step" type="submit" class="btn mt-1 btn-outline-primary" @click.prevent="unsubmitPersonal">
1375							Back
1376						</button>
1377					</div>
1378				</div>
1379
1380			</b-form>
1381
1382		</div>
1383
1384		<!-- SIDEBAR -->
1385		<!-- <portal to="pfySidebar">
1386		<section class="widget">
1387
1388			<h3 class="widget-title">Renew</h3>
1389
1390			<p>Already a member? Log in to renew your membership now.</p>
1391
1392			<b-button :href="loginURL" variant="primary" class="mb-2">Log in to renew</b-button>
1393
1394		</section>
1395		</portal> -->
1396
1397	</section>`,
1398
1399	mounted() {
1400		this.getInitialData();
1401	},
1402
1403	watch: {
1404
1405		// Hide the search results modal when the user selects a searched address.
1406		addressSearchSelected( newValue ) {
1407			if ( newValue ) this.$bvModal.hide('pfy-register-address-search-results');
1408		},
1409
1410		studentInducted( newValue ) {
1411			if ( newValue === 'no' ) this.$bvModal.show('pfy-register-student-not-inducted');
1412		}
1413
1414	},
1415
1416	methods: {
1417
1418		// INITIALIZE
1419
1420		getInitialData() {
1421
1422			var self = this;
1423
1424			var callConfig = {
1425				endpoint: 'personify/v1/register/get-initial-data',
1426				body: {},
1427				callback: self.getInitialDataCallback,
1428				silent: true,
1429			}
1430
1431			var call = new PortalCall( callConfig );
1432
1433			call.send();
1434
1435		},
1436
1437		getInitialDataCallback( call ) {
1438
1439			switch ( call.code ) {
1440
1441				case 'success':
1442
1443					this.addressTypes      = call.response.addressTypes;
1444					this.countries         = call.response.countries;
1445					this.states            = call.response.states;
1446					this.jobFunctions      = call.response.jobFunctions;
1447					this.relationshipTypes = call.response.relationshipTypes;
1448					this.graduationYears   = call.response.graduationYears;
1449					this.genders 		   = call.response.genders;
1450					this.ethnicities 	   = call.response.ethnicities;
1451
1452					return;
1453
1454				default: return;
1455
1456			}
1457
1458		},
1459
1460		// PRIMARY ROLE
1461		setPrimaryRole(role) {
1462			this.primaryRole = String( role );
1463		},
1464
1465		// EMAIL
1466		submitEmail() {
1467
1468			// Check primaryRole.
1469			this.$v.primaryRole.$touch();
1470			if ( this.$v.primaryRole.$anyError ) {
1471				this.scrollTo('#pfy-register-primary-role');
1472				return;
1473			}
1474
1475			this.$v.studentInducted.$touch();
1476			if ( this.$v.studentInducted.$anyError || this.studentInducted === 'no' ) {
1477				this.scrollTo('#pfy-register-student-inducted');
1478				this.$bvModal.show('pfy-register-student-not-inducted');
1479				return;
1480			}
1481
1482			// Check password.
1483			this.$v.passwordForm.$touch();
1484			if ( this.$v.passwordForm.$anyError ) {
1485				this.scrollTo('.pfy-register-password-form');
1486				return;
1487			}
1488
1489			// Check email.
1490			if ( !this.emailSelected ) {
1491
1492				this.$v.emailForm.$touch();
1493				if ( this.$v.$anyError ) return;
1494	
1495				var self = this;
1496	
1497				var callConfig = {
1498					endpoint: 'personify/v1/register/check-email',
1499					body: {
1500						email:    this.emailForm.email,
1501						vendorID: this.vendorID,
1502					},
1503					callback: self.submitEmailCallback,
1504					silent: false,
1505				}
1506	
1507				var call = new PortalCall( callConfig );
1508	
1509				call.send();
1510	
1511			}
1512
1513		},
1514
1515		submitEmailCallback( call ) {
1516
1517			var self = this;
1518
1519			switch ( call.code ) {
1520
1521				case 'success':
1522
1523					if ( call.response.emailAvailable ) {
1524
1525						this.emailSelected    = true;
1526						this.emailAlertExists = false;
1527
1528						this.step = 2;
1529
1530						Vue.nextTick(function(){
1531							self.scrollTo('.pfy-register-personal-form');
1532							jQuery('#pfy-register-first-name').focus();
1533						});
1534
1535					} else {
1536
1537						this.emailAlertExists = true;
1538
1539						this.step = 1;
1540
1541						Vue.nextTick(function(){
1542							self.scrollTo('.pfy-register-email-form');
1543						});
1544
1545					}
1546
1547					return;
1548
1549				default:
1550
1551					this.$bvToast.toast( call.response.message || call.message, {
1552						title: 'Error',
1553						autoHideDelay: 5000,
1554						variant: 'danger',
1555						toaster: 'b-toaster-top-center',
1556						appendToast: true
1557					});
1558
1559					return;
1560
1561			}
1562
1563		},
1564
1565		unsubmitEmail() {
1566			this.step = 1;
1567			this.emailSelected = false;
1568		},
1569
1570		// PERSONAL INFO
1571
1572		submitPersonal() {
1573
1574			var self = this;
1575
1576			// Check personal info.
1577			this.$v.personalForm.$touch();
1578			if ( this.$v.personalForm.$anyError ) {
1579
1580				this.step = 2;
1581
1582				Vue.nextTick(function(){
1583					self.scrollTo('.pfy-register-personal-form');
1584				});
1585				
1586				return;
1587
1588			}
1589
1590			this.step = 3;
1591
1592			Vue.nextTick(function(){
1593				self.scrollTo('.pfy-register-school-role-form');
1594			});
1595
1596		},
1597
1598		unsubmitPersonal() {
1599			this.step = 2;
1600		},
1601
1602		// ADDRESS SEARCH
1603
1604		submitAddressSearch() {
1605
1606			// Don't repeat.
1607			if ( this.addressSearchSelected ) return;
1608
1609			// Check form.
1610			this.$v.addressSearchForm.$touch();
1611			if ( this.$v.$anyError ) return;
1612
1613			var self = this;
1614
1615			var callConfig = {
1616				endpoint: 'personify/v1/register/search-schools',
1617				body: this.addressSearchForm,
1618				callback: self.submitAddressSearchCallback,
1619				silent: false,
1620			}
1621
1622			var call = new PortalCall( callConfig );
1623
1624			call.send();
1625
1626		},
1627
1628		submitAddressSearchCallback( call ) {
1629
1630			switch ( call.code ) {
1631
1632				case 'success':
1633
1634					this.addressSearchResults = call.response.results;
1635
1636					this.$bvModal.show('pfy-register-address-search-results');
1637
1638					return;
1639
1640				default:
1641
1642					this.$bvToast.toast( call.response.message || call.message, {
1643						title: 'Error',
1644						autoHideDelay: 5000,
1645						variant: 'danger',
1646						toaster: 'b-toaster-top-center',
1647						appendToast: true
1648					});
1649
1650					return;
1651
1652			}
1653
1654		},
1655
1656		getAddressName( address ) {
1657
1658			if ( address.SchoolName && address.SchoolName.length > 0 ) return address.SchoolName;
1659
1660			if ( address.CompanyName && address.CompanyName.length > 0 ) return address.CompanyName;
1661
1662			return address.CustomerAddressId; // default;
1663
1664		},
1665
1666		resetSearch() {
1667
1668			this.addressSearchSelected = null;
1669
1670			this.$bvModal.hide('pfy-register-address-search-results');
1671
1672		},
1673
1674		endSearch() {
1675
1676			this.resetSearch()
1677
1678			this.$bvModal.show('pfy-register-address-search-unsuccessful');
1679
1680		},
1681
1682		// SUBMISSION
1683		submit() {
1684
1685			// Check school role info.
1686			this.$v.schoolForm.$touch();
1687			if ( this.$v.schoolForm.$anyError ) {
1688				this.scrollTo('.pfy-register-school-role-form');
1689				return;
1690			}
1691
1692			// Check address.
1693			if ( this.isStudent || this.isEmployee ) {
1694
1695				this.$v.addressSearchForm.$touch();
1696				if ( this.$v.addressSearchForm.$anyError || !this.addressSearchSelected ) {
1697					this.scrollTo('.pfy-register-address-search-form');
1698					return;
1699				}
1700
1701			} else {
1702
1703				this.$v.addressManualForm.$touch();
1704				if ( this.$v.addressManualForm.$anyError ) {
1705					this.scrollTo('.pfy-register-address-manual-form');
1706					return;
1707				}
1708
1709			}
1710
1711			// Check consent.
1712			this.$v.consentForm.$touch();
1713			if ( this.$v.consentForm.$anyError ) {
1714				this.scrollTo('.pfy-register-consent-form');
1715				return;
1716			}
1717
1718			// Clear alerts.
1719			this.addressAlertUnvalidated   = false;
1720			this.addressAlertUndeliverable = false;
1721
1722			// Send.
1723			var self = this;
1724
1725			var callConfig = {
1726				endpoint: 'personify/v1/register/create-account',
1727				body: {
1728					primaryRole:         this.primaryRole,
1729					email:               this.emailForm.email,
1730					password:            this.passwordForm.password,
1731					firstName:           this.personalForm.firstName,
1732					lastName:            this.personalForm.lastName,
1733					phoneAreaCode:       this.phoneAreaCode,
1734					phoneBody:           this.phoneBody,
1735					phoneExtension:      this.phoneExtension,
1736					birthDate:           this.personalForm.birthDate,
1737					gender:              this.personalForm.gender,
1738					ethnicity:           this.personalForm.ethnicity,
1739					addressType:         this.derivedAddressType,
1740					relationshipType:    this.derivedRelationshipType,
1741					jobFunction:         this.derivedJobFunctionCode,
1742					graduationYear:      this.schoolForm.graduationYear,
1743					schoolAddress:       this.addressSearchSelected,
1744					manualName:          this.addressManualForm.name,
1745					manualLine1:         this.addressManualForm.line1,
1746					manualLine2:         this.addressManualForm.line2,
1747					manualLine3:         this.addressManualForm.line3,
1748					manualCity:          this.addressManualForm.city,
1749					manualState:         this.addressManualForm.state,
1750					manualCountry:       this.addressManualForm.country,
1751					manualZip:           this.addressManualForm.zip,
1752					manualStartDate:     this.addressManualForm.startDate,
1753					manualEndDate:       this.addressManualForm.endDate,
1754					manualDoNotValidate: this.addressManualForm.doNotValidate,
1755					consent:             this.consentForm.consent,
1756					vendorID:            this.vendorID,
1757				},
1758				callback: self.submitCallback,
1759				silent: false,
1760			}
1761
1762			var call = new PortalCall( callConfig );
1763
1764			call.send();
1765
1766		},
1767
1768		submitCallback( call ) {
1769
1770			switch ( call.code ) {
1771
1772				case 'success':
1773
1774					/*
1775					this.password = call.response.password;
1776
1777					// For third-party SSO integrations, skip the auto-login step and go straight to the provided return URL (usually the custom login page).
1778					if ( this.vendorID !== null ) {
1779						window.location = this.returnURL;
1780						return;
1781					}
1782
1783					this.submitLogin();
1784
1785					return;
1786					*/
1787
1788					window.location = this.loginURL;
1789
1790				case 'address-unvalidated':
1791
1792					// NASSP prefers not to allow unvalidated addresses to proceed.
1793
1794					/*
1795
1796					this.addressAlertUnvalidated = true;
1797
1798					this.scrollTo('.pfy-register-address-manual-form');
1799
1800					return;
1801
1802					*/
1803
1804				case 'address-not-found':
1805				case 'address-undeliverable':
1806
1807					this.addressAlertUndeliverable = true;
1808
1809					this.scrollTo('.pfy-register-address-manual-form');
1810
1811					return;
1812
1813				default:
1814
1815					this.$bvToast.toast( call.response.message || call.message, {
1816						title: 'Error',
1817						variant: 'danger',
1818						toaster: 'b-toaster-top-center',
1819						appendToast: true
1820					});
1821
1822					return;
1823
1824			}
1825
1826		},
1827
1828		// LOGIN
1829
1830		submitLogin() {
1831
1832			var self = this;
1833
1834			var call = new PortalCall({
1835				endpoint: 'personify/v1/login',
1836				body: {
1837					username:  self.emailForm.email,
1838					password:  self.password,
1839					vendorID:  self.vendorID,
1840					returnURL: self.returnURL,
1841				},
1842				callback: self.submitLoginCallback,
1843				silent: false,
1844			});
1845
1846			call.send();
1847
1848		},
1849
1850		submitLoginCallback( call ) {
1851
1852			switch ( call.code ) {
1853				case 'success':
1854
1855					window.location = call.response.returnURL;
1856					return;
1857
1858				default:
1859
1860					this.$bvToast.toast( call.response.message || call.message, {
1861						title: 'Error',
1862						variant: 'danger',
1863						toaster: 'b-toaster-top-center',
1864						appendToast: true
1865					});
1866
1867					return;
1868
1869			}
1870
1871		},
1872
1873		// FORM VALIDATION
1874
1875		validateField( fieldName ) {
1876			const { $dirty, $error } = this.$v[fieldName];
1877			return $dirty ? !$error : null;
1878		},
1879
1880		validateFormField( formName, fieldName ) {
1881			const { $dirty, $error } = this.$v[formName][fieldName];
1882			return $dirty ? !$error : null;
1883		},
1884
1885		// HELPERS
1886
1887		getFormClass( mainClass, condition ) {
1888
1889			var formClass = mainClass;
1890
1891			if ( !condition ) {
1892				formClass += ' pfy-block-disabled';
1893			}
1894
1895			return formClass;
1896
1897		},
1898
1899		formatHTML( value ) {
1900			return value.replace("\n", '<br>');
1901		},
1902
1903		scrollTo( selector ) {
1904
1905			jQuery('html, body').animate({
1906				scrollTop: jQuery(selector).offset().top - jQuery(window).height() / 3,
1907			}, 500);
1908
1909		}
1910
1911	},
1912
1913	validations: {
1914
1915		primaryRole:     { required },
1916		studentInducted: {
1917			required: requiredIf( function( nestedModel ){
1918				return Boolean( this.isStudent );
1919			})
1920		},
1921
1922		emailForm: {
1923			email: { required, email },
1924			emailConfirm: {
1925				required,
1926				email,
1927				matchEmail (val) {
1928					return Boolean( val === this.emailForm.email )
1929				}
1930			},
1931		},
1932
1933		passwordForm: {
1934			password: { required, minLength: minLength(6) },
1935		},
1936
1937		personalForm: {
1938			firstName:     { required },
1939			lastName:      { required },
1940			birthDate:     {
1941				required: requiredIf( function( nestedModel ){
1942					return Boolean( this.isStudent || this.isEmployee );
1943				})
1944			},
1945			phone:         { required, minLength: minLength(10) },
1946			gender:        { required },
1947			ethnicity:     { required },
1948		},
1949
1950		schoolForm: {
1951
1952			relationshipType: {
1953				required: requiredIf( function( nestedModel ){
1954					return this.isEmployee;
1955				})
1956			},
1957
1958			jobFunction:   {
1959				required: requiredIf( function( nestedModel ){
1960					return this.isEmployee;
1961				})
1962			},
1963
1964			graduationYear:   {
1965				required: requiredIf( function( nestedModel ){
1966					return this.isStudent;
1967				})
1968			}
1969
1970		},
1971
1972		addressSearchForm: {
1973
1974			method: { required },
1975
1976			name: {},
1977
1978			city: {},
1979
1980			state: {
1981				required: requiredIf(function( nestedModel ) {
1982					return this.addressSearchForm.method == 'search' && this.addressSearchForm.country == 'USA';
1983				})
1984			},
1985
1986			country: {
1987				required: requiredIf(function( nestedModel ) {
1988					return this.addressSearchForm.method == 'search'
1989				})
1990			},
1991
1992			schoolID: {
1993				required: requiredIf(function( nestedModel ) {
1994					return this.addressSearchForm.method == 'id'
1995				})
1996			},
1997
1998		},
1999
2000		addressManualForm: {
2001
2002			type: { required },
2003
2004			line1: {
2005				required,
2006			},
2007
2008			line2: {
2009
2010			},
2011
2012			line3: {
2013
2014			},
2015
2016			city: {
2017				required,
2018			},
2019
2020			state: {
2021				required: requiredIf( function( nestedModel ){
2022					return this.addressManualForm.country == 'USA';
2023				}),
2024			},
2025
2026			country: {
2027				required,
2028			},
2029
2030			zip: {
2031				required
2032			},
2033
2034			startDate: {
2035				required: requiredIf( function( nestedModel ){
2036					return this.addressManualForm.type == 'SEASONAL';
2037				}),
2038			},
2039
2040			endDate: {
2041				required: requiredIf( function( nestedModel ){
2042					return this.addressManualForm.type == 'SEASONAL';
2043				}),
2044			},
2045
2046			doNotValidate: {},
2047
2048		},
2049
2050		consentForm: {
2051			consent: { arrayNotEmpty },
2052		},
2053
2054	},
2055
2056});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.