feat: Add Privacy Policy acceptance to contact form and client-side validation to contact-form.js

This commit is contained in:
2025-08-25 23:04:57 -05:00
parent 04da9dde0b
commit 5cf47eb202
5 changed files with 60 additions and 14 deletions

View File

@@ -108,16 +108,37 @@ pageScripts:
<fieldset class="message-field">
<legend>Message</legend>
<label for="message">Questions or Feedback</label>
<textarea id="message" name="message" rows="15" placeholder="What questions or feedback do you have for me?" required aria-describedby="message-error"></textarea>
<textarea id="message" name="message" rows="10" placeholder="What questions or feedback do you have for me?" required aria-describedby="message-error"></textarea>
<span class="error-message" id="message-error" aria-live="polite"></span>
</fieldset>
<div class="checks">
<div class="h-captcha" data-sitekey="b63e5b64-c6f2-4154-b5a6-77169a924022"></div>
<div id="privacy" class="privacy-checkbox">
<div role="group" aria-labelledby="privacy-policy-label">
<input
type="checkbox"
id="privacy-policy"
name="privacyPolicyAgreed"
required
aria-required="true"
aria-describedby="privacy-policy-description"
>
<label id="privacy-policy-label" for="privacy-policy">
I agree to the site's
<a href="/privacy-policy" target="_blank" rel="noopener noreferrer">Privacy Policy</a>.<span classs="req-ask">*</span>
</label>
</div>
</div>
</div>
<div class="submit-reset">
<button type="submit">Send Message</button>
<button type="reset">Reset Form</button>
</div>
<div class="h-captcha" data-sitekey="b63e5b64-c6f2-4154-b5a6-77169a924022"></div>
<div class="honeypot-field" aria-hidden="true">
<label for="url">Website URL</label>

View File

@@ -11,7 +11,7 @@ isLandingPage: false
<strong>Last updated: August 25, 2025</strong>
<p>This Privacy Policy describes my policies and procedures on the collection and use of your information when you use my Service. I use your personal data to communicate with you regarding your inquiries.</p>
<p>This <strong>Privacy Policy</strong> describes my policies and procedures on the collection and use of your information when you use my Service. I use your personal data to communicate with you regarding your inquiries.</p>
<hr>
@@ -49,7 +49,7 @@ isLandingPage: false
<section id="data-collection">
<h2>What Information I Collect</h2>
<p>I collect information that you voluntarily provide to me when you express an interest in obtaining information about my Services or otherwise contact me. The personal information I collect includes:</p>
<ul>
<ul class="data-collected">
<li>First name and last name</li>
<li>Phone number</li>
<li>Email address</li>
@@ -58,8 +58,8 @@ isLandingPage: false
<li>Your message</li>
</ul>
<p>I may also collect certain technical information automatically, such as the date and time when a form is submitted, for the purpose of diagnostics and usage analysis.</p>
<p class="highlight-statement">I do not collect any information from third parties.<br>
I do not collect or process sensitive personal information.</p>
<p class="highlight-statement"><strong>I do not collect any information from third parties.<br>
I do not collect or process sensitive personal information.</strong></p>
</section>
<a class="back-to-top" href="./#top" aria-label="Back to top of page">Back to Top</a>
@@ -75,7 +75,7 @@ isLandingPage: false
<li>To prevent spam or abuse</li>
<li>To comply with legal obligations, if necessary</li>
</ul>
<p>I do not sell, rent, or share your personal information with any third parties. I may disclose information only when required by law (such as a subpoena or legal process).</p>
<p><strong>I do not sell, rent, or share your personal information with any third parties.</strong> I may disclose information only when required by law (such as a subpoena or legal process).</p>
</section>
<section id="no-tracking">
<h2>No Cookies or Tracking</h2>
@@ -88,8 +88,8 @@ isLandingPage: false
</section>
<section id="data-protection">
<h2>How I Protect Your Information</h2>
<p>I have implemented reasonable technical and organizational security measures to protect your personal data. Your information is transmitted from the contact form using HTTPS encryption, which is enforced by default on this .dev domain.</p>
<p>Submitted data undergoes multiple security checks to prevent spam and abuse, including the use of hCaptcha and rate limiting to verify the user is a human and minimize the risk of unauthorized access to stored data. The data is also validated and sanitized to ensure its integrity before it is stored in my database.</p>
<p>I have implemented reasonable technical and organizational security measures to protect your personal data. Your information is transmitted from the contact form using <a href="https://developers.google.com/search/docs/crawling-indexing/https" target="_blank" rel="noopener noreferrer">HTTPS encryption</a>, which is enforced by default on this .dev domain.</p>
<p>Submitted data undergoes multiple security checks to prevent spam and abuse, including the use of <a href="https://www.hcaptcha.com/" target="_blank" rel="noopener noreferrer">hCaptcha</a> and rate limiting to verify the user is a human and minimize the risk of unauthorized access to stored data. The data is also validated and sanitized to ensure its integrity before it is stored in my database.</p>
<p>However, security is an ongoing practice, and no method of electronic transmission or storage is ever absolutely secure. While I strive to protect your data, I cannot guarantee its absolute security.</p>
</section>
<a class="back-to-top" href="./#top" aria-label="Back to top of page">Back to Top</a>
@@ -117,6 +117,7 @@ isLandingPage: false
<li>By email: <a href="mailto:contact@dlseitz.dev">contact@dlseitz.dev</a></li>
<li>Or via the contact form on my website: <a href="https://dlseitz.dev/about/#contact" target="_blank" rel="noopener noreferrer">https://dlseitz.dev/about/#contact</a></li>
</ul>
<p>I aim to respond to all privacy-related requests within 5 business days.</p>
</section>
<a class="back-to-top" href="./#top" aria-label="Back to top of page">Back to Top</a>
</div>

