import { keepPreviousData } from '@tanstack/react-query' import { useDebounce, useIntersectionObserver } from '@uidotdev/usehooks' import { Plus } from 'lucide-react' import { ReactNode, useEffect, useMemo, useRef, useState } from 'react' import { Command, CommandGroup, CommandInput, CommandItem, CommandList, DropdownMenu, DropdownMenuContent, DropdownMenuTrigger, ScrollArea, } from 'ui' import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader' import { SIDEBAR_KEYS } from '@/components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider' import { useContentInfiniteQuery } from '@/data/content/content-infinite-query' import type { Content } from '@/data/content/content-query' import { SNIPPET_PAGE_LIMIT } from '@/data/content/sql-folders-query' import { editorPanelState } from '@/state/editor-panel-state' import { useSidebarManagerSnapshot } from '@/state/sidebar-manager-state' type SnippetDropdownProps = { projectRef?: string trigger: ReactNode side?: 'top' | 'bottom' | 'left' | 'right' align?: 'start' | 'center' | 'end' className?: string autoFocus?: boolean onSelect: (snippet: { id: string; name: string }) => void } type SqlContentItem = Extract export const SnippetDropdown = ({ projectRef, trigger, side = 'bottom', align = 'end', className, autoFocus = false, onSelect, }: SnippetDropdownProps) => { const { openSidebar } = useSidebarManagerSnapshot() const scrollRootRef = useRef(null) const [open, setOpen] = useState(false) const [search, setSearch] = useState('') const debouncedSearch = useDebounce(search, 500) const { data, isPending: isLoading, hasNextPage, fetchNextPage, isFetchingNextPage, } = useContentInfiniteQuery( { projectRef, type: 'sql', limit: SNIPPET_PAGE_LIMIT, name: search.length === 0 ? search : debouncedSearch, }, { placeholderData: keepPreviousData } ) const snippets = useMemo(() => { const items = data?.pages.flatMap((page) => page.content) ?? [] return items as SqlContentItem[] }, [data?.pages]) const [sentinelRef, entry] = useIntersectionObserver({ root: scrollRootRef.current, threshold: 0, rootMargin: '0px', }) useEffect(() => { if (entry?.isIntersecting && hasNextPage && !isFetchingNextPage && !isLoading) { fetchNextPage() } }, [entry?.isIntersecting, hasNextPage, isFetchingNextPage, isLoading, fetchNextPage]) return ( {trigger} setSearch('')} /> {isLoading ? (

Loading...

) : search.length > 0 && snippets.length === 0 ? (

No snippets found

) : ( 7 ? 'h-[210px]' : ''}> {snippets.map((snippet) => ( onSelect({ id: snippet.id, name: snippet.name })} > {snippet.name} ))}
{hasNextPage && (
)} )}
{ setOpen(false) editorPanelState.openAsNew() openSidebar(SIDEBAR_KEYS.EDITOR_PANEL) }} >

Create snippet

) }