SearchResultMenuItem.tsx 2.4 KB

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