Skip to content

Commit e218a64

Browse files
Adding Day #80
1 parent fca761d commit e218a64

File tree

7 files changed

+424
-1
lines changed

7 files changed

+424
-1
lines changed

Day #80 - Google Recaptcha/README.md

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Day #80
2+
3+
### Google reCAPTCHA
4+
🛡️ Want to Protect Your Forms from Spam and Bots using Google reCAPTCHA? In this tutorial, we’ll integrate Google reCAPTCHA v2 & v3 step-by-step with HTML, JavaScript, and a touch of modern styling! 💻🤖
5+
6+
🔥 What You’ll Learn:
7+
✅ Integrating Google reCAPTCHA – Add powerful spam protection to your forms with just HTML, CSS & JS. 🔐
8+
✅ reCAPTCHA v2 vs v3 – Understand the differences and choose what’s best for your site. 🧠
9+
✅ Seamless User Experience – Keep your UI clean while securing your forms. ✨
10+
✅ Bonus Tips – reCAPTCHA best practices and error handling techniques. 💡
11+
12+
## Warning
13+
You need to get your own api key (in video we showed how!) and replace it in index.html file on line 29 :
14+
15+
```html
16+
<div class="g-recaptcha" data-sitekey="<YOUR_API_KEY>"></div>
17+
```
18+
19+
# Screenshot
20+
Here we have project screenshot :
21+
22+
![screenshot-1](screenshot-1.png)
23+
![screenshot-2](screenshot-2.png)

Day #80 - Google Recaptcha/index.html

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="UTF-8">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<link rel="stylesheet" href="style.css">
8+
<script src="https://www.google.com/recaptcha/api.js"></script>
9+
<title>Day #80 - Google Recaptcha API</title>
10+
</head>
11+
12+
<body>
13+
14+
<div class="container">
15+
<h1>Contact Form</h1>
16+
<form id="contactForm">
17+
<div class="form-group">
18+
<label for="name">Name:</label>
19+
<input type="text" name="name" id="name" required>
20+
</div>
21+
<div class="form-group">
22+
<label for="email">Email:</label>
23+
<input type="email" name="email" id="email" required>
24+
</div>
25+
<div class="form-group">
26+
<label for="message">Message:</label>
27+
<textarea name="message" id="message" required></textarea>
28+
</div>
29+
<div class="g-recaptcha" data-sitekey="<YOUR_API_KEY>"></div>
30+
<button type="submit" class="submit-btn">Submit</button>
31+
</form>
32+
<div id="messageContainer"></div>
33+
</div>
34+
35+
36+
<script src="script.js"></script>
37+
</body>
38+
39+
</html>
294 KB
Loading
45.4 KB
Loading

Day #80 - Google Recaptcha/script.js