View File

@@ -52,11 +52,9 @@ form.addEventListener("submit", function(event) {
const honeypotField = document.getElementById("url").value.trim();
if (honeypotField.length > 0) {
console.warn("Honeypot field was filled. Blocking submission.");
// Fail silently to avoid alerting the bot.
return;
}
// Get values, including the hCaptcha response token
const firstName = document.getElementById("first-name").value.trim();
const lastName = document.getElementById("last-name").value.trim();
const organization = document.getElementById("organization").value.trim();
@@ -64,7 +62,8 @@ form.addEventListener("submit", function(event) {
const phone = document.getElementById("phone").value.trim();
const contactMethod = document.querySelector('input[name="contact-method"]:checked')?.value;
const message = document.getElementById("message").value.trim();
// Get the hCaptcha token from the global hcaptcha object
const privacyAccepted = document.getElementById("privacy").checked;
let hasErrors = false;
// Validation logic...
@@ -114,6 +113,11 @@ form.addEventListener("submit", function(event) {
hasErrors = true;
}
if (!privacyAccepted) {
showMessage("Privacy Policy must be accepted before submitting.", true);
hasErrors = true;
}
if (!hasErrors) {
// Package the form data, including the hCaptcha token
@@ -126,7 +130,8 @@ form.addEventListener("submit", function(event) {
contactMethod: contactMethod,
message: message,
url: honeypotField,
hCaptchaResponse: hCaptchaResponse // <-- THIS IS THE NEW PART
hCaptchaResponse: hCaptchaResponse,
privacyAccepted: privacyAccepted
};
// Send the data to the backend using fetch()

View File

@@ -205,6 +205,19 @@ textarea:focus {
font-weight: normal;
}
.checks {
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
}
.privacy-checkbox > div {
display: flex;
align-items: center; /* Vertically aligns items in the center */
gap: 10px; /* Adds space between the checkbox and the text */
}
/* Button */
.submit-reset {
display: flex;

View File

@@ -94,6 +94,12 @@ hr {
margin: 0;
}
/* Correctly indents all other lists */
#data-collection ul, #privacy-rights ul, #contact ul, #data-use ul {
list-style: disc; /* Re-enable bullet points for all lists inside the module */
padding-left: 20px; /* Indent the entire list */
margin-left: 10px; /* Adds additional margin */
}
.highlight-statement {
color: var(--primary-color);