feat: add rate limiting with countdown timer for docs chat

- Add in-memory rate limiter (10 requests/minute per user)
- Show informative message when limit reached explaining demo context
- Display countdown timer showing when chat becomes available again
- Auto-reset rate limit when timer expires
- Update documentation with rate limit FAQ and category selection flow

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
colinislit
2025-12-01 18:00:51 +01:00
parent 150548bc62
commit 9dc2b4f216
6 changed files with 198 additions and 12 deletions

View File

@@ -8,6 +8,7 @@ import { cn } from '@/lib/utils'
import { ChatInput } from './chat-input'
import { ChatMessages } from './chat-messages'
import { ChatSuggestions } from './chat-suggestions'
import { RateLimitMessage } from './rate-limit-message'
import { useDocsChat } from './use-docs-chat'
/**
@@ -19,7 +20,7 @@ import { useDocsChat } from './use-docs-chat'
*/
export function DocsChatWidget() {
const [isOpen, setIsOpen] = useState(false)
const { messages, isLoading, isStreaming, error, sendMessage, clearError } = useDocsChat()
const { messages, isLoading, isStreaming, error, isRateLimited, rateLimitResetTime, sendMessage, clearError, clearRateLimit } = useDocsChat()
return (
<>
@@ -106,8 +107,16 @@ export function DocsChatWidget() {
{/* Messages */}
<ChatMessages messages={messages} isStreaming={isStreaming} />
{/* Suggestions - show only when just welcome message */}
{messages.length === 1 && messages[0].id === 'welcome' && (
{/* Rate limit message */}
{isRateLimited && (
<RateLimitMessage
resetTime={rateLimitResetTime}
onReset={clearRateLimit}
/>
)}
{/* Suggestions - show only when just welcome message and not rate limited */}
{!isRateLimited && messages.length === 1 && messages[0].id === 'welcome' && (
<ChatSuggestions
onSelect={sendMessage}
disabled={isLoading || isStreaming}
@@ -117,7 +126,7 @@ export function DocsChatWidget() {
{/* Input */}
<ChatInput
onSend={sendMessage}
disabled={isLoading || isStreaming}
disabled={isLoading || isStreaming || isRateLimited}
/>
</div>
</>