SearchResultMenuItem.tsx 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. import React, { useCallback } from 'react';
  2. import { PagePathLabel, UserPicture } from '@growi/ui/dist/components';
  3. import { useDebounce } from 'usehooks-ts';
  4. import { useSWRxSearch } from '~/stores/search';
  5. import type { GetItemProps } from '../interfaces/downshift';
  6. import { SearchMenuItem } from './SearchMenuItem';
  7. type Props = {
  8. activeIndex: number | null,
  9. searchKeyword: string,
  10. getItemProps: GetItemProps,
  11. }
  12. export const SearchResultMenuItem = (props: Props): JSX.Element => {
  13. const { activeIndex, searchKeyword, getItemProps } = props;
  14. const debouncedKeyword = useDebounce(searchKeyword, 500);
  15. const isEmptyKeyword = searchKeyword.trim().length === 0;
  16. const { data: searchResult, isLoading } = useSWRxSearch(isEmptyKeyword ? null : debouncedKeyword, null, { limit: 10 });
  17. /**
  18. * SearchMenu is a combination of a list of SearchMethodMenuItem and SearchResultMenuItem (this component).
  19. * If no keywords are entered into SearchForm, SearchMethodMenuItem returns a single item. Conversely, when keywords are entered, three items are returned.
  20. * For these reasons, the starting index of SearchResultMemuItem changes depending on the presence or absence of the searchKeyword.
  21. */
  22. const getFiexdIndex = useCallback((index: number) => {
  23. return (isEmptyKeyword ? 1 : 3) + index;
  24. }, [isEmptyKeyword]);
  25. if (isLoading) {
  26. return (
  27. <>
  28. <div className="border-top mt-2 mb-2" />
  29. Searching...
  30. <div className="border-top" />
  31. </>
  32. );
  33. }
  34. if (isEmptyKeyword || searchResult == null || searchResult.data.length === 0) {
  35. return <></>;
  36. }
  37. return (
  38. <div>
  39. <div className="border-top mt-2 mb-2" />
  40. {searchResult?.data
  41. .map((item, index) => (
  42. <SearchMenuItem
  43. key={item.data._id}
  44. index={getFiexdIndex(index)}
  45. isActive={getFiexdIndex(index) === activeIndex}
  46. getItemProps={getItemProps}
  47. url={item.data._id}
  48. >
  49. <UserPicture user={item.data.creator} />
  50. <span className="ms-3 text-break text-wrap">
  51. <PagePathLabel path={item.data.path} />
  52. </span>
  53. <span className="text-body-tertiary ms-2 d-flex justify-content-center align-items-center">
  54. <span className="material-symbols-outlined fs-6 p-0">footprint</span>
  55. <span className="fs-6">{item.data.seenUsers.length}</span>
  56. </span>
  57. </SearchMenuItem>
  58. ))
  59. }
  60. </div>
  61. );
  62. };