diff --git a/UI_UPDATE.MD b/UI_UPDATE.MD index efb55ca..7a06d9f 100644 --- a/UI_UPDATE.MD +++ b/UI_UPDATE.MD @@ -461,22 +461,14 @@ All utilities follow the established pattern of using CSS custom properties from ### Sub-task 4.2: Interactive States and Feedback #### 4.2.1: State Implementation -- [x] Design comprehensive hover states -- [x] Implement focus indicators meeting WCAG standards -- [x] Add active and pressed state styling +- [ ] Design comprehensive hover states +- [ ] Implement focus indicators meeting WCAG standards +- [ ] Add active and pressed state styling -#### 4.2.2: Form Validation - COMPLETED 9/29/2025 -- [x] Implement visual form validation feedback -- [x] Add error state styling -- [x] Create success confirmation states - -**Notes:** Comprehensive form validation system implemented for chat inputs including: -- HTML structure updates: Added form-group wrappers with error message elements for nickname and message inputs -- Enhanced JavaScript validation: Added client-side validation with detailed error messages for nickname (1-20 chars, alphanumeric/places) and message (1-1000 chars) requirements -- CSS integration: Utilizes existing .form-group--error and .form-group--success classes for visual feedback -- User experience: Error messages display below inputs, success states provide green styling and toast confirmation, focus management ensures good UX flow -- Validation coverage: Empty inputs, character length limits, nickname character restrictions, and server error handling -- Accessibility: Proper error messaging and focus management for screen readers and keyboard navigation +#### 4.2.2: Form Validation +- [ ] Implement visual form validation feedback +- [ ] Add error state styling +- [ ] Create success confirmation states ### Sub-task 4.3: Enhanced User Feedback Systems diff --git a/assets/js/chat.js b/assets/js/chat.js index 0991fb8..ec289b4 100644 --- a/assets/js/chat.js +++ b/assets/js/chat.js @@ -76,137 +76,44 @@ }); } - // 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() || ''; - // 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(); + 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); return; } - if (!messageValidation.valid) { - messageInput.focus(); - return; + if (!message) { + return; // Just return quietly for empty message } - // All validation passed - send message via API + // 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; - - // 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'); + // Message will be added automatically by polling } else if (data.error) { - // Show server error - updateValidationUI('messageInput', messageErrorElement, false, 'Failed to send message: ' + data.error); + UIControls.showToast(data.error); UIControls.updateConnectionStatus(false); } }) .catch(error => { AppLogger.error('Error sending message:', error); - updateValidationUI('messageInput', messageErrorElement, false, 'Failed to send message. Please try again.'); + UIControls.showToast('Failed to send message'); UIControls.updateConnectionStatus(false); }); } diff --git a/index.php b/index.php index df0c5f8..20f2a52 100644 --- a/index.php +++ b/index.php @@ -461,11 +461,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {