SearchResultMenuItem.tsx 2.7 KB

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