diff --git a/xtablo-expo/app/(home)/(tabs)/index.tsx b/xtablo-expo/app/(home)/(tabs)/index.tsx index 23d99b9..a4d7589 100644 --- a/xtablo-expo/app/(home)/(tabs)/index.tsx +++ b/xtablo-expo/app/(home)/(tabs)/index.tsx @@ -1,17 +1,17 @@ import { router } from "expo-router"; import { ChannelList } from "stream-chat-expo"; -import { ChannelSort } from "stream-chat"; +import { ChannelSort, Channel } from "stream-chat"; import { useUser } from "@/providers/UserProvider"; -import { - View, - Text, - StyleSheet, - TouchableOpacity, - StatusBar, -} from "react-native"; +import { View, Text, StyleSheet, StatusBar } from "react-native"; import { LinearGradient } from "expo-linear-gradient"; import { Search } from "lucide-react-native"; -import React from "react"; +import React, { useMemo } from "react"; +import { + useSharedValue, + useAnimatedStyle, + interpolate, + Extrapolate, +} from "react-native-reanimated"; import { useTablosList } from "@/hooks/tablos"; import { ColorMap } from "@/constants/colors"; import { UserTablo } from "@/types/tablos.types"; @@ -21,7 +21,7 @@ const CustomChannelAvatar = ({ channel, tablos, }: { - channel: any; + channel: Channel; tablos: UserTablo[]; }) => { const tabloId = channel?.id || ""; @@ -108,25 +108,170 @@ const CustomChannelAvatar = ({ ); }; +// Custom Title Component for bigger channel names +const CustomChannelTitle = ({ channel }: { channel: Channel }) => { + const channelName = channel?.data?.name || channel?.id || "Channel"; + + return ( + + {channelName} + + ); +}; + export default function HomeScreen() { const user = useUser(); const { data: tablos } = useTablosList(); - const filters = { - members: { $in: [user.id] }, - type: "messaging", - }; + // Search animation state + // const [isSearchVisible, setIsSearchVisible] = useState(false); + // const [searchQuery, setSearchQuery] = useState(""); + // const [debouncedSearchQuery, setDebouncedSearchQuery] = useState(""); + const searchAnimation = useSharedValue(0); + // const searchInputRef = useRef(null); + + // // Debounce search query for better performance + // useEffect(() => { + // const timer = setTimeout(() => { + // setDebouncedSearchQuery(searchQuery); + // }, 300); + + // return () => clearTimeout(timer); + // }, [searchQuery]); + + // Create filters based on search query + const filters = useMemo(() => { + const baseFilters = { + members: { $in: [user.id] }, + type: "messaging", + }; + + // Add name filter when searching + // if (debouncedSearchQuery.trim()) { + // return { + // ...baseFilters, + // name: { $autocomplete: debouncedSearchQuery.trim() }, + // }; + // } + + return baseFilters; + }, [user.id]); + const sort: ChannelSort = { last_updated: -1 }; const options = { state: true, watch: true, + limit: 20, }; // Create a wrapper component for the avatar that has access to tablos data - const AvatarWithTablos = ({ channel }: { channel: any }) => ( + const AvatarWithTablos = ({ channel }: { channel: Channel }) => ( ); + // Toggle search animation + // const toggleSearch = () => { + // const toValue = isSearchVisible ? 0 : 1; + + // searchAnimation.value = withTiming(toValue, { + // duration: 300, + // }); + + // if (toValue === 1) { + // // Focus input when animation starts + // setTimeout(() => searchInputRef.current?.focus(), 150); + // } else { + // // Clear search when hiding + // setSearchQuery(""); + // setDebouncedSearchQuery(""); + // } + + // setIsSearchVisible(!isSearchVisible); + // }; + + // Close search when keyboard is dismissed + // useEffect(() => { + // const keyboardDidHideListener = Keyboard.addListener( + // "keyboardDidHide", + // () => { + // if (isSearchVisible && searchQuery === "") { + // toggleSearch(); + // } + // } + // ); + + // return () => { + // keyboardDidHideListener?.remove(); + // }; + // }, [isSearchVisible, searchQuery]); + + // Animated styles using react-native-reanimated + const animatedSearchStyle = useAnimatedStyle(() => { + const height = interpolate( + searchAnimation.value, + [0, 1], + [0, 80], + Extrapolate.CLAMP + ); + + const opacity = interpolate( + searchAnimation.value, + [0, 0.5, 1], + [0, 0, 1], + Extrapolate.CLAMP + ); + + return { + height, + opacity, + }; + }); + + // Simple search header component - no memoization + // const SearchHeader = () => ( + // + // + // + // { + // console.log("Searching for:", searchQuery); + // Keyboard.dismiss(); + // }} + // /> + // {searchQuery.length > 0 && ( + // { + // setSearchQuery(""); + // setDebouncedSearchQuery(""); + // searchInputRef.current?.focus(); + // }} + // style={styles.clearButton} + // > + // + // + // )} + // + + // {/* Search Results Info */} + // {debouncedSearchQuery.trim() && ( + // + // + // Recherche: "{debouncedSearchQuery}" + // + // + // )} + // + // ); + return ( @@ -143,31 +288,77 @@ export default function HomeScreen() { Discussions + {/* {debouncedSearchQuery.trim() + ? `Recherche: "${debouncedSearchQuery}"` + : "Gérez les conversations de vos tablos"} */} Gérez les conversations de vos tablos - - - + {/* + {isSearchVisible ? ( + + ) : ( + + )} + */} - {/* Decorative Elements + {/* Decorative Elements */} - */} + - {/* Channel List */} + {/* Channel List with animated search */} + {/* */} { + // Close search when selecting a channel + // if (isSearchVisible) { + // toggleSearch(); + // } router.push(`/channel/${channel.cid}`); }} sort={sort} options={options} PreviewAvatar={AvatarWithTablos} + PreviewTitle={CustomChannelTitle} + // ListHeaderComponent={SearchHeader} + // Show loading state during search + LoadingIndicator={() => ( + + + {/* {debouncedSearchQuery + ? "Recherche en cours..." + : "Chargement..."} */} + Chargement... + + + )} + // Show empty state when no results + EmptyStateIndicator={() => ( + + + + {/* {debouncedSearchQuery + ? "Aucun résultat" + : "Aucune conversation"} */} + Aucune conversation + + + {/* {debouncedSearchQuery + ? `Aucune conversation trouvée pour "${debouncedSearchQuery}"` + : "Vous n'avez pas encore de conversations"} */} + Vous n'avez pas encore de conversations + + + )} /> @@ -393,4 +584,75 @@ const styles = StyleSheet.create({ fontSize: 11, fontWeight: "bold", }, + // Custom Channel Title Styles + customChannelTitle: { + fontSize: 18, + fontWeight: "bold", + color: "#1f2937", + }, + + // Search Header Styles + searchHeaderContainer: { + backgroundColor: "#f8fafc", + borderBottomWidth: 1, + borderBottomColor: "#e5e7eb", + overflow: "hidden", + paddingHorizontal: 20, + }, + searchInputContainer: { + flexDirection: "row", + alignItems: "center", + backgroundColor: "white", + borderRadius: 8, + paddingHorizontal: 12, + paddingVertical: 8, + borderWidth: 1, + borderColor: "#e5e7eb", + marginTop: 15, + }, + searchIcon: { + marginRight: 10, + }, + searchInput: { + flex: 1, + fontSize: 16, + color: "#374151", + paddingVertical: 0, + fontWeight: "500", + }, + clearButton: { + padding: 5, + }, + searchInfoContainer: { + paddingTop: 10, + paddingBottom: 15, + }, + searchInfoText: { + fontSize: 14, + color: "#6b7280", + }, + searchLoadingContainer: { + paddingVertical: 20, + alignItems: "center", + }, + searchLoadingText: { + fontSize: 16, + color: "#6b7280", + }, + emptySearchContainer: { + paddingVertical: 40, + alignItems: "center", + }, + emptySearchTitle: { + fontSize: 20, + color: "#4b5563", + marginTop: 10, + }, + emptySearchMessage: { + fontSize: 16, + color: "#6b7280", + marginTop: 5, + textAlign: "center", + paddingHorizontal: 20, + }, });