161 lines
5.1 KiB
TypeScript
161 lines
5.1 KiB
TypeScript
|
|
import React, {ChangeEvent, useState} from "react";
|
||
|
|
import './Contact.css';
|
||
|
|
import { useNavigate } from 'react-router-dom'
|
||
|
|
|
||
|
|
type InputNames = "username" | "email" | "question";
|
||
|
|
|
||
|
|
interface Step {
|
||
|
|
label: string;
|
||
|
|
name: InputNames;
|
||
|
|
type: "text" | "email" | "textarea";
|
||
|
|
min_length: number;
|
||
|
|
max_length: number;
|
||
|
|
required: boolean;
|
||
|
|
pattern: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
type FormDataType = Record<InputNames, string>;
|
||
|
|
|
||
|
|
const ContactForm = () => {
|
||
|
|
|
||
|
|
const navigate = useNavigate()
|
||
|
|
|
||
|
|
const [formData, setFormData] = useState<FormDataType>({
|
||
|
|
username: "",
|
||
|
|
email: "",
|
||
|
|
question: ""
|
||
|
|
});
|
||
|
|
|
||
|
|
const [currentStep, setCurrentStep] = useState<number>(0);
|
||
|
|
const [errorMessage, setErrorMessage] = useState<string>("");
|
||
|
|
|
||
|
|
function handleChange(e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) {
|
||
|
|
const { name, value } = e.target;
|
||
|
|
setErrorMessage("");
|
||
|
|
switch (name) {
|
||
|
|
case 'username':
|
||
|
|
if (/^[a-zA-Z0-9_]*$/.test(value)) {
|
||
|
|
setFormData(prevState => ({ ...prevState, [name]: value }));
|
||
|
|
} else {
|
||
|
|
setErrorMessage('Invalid character entered. Please use only alphanumeric characters and underscores.');
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
setFormData(prevState => ({ ...prevState, [name]: value }));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
const steps: Step[] = [
|
||
|
|
{
|
||
|
|
label: "Username",
|
||
|
|
name: "username",
|
||
|
|
type: "text",
|
||
|
|
min_length: 3,
|
||
|
|
max_length: 16,
|
||
|
|
required: true,
|
||
|
|
pattern: ""
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: "Email",
|
||
|
|
name: "email",
|
||
|
|
type: "email",
|
||
|
|
min_length: 3,
|
||
|
|
max_length: 254,
|
||
|
|
required: false,
|
||
|
|
pattern: ""
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: "Question",
|
||
|
|
name: "question",
|
||
|
|
type: "textarea",
|
||
|
|
min_length: 10,
|
||
|
|
max_length: 2000,
|
||
|
|
required: true,
|
||
|
|
pattern: ""
|
||
|
|
},
|
||
|
|
]
|
||
|
|
|
||
|
|
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
||
|
|
e.preventDefault();
|
||
|
|
try {
|
||
|
|
const response = await fetch('http://localhost:8080/api/contact/submitContactForm', {
|
||
|
|
method: 'POST',
|
||
|
|
headers: {
|
||
|
|
'Content-Type': 'application/json',
|
||
|
|
},
|
||
|
|
body: JSON.stringify(formData)
|
||
|
|
})
|
||
|
|
if (!response.ok) {
|
||
|
|
alert("Your form submission was denied by the server, or the server was unable to process it, if you didn't mess with the data please contact the administrator at admin@alttd.com");
|
||
|
|
} else {
|
||
|
|
navigate('/verify-email', {
|
||
|
|
state: {
|
||
|
|
email: formData.email
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
} catch (e) {
|
||
|
|
alert("Your form submission was denied by the server, if you didn't mess with the data please contact the administrator at admin@alttd.com")
|
||
|
|
}
|
||
|
|
|
||
|
|
};
|
||
|
|
|
||
|
|
const next = () => {
|
||
|
|
setCurrentStep(current => current + 1)
|
||
|
|
}
|
||
|
|
|
||
|
|
const prev = () => {
|
||
|
|
setCurrentStep(current => Math.max(current - 1, 0))
|
||
|
|
setErrorMessage('');
|
||
|
|
}
|
||
|
|
|
||
|
|
function isNextDisabled(): boolean {
|
||
|
|
let step: Step = steps[currentStep];
|
||
|
|
if (!step)
|
||
|
|
return true;
|
||
|
|
if (!step.required)
|
||
|
|
return false;
|
||
|
|
return formData[step.name].length === 0
|
||
|
|
}
|
||
|
|
|
||
|
|
function getInputField(step: Step): JSX.Element {
|
||
|
|
switch (step.type) {
|
||
|
|
case "text":
|
||
|
|
case "email":
|
||
|
|
return <input pattern={step.pattern} type={step.type} name={step.name} minLength={step.min_length}
|
||
|
|
maxLength={step.max_length} onChange={handleChange} value={formData[step.name]} required/>
|
||
|
|
case "textarea":
|
||
|
|
return <textarea name={step.name} minLength={step.min_length} maxLength={step.max_length}
|
||
|
|
onChange={handleChange} value={formData.question} required/>
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="container">
|
||
|
|
<div>
|
||
|
|
<h1>Contact Form</h1>
|
||
|
|
</div>
|
||
|
|
{errorMessage && <p>{errorMessage}</p>}
|
||
|
|
<div>
|
||
|
|
<form onSubmit={handleSubmit}>
|
||
|
|
<div>
|
||
|
|
<label>
|
||
|
|
{steps[currentStep].label}
|
||
|
|
{getInputField(steps[currentStep])}
|
||
|
|
</label>
|
||
|
|
</div>
|
||
|
|
<button type="button" onClick={prev} disabled={currentStep === 0}>
|
||
|
|
Previous
|
||
|
|
</button>
|
||
|
|
<button type="button" onClick={next} disabled={currentStep === steps.length - 1 || isNextDisabled()}>
|
||
|
|
Next
|
||
|
|
</button>
|
||
|
|
<input type="submit" value="Submit" disabled={currentStep !== steps.length - 1}
|
||
|
|
hidden={currentStep !== steps.length - 1}/>
|
||
|
|
</form>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
};
|
||
|
|
|
||
|
|
export default ContactForm;
|