SearchResultMenuItem.tsx 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  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. </>
  31. );
  32. }
  33. if (isEmptyKeyword || searchResult == null || searchResult.data.length === 0) {
  34. return <></>;
  35. }
  36. return (
  37. <div>
  38. <div className="border-top mt-2 mb-2" />
  39. {searchResult?.data
  40. .map((item, index) => (
  41. <SearchMenuItem
  42. key={item.data._id}
  43. index={getFiexdIndex(index)}
  44. isActive={getFiexdIndex(index) === activeIndex}
  45. getItemProps={getItemProps}
  46. url={item.data._id}
  47. >
  48. <UserPicture user={item.data.creator} />
  49. <span className="ms-3 text-break text-wrap">
  50. <PagePathLabel path={item.data.path} />
  51. </span>
  52. <span className="text-body-tertiary ms-2 d-flex justify-content-center align-items-center">
  53. <span className="material-symbols-outlined fs-6 p-0">footprint</span>
  54. <span className="fs-6">{item.data.seenUsers.length}</span>
  55. </span>
  56. </SearchMenuItem>
  57. ))
  58. }
  59. </div>
  60. );
  61. };