-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement NodeJS code to enable contact form functionality
- Loading branch information
Showing
39 changed files
with
66,058 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,8 @@ | ||
# alexbates.github.io | ||
My personal portfolio. | ||
|
||
Browse by going to https://alexbates.github.io | ||
Browse by going to https://alexbates.github.io | ||
|
||
All client side files are located at both / and /public. The files at / are used for browsing at https://alexbates.github.io, while the files at /public are used for running with NodeJS. | ||
|
||
NodeJS is required for contact form functionality. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
const express = require('express'); | ||
const app = express(); | ||
// Import path module into script, | ||
const path = require('path'); | ||
// Import the nodemailer module into script, install with npm install nodemailer | ||
const nodemailer = require('nodemailer'); | ||
// The port the node app runs on | ||
const port = 3000; | ||
|
||
// For parsing application/x-www-form-urlencoded | ||
app.use(express.urlencoded({ extended: true })); | ||
// The public directory includes files the client has access to | ||
app.use(express.static(path.join(__dirname, 'public'))); | ||
|
||
app.post('/submit-form', (req, res) => { | ||
// Access form data from HTML form, including name, email, subject, and message | ||
const name = req.body.name; | ||
const email = req.body.email; | ||
const subject = req.body.subject; | ||
const message = req.body.text; | ||
// A regular expression is used to validate email address | ||
const regex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; | ||
// Form has already been validated client side | ||
// Validate form again server side. If it validates, proceeed with sending of email with contact message | ||
if(name !== '' && email !== '' && subject !== '' && message !== '' && regex.test(email)) { | ||
// Create a transporter object using SMTP transport | ||
let transporter = nodemailer.createTransport({ | ||
// Outgoing server for email account | ||
host: 'mail.REDACTED.com', | ||
// Custom port | ||
port: 2525, | ||
// Do not use SSL | ||
secure: false, | ||
auth: { | ||
// Email account username | ||
user: '[email protected]', | ||
// Email account password | ||
pass: 'REDACTEDPASSWORD' | ||
} | ||
}); | ||
|
||
// Define email options | ||
let options = { | ||
// Sender for email | ||
from: '[email protected]', | ||
// Recipient for email | ||
to: '[email protected]', | ||
// Subject for email | ||
subject: subject, | ||
// Body of email | ||
text: `Name: ${name}\nEmail: ${email}\nMessage: ${message}` | ||
}; | ||
|
||
// Send email using nodemailer | ||
transporter.sendMail(options, (error, info) => { | ||
if (error) { | ||
// Send the contact form back to client, but with an error message at top of the form | ||
res.sendFile(__dirname + '/public/contact/contact-error-email.html'); | ||
} else { | ||
// Send the contact form back to client, but with a success message at top of the form | ||
res.sendFile(__dirname + '/public/contact/contact-success.html'); | ||
} | ||
}); | ||
} | ||
else { | ||
// Send the contact form back to client, but with an error message at top of the form | ||
res.sendFile(__dirname + '/public/contact/contact-error-validate.html'); | ||
} | ||
}); | ||
|
||
app.listen(port, () => { | ||
console.log(`Server running on http://localhost:${port}`); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<!-- Control size of viewport, prevent zooming --> | ||
<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
<title>Alex Bates - Contact</title> | ||
<!-- Link a stylesheet that applies sitewide as well as one that is page specific --> | ||
<link href="../stylesheets/global-ab.css" rel='stylesheet' type='text/css'> | ||
<link href="../stylesheets/contact.css" rel='stylesheet' type='text/css'> | ||
<!-- Import externally hosted Merriweather font family --> | ||
<link href="https://fonts.googleapis.com/css2?family=Annapurna+SIL:wght@400;700&family=Fredoka:[email protected]&family=Merriweather:ital,wght@0,300;0,400;0,700;0,900;1,300;1,400;1,700;1,900&display=swap" rel="stylesheet"> | ||
<!-- Wait until DOM is loaded until loading scripts --> | ||
<script defer src="../scripts/global.js"></script> | ||
<script defer src="../scripts/contact.js"></script> | ||
</head> | ||
<body> | ||
|
||
<header class="navbar"> | ||
<!-- Create a container that is centered on screens wider than 1200px --> | ||
<div class="navbarinner"> | ||
<!-- Hamburger nav menu that only displays on mobile devices --> | ||
<nav class="mobilemenu"> | ||
<!-- Create hidden checkbox that is used to open and close menu --> | ||
<input id="hiddencheckbox" type="checkbox"> | ||
<label class="mobilemenubtn" for="hiddencheckbox"> | ||
<span></span> | ||
</label> | ||
<ul class="mobilemenubox"> | ||
<li><a class="mobilemenuitem" href="/">Home</a></li> | ||
<li><a class="mobilemenuitem" href="/about/">About</a></li> | ||
<li><a class="mobilemenuitem" href="/contact/">Contact</a></li> | ||
<!-- Github link that opens in new tab when clicked --> | ||
<li><a class="mobilemenuitem mobilegithub" href="https://github.com/alexbates/" target="_blank"> | ||
Github | ||
<!-- Credits to Flowbite for the Link icon https://flowbite.com/icons/ --> | ||
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> | ||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.2 9.8a3.4 3.4 0 0 0-4.8 0L5 13.2A3.4 3.4 0 0 0 9.8 18l.3-.3m-.3-4.5a3.4 3.4 0 0 0 4.8 0L18 9.8A3.4 3.4 0 0 0 13.2 5l-1 1"/> | ||
</svg> | ||
</a></li> | ||
</ul> | ||
</nav> | ||
<!-- Logo image that displays at left of navbar on desktop and center on mobile --> | ||
<!-- Division is used instead of img since img requires an src attribute --> | ||
<div class="logo"></div> | ||
<div class="themeselector"> | ||
<!-- Create hidden checkbox that is used to switch between themes --> | ||
<input type="checkbox" class="checkbox" id="checkbox"> | ||
<!-- Use a label that acts a button to toggle the checkbox --> | ||
<label for="checkbox" class="checkbox-label"> | ||
<span class="ts-sun">☀</span> | ||
<span class="ts-moon">☽</span> | ||
<span class="ball"></span> | ||
</label> | ||
</div> | ||
<!-- Site navigation that only appears on screens wider than 600px --> | ||
<nav class="desktopnav"> | ||
<div class="github"> | ||
<a href="https://github.com/alexbates/" target="_blank"> | ||
<!-- Credits to Flowbite for the Github icon https://flowbite.com/icons/ --> | ||
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"> | ||
<path fill-rule="evenodd" d="M12 2c-2.4 0-4.7.9-6.5 2.4a10.5 10.5 0 0 0-2 13.1A10 10 0 0 0 8.7 22c.5 0 .7-.2.7-.5v-2c-2.8.7-3.4-1.1-3.4-1.1-.1-.6-.5-1.2-1-1.5-1-.7 0-.7 0-.7a2 2 0 0 1 1.5 1.1 2.2 2.2 0 0 0 1.3 1 2 2 0 0 0 1.6-.1c0-.6.3-1 .7-1.4-2.2-.3-4.6-1.2-4.6-5 0-1.1.4-2 1-2.8a4 4 0 0 1 .2-2.7s.8-.3 2.7 1c1.6-.5 3.4-.5 5 0 2-1.3 2.8-1 2.8-1 .3.8.4 1.8 0 2.7a4 4 0 0 1 1 2.7c0 4-2.3 4.8-4.5 5a2.5 2.5 0 0 1 .7 2v2.8c0 .3.2.6.7.5a10 10 0 0 0 5.4-4.4 10.5 10.5 0 0 0-2.1-13.2A9.8 9.8 0 0 0 12 2Z" clip-rule="evenodd"/> | ||
</svg> | ||
</a> | ||
</div> | ||
<!-- An unordered list contains links to other pages --> | ||
<ul class="navlist"> | ||
<li><span><a href="/">Home</a></span></li><li><span><a href="/about/">About</a></span></li><li class="active"><span>Contact</span></li> | ||
</ul> | ||
</nav> | ||
</div> | ||
</header> | ||
<main> | ||
<!-- A fixed height division allows content to overflow, while still being contained within main --> | ||
<div class="block1"> | ||
<!-- division has fixed width and is centered on screens wider than 1200px --> | ||
<div class="maininner"> | ||
<!-- Appears on left side on desktop and top on mobile --> | ||
<div class="mainleft"> | ||
<!-- Credits to Flowbite for the Mailbox icon https://flowbite.com/icons/ --> | ||
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> | ||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 16v-5.5C11 8.5 9.4 7 7.5 7m3.5 9H4v-5.5C4 8.5 5.6 7 7.5 7m3.5 9v4M7.5 7H14m0 0V4h2.5M14 7v3m-3.5 6H20v-6a3 3 0 0 0-3-3m-2 9v4m-8-6.5h1"/> | ||
</svg> | ||
<h1>Reach Out</h1> | ||
<h3>Use this form to send me an email.</h3> | ||
</div> | ||
<!-- Appears on right side on desktop and bottom on mobile --> | ||
<div class="mainright"> | ||
<h2>Send Me a Message</h2> | ||
<!-- Display error message if email fails to send server side --> | ||
<p id="formError">Error: the email failed to send.</p> | ||
<!-- Contact form labels describe the content of the inputs and text area --> | ||
<!-- Form label spans are used for error messages and are empty except when validation fails --> | ||
<!-- Form inputs, textarea, and spans use unique ids to enable manipulation with javascript --> | ||
<form id="form" class="contactform" action="/submit-form" method="post"> | ||
<label for="name">Name <span id="errorname" class="errorspan"></span></label> | ||
<input id="name" name="name" type="text"> | ||
<label for="email">Email <span id="erroremail" class="errorspan"></span></label> | ||
<input id="email" name="email" type="text"> | ||
<label for="subject">Subject <span id="errorsubject" class="errorspan"></span></label> | ||
<input id="subject" name="subject" type="text"> | ||
<label for="message"><span class="your">Your </span>Message <span id="errormessage" class="errorspan"></span></label> | ||
<textarea rows="3" id="message" name="text"></textarea> | ||
<!-- Form submit button consists of 'Send' text and icon contained within spans --> | ||
<button type="submit"> | ||
<span class="btn-text">Send</span> | ||
<span class="btn-icon"> | ||
<!-- Credits to Flowbite for the Paper Plane (send) icon https://flowbite.com/icons/ --> | ||
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"> | ||
<path fill-rule="evenodd" d="M12 2c.4 0 .8.3 1 .6l7 18a1 1 0 0 1-1.4 1.3L13 19.5V13a1 1 0 1 0-2 0v6.5L5.4 22A1 1 0 0 1 4 20.6l7-18a1 1 0 0 1 1-.6Z" clip-rule="evenodd"/> | ||
</svg> | ||
</span> | ||
</button> | ||
</form> | ||
</div> | ||
</div> | ||
</div> | ||
</main> | ||
|
||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<!-- Control size of viewport, prevent zooming --> | ||
<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
<title>Alex Bates - Contact</title> | ||
<!-- Link a stylesheet that applies sitewide as well as one that is page specific --> | ||
<link href="../stylesheets/global-ab.css" rel='stylesheet' type='text/css'> | ||
<link href="../stylesheets/contact.css" rel='stylesheet' type='text/css'> | ||
<!-- Import externally hosted Merriweather font family --> | ||
<link href="https://fonts.googleapis.com/css2?family=Annapurna+SIL:wght@400;700&family=Fredoka:[email protected]&family=Merriweather:ital,wght@0,300;0,400;0,700;0,900;1,300;1,400;1,700;1,900&display=swap" rel="stylesheet"> | ||
<!-- Wait until DOM is loaded until loading scripts --> | ||
<script defer src="../scripts/global.js"></script> | ||
<script defer src="../scripts/contact.js"></script> | ||
</head> | ||
<body> | ||
|
||
<header class="navbar"> | ||
<!-- Create a container that is centered on screens wider than 1200px --> | ||
<div class="navbarinner"> | ||
<!-- Hamburger nav menu that only displays on mobile devices --> | ||
<nav class="mobilemenu"> | ||
<!-- Create hidden checkbox that is used to open and close menu --> | ||
<input id="hiddencheckbox" type="checkbox"> | ||
<label class="mobilemenubtn" for="hiddencheckbox"> | ||
<span></span> | ||
</label> | ||
<ul class="mobilemenubox"> | ||
<li><a class="mobilemenuitem" href="/">Home</a></li> | ||
<li><a class="mobilemenuitem" href="/about/">About</a></li> | ||
<li><a class="mobilemenuitem" href="/contact/">Contact</a></li> | ||
<!-- Github link that opens in new tab when clicked --> | ||
<li><a class="mobilemenuitem mobilegithub" href="https://github.com/alexbates/" target="_blank"> | ||
Github | ||
<!-- Credits to Flowbite for the Link icon https://flowbite.com/icons/ --> | ||
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> | ||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.2 9.8a3.4 3.4 0 0 0-4.8 0L5 13.2A3.4 3.4 0 0 0 9.8 18l.3-.3m-.3-4.5a3.4 3.4 0 0 0 4.8 0L18 9.8A3.4 3.4 0 0 0 13.2 5l-1 1"/> | ||
</svg> | ||
</a></li> | ||
</ul> | ||
</nav> | ||
<!-- Logo image that displays at left of navbar on desktop and center on mobile --> | ||
<!-- Division is used instead of img since img requires an src attribute --> | ||
<div class="logo"></div> | ||
<div class="themeselector"> | ||
<!-- Create hidden checkbox that is used to switch between themes --> | ||
<input type="checkbox" class="checkbox" id="checkbox"> | ||
<!-- Use a label that acts a button to toggle the checkbox --> | ||
<label for="checkbox" class="checkbox-label"> | ||
<span class="ts-sun">☀</span> | ||
<span class="ts-moon">☽</span> | ||
<span class="ball"></span> | ||
</label> | ||
</div> | ||
<!-- Site navigation that only appears on screens wider than 600px --> | ||
<nav class="desktopnav"> | ||
<div class="github"> | ||
<a href="https://github.com/alexbates/" target="_blank"> | ||
<!-- Credits to Flowbite for the Github icon https://flowbite.com/icons/ --> | ||
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"> | ||
<path fill-rule="evenodd" d="M12 2c-2.4 0-4.7.9-6.5 2.4a10.5 10.5 0 0 0-2 13.1A10 10 0 0 0 8.7 22c.5 0 .7-.2.7-.5v-2c-2.8.7-3.4-1.1-3.4-1.1-.1-.6-.5-1.2-1-1.5-1-.7 0-.7 0-.7a2 2 0 0 1 1.5 1.1 2.2 2.2 0 0 0 1.3 1 2 2 0 0 0 1.6-.1c0-.6.3-1 .7-1.4-2.2-.3-4.6-1.2-4.6-5 0-1.1.4-2 1-2.8a4 4 0 0 1 .2-2.7s.8-.3 2.7 1c1.6-.5 3.4-.5 5 0 2-1.3 2.8-1 2.8-1 .3.8.4 1.8 0 2.7a4 4 0 0 1 1 2.7c0 4-2.3 4.8-4.5 5a2.5 2.5 0 0 1 .7 2v2.8c0 .3.2.6.7.5a10 10 0 0 0 5.4-4.4 10.5 10.5 0 0 0-2.1-13.2A9.8 9.8 0 0 0 12 2Z" clip-rule="evenodd"/> | ||
</svg> | ||
</a> | ||
</div> | ||
<!-- An unordered list contains links to other pages --> | ||
<ul class="navlist"> | ||
<li><span><a href="/">Home</a></span></li><li><span><a href="/about/">About</a></span></li><li class="active"><span>Contact</span></li> | ||
</ul> | ||
</nav> | ||
</div> | ||
</header> | ||
<main> | ||
<!-- A fixed height division allows content to overflow, while still being contained within main --> | ||
<div class="block1"> | ||
<!-- division has fixed width and is centered on screens wider than 1200px --> | ||
<div class="maininner"> | ||
<!-- Appears on left side on desktop and top on mobile --> | ||
<div class="mainleft"> | ||
<!-- Credits to Flowbite for the Mailbox icon https://flowbite.com/icons/ --> | ||
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> | ||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 16v-5.5C11 8.5 9.4 7 7.5 7m3.5 9H4v-5.5C4 8.5 5.6 7 7.5 7m3.5 9v4M7.5 7H14m0 0V4h2.5M14 7v3m-3.5 6H20v-6a3 3 0 0 0-3-3m-2 9v4m-8-6.5h1"/> | ||
</svg> | ||
<h1>Reach Out</h1> | ||
<h3>Use this form to send me an email.</h3> | ||
</div> | ||
<!-- Appears on right side on desktop and bottom on mobile --> | ||
<div class="mainright"> | ||
<h2>Send Me a Message</h2> | ||
<!-- Display error message if form does not validate server side --> | ||
<p id="formError">Error: email is invalid or fields are missing.</p> | ||
<!-- Contact form labels describe the content of the inputs and text area --> | ||
<!-- Form label spans are used for error messages and are empty except when validation fails --> | ||
<!-- Form inputs, textarea, and spans use unique ids to enable manipulation with javascript --> | ||
<form id="form" class="contactform" action="/submit-form" method="post"> | ||
<label for="name">Name <span id="errorname" class="errorspan"></span></label> | ||
<input id="name" name="name" type="text"> | ||
<label for="email">Email <span id="erroremail" class="errorspan"></span></label> | ||
<input id="email" name="email" type="text"> | ||
<label for="subject">Subject <span id="errorsubject" class="errorspan"></span></label> | ||
<input id="subject" name="subject" type="text"> | ||
<label for="message"><span class="your">Your </span>Message <span id="errormessage" class="errorspan"></span></label> | ||
<textarea rows="3" id="message" name="text"></textarea> | ||
<!-- Form submit button consists of 'Send' text and icon contained within spans --> | ||
<button type="submit"> | ||
<span class="btn-text">Send</span> | ||
<span class="btn-icon"> | ||
<!-- Credits to Flowbite for the Paper Plane (send) icon https://flowbite.com/icons/ --> | ||
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24"> | ||
<path fill-rule="evenodd" d="M12 2c.4 0 .8.3 1 .6l7 18a1 1 0 0 1-1.4 1.3L13 19.5V13a1 1 0 1 0-2 0v6.5L5.4 22A1 1 0 0 1 4 20.6l7-18a1 1 0 0 1 1-.6Z" clip-rule="evenodd"/> | ||
</svg> | ||
</span> | ||
</button> | ||
</form> | ||
</div> | ||
</div> | ||
</div> | ||
</main> | ||
|
||
</body> | ||
</html> |
Oops, something went wrong.