This commit is contained in:
Peter
2025-06-17 19:22:58 +01:00
parent 623b29dea4
commit 283ea68ff8
6 changed files with 574 additions and 24 deletions

113
quote.php
View File

@@ -39,6 +39,10 @@ $canonical_url = "https://ukdataservices.co.uk/quote";
<!-- Styles -->
<link rel="stylesheet" href="assets/css/main.css">
<!-- Google reCAPTCHA v3 -->
<?php require_once '.recaptcha-config.php'; ?>
<script src="https://www.google.com/recaptcha/api.js?render=<?php echo RECAPTCHA_SITE_KEY; ?>"></script>
<!-- Quote Page Schema -->
<script type="application/ld+json">
{
@@ -667,11 +671,67 @@ $canonical_url = "https://ukdataservices.co.uk/quote";
});
});
// Form submission
// Enhanced form submission with reCAPTCHA
const quoteForm = document.getElementById('quote-form');
// Track form interactions
let formInteractions = {
mouseMovements: 0,
keystrokes: 0,
focusEvents: 0,
startTime: Date.now(),
fields: {}
};
// Add hidden timestamp field
const timestampField = document.createElement('input');
timestampField.type = 'hidden';
timestampField.name = 'form_timestamp';
timestampField.value = Date.now();
quoteForm.appendChild(timestampField);
// Add hidden interaction token
const interactionToken = document.createElement('input');
interactionToken.type = 'hidden';
interactionToken.name = 'interaction_token';
quoteForm.appendChild(interactionToken);
// Track mouse movements
document.addEventListener('mousemove', function() {
if (formInteractions.mouseMovements < 100) {
formInteractions.mouseMovements++;
}
});
// Track form field interactions
quoteForm.querySelectorAll('input, textarea, select').forEach(field => {
field.addEventListener('keydown', function() {
formInteractions.keystrokes++;
});
field.addEventListener('focus', function() {
formInteractions.focusEvents++;
});
});
quoteForm.addEventListener('submit', function(e) {
e.preventDefault();
// Calculate interaction score
const timeSpent = Date.now() - formInteractions.startTime;
const interactionScore = Math.min(100,
(timeSpent > 5000 ? 20 : 0) +
(formInteractions.mouseMovements > 10 ? 20 : 0) +
(formInteractions.keystrokes > 20 ? 20 : 0) +
(formInteractions.focusEvents > 3 ? 10 : 0)
);
// Set interaction token
interactionToken.value = btoa(JSON.stringify({
score: interactionScore,
time: timeSpent,
interactions: formInteractions.mouseMovements + formInteractions.keystrokes + formInteractions.focusEvents
}));
// Validate form
const services = document.querySelectorAll('input[name="services[]"]:checked');
const projectScale = document.querySelector('input[name="project_scale"]:checked');
@@ -711,23 +771,40 @@ $canonical_url = "https://ukdataservices.co.uk/quote";
return;
}
// Submit form
const submitButton = this.querySelector('button[type="submit"]');
const originalText = submitButton.textContent;
submitButton.textContent = 'Sending Quote Request...';
submitButton.disabled = true;
const formData = new FormData(this);
fetch('quote-handler.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert('Thank you! Your quote request has been sent. We will get back to you within 24 hours with a detailed proposal.');
this.reset();
// Execute reCAPTCHA
const self = this;
grecaptcha.ready(function() {
grecaptcha.execute('<?php echo RECAPTCHA_SITE_KEY; ?>', {action: 'quote'}).then(function(token) {
document.getElementById('recaptchaResponseQuote').value = token;
// Submit form
const submitButton = self.querySelector('button[type="submit"]');
const originalText = submitButton.textContent;
submitButton.textContent = 'Sending Quote Request...';
submitButton.disabled = true;
const formData = new FormData(self);
fetch('quote-handler.php', {
method: 'POST',
body: formData,
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert('Thank you! Your quote request has been sent. We will get back to you within 24 hours with a detailed proposal.');
self.reset();
// Reset interaction tracking
formInteractions = {
mouseMovements: 0,
keystrokes: 0,
focusEvents: 0,
startTime: Date.now(),
fields: {}
};
// Reset styling
checkboxItems.forEach(item => item.classList.remove('checked'));
radioItems.forEach(item => item.classList.remove('checked'));