+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Configuration
2+
const CONFIG = { displayTime: 500000, loadingTime: 1500, maxRetries: 3 };
3+
const state = { retryCount: 0 };
4+
5+
// Form submission handler
6+
document.getElementById('contactForm').addEventListener('submit', async function (e) {
7+
e.preventDefault();
8+
try {
9+
const formData = validateFormData({
10+
name: document.getElementById('name').value.trim(),
11+
email: document.getElementById('email').value.trim(),
12+
message: document.getElementById('message').value.trim()
13+
});
14+
const recaptchaResponse = await getRecaptchaResponse();
15+
await processFormSubmission(formData, recaptchaResponse);
16+
} catch (error) {
17+
handleError(error);
18+
}
19+
});
20+
21+
// Core functions
22+
function validateFormData(data) {
23+
const errors = [];
24+
if (!data.name) errors.push('Name is required!');
25+
if (!data.email) errors.push('Email is required!');
26+
if (!data.message) errors.push('Message is required!');
27+
if (data.email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email)) errors.push('Invalid email!');
28+
if (errors.length) throw new Error(errors.join(', '));
29+
return data;
30+
}
31+
32+
async function getRecaptchaResponse() {
33+
const response = grecaptcha.getResponse();
34+
if (!response) throw new Error('Please complete the reCAPTCHA verification');
35+
return response;
36+
}
37+
38+
async function processFormSubmission(formData, recaptchaResponse) {
39+
showMessage('Verifying reCAPTCHA and submitting form...', 'info');
40+
try {
41+
await new Promise(resolve => setTimeout(resolve, CONFIG.loadingTime));
42+
const info = await extractRecaptchaInfo(recaptchaResponse);
43+
displaySuccessMessage(info);
44+
resetForm();
45+
} catch (error) {
46+
throw new Error(`Form submission failed: ${error.message}`);
47+
}
48+
}
49+
50+
async function extractRecaptchaInfo(response) {
51+
const timestamp = new Date();
52+
return {
53+
timestamp: timestamp.toLocaleTimeString(),
54+
date: timestamp.toLocaleDateString(),
55+
browserInfo: getBrowserInfo(),
56+
deviceInfo: getDeviceInfo()
57+
};
58+
}
59+
60+
// Helper functions
61+
function getBrowserInfo() {
62+
const ua = navigator.userAgent;
63+
const browser = {
64+
chrome: /Chrome\/([0-9.]+)/,
65+
firefox: /Firefox\/([0-9.]+)/,
66+
safari: /Version\/([0-9.]+).*Safari/,
67+
edge: /Edg\/([0-9.]+)/,
68+
ie: /MSIE ([0-9.]+)/
69+
};
70+
71+
for (const [name, regex] of Object.entries(browser)) {
72+
const match = ua.match(regex);
73+
if (match) return { name: name.charAt(0).toUpperCase() + name.slice(1), version: match[1] };
74+
}
75+
return { name: 'Unknown', version: 'Unknown' };
76+
}
77+
78+
function getDeviceInfo() {
79+
return {
80+
screenSize: `${window.innerWidth}x${window.innerHeight}`,
81+
platform: navigator.platform,
82+
language: navigator.language
83+
};
84+
}
85+
86+
function displaySuccessMessage(info) {
87+
const successMessage = `
88+
<div class="recaptcha-details">
89+
<h3>reCAPTCHA Verification Details</h3>
90+
<div class="info-grid">
91+
<div class="info-card">
92+
<div class="info-icon">🌐</div>
93+
<div class="info-content">
94+
<h4>Browser Information</h4>
95+
<p>${info.browserInfo.name} ${info.browserInfo.version}</p>
96+
<p>Platform: ${info.deviceInfo.platform}</p>
97+
<p>Language: ${info.deviceInfo.language}</p>
98+
</div>
99+
</div>
100+
<div class="info-card">
101+
<div class="info-icon">📱</div>
102+
<div class="info-content">
103+
<h4>Device Details</h4>
104+
<p>Screen: ${info.deviceInfo.screenSize}</p>
105+
<p>Time: ${info.timestamp}</p>
106+
<p>Date: ${info.date}</p>
107+
</div>
108+
</div>
109+
</div>
110+
</div>
111+
`;
112+
showMessage(successMessage, 'success');
113+
}
114+
115+
function resetForm() {
116+
document.getElementById('contactForm').reset();
117+
grecaptcha.reset();
118+
state.retryCount = 0;
119+
}
120+
121+
function handleError(error) {
122+
console.error('Error:', error);
123+
if (state.retryCount < CONFIG.maxRetries) {
124+
state.retryCount++;
125+
showMessage(`Error: ${error.message}. Retrying... (${state.retryCount}/${CONFIG.maxRetries})`, 'error');
126+
setTimeout(() => grecaptcha.reset(), 1000);
127+
} else {
128+
showMessage(`Error: ${error.message}. Please try again later.`, 'error');
129+
state.retryCount = 0;
130+
}
131+
}
132+
133+
function showMessage(message, type) {
134+
const messageContainer = document.getElementById('messageContainer');
135+
messageContainer.innerHTML = message;
136+
messageContainer.className = type + ' visible';
137+
138+
if (type === 'info') {
139+
messageContainer.classList.add('loading');
140+
}
141+
142+
if (type !== 'info') {
143+
setTimeout(() => {
144+
messageContainer.innerHTML = '';
145+
messageContainer.className = '';
146+
}, CONFIG.displayTime);
147+
}
148+
}
149+
150+
// reCAPTCHA expiration handler
151+
window.onload = function () {
152+
window.recaptchaExpired = () => showMessage('reCAPTCHA has expired. Please verify again!', 'error');
153+
};

0 commit comments

Comments
 (0)