UNPKG

react-native-ajora

Version:

The most complete AI agent UI for React Native

140 lines 4.61 kB
import React, { useState, useEffect, useCallback } from "react"; import { StyleSheet, Text, View, TouchableOpacity, Dimensions, } from "react-native"; const DocSearchTool = ({ message, request, onResponse, submitQuery: _submitQuery, }) => { const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const styles = createStyles(); const { tool } = request; const rawQuery = (tool.args || {}).query; const queryArray = Array.isArray(rawQuery) ? rawQuery.filter(Boolean).map(String) : rawQuery != null ? [String(rawQuery)] : []; const queryString = queryArray.join(" "); const performSearch = useCallback(async () => { setLoading(true); setError(null); try { // Server performs the actual search; this enables Retry UX and status update if (onResponse && request) { onResponse({ callId: request.callId, response: { error: "Search request sent to server" }, }); } } catch { setError("Failed to search documents"); if (onResponse && request) { onResponse({ callId: request.callId, response: { error: "Failed to search documents" }, }); } } finally { setLoading(false); } }, [request, onResponse]); useEffect(() => { if (request?.tool.name === "search_document") { if (request.tool.response) { const serverResponse = request.tool.response; if (serverResponse.error) { setError(serverResponse.error); setLoading(false); return; } // Even with a valid response, we keep the UI minimal (no results list) setLoading(false); setError(null); } else { setLoading(true); setError(null); } } }, [request]); if (!request) { return null; } if (error && !request.tool.response) { return (<View style={styles.container}> <View style={styles.errorContainer}> <Text style={styles.errorText}>{error}</Text> <TouchableOpacity style={styles.retryButton} onPress={performSearch}> <Text style={styles.retryText}>Retry</Text> </TouchableOpacity> </View> </View>); } const isSearching = loading && !request.tool.response; return (<View style={styles.container}> <View style={styles.loadingContainerSearched}> <Text style={styles.loadingTextSearched}> <Text style={{ fontWeight: "bold" }}> {isSearching ? "Searching for" : "Searched for"} </Text>{" "} "{queryString}"... </Text> </View> </View>); }; DocSearchTool.displayName = "search_document"; export default DocSearchTool; // Get responsive card width similar to WebSearchTool const getCardWidth = () => { const screenWidth = Dimensions.get("window").width; const cardWidth = screenWidth * 0.9; return Math.min(Math.max(cardWidth, 280), 400); }; const createStyles = () => { const cardWidth = getCardWidth(); return StyleSheet.create({ container: { // marginVertical: 8, }, loadingContainerSearched: { width: cardWidth, gap: 10, padding: 16, backgroundColor: "#f8f9fa", borderRadius: 12, borderWidth: 1, borderColor: "#e2e8f0", }, loadingTextSearched: { fontSize: 14, color: "#6b7280", }, errorContainer: { width: cardWidth, padding: 16, backgroundColor: "#fef2f2", borderRadius: 12, borderWidth: 1, borderColor: "#fecaca", alignItems: "center", }, errorText: { fontSize: 14, color: "#dc2626", textAlign: "center", marginTop: 8, marginBottom: 12, }, retryButton: { paddingHorizontal: 16, paddingVertical: 8, backgroundColor: "#dc2626", borderRadius: 6, }, retryText: { color: "#ffffff", fontSize: 14, fontWeight: "600", }, }); }; //# sourceMappingURL=DocSearchTool.js.map