This commit is contained in:
Philippe Torrel
2026-10-27 14:34:42 +01:00
parent acf2deaea3
commit 3367fea887
261 changed files with 24597 additions and 48 deletions
@@ -11,6 +11,7 @@
"bootstrap": "^5.3.8",
"react": "^19.3.1",
"react-dom": "^19.3.1",
"react-hook-form": "^7.91.0",
"react-icons": "^5.7.0",
"react-router-dom": "^7.18.4"
},
@@ -988,7 +989,7 @@
"version": "19.3.0",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.3.0.tgz",
"integrity": "sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==",
"dev": true,
"devOptional": true,
"license": "MIT",
"dependencies": {
"csstype": "^3.2.2"
@@ -1098,7 +1099,7 @@
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
"dev": true,
"devOptional": true,
"license": "MIT"
},
"node_modules/detect-libc": {
@@ -1605,6 +1606,28 @@
"react": "^19.3.1"
}
},
"node_modules/react-hook-form": {
"version": "7.91.0",
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.91.0.tgz",
"integrity": "sha512-5BEBUnCBwa28AFXYTYmOaB/+CSpJ/+CWVASHEvIGUzFdHyUiPHeRhG7r5hOZ8nZi0yP7pbHdFNXO/p31EKTJFQ==",
"license": "MIT",
"engines": {
"node": ">=18.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/react-hook-form"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8.0 || ^17 || ^18 || ^19"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/react-icons": {
"version": "5.7.0",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.7.0.tgz",
@@ -13,6 +13,7 @@
"bootstrap": "^5.3.8",
"react": "^19.3.1",
"react-dom": "^19.3.1",
"react-hook-form": "^7.91.0",
"react-icons": "^5.7.0",
"react-router-dom": "^7.18.4"
},
@@ -1,49 +1,25 @@
import validate from '../../../utils/validators/validate';
import { useState } from 'react';
import { useForm } from 'react-hook-form';
const FormContact = (props) => {
// const { } = props;
const INITIAL_FORM_DATA = {
firstname: '',
lastname: '',
email: '',
message: '',
};
const {
register,
handleSubmit,
formState: { errors },
} = useForm();
// Hooks
const [formData, setFormData] = useState(INITIAL_FORM_DATA);
const [errors, setErrors] = useState({});
// EventHandlers
const handleSubmit = (e) => {
e.preventDefault();
const form = e.currentTarget;
const errors = validate(formData);
if (Object.keys(errors).length === 0) {
// AJAX/FETCH send to server
console.log('FormData: ', formData);
setFormData(INITIAL_FORM_DATA); // reset
form.reset(); // not necessary in react
setErrors({});
} else {
console.error('Form submit error');
setErrors(errors);
const onSubmit = (data) => {
// Event wird nur getriggert, wenn kein Fehler
console.log('submitted');
console.log();
if (errors) {
console.log(errors);
}
};
const handleChange = (e) => {
// console.log('Event: ', e);
const { name, value } = e.target;
setFormData((state) => ({ ...state, [name]: value }));
// console.log({ [e.target.name]: e.target.value });
// console.log('formData: ', formData);
};
return (
<form className="m-form-contact form-contact" noValidate={true} onSubmit={handleSubmit}>
<form className="m-form-contact form-contact" noValidate={true} onSubmit={handleSubmit(onSubmit)}>
<div className="row">
<div className="col-12 col-sm-6">
<div className="mb-3">
@@ -54,12 +30,15 @@ const FormContact = (props) => {
type="text"
name="firstname"
id="input-firstname"
{...register('firstname', {
required: 'Firstname is required',
mixLength: { value: 2, message: 'Firstname must have at least 2 characters.' },
maxLength: 60,
})}
className={`form-control ${errors.firstname ? 'is-invalid' : ''}`}
onChange={handleChange}
value={formData.firstname}
/>
<div className="valid-feedback">OK</div>
<div className="invalid-feedback">{errors?.firstname || 'Error'}</div>
<div className="invalid-feedback">{errors?.firstname?.message || 'Error'}</div>
</div>
</div>
<div className="col-12 col-sm-6">
@@ -71,10 +50,14 @@ const FormContact = (props) => {
type="text"
name="lastname"
id="input-lastname"
onChange={handleChange}
{...register('lastname', {
required: 'Lastname is required',
mixLength: { value: 2, message: 'Lastname must have at least 2 characters.' },
maxLength: 80,
})}
className={`form-control ${errors.lastname ? 'is-invalid' : ''}`}
/>
<div className="invalid-feedback">{errors?.lastname || 'Error'}</div>
<div className="invalid-feedback">{errors?.lastname?.message || 'Error'}</div>
</div>
</div>
</div>
@@ -88,10 +71,14 @@ const FormContact = (props) => {
type="email"
id="input-email"
name="email"
onChange={handleChange}
{...register('email', {
required: 'Email is not valid',
pattern:
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
})}
className={`form-control ${errors.email ? 'is-invalid' : ''}`}
/>
<div className="invalid-feedback">{errors?.email || 'Error'}</div>
<div className="invalid-feedback">{errors?.email?.message || 'Error'}</div>
</div>
</div>
</div>
@@ -106,9 +93,13 @@ const FormContact = (props) => {
id="textarea-message"
cols="30"
rows="5"
onChange={handleChange}
{...register('message', {
required: 'Message invalid',
minLength: { value: 10, message: 'Message to short' },
maxLength: { value: 1000, message: 'Message to long' },
})}
className={`form-control ${errors.message ? 'is-invalid' : ''}`}></textarea>
<div className="invalid-feedback">{errors?.message || 'Error'}</div>
<div className="invalid-feedback">{errors?.message?.message || 'Error'}</div>
</div>
</div>
</div>