diff --git a/server/database/confirmations.json b/server/database/confirmations.json index 9e26dfe..b4f5feb 100644 --- a/server/database/confirmations.json +++ b/server/database/confirmations.json @@ -1 +1 @@ -{} \ No newline at end of file +{"i6bxw12wk2k5lzpk":{"number":32,"timestamp":1572855599882,"message":"Henl"}} \ No newline at end of file diff --git a/server/database/data.json b/server/database/data.json index 70a5157..4e16b67 100644 --- a/server/database/data.json +++ b/server/database/data.json @@ -1 +1 @@ -{"data":[false,false,false,false,false,false,false,false,false,false,false,false,true,false,false,false,false,false,false,true,false,false,false,false,true,false,false,false,false,false,false,true,false,false,false,false,false,true,false,false,false,false,false,false,false,false,false,false,false,true,false,false,false,false,false,false,false,false,false,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,false,false,false,false,false,false,false,false,false,false,false,false,false]} \ No newline at end of file +[false,false,false,false,false,false,false,false,false,false,false,false,true,false,false,false,false,false,false,true,false,false,false,false,true,false,false,false,false,false,false,true,false,false,false,false,false,true,false,false,false,false,false,false,false,false,false,false,false,true,false,false,false,false,false,false,false,false,false,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,false,false,false,false,false,false,false,false,false,false,false,false,false] diff --git a/server/routes/index.js b/server/routes/index.js index 85658e6..4602492 100644 --- a/server/routes/index.js +++ b/server/routes/index.js @@ -7,7 +7,7 @@ const path = __dirname + '/../database/data.json' /* GET home page. */ router.get('/', function(req, res, next) { - res.json(JSON.parse(fs.readFileSync(path).toString())); + res.json({ result: { success: true, data: JSON.parse(fs.readFileSync(path).toString())}}); }); router.post('/login', (req, res, _next) => { @@ -21,7 +21,7 @@ router.post('/login', (req, res, _next) => { router.post('/update/:index', (req, res, _next) => { if (req.body.username === 'Mediatheek' && req.body.password === '@MediatheekHetHeerenlanden!') { const data = JSON.parse(fs.readFileSync(path).toString()); - data.data[Number(req.params.index)] = data.data[Number(req.params.index)] ? false : true; + data[Number(req.params.index)] = data[Number(req.params.index)] ? false : true; fs.writeFileSync(path, JSON.stringify(data)); } res.send(null); diff --git a/server/routes/mail.js b/server/routes/mail.js index 3dfd3e4..8769090 100644 --- a/server/routes/mail.js +++ b/server/routes/mail.js @@ -15,8 +15,19 @@ const readJsonFile = (file) => { return JSON.parse(fs.readFileSync(path.join(__dirname, file)).toString()); }; +/** This function is for the validation of the email address. + * Required arguments (in POST) are: + * email: string + * message: string + * number: number + * name: string + */ router.post('/', (req, res, _next) => { + + // Generate an id. const id = uniqid(); + + // Send an email with a link to validate the id. sendmail({ from: 'surpise-box@jobbel.nl', to: req.body.email, @@ -24,6 +35,7 @@ router.post('/', (req, res, _next) => { html: ` +

Beste ${req.body.name},

Deze email is verzonden omdat u surprise box ${req.body.number} voor de kerstmarkt van Het Heerenlanden heeft aangevraagd.
Om uw aanvraag te bevestigen, moet u om de volgende link klikken:
@@ -34,22 +46,38 @@ router.post('/', (req, res, _next) => { `, + + // Once it is sent }, function(err, reply) { + + // If there's an error if (err) { + // Notify the front-end res.json({result: {success: false, data: err}}); } else { + + // Add the user's data to the database identified by the id. writeJsonFile(confirmationsPath, { + // Make sure that the other records are preserved. ...readJsonFile(confirmationsPath), + // Then add the new one [id]: { + 'name': req.body.name, 'number': Number(req.body.number), - 'timestamp': Date.now() + 'timestamp': Date.now(), + 'message': req.body.message } }) + // Notify the front-end res.json({result: {success: true, data: reply}}); } }); }); +/** This function is used when a user clicks on the link in their email. + * + * This should be extremely user-friendly. + */ router.get('/validate/:id', (req, res, _next) => { const data = readJsonFile(confirmationsPath); const id = req.params.id; @@ -58,7 +86,8 @@ router.get('/validate/:id', (req, res, _next) => { if (data[id] && Date.now() <= (data[id].timestamp + 3600000 /* one hour in milliseconds */)) { // send success result - res.json({result: {success: true, data: data[id].number}}); + // res.json({result: {success: true, data: data[id].number}}); + res.render('validate-success', {number: data[id].number}) // Delete the record delete data[id]; @@ -69,7 +98,8 @@ router.get('/validate/:id', (req, res, _next) => { if (data[id] && Date.now() > (data[id].timestamp + 3600000)) { // send result - res.json({result: {success: false, data: 'expired'}}); + //res.json({result: {success: false, data: 'expired'}}); + res.render('validate-error', {data: 'expired', number: data[id].number }); // delete the record delete data[id]; @@ -77,7 +107,8 @@ router.get('/validate/:id', (req, res, _next) => { // If the id is not found } else { - res.json({result: {success: false, data: 'ID not found'}}); + //res.json({result: {success: false, data: 'ID not found'}}); + res.render('validate-error', {data: 'not found'}); } } }); diff --git a/server/views/validate-error.pug b/server/views/validate-error.pug new file mode 100644 index 0000000..b8ef317 --- /dev/null +++ b/server/views/validate-error.pug @@ -0,0 +1,8 @@ +extends layout.pug +block content + if data == 'expired' + h1 Uw aanvraag is verlopen + p Probeer uw aanvraag voor surprise box #{number} opnieuw in te dienen. + else if data == 'not found' + h1 Een aanvraag met de gegeven ID is niet gevonden + p Als u gelooft dat dit een fout is, meld het dan bij het surprise box team van Het Heerenlanden. diff --git a/server/views/validate-success.pug b/server/views/validate-success.pug new file mode 100644 index 0000000..ba75bbe --- /dev/null +++ b/server/views/validate-success.pug @@ -0,0 +1,4 @@ +extends layout.pug +block content + h1 Uw aanvraag voor box #{number} is sucessvol verstuurd! + p U krijgt binnenkort antwoord van het surprise box team van Het Heerenlanden. diff --git a/src/app/app.component.html b/src/app/app.component.html index 1d38334..f455580 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,8 +1,10 @@

+
-
\ No newline at end of file + + diff --git a/src/app/app.component.scss b/src/app/app.component.scss index 3948d74..8271b68 100644 --- a/src/app/app.component.scss +++ b/src/app/app.component.scss @@ -16,7 +16,7 @@ body { @if type-of($number) == 'number' and not unitless($number) { @return $number / ($number * 0 + 1); } - + @return $number; } @@ -44,7 +44,7 @@ nav { top: 50%; right: 20px; transform: translate(0, -50%); - i { + fa-icon { padding: 5px; } } @@ -62,4 +62,13 @@ main { border-radius: 1em; background-color: #ffffff; text-align: center; -} \ No newline at end of file +} + +.overlay { + background-color: rgba(0,0,0,0.5); + position:fixed; + left:0; + top: 0; + width:100%; + height:100%; +} diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 471edab..4d347ae 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,4 +1,6 @@ import { Component } from '@angular/core'; +import { FormService } from './services/form.service'; +import { faSignInAlt } from '@fortawesome/free-solid-svg-icons'; @Component({ selector: 'app-root', @@ -6,5 +8,9 @@ import { Component } from '@angular/core'; styleUrls: ['./app.component.scss'] }) export class AppComponent { - title = 'HHFSBRS'; + + faSignInAlt = faSignInAlt; + + constructor(public form: FormService) { } + } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 6b4b4bc..3e170d6 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -8,12 +8,14 @@ import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { HomeComponent } from './components/home/home.component'; import { LoginComponent } from './components/login/login.component'; +import { FormComponent } from './components/form/form.component'; @NgModule({ declarations: [ AppComponent, HomeComponent, - LoginComponent + LoginComponent, + FormComponent ], imports: [ BrowserModule, diff --git a/src/app/components/form/form.component.html b/src/app/components/form/form.component.html new file mode 100644 index 0000000..3193ec4 --- /dev/null +++ b/src/app/components/form/form.component.html @@ -0,0 +1,27 @@ +
+ + + +
+ +

Formulier voor surpise box {{ number }}

+ + +
+ + +
+ + +
+ + + +
+ +
+

Uw aanvraag is ingediend

+

Check uw mailbox om uw aanvrag te valideren. Als u de mail niet kan vinden, check dan ook uw spam.

+
+ +
diff --git a/src/app/components/form/form.component.scss b/src/app/components/form/form.component.scss new file mode 100644 index 0000000..72536e1 --- /dev/null +++ b/src/app/components/form/form.component.scss @@ -0,0 +1,16 @@ +.container { + background: white; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + padding-bottom: 20px; + + fa-icon { + position: relative; + float: right; + padding-right: 10px; + padding-top: 10px; + cursor: pointer; + } +} diff --git a/src/app/components/form/form.component.spec.ts b/src/app/components/form/form.component.spec.ts new file mode 100644 index 0000000..0ace80a --- /dev/null +++ b/src/app/components/form/form.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { FormComponent } from './form.component'; + +describe('FormComponent', () => { + let component: FormComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ FormComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(FormComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/form/form.component.ts b/src/app/components/form/form.component.ts new file mode 100644 index 0000000..743603c --- /dev/null +++ b/src/app/components/form/form.component.ts @@ -0,0 +1,45 @@ +import { Component, OnInit, Input } from '@angular/core'; +import { FormBuilder, Validators } from '@angular/forms'; +import { DataService } from 'src/app/services/data.service'; +import { faTimes } from '@fortawesome/free-solid-svg-icons'; +import { FormService } from 'src/app/services/form.service'; + +@Component({ + selector: 'app-form', + templateUrl: './form.component.html', + styleUrls: ['./form.component.scss'] +}) +export class FormComponent implements OnInit { + // tslint:disable-next-line: no-input-rename + @Input('number') number: number; + + faTimes = faTimes; + + form = this.fb.group({ + email: ['', [Validators.email, Validators.required]], + name: ['', Validators.required], + message: ['', Validators.required] + }); + + submitted = false; + + constructor( + private fb: FormBuilder, + private data: DataService, + public formService: FormService + ) { } + + ngOnInit() { + } + + onSubmit() { + const value = this.form.value; + + value.number = 32; + + this.data.mail(value.email, value.number, value.message, value.name).subscribe(res => { + this.submitted = true; + }); + } + +} diff --git a/src/app/components/home/home.component.html b/src/app/components/home/home.component.html index 88fae81..6cfc113 100644 --- a/src/app/components/home/home.component.html +++ b/src/app/components/home/home.component.html @@ -12,8 +12,9 @@
Log uit
-
- +
+ + {{ i + 1 }}
{{ item ? 'Gereserveerd' : 'Klik om te reserveren' }}
diff --git a/src/app/components/home/home.component.scss b/src/app/components/home/home.component.scss index 7e4808a..bda9e1f 100644 --- a/src/app/components/home/home.component.scss +++ b/src/app/components/home/home.component.scss @@ -1,5 +1,9 @@ // HLC blue (0,175,241) red (247,0,0) yellow (255,255,0) + a.disabled { + cursor: not-allowed; + } + p:nth-child(2) { border-bottom: 1px solid rgba(0,0,0,0.5); font-weight: bold; diff --git a/src/app/components/home/home.component.ts b/src/app/components/home/home.component.ts index 25f8323..58c5268 100644 --- a/src/app/components/home/home.component.ts +++ b/src/app/components/home/home.component.ts @@ -3,6 +3,7 @@ import { Observable } from 'rxjs'; import { ApiData, DataService } from 'src/app/services/data.service'; import { Router } from '@angular/router'; import { faGift } from '@fortawesome/free-solid-svg-icons'; +import { FormService } from 'src/app/services/form.service'; @Component({ selector: 'app-home', @@ -18,7 +19,8 @@ export class HomeComponent implements OnInit { constructor( private dataService: DataService, - private router: Router + private router: Router, + public form: FormService ) { } ngOnInit() { diff --git a/src/app/services/data.service.ts b/src/app/services/data.service.ts index e47a0ea..b3e5bb0 100644 --- a/src/app/services/data.service.ts +++ b/src/app/services/data.service.ts @@ -3,7 +3,10 @@ import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; export interface ApiData { - data: Array; + result: { + success: boolean, + data: any + }; } @Injectable({ @@ -26,4 +29,9 @@ export class DataService { update(index: number, username: string, password: string): Observable { return this.http.post(this.apiUrl + '/update/' + index, {username, password}); } + + // tslint:disable-next-line: variable-name + mail(email: string, number: number, message: string, name: string): Observable { + return this.http.post(this.apiUrl + '/mail/', {email, number, message, name}); + } } diff --git a/src/app/services/form.service.spec.ts b/src/app/services/form.service.spec.ts new file mode 100644 index 0000000..6e4756e --- /dev/null +++ b/src/app/services/form.service.spec.ts @@ -0,0 +1,12 @@ +import { TestBed } from '@angular/core/testing'; + +import { FormService } from './form.service'; + +describe('FormService', () => { + beforeEach(() => TestBed.configureTestingModule({})); + + it('should be created', () => { + const service: FormService = TestBed.get(FormService); + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/services/form.service.ts b/src/app/services/form.service.ts new file mode 100644 index 0000000..d3a6589 --- /dev/null +++ b/src/app/services/form.service.ts @@ -0,0 +1,22 @@ +import { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root' +}) +export class FormService { + + visible = false; + number: number; + + showForm(number: number) { + this.number = number; + this.visible = true; + } + + hideForm() { + this.visible = false; + this.number = undefined; + } + + constructor() { } +} diff --git a/src/index.html b/src/index.html index 28af454..4dadbae 100644 --- a/src/index.html +++ b/src/index.html @@ -7,7 +7,6 @@ -