import React, { useState, useCallback, useRef } from 'react'; import { View, Text, StyleSheet, FlatList, TextInput, TouchableOpacity, KeyboardAvoidingView, Platform, Alert, } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { SafeAreaView } from 'react-native-safe-area-context'; import { api } from '@/services/api'; import { useBeneficiary } from '@/contexts/BeneficiaryContext'; import { AppColors, BorderRadius, FontSizes, Spacing } from '@/constants/theme'; import type { Message } from '@/types'; export default function ChatScreen() { const { currentBeneficiary, getBeneficiaryContext } = useBeneficiary(); const [messages, setMessages] = useState([ { id: '1', role: 'assistant', content: 'Hello! I\'m Julia, your AI assistant. How can I help you today?', timestamp: new Date(), }, ]); const [input, setInput] = useState(''); const [isSending, setIsSending] = useState(false); const flatListRef = useRef(null); const lastSendTimeRef = useRef(0); const SEND_COOLDOWN_MS = 1000; // 1 second cooldown between messages const handleSend = useCallback(async () => { const trimmedInput = input.trim(); if (!trimmedInput || isSending) return; // Debounce: prevent rapid-fire messages const now = Date.now(); if (now - lastSendTimeRef.current < SEND_COOLDOWN_MS) { return; } lastSendTimeRef.current = now; // Security: require beneficiary to be selected if (!currentBeneficiary?.id) { Alert.alert( 'Select Patient', 'Please select a patient from the Patients tab before starting a conversation.', [{ text: 'OK' }] ); return; } const userMessage: Message = { id: Date.now().toString(), role: 'user', content: trimmedInput, timestamp: new Date(), }; setMessages((prev) => [...prev, userMessage]); setInput(''); setIsSending(true); try { // Prepend beneficiary context to the question if available const beneficiaryContext = getBeneficiaryContext(); const questionWithContext = beneficiaryContext ? `${beneficiaryContext} ${trimmedInput}` : trimmedInput; // Pass deployment_id from selected beneficiary (required, no fallback) const deploymentId = currentBeneficiary.id.toString(); const response = await api.sendMessage(questionWithContext, deploymentId); if (response.ok && response.data?.response) { const assistantMessage: Message = { id: (Date.now() + 1).toString(), role: 'assistant', content: response.data.response.body, timestamp: new Date(), }; setMessages((prev) => [...prev, assistantMessage]); } else { const errorMessage: Message = { id: (Date.now() + 1).toString(), role: 'assistant', content: 'Sorry, I encountered an error. Please try again.', timestamp: new Date(), }; setMessages((prev) => [...prev, errorMessage]); } } catch (error) { const errorMessage: Message = { id: (Date.now() + 1).toString(), role: 'assistant', content: 'Sorry, I couldn\'t connect to the server. Please check your internet connection.', timestamp: new Date(), }; setMessages((prev) => [...prev, errorMessage]); } finally { setIsSending(false); } }, [input, isSending, currentBeneficiary, getBeneficiaryContext]); const renderMessage = ({ item }: { item: Message }) => { const isUser = item.role === 'user'; return ( {!isUser && ( J )} {item.content} {item.timestamp.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })} ); }; return ( {/* Header */} J Julia AI {isSending ? 'Typing...' : currentBeneficiary ? `About ${currentBeneficiary.name}` : 'Online'} Alert.alert('Coming Soon', 'Chat settings will be available in a future update.')} > {/* Messages */} item.id} renderItem={renderMessage} contentContainerStyle={styles.messagesList} showsVerticalScrollIndicator={false} onContentSizeChange={() => flatListRef.current?.scrollToEnd({ animated: true })} /> {/* Input */} ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: AppColors.surface, }, header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingHorizontal: Spacing.md, paddingVertical: Spacing.sm, backgroundColor: AppColors.background, borderBottomWidth: 1, borderBottomColor: AppColors.border, }, headerInfo: { flexDirection: 'row', alignItems: 'center', }, headerAvatar: { width: 40, height: 40, borderRadius: BorderRadius.full, backgroundColor: AppColors.success, justifyContent: 'center', alignItems: 'center', marginRight: Spacing.sm, }, headerAvatarText: { fontSize: FontSizes.lg, fontWeight: '600', color: AppColors.white, }, headerTitle: { fontSize: FontSizes.lg, fontWeight: '600', color: AppColors.textPrimary, }, headerSubtitle: { fontSize: FontSizes.sm, color: AppColors.success, }, headerButton: { padding: Spacing.xs, }, chatContainer: { flex: 1, }, messagesList: { padding: Spacing.md, paddingBottom: Spacing.lg, }, messageContainer: { flexDirection: 'row', marginBottom: Spacing.md, alignItems: 'flex-end', }, userMessageContainer: { justifyContent: 'flex-end', }, assistantMessageContainer: { justifyContent: 'flex-start', }, avatarContainer: { width: 32, height: 32, borderRadius: BorderRadius.full, backgroundColor: AppColors.success, justifyContent: 'center', alignItems: 'center', marginRight: Spacing.xs, }, avatarText: { fontSize: FontSizes.sm, fontWeight: '600', color: AppColors.white, }, messageBubble: { maxWidth: '75%', padding: Spacing.sm + 4, borderRadius: BorderRadius.lg, }, userBubble: { backgroundColor: AppColors.primary, borderBottomRightRadius: BorderRadius.sm, }, assistantBubble: { backgroundColor: AppColors.background, borderBottomLeftRadius: BorderRadius.sm, }, messageText: { fontSize: FontSizes.base, lineHeight: 22, }, userMessageText: { color: AppColors.white, }, assistantMessageText: { color: AppColors.textPrimary, }, timestamp: { fontSize: FontSizes.xs, color: AppColors.textMuted, marginTop: Spacing.xs, alignSelf: 'flex-end', }, userTimestamp: { color: 'rgba(255,255,255,0.7)', }, inputContainer: { flexDirection: 'row', alignItems: 'flex-end', padding: Spacing.md, backgroundColor: AppColors.background, borderTopWidth: 1, borderTopColor: AppColors.border, }, input: { flex: 1, backgroundColor: AppColors.surface, borderRadius: BorderRadius.xl, paddingHorizontal: Spacing.md, paddingVertical: Spacing.sm, fontSize: FontSizes.base, color: AppColors.textPrimary, maxHeight: 100, marginRight: Spacing.sm, }, sendButton: { width: 44, height: 44, borderRadius: BorderRadius.full, backgroundColor: AppColors.primary, justifyContent: 'center', alignItems: 'center', }, sendButtonDisabled: { backgroundColor: AppColors.surface, }, });