import React, { useCallback, useImperativeHandle, useMemo, useRef, useState, } from 'react' import {TextInput, View} from 'react-native' import {useWindowDimensions} from 'react-native' import {Image} from 'expo-image' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {logEvent} from '#/lib/statsig/statsig' import {cleanError} from '#/lib/strings/errors' import {isWeb} from '#/platform/detection' import { Gif, useFeaturedGifsQuery, useGifSearchQuery, } from '#/state/queries/tenor' import {ErrorScreen} from '#/view/com/util/error/ErrorScreen' import {ErrorBoundary} from '#/view/com/util/ErrorBoundary' import {ListMethods} from '#/view/com/util/List' import {atoms as a, ios, native, useBreakpoints, useTheme} from '#/alf' import * as Dialog from '#/components/Dialog' import * as TextField from '#/components/forms/TextField' import {useThrottledValue} from '#/components/hooks/useThrottledValue' import {ArrowLeft_Stroke2_Corner0_Rounded as Arrow} from '#/components/icons/Arrow' import {MagnifyingGlass2_Stroke2_Corner0_Rounded as Search} from '#/components/icons/MagnifyingGlass2' import {Button, ButtonIcon, ButtonText} from '../Button' import {ListFooter, ListMaybePlaceholder} from '../Lists' import {PortalComponent} from '../Portal' export function GifSelectDialog({ controlRef, onClose, onSelectGif: onSelectGifProp, Portal, }: { controlRef: React.RefObject<{open: () => void}> onClose: () => void onSelectGif: (gif: Gif) => void Portal?: PortalComponent }) { const control = Dialog.useDialogControl() useImperativeHandle(controlRef, () => ({ open: () => control.open(), })) const onSelectGif = useCallback( (gif: Gif) => { control.close(() => onSelectGifProp(gif)) }, [control, onSelectGifProp], ) const renderErrorBoundary = useCallback( (error: any) => , [], ) return ( ) } function GifList({ control, onSelectGif, }: { control: Dialog.DialogControlProps onSelectGif: (gif: Gif) => void }) { const {_} = useLingui() const t = useTheme() const {gtMobile} = useBreakpoints() const textInputRef = useRef(null) const listRef = useRef(null) const [undeferredSearch, setSearch] = useState('') const search = useThrottledValue(undeferredSearch, 500) const {height} = useWindowDimensions() const isSearching = search.length > 0 const trendingQuery = useFeaturedGifsQuery() const searchQuery = useGifSearchQuery(search) const { data, fetchNextPage, isFetchingNextPage, hasNextPage, error, isPending, isError, refetch, } = isSearching ? searchQuery : trendingQuery const flattenedData = useMemo(() => { return data?.pages.flatMap(page => page.results) || [] }, [data]) const renderItem = useCallback( ({item}: {item: Gif}) => { return }, [onSelectGif], ) const onEndReached = React.useCallback(() => { if (isFetchingNextPage || !hasNextPage || error) return fetchNextPage() }, [isFetchingNextPage, hasNextPage, error, fetchNextPage]) const hasData = flattenedData.length > 0 const onGoBack = useCallback(() => { if (isSearching) { // clear the input and reset the state textInputRef.current?.clear() setSearch('') } else { control.close() } }, [control, isSearching]) const listHeader = useMemo(() => { return ( {/* cover top corners */} {!gtMobile && isWeb && ( )} { setSearch(text) listRef.current?.scrollToOffset({offset: 0, animated: false}) }} returnKeyType="search" clearButtonMode="while-editing" inputRef={textInputRef} maxLength={50} onKeyPress={({nativeEvent}) => { if (nativeEvent.key === 'Escape') { control.close() } }} /> ) }, [gtMobile, t.atoms.bg, _, control]) return ( <> {gtMobile && } {listHeader} {!hasData && ( )} } stickyHeaderIndices={[0]} onEndReached={onEndReached} onEndReachedThreshold={4} keyExtractor={(item: Gif) => item.id} // @ts-expect-error web only style={isWeb && {minHeight: '100vh'}} keyboardDismissMode="on-drag" ListFooterComponent={ hasData ? ( ) : null } /> ) } function DialogError({details}: {details?: string}) { const {_} = useLingui() const control = Dialog.useDialogContext() return ( ) } export function GifPreview({ gif, onSelectGif, }: { gif: Gif onSelectGif: (gif: Gif) => void }) { const {gtTablet} = useBreakpoints() const {_} = useLingui() const t = useTheme() const onPress = useCallback(() => { logEvent('composer:gif:select', {}) onSelectGif(gif) }, [onSelectGif, gif]) return ( ) }