|
1 | | -import { Text, View } from "react-native"; |
2 | | -import { type Message, MessagesList } from "../../components/MessagesList"; |
3 | | - |
4 | | -// Sample messages for demo |
5 | | -const SAMPLE_MESSAGES: Message[] = [ |
6 | | - { id: "1", text: "Hello!" }, |
7 | | - { id: "2", text: "How can I help you today?" }, |
8 | | - { id: "3", text: "Welcome to the chat." }, |
9 | | -]; |
| 1 | +import { useState } from "react"; |
| 2 | +import { |
| 3 | + KeyboardAvoidingView, |
| 4 | + Platform, |
| 5 | + ScrollView, |
| 6 | + Text, |
| 7 | + TextInput, |
| 8 | + TouchableOpacity, |
| 9 | + View, |
| 10 | +} from "react-native"; |
| 11 | +import { SafeAreaView } from "react-native-safe-area-context"; |
| 12 | +import { useMaxStore } from "../../stores/maxStore"; |
10 | 13 |
|
11 | 14 | export default function ChatScreen() { |
| 15 | + const [inputText, setInputText] = useState(""); |
| 16 | + const { |
| 17 | + thread, |
| 18 | + conversation, |
| 19 | + streamingActive, |
| 20 | + askMax, |
| 21 | + stopGeneration, |
| 22 | + resetThread, |
| 23 | + } = useMaxStore(); |
| 24 | + |
| 25 | + const handleSend = async () => { |
| 26 | + const trimmed = inputText.trim(); |
| 27 | + if (!trimmed) return; |
| 28 | + setInputText(""); |
| 29 | + await askMax(trimmed); |
| 30 | + }; |
| 31 | + |
12 | 32 | return ( |
13 | | - <View className="flex-1 bg-dark-bg"> |
14 | | - {/* Header */} |
15 | | - <View className="px-6 pt-16 pb-4"> |
16 | | - <Text className="mb-2 font-bold text-3xl text-white">Chat</Text> |
17 | | - <Text className="text-base text-dark-text-muted"> |
18 | | - Start a new conversation |
19 | | - </Text> |
20 | | - </View> |
21 | | - |
22 | | - {/* Messages - FlatList handles its own scrolling */} |
23 | | - <View className="flex-1 pb-32"> |
24 | | - <MessagesList messages={SAMPLE_MESSAGES} /> |
25 | | - </View> |
26 | | - </View> |
| 33 | + <SafeAreaView className="flex-1 bg-black" edges={["top", "left", "right"]}> |
| 34 | + <KeyboardAvoidingView |
| 35 | + behavior={Platform.OS === "ios" ? "padding" : "height"} |
| 36 | + className="flex-1" |
| 37 | + keyboardVerticalOffset={0} |
| 38 | + > |
| 39 | + {/* Header */} |
| 40 | + <View className="flex-row items-center justify-between border-gray-800 border-b px-4 py-3"> |
| 41 | + <Text className="font-bold text-lg text-white">Max Chat</Text> |
| 42 | + <View className="flex-row gap-3"> |
| 43 | + {streamingActive && ( |
| 44 | + <TouchableOpacity onPress={stopGeneration}> |
| 45 | + <Text className="text-red-500">Stop</Text> |
| 46 | + </TouchableOpacity> |
| 47 | + )} |
| 48 | + <TouchableOpacity onPress={resetThread}> |
| 49 | + <Text className="text-blue-500">Reset</Text> |
| 50 | + </TouchableOpacity> |
| 51 | + </View> |
| 52 | + </View> |
| 53 | + |
| 54 | + {/* JSON Output */} |
| 55 | + <ScrollView className="flex-1 p-4"> |
| 56 | + {/* Conversation metadata */} |
| 57 | + {conversation && ( |
| 58 | + <View className="mb-4"> |
| 59 | + <Text className="mb-1 font-bold text-green-400"> |
| 60 | + Conversation: |
| 61 | + </Text> |
| 62 | + <Text className="font-mono text-green-300 text-xs"> |
| 63 | + {JSON.stringify(conversation, null, 2)} |
| 64 | + </Text> |
| 65 | + </View> |
| 66 | + )} |
| 67 | + |
| 68 | + {/* Status */} |
| 69 | + <View className="mb-4"> |
| 70 | + <Text className="text-gray-400"> |
| 71 | + Streaming: {streamingActive ? "true" : "false"} |
| 72 | + </Text> |
| 73 | + <Text className="text-gray-400">Messages: {thread.length}</Text> |
| 74 | + </View> |
| 75 | + |
| 76 | + {/* Messages */} |
| 77 | + {thread.map((message, index) => ( |
| 78 | + <View key={message.id || `msg-${index}`} className="mb-4"> |
| 79 | + <Text className="mb-1 font-bold text-yellow-400"> |
| 80 | + [{index}] {message.type} ({message.status}) |
| 81 | + </Text> |
| 82 | + <Text className="font-mono text-white text-xs"> |
| 83 | + {JSON.stringify(message, null, 2)} |
| 84 | + </Text> |
| 85 | + </View> |
| 86 | + ))} |
| 87 | + |
| 88 | + {thread.length === 0 && !streamingActive && ( |
| 89 | + <Text className="text-center text-gray-500"> |
| 90 | + Send a message to start |
| 91 | + </Text> |
| 92 | + )} |
| 93 | + |
| 94 | + {thread.length > 0 && !streamingActive && ( |
| 95 | + <TouchableOpacity onPress={resetThread} className="mt-4 py-2"> |
| 96 | + <Text className="text-center text-blue-500 underline"> |
| 97 | + Start a new chat |
| 98 | + </Text> |
| 99 | + </TouchableOpacity> |
| 100 | + )} |
| 101 | + </ScrollView> |
| 102 | + |
| 103 | + {/* Input */} |
| 104 | + <View className="flex-row items-center gap-2 border-gray-800 border-t p-4"> |
| 105 | + <TextInput |
| 106 | + className="flex-1 rounded-lg bg-gray-800 px-4 py-3 text-white" |
| 107 | + placeholder="Type a message..." |
| 108 | + placeholderTextColor="#666" |
| 109 | + value={inputText} |
| 110 | + onChangeText={setInputText} |
| 111 | + onSubmitEditing={handleSend} |
| 112 | + editable={!streamingActive} |
| 113 | + /> |
| 114 | + <TouchableOpacity |
| 115 | + onPress={handleSend} |
| 116 | + disabled={!inputText.trim() || streamingActive} |
| 117 | + className={`rounded-lg px-4 py-3 ${ |
| 118 | + inputText.trim() && !streamingActive |
| 119 | + ? "bg-blue-600" |
| 120 | + : "bg-gray-700" |
| 121 | + }`} |
| 122 | + > |
| 123 | + <Text className="text-white">Send</Text> |
| 124 | + </TouchableOpacity> |
| 125 | + </View> |
| 126 | + </KeyboardAvoidingView> |
| 127 | + </SafeAreaView> |
27 | 128 | ); |
28 | 129 | } |
0 commit comments