Files
spotlightcam/frontend/src/components/chat/ChatInput.jsx
Radosław Gierwiało 4a91a10aff feat(chat): add 2000 character limit for messages
Added message length validation to prevent spam and improve UX with
character counter feedback.

Backend:
- Added MESSAGE_MAX_LENGTH constant (2000 characters)
- Validation in send_event_message handler:
  - Check if content is string
  - Check if not empty after trim
  - Check if not exceeding max length
- Validation in send_match_message handler (same checks)
- Returns error message if validation fails

Frontend:
- Added MESSAGE_MAX_LENGTH constant (2000 characters)
- ChatInput component enhancements:
  - maxLength attribute on input (hard limit)
  - Character counter shows when >80% of limit
  - Counter turns red when at limit
  - Submit button disabled when at limit
  - Counter format: "X/2000"

UX:
- User sees counter at 1600+ characters (80% of limit)
- Hard limit prevents typing beyond 2000 chars
- Clear visual feedback (red text) when at limit
- Consistent validation on both event and match chats

Security:
- Prevents spam with extremely long messages
- Protects against potential DoS via message size
- Database already uses TEXT type (supports limit)
2025-12-02 23:46:54 +01:00

70 lines
2.3 KiB
JavaScript

import { Send } from 'lucide-react';
import { MESSAGE_MAX_LENGTH } from '../../constants';
/**
* Chat Input component with send button and character counter
*
* @param {string} value - Input value
* @param {function} onChange - Change handler for input
* @param {function} onSubmit - Submit handler for form
* @param {boolean} disabled - Whether input is disabled (e.g., when not connected)
* @param {string} placeholder - Placeholder text (default: "Write a message...")
* @param {string} className - Additional classes for the form
* @param {boolean} autoFocus - Whether to autofocus the input
*/
const ChatInput = ({
value,
onChange,
onSubmit,
disabled = false,
placeholder = 'Write a message...',
className = '',
autoFocus = false
}) => {
const handleSubmit = (e) => {
e.preventDefault();
if (!value.trim() || disabled) return;
onSubmit(e);
};
const charCount = value.length;
const isNearLimit = charCount > MESSAGE_MAX_LENGTH * 0.8; // 80% of limit
const isOverLimit = charCount > MESSAGE_MAX_LENGTH;
return (
<div className="space-y-1">
<form onSubmit={handleSubmit} className={`flex space-x-2 ${className}`}>
<input
type="text"
value={value}
onChange={onChange}
placeholder={placeholder}
disabled={disabled}
autoFocus={autoFocus}
maxLength={MESSAGE_MAX_LENGTH}
className="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:ring-primary-500 focus:border-primary-500 disabled:opacity-50 disabled:cursor-not-allowed"
/>
<button
type="submit"
disabled={disabled || !value.trim() || isOverLimit}
className="px-4 py-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
aria-label="Send message"
>
<Send className="w-5 h-5" />
</button>
</form>
{/* Character counter - show when approaching limit */}
{isNearLimit && (
<div className="text-right">
<span className={`text-xs ${isOverLimit ? 'text-red-600' : 'text-gray-500'}`}>
{charCount}/{MESSAGE_MAX_LENGTH}
</span>
</div>
)}
</div>
);
};
export default ChatInput;