index.tsx raw

   1  import SearchBar, { TSearchBarRef } from '@/components/SearchBar'
   2  import SearchResult from '@/components/SearchResult'
   3  import { Button } from '@/components/ui/button'
   4  import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
   5  import { toSearch } from '@/lib/link'
   6  import { parseNakReqCommand } from '@/lib/nak-parser'
   7  import { useSecondaryPage } from '@/PageManager'
   8  import { TSearchParams } from '@/types'
   9  import { ChevronLeft } from 'lucide-react'
  10  import { forwardRef, useEffect, useMemo, useRef, useState } from 'react'
  11  
  12  const SearchPage = forwardRef(({ index }: { index?: number }, ref) => {
  13    const { push, pop } = useSecondaryPage()
  14    const [input, setInput] = useState('')
  15    const searchBarRef = useRef<TSearchBarRef>(null)
  16    const searchParams = useMemo(() => {
  17      const params = new URLSearchParams(window.location.search)
  18      const type = params.get('t')
  19      if (
  20        type !== 'profile' &&
  21        type !== 'profiles' &&
  22        type !== 'notes' &&
  23        type !== 'hashtag' &&
  24        type !== 'relay' &&
  25        type !== 'nak'
  26      ) {
  27        return null
  28      }
  29      const search = params.get('q')
  30      if (!search) {
  31        return null
  32      }
  33      const input = params.get('i') ?? ''
  34      let request = undefined
  35      if (type === 'nak') {
  36        try {
  37          request = parseNakReqCommand(input)
  38        } catch {
  39          // ignore invalid request param
  40        }
  41      }
  42      setInput(input || search)
  43      return { type, search, input, request } as TSearchParams
  44    }, [])
  45  
  46    useEffect(() => {
  47      if (!window.location.search) {
  48        searchBarRef.current?.focus()
  49      }
  50    }, [])
  51  
  52    const onSearch = (params: TSearchParams | null) => {
  53      if (params) {
  54        push(toSearch(params))
  55      }
  56    }
  57  
  58    return (
  59      <SecondaryPageLayout
  60        ref={ref}
  61        index={index}
  62        titlebar={
  63          <div className="flex items-center gap-1 h-full">
  64            <Button variant="ghost" size="titlebar-icon" onClick={() => pop()}>
  65              <ChevronLeft />
  66            </Button>
  67            <SearchBar ref={searchBarRef} input={input} setInput={setInput} onSearch={onSearch} />
  68          </div>
  69        }
  70        displayScrollToTopButton
  71      >
  72        <SearchResult searchParams={searchParams} />
  73      </SecondaryPageLayout>
  74    )
  75  })
  76  SearchPage.displayName = 'SearchPage'
  77  export default SearchPage
  78