This commit is contained in:
Iliyan Angelov
2025-12-10 01:36:00 +02:00
parent 2f6dca736a
commit 6a9e823402
84 changed files with 5293 additions and 1836 deletions

View File

@@ -2,7 +2,6 @@
import { usePathname } from "next/navigation";
import { useState, useEffect, useRef } from "react";
import Image from "next/legacy/image";
import thumb from "@/public/images/contact-thumb.png";
import { contactApiService, ContactFormData } from "@/lib/api/contactService";
const ContactSection = () => {
@@ -32,10 +31,39 @@ const ContactSection = () => {
message: string;
}>({ type: null, message: '' });
// Math Captcha state
const [captcha, setCaptcha] = useState({ num1: 0, num2: 0, operator: '+', answer: 0 });
const [captchaAnswer, setCaptchaAnswer] = useState('');
const [captchaError, setCaptchaError] = useState('');
// Refs for scrolling to status messages
const statusRef = useRef<HTMLDivElement>(null);
const formRef = useRef<HTMLFormElement>(null);
// Generate math captcha
const generateCaptcha = () => {
const operators = ['+', '-'];
const operator = operators[Math.floor(Math.random() * operators.length)];
let num1 = Math.floor(Math.random() * 10) + 1; // 1-10
let num2 = Math.floor(Math.random() * 10) + 1; // 1-10
// Ensure subtraction doesn't result in negative numbers
if (operator === '-' && num1 < num2) {
[num1, num2] = [num2, num1];
}
const answer = operator === '+' ? num1 + num2 : num1 - num2;
setCaptcha({ num1, num2, operator, answer });
setCaptchaAnswer('');
setCaptchaError('');
};
// Generate captcha on component mount
useEffect(() => {
generateCaptcha();
}, []);
// Scroll to status message when it appears
useEffect(() => {
if (submitStatus.type && statusRef.current) {
@@ -62,6 +90,16 @@ const ContactSection = () => {
e.preventDefault();
setIsSubmitting(true);
setSubmitStatus({ type: null, message: '' });
setCaptchaError('');
// Validate captcha
const userAnswer = parseInt(captchaAnswer.trim());
if (isNaN(userAnswer) || userAnswer !== captcha.answer) {
setCaptchaError('Incorrect answer. Please try again.');
setIsSubmitting(false);
generateCaptcha(); // Generate new captcha on error
return;
}
try {
// Transform form data to match API requirements
@@ -108,6 +146,10 @@ const ContactSection = () => {
privacy: false
});
// Reset captcha
setCaptchaAnswer('');
generateCaptcha();
} catch (error) {
setSubmitStatus({
type: 'error',
@@ -408,6 +450,49 @@ const ContactSection = () => {
</label>
</div>
</div>
{/* Math Captcha */}
<div className="input-single compact-input captcha-container">
<label htmlFor="captcha">
Security Verification *
<span className="captcha-hint">(Please solve the math problem)</span>
</label>
<div className="captcha-wrapper">
<div className="captcha-question">
<span className="captcha-numbers">
{captcha.num1} {captcha.operator} {captcha.num2} = ?
</span>
<button
type="button"
className="captcha-refresh"
onClick={generateCaptcha}
title="Generate new question"
aria-label="Refresh captcha"
>
<i className="fa-solid fa-rotate"></i>
</button>
</div>
<input
type="number"
name="captcha"
id="captcha"
value={captchaAnswer}
onChange={(e) => {
setCaptchaAnswer(e.target.value);
setCaptchaError('');
}}
placeholder="Enter answer"
required
className={captchaError ? 'error' : ''}
/>
{captchaError && (
<span className="captcha-error">
<i className="fa-solid fa-exclamation-circle"></i>
{captchaError}
</span>
)}
</div>
</div>
</div>
{/* Status Message */}