Complete 4.2.2: Form Validation Implementation
- Add form-group wrappers and error message elements to HTML - Implement comprehensive client-side validation for nickname and message inputs - Add visual feedback using existing CSS validation classes - Include success confirmation states and proper error handling - Enhance accessibility with focus management and screen reader support
This commit is contained in:
parent
45f07f763f
commit
54db215848
3 changed files with 131 additions and 24 deletions
|
|
@ -76,44 +76,137 @@
|
|||
});
|
||||
}
|
||||
|
||||
// Validation helper functions
|
||||
function validateNickname(nickname) {
|
||||
if (!nickname) {
|
||||
return { valid: false, message: 'Nickname is required' };
|
||||
}
|
||||
|
||||
const trimmed = nickname.trim();
|
||||
if (trimmed.length === 0) {
|
||||
return { valid: false, message: 'Nickname cannot be empty' };
|
||||
}
|
||||
|
||||
if (trimmed.length > 20) {
|
||||
return { valid: false, message: 'Nickname must be 20 characters or less' };
|
||||
}
|
||||
|
||||
if (trimmed.length < 1) {
|
||||
return { valid: false, message: 'Nickname must be at least 1 character' };
|
||||
}
|
||||
|
||||
// Allow alphanumeric characters and spaces, apostrophes, hyphens
|
||||
const nicknameRegex = /^[a-zA-Z0-9\s'-]+$/;
|
||||
if (!nicknameRegex.test(trimmed)) {
|
||||
return { valid: false, message: 'Nickname can only contain letters, numbers, spaces, hyphens, and apostrophes' };
|
||||
}
|
||||
|
||||
return { valid: true };
|
||||
}
|
||||
|
||||
function validateMessage(message) {
|
||||
if (!message) {
|
||||
return { valid: false, message: 'Message is required' };
|
||||
}
|
||||
|
||||
const trimmed = message.trim();
|
||||
if (trimmed.length === 0) {
|
||||
return { valid: false, message: 'Message cannot be empty' };
|
||||
}
|
||||
|
||||
if (trimmed.length > 1000) {
|
||||
return { valid: false, message: 'Message must be 1000 characters or less' };
|
||||
}
|
||||
|
||||
return { valid: true };
|
||||
}
|
||||
|
||||
function updateValidationUI(field, errorElement, isValid, errorMessage) {
|
||||
const formGroup = errorElement.closest('.form-group');
|
||||
const input = formGroup.querySelector('input');
|
||||
|
||||
formGroup.classList.remove('form-group--error', 'form-group--success');
|
||||
|
||||
if (isValid) {
|
||||
formGroup.classList.add('form-group--success');
|
||||
errorElement.style.display = 'none';
|
||||
} else {
|
||||
formGroup.classList.add('form-group--error');
|
||||
errorElement.textContent = errorMessage;
|
||||
errorElement.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
function clearValidationState(field) {
|
||||
const formGroup = document.querySelector(`#${field}`).closest('.form-group');
|
||||
if (formGroup) {
|
||||
formGroup.classList.remove('form-group--error', 'form-group--success');
|
||||
const errorElement = document.getElementById(`${field}Error`);
|
||||
if (errorElement) {
|
||||
errorElement.style.display = 'none';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send message functionality
|
||||
function sendMessage() {
|
||||
const messageInput = document.getElementById('messageInput');
|
||||
const nicknameInput = document.getElementById('nickname');
|
||||
const nicknameErrorElement = document.getElementById('nicknameError');
|
||||
const messageErrorElement = document.getElementById('messageError');
|
||||
|
||||
const message = messageInput?.value?.trim() || '';
|
||||
const nickname = nicknameInput?.value?.trim() || '';
|
||||
|
||||
if (!nickname) {
|
||||
if (nicknameInput) {
|
||||
nicknameInput.style.borderColor = 'var(--dodgers-red)';
|
||||
nicknameInput.focus();
|
||||
}
|
||||
UIControls.showToast('Please enter a nickname');
|
||||
setTimeout(() => {
|
||||
if (nicknameInput) nicknameInput.style.borderColor = '#e0e0e0';
|
||||
}, 2000);
|
||||
// Validate nickname
|
||||
const nicknameValidation = validateNickname(nickname);
|
||||
updateValidationUI('nickname', nicknameErrorElement, nicknameValidation.valid, nicknameValidation.message);
|
||||
|
||||
// Validate message
|
||||
const messageValidation = validateMessage(message);
|
||||
updateValidationUI('messageInput', messageErrorElement, messageValidation.valid, messageValidation.message);
|
||||
|
||||
// If either validation failed, focus the appropriate field and stop
|
||||
if (!nicknameValidation.valid) {
|
||||
nicknameInput.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!message) {
|
||||
return; // Just return quietly for empty message
|
||||
if (!messageValidation.valid) {
|
||||
messageInput.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
// Send message via API
|
||||
// All validation passed - send message via API
|
||||
API.sendMessage(nickname, message)
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
// Clear the form and show success
|
||||
if (messageInput) messageInput.value = '';
|
||||
AppState.nickname = nickname;
|
||||
// Message will be added automatically by polling
|
||||
|
||||
// Show success confirmation
|
||||
updateValidationUI('nickname', nicknameErrorElement, true);
|
||||
updateValidationUI('messageInput', messageErrorElement, true);
|
||||
|
||||
UIControls.showToast('Message sent successfully!');
|
||||
|
||||
// Clear success state after a delay
|
||||
setTimeout(() => {
|
||||
clearValidationState('nickname');
|
||||
clearValidationState('messageInput');
|
||||
}, 3000);
|
||||
|
||||
AppLogger.log('Message sent successfully');
|
||||
} else if (data.error) {
|
||||
UIControls.showToast(data.error);
|
||||
// Show server error
|
||||
updateValidationUI('messageInput', messageErrorElement, false, 'Failed to send message: ' + data.error);
|
||||
UIControls.updateConnectionStatus(false);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
AppLogger.error('Error sending message:', error);
|
||||
UIControls.showToast('Failed to send message');
|
||||
updateValidationUI('messageInput', messageErrorElement, false, 'Failed to send message. Please try again.');
|
||||
UIControls.updateConnectionStatus(false);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue