Skip to content

Commit

Permalink
add form contact
Browse files Browse the repository at this point in the history
  • Loading branch information
n0m3l4c000nt35 committed Feb 9, 2025
1 parent 8c5c00a commit d741be5
Show file tree
Hide file tree
Showing 4 changed files with 302 additions and 4 deletions.
30 changes: 28 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,34 @@ <h3 class="article__title">Centro de Operaciones Municipal de Tres de Febrero -
</main>
<section id="contacto" class="body__section">
<h2 class="section__title">Contacto</h2>
<form action=""></form>
<p style="text-align: center;">Coming soon...</p>
<div class="form-container" role="main">
<form id="contactForm" novalidate>
<div class="form-group">
<input type="text" class="form-control" id="name" name="name" placeholder=" " required minlength="2"
maxlength="50" pattern="^[a-zA-ZáéíóúÁÉÍÓÚñÑ\s]+$" aria-required="true" aria-describedby="nameError">
<label class="form-label" for="name">Nombre</label>
<span id="nameError" class="error-message" role="alert"></span>
</div>

<div class="form-group">
<input type="email" class="form-control" id="email" name="email" placeholder=" " required maxlength="100"
pattern="[a-z0-9._+-]+@[a-z0-9.-]+\.[a-z]{2,}$" aria-required="true" aria-describedby="emailError">
<label class="form-label" for="email">Email</label>
<span id="emailError" class="error-message" role="alert"></span>
</div>

<div class="form-group">
<textarea class="form-control" id="message" name="message" placeholder=" " required minlength="10"
maxlength="500" aria-required="true" aria-describedby="messageError"></textarea>
<label class="form-label" for="message">Mensaje</label>
<span id="messageError" class="error-message" role="alert"></span>
</div>

<button type="submit" class="submit-btn" id="submitBtn">
Enviar mensaje
</button>
</form>
</div>
</section>
<footer class="body__footer">
<address class="footer__address">
Expand Down
133 changes: 133 additions & 0 deletions scripts/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,9 +262,142 @@ class InfiniteCarousel {
}
}

class FormValidator {
constructor(formId) {
this.form = document.getElementById(formId);
this.submitButton = this.form.querySelector('button[type="submit"]');

this.validations = {
name: {
required: 'Por favor, ingresa tu nombre',
minLength: 'El nombre debe tener al menos 2 caracteres',
pattern: 'Por favor, ingresa un nombre válido (solo letras y espacios)',
validate: (value) => {
if (value.trim().length < 2) return 'El nombre debe tener al menos 2 caracteres';
if (!/^[a-zA-ZáéíóúÁÉÍÓÚñÑ\s]+$/.test(value)) return 'Por favor, ingresa un nombre válido';
return '';
}
},
email: {
required: 'Por favor, ingresa tu email',
pattern: 'Por favor, ingresa un email válido',
validate: (value) => {
const emailRegex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
if (!emailRegex.test(value)) return 'Por favor, ingresa un email válido';
return '';
}
},
message: {
required: 'Por favor, ingresa tu mensaje',
minLength: 'El mensaje debe tener al menos 10 caracteres',
maxLength: 'El mensaje no debe exceder los 500 caracteres',
validate: (value) => {
if (value.trim().length < 10) return 'El mensaje debe tener al menos 10 caracteres';
if (value.length > 500) return 'El mensaje no debe exceder los 500 caracteres';
return '';
}
}
};

this.setupEventListeners();
}

setupEventListeners() {
this.form.querySelectorAll('.form-control').forEach(input => {
['input', 'blur'].forEach(eventType => {
input.addEventListener(eventType, () => {
this.validateField(input);
this.updateSubmitButtonState();
});
});
});

this.form.addEventListener('submit', (e) => this.handleSubmit(e));
}

validateField(field) {
const fieldName = field.name;
const value = field.value.trim();
const validation = this.validations[fieldName];
const errorElement = document.getElementById(`${fieldName}Error`);

field.classList.remove('error', 'success');
errorElement.textContent = '';
errorElement.classList.remove('visible');

if (!value && field.hasAttribute('required')) {
this.showError(field, errorElement, validation.required);
return false;
}

if (value && validation.validate) {
const errorMessage = validation.validate(value);
if (errorMessage) {
this.showError(field, errorElement, errorMessage);
return false;
}
}

field.classList.add('success');
return true;
}

showError(field, errorElement, message) {
field.classList.add('error');
errorElement.textContent = message;
errorElement.classList.add('visible');
}

updateSubmitButtonState() {
const isValid = Array.from(this.form.querySelectorAll('.form-control'))
.every(field => this.validateField(field));

this.submitButton.disabled = !isValid;
}

async handleSubmit(e) {
e.preventDefault();

if (!this.isFormValid()) return;

this.submitButton.disabled = true;
this.submitButton.textContent = 'Enviando...';

try {
await this.simulateFormSubmission();

this.form.reset();
this.form.querySelectorAll('.form-control').forEach(input => {
input.classList.remove('success');
});

} catch (error) {
alert('Hubo un error al enviar el formulario. Por favor, intenta nuevamente.');
} finally {
this.submitButton.disabled = false;
this.submitButton.textContent = 'Enviar mensaje';
}
}

isFormValid() {
return Array.from(this.form.querySelectorAll('.form-control'))
.every(field => this.validateField(field));
}

simulateFormSubmission() {
return new Promise((resolve) => {
const formData = Object.fromEntries(new FormData(this.form));
console.log('Datos del formulario:', formData);
alert("Coming soon...");
setTimeout(resolve, 1000);
});
}
}

