Skip to content

Commit 0ddf20e

Browse files
author
Salma Alam-Naylor
committed
Form set up
1 parent be067a3 commit 0ddf20e

15 files changed

+330
-2
lines changed

apps/fretonator-web/src/app/app-routing.module.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,17 @@ const about: Route = {
1111
loadChildren: () => import('./pages/about/about.module').then((mod) => mod.AboutModule),
1212
};
1313

14+
const contact: Route = {
15+
path: 'contact',
16+
loadChildren: () => import('./pages/contact/contact.module').then((mod) => mod.ContactModule),
17+
};
18+
1419
const notFound: Route = {
1520
path: '**',
1621
loadChildren: () => import('./pages/not-found/not-found.module').then((mod) => mod.NotFoundModule),
1722
};
1823

19-
const routes: Routes = [home, about, notFound];
24+
const routes: Routes = [home, about, contact, notFound];
2025

2126
@NgModule({
2227
imports: [

apps/fretonator-web/src/app/common/header/header.component.html

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,18 @@
4646
>About</a
4747
>
4848
</li>
49+
<li class="header__linksItem">
50+
<a [routerLink]="['/', 'contact']"
51+
routerLinkActive="header__linksItemLink--active"
52+
class="header__linksItemLink"
53+
>Contact</a
54+
>
55+
</li>
4956
<li class="header__linksItem">
5057
<a href="https://www.buymeacoffee.com/fretonator"
5158
rel="nofollow noopener noreferrer"
5259
class="header__linksItemLink"
53-
target="_blank">Support</a>
60+
target="_blank">Donate</a>
5461
</li>
5562
</ul>
5663
</header>
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<form [name]="formName"
2+
data-netlify="true"
3+
method="POST"
4+
action="/contact/success"
5+
netlify-honeypot="bot-field"
6+
[formGroup]="form"
7+
(ngSubmit)="onSubmit()">
8+
<div>
9+
<label for="name">
10+
Name
11+
</label>
12+
<input id="name" name="Name" type="text" formControlName="name">
13+
<ng-container *ngIf="name.touched">
14+
<p *ngIf="name.errors?.required">Enter your name, yo!</p>
15+
<p *ngIf="name.errors?.pattern">Please enter a valid name!</p>
16+
<p *ngIf="name.errors?.maxlength">Come on, your name isn't actually {{name.errors?.maxlength.actualLength}}
17+
characters long!</p>
18+
<pre>{{name.errors | json}}</pre>
19+
</ng-container>
20+
</div>
21+
<div>
22+
<label for="email">
23+
Email
24+
</label>
25+
<input id="email" name="Email" type="email" formControlName="email">
26+
<ng-container *ngIf="email.touched">
27+
<p *ngIf="email.errors?.email">An email address isn't required, but if you'd like me to reply to your message,
28+
please enter a valid email address!</p>
29+
<pre>{{email.errors | json}}</pre>
30+
</ng-container>
31+
32+
</div>
33+
<div>
34+
<label for="message">
35+
Message
36+
</label>
37+
<textarea id="message" name="Message" formControlName="message"></textarea>
38+
<ng-container *ngIf="message.touched">
39+
<p *ngIf="message.errors?.required">Go on, give me some feedback!</p>
40+
<p *ngIf="message.errors?.minlength">Go on, give me some feedback!</p>
41+
<pre>{{message.errors | json}}</pre>
42+
</ng-container>
43+
44+
<div>
45+
<label for="bot-field">Don't fill this out if you're human!</label>
46+
<input type="text" id="bot-field" name="bot-field" formControlName="honeypot">
47+
<pre>{{honeypot.errors | json}}</pre>
48+
</div>
49+
50+
<input type="submit" class="form__submit" formControlName="submit" aria-label="Submit Form"/>
51+
<p *ngIf="formSubmitError">Oh no! Didn't work.</p>
52+
</div>
53+
54+
</form>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@import '../../../../styles/mixins';
2+
3+
.form__submit {
4+
@include hard_button_base();
5+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { ContactIndexComponent } from './contact-index.component';
4+
5+
describe('ContactIndexComponent', () => {
6+
let component: ContactIndexComponent;
7+
let fixture: ComponentFixture<ContactIndexComponent>;
8+
9+
beforeEach(async(() => {
10+
TestBed.configureTestingModule({
11+
declarations: [ ContactIndexComponent ]
12+
})
13+
.compileComponents();
14+
}));
15+
16+
beforeEach(() => {
17+
fixture = TestBed.createComponent(ContactIndexComponent);
18+
component = fixture.componentInstance;
19+
fixture.detectChanges();
20+
});
21+
22+
it('should create', () => {
23+
expect(component).toBeTruthy();
24+
});
25+
});
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import { Component, OnInit } from '@angular/core';
2+
import { FormControl, FormGroup, Validators } from '@angular/forms';
3+
import { FormService } from '../form.service';
4+
import { tap } from 'rxjs/operators';
5+
import { Router } from '@angular/router';
6+
7+
@Component({
8+
selector: 'app-contact-index',
9+
templateUrl: './contact-index.component.html',
10+
styleUrls: ['./contact-index.component.scss']
11+
})
12+
export class ContactIndexComponent implements OnInit {
13+
formName: 'contact';
14+
formSubmitError = false;
15+
form = new FormGroup({
16+
honeypot: new FormControl('', [
17+
Validators.maxLength(0)
18+
]),
19+
name: new FormControl('', [
20+
Validators.required,
21+
Validators.maxLength(81),
22+
Validators.pattern(/[a-zA-Z]+(([',. -][a-zA-Z ])?[a-zA-Z]*)/)
23+
]),
24+
email: new FormControl('', [
25+
Validators.email
26+
]),
27+
message: new FormControl('', [
28+
Validators.required,
29+
Validators.minLength(30)
30+
]),
31+
submit: new FormControl('Submit', [])
32+
}, {
33+
updateOn: 'blur'
34+
});
35+
36+
constructor(private formService: FormService, private router: Router) {
37+
}
38+
39+
ngOnInit(): void {
40+
}
41+
42+
onSubmit() {
43+
if (this.form.invalid) {
44+
this.form.markAllAsTouched();
45+
return;
46+
}
47+
48+
this.formSubmitError = false;
49+
this.submit.disable();
50+
51+
const form = {
52+
Name: this.name.value,
53+
Email: this.email.value,
54+
Message: this.message.value,
55+
'form-name': this.formName,
56+
'bot-field': this.honeypot.value
57+
};
58+
59+
this.formService.submit('/contact/success', form)
60+
.pipe(tap(() => this.submit.enable()))
61+
.subscribe(
62+
() => this.onSuccess(),
63+
(err) => this.onFail());
64+
}
65+
66+
async onSuccess() {
67+
await (this.router.navigate(['/', 'contact', 'success']));
68+
}
69+
70+
onFail() {
71+
this.formSubmitError = true;
72+
}
73+
74+
get name() {
75+
return this.form.get('name');
76+
}
77+
78+
get email() {
79+
return this.form.get('email');
80+
}
81+
82+
get message() {
83+
return this.form.get('message');
84+
}
85+
86+
get submit() {
87+
return this.form.get('submit');
88+
}
89+
90+
get honeypot() {
91+
return this.form.get('honeypot');
92+
}
93+
94+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { NgModule } from '@angular/core';
2+
import { Route, RouterModule, Routes } from '@angular/router';
3+
import { ContactIndexComponent } from './contact-index/contact-index.component';
4+
import { ContactSuccessComponent } from './contact-success/contact-success.component';
5+
6+
const contact: Route = {
7+
path: '',
8+
pathMatch: 'full',
9+
component: ContactIndexComponent,
10+
};
11+
12+
const success: Route = {
13+
path: 'success',
14+
component: ContactSuccessComponent,
15+
};
16+
17+
const routes: Routes = [contact, success];
18+
19+
@NgModule({
20+
imports: [RouterModule.forChild(routes)],
21+
exports: [RouterModule]
22+
})
23+
export class ContactRoutingModule { }
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<p>contact-success works!</p>

apps/fretonator-web/src/app/pages/contact/contact-success/contact-success.component.scss

Whitespace-only changes.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { ContactSuccessComponent } from './contact-success.component';
4+
5+
describe('ContactSuccessComponent', () => {
6+
let component: ContactSuccessComponent;
7+
let fixture: ComponentFixture<ContactSuccessComponent>;
8+
9+
beforeEach(async(() => {
10+
TestBed.configureTestingModule({
11+
declarations: [ ContactSuccessComponent ]
12+
})
13+
.compileComponents();
14+
}));
15+
16+
beforeEach(() => {
17+
fixture = TestBed.createComponent(ContactSuccessComponent);
18+
component = fixture.componentInstance;
19+
fixture.detectChanges();
20+
});
21+
22+
it('should create', () => {
23+
expect(component).toBeTruthy();
24+
});
25+
});

0 commit comments

Comments
 (0)