vbs registration
continuous-integration/drone Build is failing
Details
continuous-integration/drone Build is failing
Details
parent
4739e0d6e1
commit
a8abe3f3d8
|
|
@ -22,6 +22,7 @@ import { ImageComponent } from './components/image/image.component';
|
||||||
import { VideoComponent } from './components/video/video.component';
|
import { VideoComponent } from './components/video/video.component';
|
||||||
import { FCCPermitPageComponent } from './components/fcc-permit-page/fcc-permit-page.component';
|
import { FCCPermitPageComponent } from './components/fcc-permit-page/fcc-permit-page.component';
|
||||||
import { BalloonComponent } from './components/balloon/balloon.component';
|
import { BalloonComponent } from './components/balloon/balloon.component';
|
||||||
|
import { VbsPageComponent } from './components/vbs-page/vbs-page.component';
|
||||||
|
|
||||||
const routes =
|
const routes =
|
||||||
[
|
[
|
||||||
|
|
@ -120,6 +121,10 @@ const routes =
|
||||||
{
|
{
|
||||||
path: 'balloon',
|
path: 'balloon',
|
||||||
component: BalloonComponent
|
component: BalloonComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'vbs',
|
||||||
|
component: VbsPageComponent
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,10 @@ import { MatButtonModule,
|
||||||
MatOptionModule,
|
MatOptionModule,
|
||||||
MatRadioModule,
|
MatRadioModule,
|
||||||
MatAutocompleteModule,
|
MatAutocompleteModule,
|
||||||
MatCheckboxModule} from '@angular/material';
|
MatCheckboxModule,
|
||||||
|
MatDatepickerModule,
|
||||||
|
MatNativeDateModule,
|
||||||
|
MatCardModule} from '@angular/material';
|
||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import 'hammerjs';
|
import 'hammerjs';
|
||||||
|
|
||||||
|
|
@ -86,7 +89,7 @@ import { VideoComponent } from './components/video/video.component';
|
||||||
import { YoutubeListService } from './components/youtube-list/youtube-list-service';
|
import { YoutubeListService } from './components/youtube-list/youtube-list-service';
|
||||||
import { VideoItemComponent } from './components/video-item/video-item.component';
|
import { VideoItemComponent } from './components/video-item/video-item.component';
|
||||||
import { YoutubePopupComponent } from './components/popups/youtube-popup/youtube-popup.component';
|
import { YoutubePopupComponent } from './components/popups/youtube-popup/youtube-popup.component';
|
||||||
|
import { VbsPageComponent } from './components/vbs-page/vbs-page.component';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -143,7 +146,8 @@ import { YoutubePopupComponent } from './components/popups/youtube-popup/youtube
|
||||||
YoutubeListComponent,
|
YoutubeListComponent,
|
||||||
VideoComponent,
|
VideoComponent,
|
||||||
VideoItemComponent,
|
VideoItemComponent,
|
||||||
YoutubePopupComponent
|
YoutubePopupComponent,
|
||||||
|
VbsPageComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
|
|
@ -162,7 +166,10 @@ import { YoutubePopupComponent } from './components/popups/youtube-popup/youtube
|
||||||
MatDialogModule,
|
MatDialogModule,
|
||||||
MatAutocompleteModule,
|
MatAutocompleteModule,
|
||||||
MatRadioModule,
|
MatRadioModule,
|
||||||
MatCheckboxModule
|
MatCheckboxModule,
|
||||||
|
MatCardModule,
|
||||||
|
MatDatepickerModule,
|
||||||
|
MatNativeDateModule
|
||||||
],
|
],
|
||||||
providers: [LoginService,PrintService,UserService,GoogleAnalyticsService,SermonService,TransactionService,EventService,EmailService,MissionarySupportService,YoutubeListService,WindowRefService],
|
providers: [LoginService,PrintService,UserService,GoogleAnalyticsService,SermonService,TransactionService,EventService,EmailService,MissionarySupportService,YoutubeListService,WindowRefService],
|
||||||
entryComponents: [AddSermonPopupComponent,
|
entryComponents: [AddSermonPopupComponent,
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,17 @@
|
||||||
<div id="content-wrapper">
|
<div id="content-wrapper">
|
||||||
|
|
||||||
<div style="text-align: center; position: relative; margin-bottom: 15px; " *ngIf="showVBS">
|
<div style="text-align: center; position: relative; margin-bottom: 15px; " *ngIf="showVBS">
|
||||||
<div style="position: absolute; width: 100%; height: calc(65% + 15px); top: 35%; background-color: white;"></div>
|
<div style="position: absolute; width: 100%; height: calc(65% + 15px); top: 35%; background-color: rgb(240,240,240);"></div>
|
||||||
<img src="assets/images/home-images/tiny/VBS_small.jpg" style="width:75%; max-width: 350px; position: relative; z-index: 1; box-shadow: 0 0 20px pink;" >
|
<a routerLink="/vbs" style="display: block; width:75%; max-width: 350px; position: relative; z-index: 1; margin-left: auto; margin-right: auto;">
|
||||||
|
<img src="assets/images/home-images/tiny/VBS_small.jpg" style="width:100%; height: auto; display: block; box-shadow: 0 0 20px gray;" >
|
||||||
|
<div style="margin-top: 30px; font-size: 30px;">
|
||||||
|
Click To Register!
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div style="height: 2px; background-color: lightgray;">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row tint" *ngIf="showVGC" >
|
<div class="row tint" *ngIf="showVGC" >
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ export class HomeComponent {
|
||||||
backgroundTop: string = "0px";
|
backgroundTop: string = "0px";
|
||||||
|
|
||||||
public get showVGC() : boolean {
|
public get showVGC() : boolean {
|
||||||
|
return false;
|
||||||
let maxDate = new Date(2024,7,15,11); // August 15th 2018 -- Set the month one month behind since JavaScript dates are 0 based
|
let maxDate = new Date(2024,7,15,11); // August 15th 2018 -- Set the month one month behind since JavaScript dates are 0 based
|
||||||
let now = new Date();
|
let now = new Date();
|
||||||
if (now.getFullYear() > maxDate.getFullYear()) return false;
|
if (now.getFullYear() > maxDate.getFullYear()) return false;
|
||||||
|
|
@ -63,7 +63,8 @@ export class HomeComponent {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
public get showVBS(): boolean {
|
public get showVBS(): boolean {
|
||||||
let maxDate = new Date(2019,7,22); // August 22nd 2018 -- Set the month one month behind since JavaScript dates are 0 based
|
return false;
|
||||||
|
let maxDate = new Date(2026,7,13); // August 22nd 2018 -- Set the month one month behind since JavaScript dates are 0 based
|
||||||
let now = new Date();
|
let now = new Date();
|
||||||
if (now.getFullYear() > maxDate.getFullYear()) return false;
|
if (now.getFullYear() > maxDate.getFullYear()) return false;
|
||||||
if (now.getFullYear() == maxDate.getFullYear()) {
|
if (now.getFullYear() == maxDate.getFullYear()) {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,10 @@
|
||||||
padding: 20px 10px 10px 10px;
|
padding: 20px 10px 10px 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.width100{
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
|
||||||
.side-bar{
|
.side-bar{
|
||||||
width: 30%;
|
width: 30%;
|
||||||
display: table-cell;
|
display: table-cell;
|
||||||
|
|
@ -27,6 +31,10 @@
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.display-none {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
@media(max-width:800px){
|
@media(max-width:800px){
|
||||||
.side-bar{
|
.side-bar{
|
||||||
display: block;
|
display: block;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
<div id="content-wrapper">
|
<div id="content-wrapper">
|
||||||
<div id="content">
|
<div id="content">
|
||||||
<div class="main-content align-top">
|
<div class="main-content align-top" [class.width100]="hideAlways">
|
||||||
<ng-content select="[mainContent]"></ng-content>
|
<ng-content select="[mainContent]"></ng-content>
|
||||||
</div><!--
|
</div><!--
|
||||||
--><div class="side-bar align-top" [class.hide-on-mobile]="hideSideBarOnMobile" [class.fixed-side-bar]="fixedSideBar">
|
--><div class="side-bar align-top" [class.hide-on-mobile]="hideSideBarOnMobile" [class.display-none]="true" [class.fixed-side-bar]="fixedSideBar">
|
||||||
<ng-content select="[sideBar]"></ng-content>
|
<ng-content select="[sideBar]"></ng-content>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,11 @@ import { Component, Input, OnInit } from '@angular/core';
|
||||||
})
|
})
|
||||||
export class SecondaryPageComponent implements OnInit {
|
export class SecondaryPageComponent implements OnInit {
|
||||||
@Input()
|
@Input()
|
||||||
public hideSideBarOnMobile: boolean;
|
public hideSideBarOnMobile: boolean = true;
|
||||||
@Input()
|
@Input()
|
||||||
public fixedSideBar: boolean;
|
public fixedSideBar: boolean = true;
|
||||||
|
@Input()
|
||||||
|
public hideAlways: boolean = true;
|
||||||
|
|
||||||
constructor(){
|
constructor(){
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
.w-50 {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w-100 {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header{
|
||||||
|
font-size: 1.2em;
|
||||||
|
font-weight: bold;
|
||||||
|
border-bottom: 1px solid gray;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row-1-col {
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row-2-col {
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
gap: 10px;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media(max-width:600px){
|
||||||
|
.form-row-2-col {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-container {
|
||||||
|
width: 800px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media(max-width:800px){
|
||||||
|
.form-container {
|
||||||
|
width: auto;
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-label {
|
||||||
|
font-weight: bold;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
font-size: 1.15rem;
|
||||||
|
margin-top: 35px;
|
||||||
|
color: black;
|
||||||
|
font-weight: 400;
|
||||||
|
font-family: Arial, Helvetica, sans-serif
|
||||||
|
}
|
||||||
|
|
||||||
|
ol > li {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-label {
|
||||||
|
font-size: 1.15rem;
|
||||||
|
color: black;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
label.sub {
|
||||||
|
margin-top: 0px;
|
||||||
|
font-size: .85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-radio-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-radio-button {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
margin: 15px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,216 @@
|
||||||
|
|
||||||
|
<secondary-page-component [hideAlways]="true" >
|
||||||
|
<div mainContent>
|
||||||
|
<div class="form-container">
|
||||||
|
<h1 class="center" style="background-color: lightblue; padding:10px;">
|
||||||
|
Vacation Bible School Registration
|
||||||
|
</h1>
|
||||||
|
<form [formGroup]="form" (ngSubmit)="onSubmit()">
|
||||||
|
<div *ngIf="studentStep">
|
||||||
|
<h2 class="center" style="margin:25px;">Student Information</h2>
|
||||||
|
<div class="form-row-2-col">
|
||||||
|
<mat-form-field class="w-100" [class.background-error]="hasErrors('firstName')">
|
||||||
|
<mat-label>First Name</mat-label>
|
||||||
|
<input matInput type="text" formControlName="firstName" required>
|
||||||
|
<mat-error>Please enter student first name</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field class="w-100" [class.background-error]="hasErrors('lastName')">
|
||||||
|
<mat-label>Last Name</mat-label>
|
||||||
|
<input matInput type="text" formControlName="lastName" required>
|
||||||
|
<mat-error>Please enter student last name</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="form-row-2-col">
|
||||||
|
<mat-form-field class="w-100" [class.background-error]="hasErrors('grade')">
|
||||||
|
<mat-label>Grade</mat-label>
|
||||||
|
<input matInput type="number" formControlName="grade" required>
|
||||||
|
<mat-error>Please enter student grade</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="w-100" [class.background-error]="hasErrors('dob')">
|
||||||
|
<mat-label>Birthday</mat-label>
|
||||||
|
<input matInput [matDatepicker]="picker" (click)="picker.open()" formControlName="dob" required readonly>
|
||||||
|
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
|
||||||
|
<mat-datepicker touchUi #picker></mat-datepicker>
|
||||||
|
<mat-error>Please enter student birthday</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="form-row-1-col">
|
||||||
|
<div>
|
||||||
|
<label id="studentHasAllergiesLabel">Does the student have any allergies?</label>
|
||||||
|
<mat-radio-group aria-label="Student has allergies" formControlName="hasAllergies" aria-labelledby="studentHasAllergiesLabel">
|
||||||
|
<mat-radio-button class="radio-button" value="true">Yes</mat-radio-button>
|
||||||
|
<mat-radio-button class="radio-button" value="false">No</mat-radio-button>
|
||||||
|
</mat-radio-group>
|
||||||
|
</div>
|
||||||
|
<mat-form-field *ngIf="form.get('hasAllergies').value === 'true'" class="w-100" [class.background-error]="hasErrors('allergies')">
|
||||||
|
<mat-label>Allergies</mat-label>
|
||||||
|
<textarea matInput type="text" formControlName="allergies"></textarea>
|
||||||
|
<mat-error>Please enter student allergies</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="form-row-1-col">
|
||||||
|
<div>
|
||||||
|
<label id="studentHasDietaryRestrictionsLabel">Does the student have any dietary restrictions?</label>
|
||||||
|
<mat-radio-group aria-label="Student has allergies" formControlName="hasDietaryRestrictions" aria-labelledby="studentHasDietaryRestrictionsLabel">
|
||||||
|
<mat-radio-button class="radio-button" value="true">Yes</mat-radio-button>
|
||||||
|
<mat-radio-button class="radio-button" value="false">No</mat-radio-button>
|
||||||
|
</mat-radio-group>
|
||||||
|
</div>
|
||||||
|
<mat-form-field *ngIf="form.get('hasDietaryRestrictions').value === 'true'" class="w-100" [class.background-error]="hasErrors('dietaryRestrictions')">
|
||||||
|
<mat-label>Dietary Restrictions</mat-label>
|
||||||
|
<textarea matInput type="text" formControlName="dietaryRestrictions"></textarea>
|
||||||
|
<mat-error>Please enter student dietary restrictions</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="form-row-1-col">
|
||||||
|
<div>
|
||||||
|
<label id="studentAttendedInPastLabel">Has the student attended VBS in the past?</label>
|
||||||
|
<mat-radio-group aria-label="Student Attended In Past" formControlName="attendedInPast" aria-labelledby="studentAttendedInPastLabel">
|
||||||
|
<mat-radio-button class="radio-button" value="true">Yes</mat-radio-button>
|
||||||
|
<mat-radio-button class="radio-button" value="false">No</mat-radio-button>
|
||||||
|
</mat-radio-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row-1-col">
|
||||||
|
<div>
|
||||||
|
<label id="studentRidesBus">Does the student currently ride the bus or van?</label>
|
||||||
|
<mat-radio-group aria-label="Student Rides The Bus or Van" formControlName="ridesBus" aria-labelledby="studentRidesBus">
|
||||||
|
<mat-radio-button class="radio-button" value="true">Yes</mat-radio-button>
|
||||||
|
<mat-radio-button class="radio-button" value="false">No</mat-radio-button>
|
||||||
|
</mat-radio-group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; justify-content: flex-end; margin-bottom:20px;">
|
||||||
|
<button [disabled]="!studentComplete()" mat-raised-button color="primary" (click)="gotoParentStep()">Next</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="parentStep">
|
||||||
|
<h2 class="center" style="margin:25px;">Parent/Guardian Information</h2>
|
||||||
|
<div class="form-row-2-col">
|
||||||
|
<mat-form-field class="w-100" [class.background-error]="hasErrors('parentFirstName')">
|
||||||
|
<mat-label>First Name</mat-label>
|
||||||
|
<input matInput type="text" formControlName="parentFirstName" required>
|
||||||
|
<mat-error>Please enter parent/guardian name</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field class="w-100" [class.background-error]="hasErrors('parentLastName')">
|
||||||
|
<mat-label>Last Name</mat-label>
|
||||||
|
<input matInput type="text" formControlName="parentLastName" required>
|
||||||
|
<mat-error>Please enter parent/guardian name</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="form-row-1-col">
|
||||||
|
<mat-form-field class="w-100" [class.background-error]="hasErrors('address1')">
|
||||||
|
<mat-label>Address Line 1</mat-label>
|
||||||
|
<input matInput type="text" formControlName="address1" required>
|
||||||
|
<mat-error>Please enter parent/guardian address</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field class="w-100" [class.background-error]="hasErrors('address2')">
|
||||||
|
<mat-label>Address Line 2</mat-label>
|
||||||
|
<input matInput type="text" formControlName="address2">
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="form-row-2-col">
|
||||||
|
<mat-form-field class="w-100" [class.background-error]="hasErrors('city')">
|
||||||
|
<mat-label>City</mat-label>
|
||||||
|
<input matInput type="text" formControlName="city" required>
|
||||||
|
<mat-error>Please enter parent/guardian city</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field class="w-100" [class.background-error]="hasErrors('state')">
|
||||||
|
<mat-label>State *</mat-label>
|
||||||
|
<mat-select formControlName="state">
|
||||||
|
<!-- Empty option to allow clearing the choice -->
|
||||||
|
<mat-option [value]="null">-- Select a State --</mat-option>
|
||||||
|
|
||||||
|
<!-- Dynamically loop over the array mapping code to value and name to label -->
|
||||||
|
<mat-option *ngFor="let state of stateList" [value]="state.code">
|
||||||
|
{{ state.name }}
|
||||||
|
</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
<mat-error>Please enter parent/guardian state</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
|
||||||
|
<mat-form-field class="w-100" [class.background-error]="hasErrors('zip')">
|
||||||
|
<mat-label>Zip</mat-label>
|
||||||
|
<input matInput type="text" formControlName="zip" required>
|
||||||
|
<mat-error>Please enter parent/guardian zip</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="form-row-2-col">
|
||||||
|
<mat-form-field class="w-100" [class.background-error]="hasErrors('parentHomePhone')">
|
||||||
|
<mat-label>Home Phone</mat-label>
|
||||||
|
<input matInput type="tel" formControlName="parentHomePhone">
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field class="w-100" [class.background-error]="hasErrors('parentMobilePhone')">
|
||||||
|
<mat-label>Mobile Phone</mat-label>
|
||||||
|
<input matInput type="tel" formControlName="parentMobilePhone" required>
|
||||||
|
<mat-error>Please enter parent/guardian mobile phone (must be 10 digits)</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="form-row-2-col">
|
||||||
|
<mat-form-field class="w-100" [class.background-error]="hasErrors('parentWorkPhone')">
|
||||||
|
<mat-label>Work Phone</mat-label>
|
||||||
|
<input matInput type="tel" formControlName="parentWorkPhone">
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field class="w-100" [class.background-error]="hasErrors('parentEmail')">
|
||||||
|
<mat-label>Email</mat-label>
|
||||||
|
<input matInput type="email" formControlName="parentEmail" required>
|
||||||
|
<mat-error>Please enter parent/guardian email</mat-error>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; justify-content: space-between; margin-bottom: 20px;">
|
||||||
|
<button mat-raised-button color="primary" (click)="gotoStudentStep()">Back</button>
|
||||||
|
<button [disabled]="!parentComplete()" mat-raised-button color="primary" (click)="gotoEmergencyStep()">Next</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="emergencyStep">
|
||||||
|
<h2 class="center" style="margin:25px;">Emergency Contact Information</h2>
|
||||||
|
<div class="form-row-1-col">
|
||||||
|
<mat-checkbox matPrefix formControlName="emergencySameAsParent">Same as Parent/Guardian</mat-checkbox>
|
||||||
|
</div>
|
||||||
|
<div class="form-row-2-col">
|
||||||
|
<mat-form-field class="w-100" [class.background-error]="hasErrors('emergencyFirstName')">
|
||||||
|
<mat-label>First Name</mat-label>
|
||||||
|
<input matInput type="text" formControlName="emergencyFirstName">
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field class="w-100" [class.background-error]="hasErrors('emergencyLastName')">
|
||||||
|
<mat-label>Last Name</mat-label>
|
||||||
|
<input matInput type="text" formControlName="emergencyLastName">
|
||||||
|
</mat-form-field>
|
||||||
|
|
||||||
|
<mat-form-field class="w-100" [class.background-error]="hasErrors('emergencyPhone')">
|
||||||
|
<mat-label>Phone</mat-label>
|
||||||
|
<input matInput type="tel" formControlName="emergencyPhone">
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input type="hidden" formControlName="hp">
|
||||||
|
<div style="display: flex; justify-content: space-between; margin-bottom: 20px;">
|
||||||
|
<button [disabled]="submitting" mat-raised-button color="primary" (click)="gotoParentStep()">Back</button>
|
||||||
|
<button [disabled]="!emergencyComplete() || submitting" mat-raised-button color="primary" (click)="submit()">Submit</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="completeStep">
|
||||||
|
<h2 class="center" style="margin:25px;">Complete!</h2>
|
||||||
|
<h4 class="center">{{form.get('firstName').value}} has been registered!</h4>
|
||||||
|
<div class="center" style="margin-top:20px;">
|
||||||
|
<button mat-raised-button color="primary" (click)="registerAnotherStudent()">Register Another Student</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</secondary-page-component>
|
||||||
|
|
@ -0,0 +1,253 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { FormGroup, FormBuilder, Validators, FormArray, FormControl, ValidatorFn, ValidationErrors } from '@angular/forms';
|
||||||
|
import { MissionarySupportService } from 'src/app/services/missionary-support-service';
|
||||||
|
import { MatDialog, MatDialogConfig } from '@angular/material';
|
||||||
|
import { OkPopupComponent } from '../popups/ok-popup/ok-popup.component';
|
||||||
|
import { EmailService } from 'src/app/services/email.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-vbs-page',
|
||||||
|
templateUrl: './vbs-page.component.html',
|
||||||
|
styleUrls: ['./vbs-page.component.css']
|
||||||
|
})
|
||||||
|
export class VbsPageComponent implements OnInit {
|
||||||
|
|
||||||
|
form: FormGroup;
|
||||||
|
submitButtonText: string = 'Submit';
|
||||||
|
submitButtonDisabled: boolean = false;
|
||||||
|
errorMessages: string[] = [];
|
||||||
|
public students: Student[] = [];
|
||||||
|
public studentStep: boolean = true;
|
||||||
|
public parentStep: boolean = false;
|
||||||
|
public emergencyStep: boolean = false;
|
||||||
|
public completeStep: boolean = false;
|
||||||
|
public submitting: boolean = false;
|
||||||
|
|
||||||
|
constructor(private formBuilder: FormBuilder, private matDialog: MatDialog, private emailService: EmailService, private missionarySupportService: MissionarySupportService) {
|
||||||
|
//this.setupForm();
|
||||||
|
this.form = this.formBuilder.group({
|
||||||
|
firstName: ['', [Validators.required]],
|
||||||
|
lastName: ['', [Validators.required]],
|
||||||
|
grade: ['', [Validators.required]],
|
||||||
|
dob: [null, [Validators.required]],
|
||||||
|
hasAllergies: [null, [Validators.required]],
|
||||||
|
allergies: ['', [Validators.required]],
|
||||||
|
hasDietaryRestrictions: [null, [Validators.required]],
|
||||||
|
dietaryRestrictions: ['', [Validators.required]],
|
||||||
|
attendedInPast: [null, [Validators.required]],
|
||||||
|
ridesBus: [null, [Validators.required]],
|
||||||
|
parentFirstName: ['', [Validators.required]],
|
||||||
|
parentLastName: ['', [Validators.required]],
|
||||||
|
parentHomePhone: ['', []],
|
||||||
|
parentMobilePhone: ['', [Validators.required]],
|
||||||
|
parentWorkPhone: ['', []],
|
||||||
|
parentEmail: ['', [Validators.required]],
|
||||||
|
address1: ['', [Validators.required]],
|
||||||
|
address2: ['', [Validators.required]],
|
||||||
|
city: ['', [Validators.required]],
|
||||||
|
state: ['', [Validators.required]],
|
||||||
|
zip: ['', [Validators.required]],
|
||||||
|
emergencySameAsParent: ['', []],
|
||||||
|
emergencyFirstName: ['', []],
|
||||||
|
emergencyLastName: ['', []],
|
||||||
|
emergencyPhone: ['', []],
|
||||||
|
hp: ['.', [Validators.required]]
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
hasErrors(formControlName: string): boolean {
|
||||||
|
let res = this.form.get(formControlName) && typeof this.form.get(formControlName).errors !== 'undefined';
|
||||||
|
if (res === true) {
|
||||||
|
res = this.form.get(formControlName).dirty || (this.form.get(formControlName).touched && this.form.get(formControlName).valid === false);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
studentComplete(): boolean {
|
||||||
|
var firstName = this.form.get('firstName');
|
||||||
|
var lastName = this.form.get('lastName');
|
||||||
|
var grade = this.form.get('grade');
|
||||||
|
var dob = this.form.get('dob');
|
||||||
|
var hasAllergies = this.form.get('hasAllergies');
|
||||||
|
var hasDietaryRestrictions = this.form.get('hasDietaryRestrictions');
|
||||||
|
var allergies = this.form.get('allergies');
|
||||||
|
var dietaryRestrictions = this.form.get('dietaryRestrictions');
|
||||||
|
var attendedInPast = this.form.get('attendedInPast');
|
||||||
|
var ridesBus = this.form.get('ridesBus');
|
||||||
|
|
||||||
|
var hasFirst = firstName && firstName.value && firstName.value.length > 2;
|
||||||
|
var hasLast = lastName && lastName.value && lastName.value.length > 2;
|
||||||
|
var hasGrade = grade && grade.value && grade.value > 0;
|
||||||
|
var hasDob = dob && dob.value != null;
|
||||||
|
var hasAllergiesComplete = hasAllergies && hasAllergies.value != null;
|
||||||
|
var hasDietaryRestrictionsComplete = hasDietaryRestrictions && hasDietaryRestrictions.value != null;
|
||||||
|
var allergiesComplete = allergies && allergies.value && allergies.value.length > 2;
|
||||||
|
var dietaryRestrictionsComplete = dietaryRestrictions && dietaryRestrictions.value && dietaryRestrictions.value.length > 2;
|
||||||
|
var hasAttendedInPast = attendedInPast && attendedInPast.value != null;
|
||||||
|
var hasRidesBus = ridesBus && ridesBus.value != null;
|
||||||
|
|
||||||
|
var validAllergies = hasAllergiesComplete && ((hasAllergies.value === 'true' && allergiesComplete) || (hasAllergies.value === 'false'));
|
||||||
|
var validDietaryRestrictions = hasDietaryRestrictionsComplete && ((hasDietaryRestrictions.value === 'true' && dietaryRestrictionsComplete) || (hasDietaryRestrictions.value === 'false'));
|
||||||
|
|
||||||
|
return hasFirst && hasLast && hasGrade && hasDob && validAllergies && validDietaryRestrictions && hasRidesBus && hasAttendedInPast;
|
||||||
|
}
|
||||||
|
|
||||||
|
parentComplete(): boolean {
|
||||||
|
var first = this.form.get('parentFirstName');
|
||||||
|
var last = this.form.get('parentLastName');
|
||||||
|
var mobilePhone = this.form.get('parentMobilePhone');
|
||||||
|
var email = this.form.get('parentEmail');
|
||||||
|
var address1 = this.form.get('address1');
|
||||||
|
var city = this.form.get('city');
|
||||||
|
var state = this.form.get('state');
|
||||||
|
var zip = this.form.get('zip');
|
||||||
|
|
||||||
|
var hasFirst = first && first.value && first.value.length > 1;
|
||||||
|
var hasLast = last && last.value && last.value.length > 1;
|
||||||
|
var hasMobilePhone = mobilePhone && mobilePhone.value && mobilePhone.value.length > 9;
|
||||||
|
var hasEmail = email && email.value && this.isValidEmail(email.value);
|
||||||
|
var hasAddress1 = address1 && address1.value && address1.value.length > 2;
|
||||||
|
var hasCity = city && city.value && city.value.length > 2;
|
||||||
|
var hasState = state && state.value && state.value.length > 0;
|
||||||
|
var hasZip = zip && zip.value && zip.value.length > 2;
|
||||||
|
|
||||||
|
return hasFirst && hasLast && hasMobilePhone && hasEmail && hasAddress1 && hasCity && hasState && hasZip;
|
||||||
|
}
|
||||||
|
|
||||||
|
emergencyComplete(): boolean {
|
||||||
|
var same = this.form.get('emergencySameAsParent');
|
||||||
|
var first = this.form.get('emergencyFirstName');
|
||||||
|
var last = this.form.get('emergencyLastName');
|
||||||
|
var phone = this.form.get('emergencyPhone');
|
||||||
|
|
||||||
|
var isSame = same && same.value && same.value === true;
|
||||||
|
var hasFirst = first && first.value && first.value.length > 2;
|
||||||
|
var hasLast = last && last.value && last.value.length > 2;
|
||||||
|
var hasPhone = phone && phone.value && phone.value.length > 9;
|
||||||
|
|
||||||
|
if (isSame) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasFirst && hasLast && hasPhone;
|
||||||
|
}
|
||||||
|
|
||||||
|
isValidEmail(email: string) {
|
||||||
|
// The official regex standard used by most frontend validation engines
|
||||||
|
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
||||||
|
return emailRegex.test(email);
|
||||||
|
}
|
||||||
|
|
||||||
|
gotoStudentStep() {
|
||||||
|
this.studentStep = true;
|
||||||
|
this.parentStep = false;
|
||||||
|
this.emergencyStep = false;
|
||||||
|
this.completeStep = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
gotoParentStep() {
|
||||||
|
this.studentStep = false;
|
||||||
|
this.parentStep = true;
|
||||||
|
this.emergencyStep = false;
|
||||||
|
this.completeStep = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
gotoEmergencyStep() {
|
||||||
|
this.studentStep = false;
|
||||||
|
this.parentStep = false;
|
||||||
|
this.emergencyStep = true;
|
||||||
|
this.completeStep = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
gotoCompleteStep() {
|
||||||
|
this.studentStep = false;
|
||||||
|
this.parentStep = false;
|
||||||
|
this.emergencyStep = false;
|
||||||
|
this.completeStep = true;
|
||||||
|
this.submitting = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
submit() {
|
||||||
|
if (this.submitting === true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.submitting = true;
|
||||||
|
this.emailService.sendVbsEmail(this.form.value)
|
||||||
|
.subscribe(
|
||||||
|
success => {this.gotoCompleteStep()},
|
||||||
|
error => {this.submitError();});
|
||||||
|
}
|
||||||
|
|
||||||
|
private submitError(){
|
||||||
|
this.submitting = false;
|
||||||
|
console.error("error");
|
||||||
|
let opts = new MatDialogConfig;
|
||||||
|
opts.data = { title:'Error','message':'Error submitting registration form. Please try again or contact us at (406) 494 - 5028.' };
|
||||||
|
let popup = this.matDialog.open(OkPopupComponent,opts);
|
||||||
|
this.submitButtonText = "Submit";
|
||||||
|
this.submitButtonDisabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerAnotherStudent() {
|
||||||
|
this.completeStep = false;
|
||||||
|
this.studentStep = true;
|
||||||
|
this.form.get('firstName').reset();
|
||||||
|
this.form.get('lastName').reset();
|
||||||
|
this.form.get('grade').reset();
|
||||||
|
this.form.get('dob').reset();
|
||||||
|
this.form.get('hasAllergies').reset();
|
||||||
|
this.form.get('allergies').reset();
|
||||||
|
this.form.get('hasDietaryRestrictions').reset();
|
||||||
|
this.form.get('dietaryRestrictions').reset();
|
||||||
|
this.form.get('attendedInPast').reset();
|
||||||
|
this.form.get('ridesBus').reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public stateList = [
|
||||||
|
{ code: 'AL', name: 'Alabama' }, { code: 'AK', name: 'Alaska' }, { code: 'AZ', name: 'Arizona' },
|
||||||
|
{ code: 'AR', name: 'Arkansas' }, { code: 'CA', name: 'California' }, { code: 'CO', name: 'Colorado' },
|
||||||
|
{ code: 'CT', name: 'Connecticut' }, { code: 'DE', name: 'Delaware' }, { code: 'FL', name: 'Florida' },
|
||||||
|
{ code: 'GA', name: 'Georgia' }, { code: 'HI', name: 'Hawaii' }, { code: 'ID', name: 'Idaho' },
|
||||||
|
{ code: 'IL', name: 'Illinois' }, { code: 'IN', name: 'Indiana' }, { code: 'IA', name: 'Iowa' },
|
||||||
|
{ code: 'KS', name: 'Kansas' }, { code: 'KY', name: 'Kentucky' }, { code: 'LA', name: 'Louisiana' },
|
||||||
|
{ code: 'ME', name: 'Maine' }, { code: 'MD', name: 'Maryland' }, { code: 'MA', name: 'Massachusetts' },
|
||||||
|
{ code: 'MI', name: 'Michigan' }, { code: 'MN', name: 'Minnesota' }, { code: 'MS', name: 'Mississippi' },
|
||||||
|
{ code: 'MO', name: 'Missouri' }, { code: 'MT', name: 'Montana' }, { code: 'NE', name: 'Nebraska' },
|
||||||
|
{ code: 'NV', name: 'Nevada' }, { code: 'NH', name: 'New Hampshire' }, { code: 'NJ', name: 'New Jersey' },
|
||||||
|
{ code: 'NM', name: 'New Mexico' }, { code: 'NY', name: 'New York' }, { code: 'NC', name: 'North Carolina' },
|
||||||
|
{ code: 'ND', name: 'North Dakota' }, { code: 'OH', name: 'Ohio' }, { code: 'OK', name: 'Oklahoma' },
|
||||||
|
{ code: 'OR', name: 'Oregon' }, { code: 'PA', name: 'Pennsylvania' }, { code: 'RI', name: 'Rhode Island' },
|
||||||
|
{ code: 'SC', name: 'South Carolina' }, { code: 'SD', name: 'South Dakota' }, { code: 'TN', name: 'Tennessee' },
|
||||||
|
{ code: 'TX', name: 'Texas' }, { code: 'UT', name: 'Utah' }, { code: 'VT', name: 'Vermont' },
|
||||||
|
{ code: 'VA', name: 'Virginia' }, { code: 'WA', name: 'Washington' }, { code: 'WV', name: 'West Virginia' },
|
||||||
|
{ code: 'WI', name: 'Wisconsin' }, { code: 'WY', name: 'Wyoming' }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
class Student {
|
||||||
|
public firstName: string;
|
||||||
|
public lastName: string;
|
||||||
|
public grade: number;
|
||||||
|
public birthday: string;
|
||||||
|
public allergies: string;
|
||||||
|
public dietaryRestrictions: string;
|
||||||
|
public attendedInPast: boolean;
|
||||||
|
public ridesBus: boolean;
|
||||||
|
public guardian: Guardian
|
||||||
|
public emergencyContact: EmergencyContact;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Guardian {
|
||||||
|
public firstName: string;
|
||||||
|
public lastName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class EmergencyContact {
|
||||||
|
public firstName: string;
|
||||||
|
public lastName: string;
|
||||||
|
}
|
||||||
|
|
@ -20,4 +20,5 @@ export const USER_GET_ALL_URL = environment.baseUrl + "/api2/users/a";
|
||||||
export const LOGIN_URL = environment.baseUrl + '/api2/login';
|
export const LOGIN_URL = environment.baseUrl + '/api2/login';
|
||||||
export const LOGIN_VALIDATE_TOKEN = '';
|
export const LOGIN_VALIDATE_TOKEN = '';
|
||||||
export const EMAIL_URL = environment.baseUrl + "/api2/email";
|
export const EMAIL_URL = environment.baseUrl + "/api2/email";
|
||||||
|
export const VBS_REGISTRATION_URL = environment.baseUrl + "/api2/vbs";
|
||||||
export const RANDOM_VERSE_URL = "//www.kingjamesbibleonline.org/popular-bible-verses-widget.php";
|
export const RANDOM_VERSE_URL = "//www.kingjamesbibleonline.org/popular-bible-verses-widget.php";
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { catchError } from 'rxjs/operators';
|
||||||
|
|
||||||
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
|
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { EMAIL_URL } from '../constants/urls';
|
import { EMAIL_URL, VBS_REGISTRATION_URL } from '../constants/urls';
|
||||||
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
|
@ -32,6 +32,11 @@ export class EmailService {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendVbsEmail(formData) {
|
||||||
|
return this.httpClient.post(VBS_REGISTRATION_URL, formData, {withCredentials:true})
|
||||||
|
.pipe(catchError(this.handleError));
|
||||||
|
}
|
||||||
|
|
||||||
private handleError(error: HttpErrorResponse) {
|
private handleError(error: HttpErrorResponse) {
|
||||||
if (error.error instanceof ErrorEvent) {
|
if (error.error instanceof ErrorEvent) {
|
||||||
// A client-side or network error occurred. Handle it accordingly.
|
// A client-side or network error occurred. Handle it accordingly.
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ router.use("/events", require("./events"));
|
||||||
router.use("/login", require("./login"));
|
router.use("/login", require("./login"));
|
||||||
router.use("/email", require("./email"));
|
router.use("/email", require("./email"));
|
||||||
router.use("/transactions", require("./transactions"));
|
router.use("/transactions", require("./transactions"));
|
||||||
|
router.use("/vbs", require("./vbs"));
|
||||||
|
|
||||||
|
|
||||||
router.use('/share',require('./share'));
|
router.use('/share',require('./share'));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,181 @@
|
||||||
|
var express = require('express');
|
||||||
|
var router = express.Router();
|
||||||
|
const nodemailer = require('nodemailer');
|
||||||
|
|
||||||
|
let transporter = nodemailer.createTransport({
|
||||||
|
host: 'smtp.ionos.com',
|
||||||
|
port: 587,
|
||||||
|
secure: false,
|
||||||
|
auth:{
|
||||||
|
user: 'mail@ofbbutte.com',
|
||||||
|
pass: '@2014OfbPwd'
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get("/",function(req,res){
|
||||||
|
res.status(200).json({"message":"Hello World"});
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/", function(req,res){
|
||||||
|
console.log(req.body);
|
||||||
|
//This is the honeypot field
|
||||||
|
//If it has something in it then we know it was filled out by a bot
|
||||||
|
if (!req.body.hp || req.body.hp != '.'){
|
||||||
|
res.status(200).json({"status":200,"message":"Success!"});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mailOptions = {
|
||||||
|
from: 'donotreply@ofbbutte.com',
|
||||||
|
to: 'djabsher@gmail.com',
|
||||||
|
subject: 'OFB - VBS Registration' + req.body.firstName,
|
||||||
|
html: generateRegistrationEmailHTML(req.body)
|
||||||
|
};
|
||||||
|
transporter.sendMail(mailOptions,(error, info) =>{
|
||||||
|
if (error){
|
||||||
|
console.log(error);
|
||||||
|
res.status(400).json({"status":400,"message":"There was an error","error":error.response});
|
||||||
|
} else {
|
||||||
|
res.status(200).json({"status":200,"message":"Success"});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a sectioned HTML email string for the registration form.
|
||||||
|
* Displays all fields even if they are empty.
|
||||||
|
* @param {Object} data - The value object from this.form.value
|
||||||
|
* @returns {string} Ready-to-send HTML string
|
||||||
|
*/
|
||||||
|
function generateRegistrationEmailHTML(data) {
|
||||||
|
|
||||||
|
// Helper to cleanly format boolean true/false fields
|
||||||
|
const formatBool = (val) => {
|
||||||
|
if (val === true || val === 'true') return 'Yes';
|
||||||
|
if (val === false || val === 'false') return 'No';
|
||||||
|
return val;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper to ensure we don't render literal 'null' or 'undefined' text
|
||||||
|
const sanitizeValue = (val) => {
|
||||||
|
if (val === null || val === undefined) return '';
|
||||||
|
return String(val).trim();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Define the layout sections and human-readable labels
|
||||||
|
const sections = [
|
||||||
|
{
|
||||||
|
title: "Student Information",
|
||||||
|
fields: [
|
||||||
|
{ label: "Student Name", value: `${sanitizeValue(data.firstName)} ${sanitizeValue(data.lastName)}`.trim() },
|
||||||
|
{ label: "Grade", value: sanitizeValue(data.grade) },
|
||||||
|
{ label: "Date of Birth", value: sanitizeValue(data.dob) },
|
||||||
|
{ label: "Has Allergies?", value: sanitizeValue(formatBool(data.hasAllergies)) },
|
||||||
|
{ label: "Allergies", value: sanitizeValue(data.allergies) },
|
||||||
|
{ label: "Has Dietary Restrictions?", value: sanitizeValue(formatBool(data.hasDietaryRestrictions)) },
|
||||||
|
{ label: "Dietary Restrictions", value: sanitizeValue(data.dietaryRestrictions) },
|
||||||
|
{ label: "Attended in Past?", value: sanitizeValue(formatBool(data.attendedInPast)) },
|
||||||
|
{ label: "Rides Bus?", value: sanitizeValue(formatBool(data.ridesBus)) }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Parent / Guardian Contact",
|
||||||
|
fields: [
|
||||||
|
{ label: "Parent Name", value: `${sanitizeValue(data.parentFirstName)} ${sanitizeValue(data.parentLastName)}`.trim() },
|
||||||
|
{ label: "Email", value: sanitizeValue(data.parentEmail) },
|
||||||
|
{ label: "Mobile Phone", value: sanitizeValue(data.parentMobilePhone) },
|
||||||
|
{ label: "Home Phone", value: sanitizeValue(data.parentHomePhone) },
|
||||||
|
{ label: "Work Phone", value: sanitizeValue(data.parentWorkPhone) },
|
||||||
|
{ label: "Address", value: `${sanitizeValue(data.address1)}${data.address2 ? ', ' + sanitizeValue(data.address2) : ''}, ${sanitizeValue(data.city)}, ${sanitizeValue(data.state)} ${sanitizeValue(data.zip)}`.trim().replace(/^,|,$/g, '') }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Emergency Contact",
|
||||||
|
fields: [
|
||||||
|
{ label: "Same as Parent?", value: sanitizeValue(formatBool(data.emergencySameAsParent)) },
|
||||||
|
{ label: "Emergency Name", value: `${sanitizeValue(data.emergencyFirstName)} ${sanitizeValue(data.emergencyLastName)}`.trim() },
|
||||||
|
{ label: "Emergency Phone", value: sanitizeValue(data.emergencyPhone) }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
// Map the sections array into HTML tables (No filtering out fields!)
|
||||||
|
const htmlContent = sections.map(section => {
|
||||||
|
const rows = section.fields.map(field => `
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 10px 12px; border-bottom: 1px solid #edf2f7; font-weight: 600; color: #4a5568; width: 35%; font-size: 14px;">
|
||||||
|
${field.label}
|
||||||
|
</td>
|
||||||
|
<td style="padding: 10px 12px; border-bottom: 1px solid #edf2f7; color: #2d3748; font-size: 14px;">
|
||||||
|
${field.value}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
`).join('');
|
||||||
|
|
||||||
|
return `
|
||||||
|
<h3 style="color: #4f46e5; font-size: 16px; margin-top: 24px; margin-bottom: 10px; border-bottom: 2px solid #e2e8f0; padding-bottom: 6px; font-weight: 600;">
|
||||||
|
${section.title}
|
||||||
|
</h3>
|
||||||
|
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse; margin-bottom: 15px;">
|
||||||
|
<tbody>
|
||||||
|
${rows}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
`;
|
||||||
|
}).join('');
|
||||||
|
|
||||||
|
return `
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>New Registration Submission</title>
|
||||||
|
</head>
|
||||||
|
<body style="margin: 0; padding: 0; background-color: #f7fafc; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;">
|
||||||
|
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="background-color: #f7fafc; padding: 24px 0;">
|
||||||
|
<tr>
|
||||||
|
<td align="center">
|
||||||
|
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 650px; background-color: #ffffff; border-radius: 8px; overflow: hidden; box-shadow: 0 4px 6px rgba(0,0,0,0.05); border: 1px solid #e2e8f0;">
|
||||||
|
|
||||||
|
<!-- Header Banner -->
|
||||||
|
<tr>
|
||||||
|
<td style="background-color: #4f46e5; padding: 24px; text-align: center;">
|
||||||
|
<h1 style="color: #ffffff; margin: 0; font-size: 20px; font-weight: 600; letter-spacing: 0.5px;">
|
||||||
|
New Registration Submitted
|
||||||
|
</h1>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Content Body -->
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 24px 32px;">
|
||||||
|
<p style="margin-top: 0; margin-bottom: 16px; font-size: 15px; color: #718096; line-height: 1.5;">
|
||||||
|
A new form submission has been received.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
${htmlContent}
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<tr>
|
||||||
|
<td style="background-color: #f8fafc; padding: 20px; text-align: center; font-size: 12px; color: #a0aec0; border-top: 1px solid #edf2f7;">
|
||||||
|
This email was automatically generated and sent from the registration system.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
Loading…
Reference in New Issue