document.addEventListener('DOMContentLoaded', () => {
const container = document.querySelector('.carousel-container');
new InfiniteCarousel(container);
new FormValidator('contactForm');
updateTitleOnScroll();
setYearCopyright();
});
4 changes: 4 additions & 0 deletions styles/media-queries.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
max-width: 600px;
margin-inline: auto;
}

.form-container {
margin-inline: auto;
}
}

@media (min-width: 48em) {
Expand Down
139 changes: 137 additions & 2 deletions styles/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,11 @@ a {
.profile__container {
width: 150px;
height: 150px;
outline: 1px solid var(--thirdColor);
outline-offset: 5px;
outline: 2px solid var(--thirdColor);
outline-offset: 8px;
margin-inline: auto;
margin-bottom: 5rem;
border: 1px solid white;
border-radius: 50%;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
overflow: hidden;
Expand Down Expand Up @@ -205,10 +206,22 @@ a {
left: 1rem;
}

.carousel-button.prev:focus {
outline: 2px solid var(--focusColor);
outline-offset: 2px;
border-radius: 50%;
}

.carousel-button.next {
right: 1rem;
}

.carousel-button.next:focus {
outline: 2px solid var(--focusColor);
outline-offset: 2px;
border-radius: 50%;
}

.carousel-progress {
position: absolute;
bottom: 1rem;
Expand Down Expand Up @@ -409,6 +422,128 @@ a {
text-align: center;
}

.form-container {
max-width: 500px;
margin-inline: 0.5rem;
}

.form-group {
position: relative;
margin-bottom: 1.5rem;
}

.form-control {
width: 100%;
padding: 0.75rem;
border: 2px solid var(--backgroundLightColor);
background: transparent;
color: var(--fontLightColor);
font-family: var(--fontFamily);
font-size: 1rem;
transition: all 0.3s ease;
}

.form-control:focus {
outline: none;
border-color: var(--thirdColor);
box-shadow: 0 0 0 1px var(--thirdColor);
}

.form-label {
position: absolute;
left: 1rem;
top: 0.875rem;
transform: translateY(0);
background-color: var(--darkColor);
padding: 0 0.25rem;
transition: all 0.3s ease;
pointer-events: none;
}

.form-group textarea~.form-label {
top: 0.875rem;
transform: translateY(0);
}

.form-control:focus~.form-label,
.form-control:not(:placeholder-shown)~.form-label {
top: -0.5rem;
transform: translateY(0) scale(0.9);
}

.form-control.error:focus~.form-label,
.form-control.error:not(:placeholder-shown)~.form-label {
color: #dc2626;
}

.form-control.success:focus~.form-label,
.form-control.success:not(:placeholder-shown)~.form-label {
color: #059669;
}

textarea.form-control {
min-height: 120px;
resize: none;
}

.error-message {
display: none;
font-size: 0.875rem;
color: #dc2626;
margin-top: 0.5rem;
padding-left: 0.75rem;
}

.error-message.visible {
display: block;
}

.submit-btn {
width: 100%;
border: 1px solid transparent;
/* border-radius: 8px; */
padding: 0.75rem;
color: var(--fontDarkColor);
font-family: var(--fontFamily);
font-size: 1rem;
cursor: pointer;
transition: all 0.3s ease;
}

.submit-btn:hover:not(:disabled) {
border-color: var(--backgroundLightColor);
background-color: transparent;
color: var(--fontLightColor);
}

.submit-btn:disabled {
background-color: var(--thirdColor);
cursor: not-allowed;
}

.submit-btn:focus {
outline: none;
box-shadow: 0 0 0 2px white, 0 0 0 4px #2563eb;
}

@media (prefers-reduced-motion: reduce) {
* {
transition-duration: 0.01ms !important;
}
}

.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}

.body__footer {
padding-inline: 1rem;
padding-bottom: 1rem;
Expand Down

0 comments on commit d741be5

Please sign in to comment.