react-instantsearch-dom#InstantSearch JavaScript Examples

The following examples show how to use react-instantsearch-dom#InstantSearch. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: MobileSearch.component.jsx    From nextjs-woocommerce with GNU General Public License v3.0 6 votes vote down vote up
MobileSearch = () => {
  const [search, setSearch] = useState(null);
  const [hasFocus, sethasFocus] = useState(false);
  return (
    <div className="inline mt-4 md:hidden">
      <InstantSearch
        indexName={process.env.NEXT_PUBLIC_ALGOLIA_INDEX_NAME}
        searchClient={searchClient}
      >
        <SearchBox
          translations={{
            submitTitle: 'Søk',
            resetTitle: 'Slett søketekst',
            placeholder: 'Søk etter produkter',
          }}
          className={`px-4 py-2 text-base bg-white border outline-none rounded ${
            hasFocus ? 'border-black' : 'border-gray-400'
          }`}
          onFocus={() => {
            sethasFocus(true);
          }}
          onBlur={() => {
            sethasFocus(false);
          }}
          onReset={() => {
            setSearch(null);
          }}
          onChange={(text) => {
            setSearch(text.target.value);
          }}
        />
        {search && <Hits className="absolute" hitComponent={SearchResults} />}
      </InstantSearch>
    </div>
  );
}
Example #2
Source File: provider.js    From plataforma-sabia with MIT License 6 votes vote down vote up
AlgoliaSearchProvider = ({
	indexType,
	indexName,
	children,
	useProxy,
	searchState,
	onSearchStateChange,
	createURL,
	resultsState,
	onSearchParameters,
	widgetsCollector,
}) => (
	<InstantSearch
		indexName={indexName || algoliaDefaultConfig[indexType].querySuggestionsIndex}
		searchClient={useProxy ? searchClient : algoliaClient}
		onSearchStateChange={onSearchStateChange}
		searchState={searchState}
		createURL={createURL}
		resultsState={resultsState}
		onSearchParameters={onSearchParameters}
		widgetsCollector={widgetsCollector}
	>
		{children}
	</InstantSearch>
)
Example #3
Source File: index.js    From gatsby-plugin-typesense with Apache License 2.0 6 votes vote down vote up
export default function Home() {
  const Hit = ({ hit }) => (
    <p>
      {hit.title} - {hit.description}
    </p>
  )

  return (
    <div>
      <Header pageName="Home" />
      <div data-typesense-field={"description"}>
        This is some home page content
      </div>

      <InstantSearch searchClient={searchClient} indexName="pages_v1">
        <SearchBox />
        <Stats />
        <Hits hitComponent={Hit} />
      </InstantSearch>

      <Footer />
    </div>
  )
}
Example #4
Source File: PlayerSearch.js    From fifa with GNU General Public License v3.0 6 votes vote down vote up
render() {
    const { theme } = this.context;

    return (
      <div
        className="items-collection d-none d-sm-block"
        style={{
          background: theme.useFluentDesign ? theme.acrylicTexture80.background : 'none'
        }}
      >
        <InstantSearch
          indexName="dev_PLAYERS"
          searchClient={customSearchClient}
          stalledSearchDelay={500}
        >
          <SearchBox
            showLoadingIndicator
            translations={{
              submitTitle: 'Submit your search query.',
              resetTitle: 'Clear your search query.',
              placeholder: 'Search players here...'
            }}
            onChange={e => this.setState({ searchParameter: e.target.value })}
          />
          <this.PlayerHits />
        </InstantSearch>
      </div>
    );
  }
Example #5
Source File: index.jsx    From elliot-serverless-ecommerce with MIT License 6 votes vote down vote up
Search = () => {
	const [search, toggleSearch] = useState(false);

	const handleSearchChange = e => {
		if (e.target.value === "") {
			return toggleSearch(false);
		}
		toggleSearch(true);
	};

	return (
		<Wrapper>
			<InstantSearch
				searchClient={searchClient}
				indexName={`elliot_product_index_${ENVIRONMENT || "production"}`}
			>
				<Configure
					hitsPerPage={20}
					filters={`'domain_id':${ELLIOT_DOMAIN_ID} AND 'filter_param':'PUBLISHED' AND 'productCheckouts.slug':${ELLIOT_STORE_FRONT_NAME}`}
				/>
				<SearchBox
					autoFocus={false}
					onClick={e => handleSearchChange(e)}
					onChange={e => handleSearchChange(e)}
					onReset={() => toggleSearch(false)}
				/>
				{search && <Results />}
			</InstantSearch>
		</Wrapper>
	);
}
Example #6
Source File: Algolia.js    From gatsby-airtable-design-project with BSD Zero Clause License 6 votes vote down vote up
Search = () => {
  return (
    <Wrapper>
      <Title title="Algolia Search" />
      <InstantSearch
        indexName={process.env.GATSBY_ALGOLIA_INDEX_NAME}
        searchClient={searchClient}
      >
        <SearchBox />
        <Container className="section-center">
          <NewHits />
        </Container>
      </InstantSearch>
    </Wrapper>
  )
}
Example #7
Source File: index.js    From my-personal-blog-gatsby with MIT License 6 votes vote down vote up
Search = ({ algolia }) => {
  const searchClient = algoliasearch(algolia.appId, algolia.searchOnlyApiKey);

  return (
    <s.SearchWrapper>
      <InstantSearch searchClient={searchClient} indexName={algolia.indexName}>
        <SearchBox autoFocus translations={{ placeholder: 'Pesquisar...' }} />

        <Stats
          translations={{
            stats(nbHits, timeSpentMs) {
              return `${nbHits} resultados encontrados em ${timeSpentMs}ms`;
            },
          }}
        />
        <Hits hitComponent={Hit} />
      </InstantSearch>
    </s.SearchWrapper>
  );
}
Example #8
Source File: index.js    From website with MIT License 6 votes vote down vote up
NposPage = ({ sortByQuery, query = '' }) => {
  const [sortBy, setSortBy] = useState(sortByQuery ? sortByQuery : nposSortByRule().defaultRefinement);

  return (
    <InstantSearch searchClient={searchClient} indexName="wishes">
      <Container>
        <BlackText style={{ marginTop: '20px' }} size="large">
          {query ? `Search results for "${query}"` : null}
        </BlackText>
        <Grid
          columnGap="20px"
          desktop={{
            columns: '1fr 6fr',
          }}
          rows="1fr auto"
        >
          <GridSectionContainer>
            <NposSortFilterPanel sortItems={nposSortByRule().items} sortDefaultRefinement={sortBy} query={query} />
          </GridSectionContainer>

          <GridSectionContainer>
            <BlackText style={{ marginBottom: '10px' }} size="large">
              All NPOs
            </BlackText>

            {/* Algolia */}
            <Configure filters={getNpoNotBlocked()} hitsPerPage={NPOS_BATCH_SIZE} query={query} />
            <UsersContainer>
              {/* Desktop,Tablet,Mobile has infinite scrolling  */}
              <NposInfiniteHit minHitsPerPage={NPOS_BATCH_SIZE} />
            </UsersContainer>
          </GridSectionContainer>
        </Grid>
      </Container>
    </InstantSearch>
  );
}
Example #9
Source File: index.js    From emprezzo with MIT License 6 votes vote down vote up
export default function Search({ indices, collapse, homepage, hitsAsGrid, variation }) {
  const ref = createRef()
  const [query, setQuery] = useState(``)
  const [focus, setFocus] = useState(false)
  const searchClient = algoliasearch(
    process.env.GATSBY_ALGOLIA_APP_ID,
    process.env.GATSBY_ALGOLIA_SEARCH_KEY
  )
  useOnClickOutside(ref, () => setFocus(false))
  return (
    <Root ref={ref}>
      <InstantSearch
        searchClient={searchClient}
        indexName={indices[0].name}
        onSearchStateChange={({ query }) => setQuery(query)}
      >
        <Input onFocus={() => setFocus(true)} {...{ collapse, focus }} variation={variation} />
        <HitsWrapper show={query.length > 0 && focus} asGrid={hitsAsGrid} homepage={homepage}>
          {indices.map(({ name, title, type }) => (
            <Index key={name} indexName={name}>
              <header>
                <h3>{title}</h3>
                <Stats />
              </header>
              <Results />
              <Hits type={type} onClick={() => setFocus(false)} />
            </Index>
          ))}

        </HitsWrapper>
      </InstantSearch>
    </Root>
  )
}
Example #10
Source File: ViewAllDonationsPage.js    From website with MIT License 5 votes vote down vote up
ViewAllDonationsPage = ({ sortByQuery, query = '' }) => {
  const user = useUser();
  const [sortBy, setSortBy] = useState(sortByQuery ? sortByQuery : donationsSortByRule().defaultRefinement);
  const category = {
    id: '',
    name: 'All donations',
  };
  const [latLngFilter, setLatLngFilter] = useState('');

  const onLatLngUpdated = (latLng) => {
    setLatLngFilter(latLng);
  };

  return (
    <InstantSearch searchClient={searchClient} indexName="donations">
      <ViewAllDonationsContainer>
        <Categories type="donations" />

        <BlackText style={{ marginTop: '10px' }} size="large">
          {query ? `Search results for "${query}"` : null}
        </BlackText>

        <Grid
          columnGap="20px"
          desktop={{
            columns: '1fr 6fr',
          }}
          rows="1fr auto"
        >
          <GridSectionContainer>
            <DonationsSortFilterPanel
              sortItems={donationsSortByRule().items}
              sortDefaultRefinement={sortBy}
              category={null}
              onLatLngUpdated={onLatLngUpdated}
            />
          </GridSectionContainer>

          <GridSectionContainer>
            <BlackText style={{ marginBottom: '10px' }} size="large">
              {category.name}
            </BlackText>

            {/* Algolia */}
            <Configure
              filters={getByStatus('pending')}
              hitsPerPage={DONATIONS_BATCH_SIZE}
              query={query}
              aroundLatLng={latLngFilter}
              aroundRadius={10000}
              enablePersonalization={true}
              userToken={user?.userId}
              clickAnalytics={true}
            />
            <DonationsContainer>
              {/* Desktop,Tablet,Mobile has infinite scrolling  */}
              <DonationsInfiniteHit category={category} minHitsPerPage={DONATIONS_BATCH_SIZE} />
            </DonationsContainer>
          </GridSectionContainer>
        </Grid>
      </ViewAllDonationsContainer>
    </InstantSearch>
  );
}
Example #11
Source File: AlgoliaSearchBox.component.jsx    From nextjs-woocommerce with GNU General Public License v3.0 5 votes vote down vote up
AlgoliaSearchBox = () => {
  const [search, setSearch] = useState(null);
  const [hasFocus, sethasFocus] = useState(false);

  return (
    <div className="hidden mt-2 md:inline xl:inline">
      <div className="">
        <InstantSearch
          indexName={process.env.NEXT_PUBLIC_ALGOLIA_INDEX_NAME}
          searchClient={searchClient}
        >
          {/*We need to conditionally add a border because the element has position:fixed*/}
          <SearchBox
            aria-label="Søk her"
            translations={{
              submitTitle: 'Søk',
              resetTitle: 'Slett søketekst',
              placeholder: 'Søk etter produkter',
            }}
            className={`px-4 py-2 text-base bg-white border outline-none rounded ${
              hasFocus ? 'border-black' : 'border-gray-400'
            }`}
            onFocus={() => {
              sethasFocus(true);
            }}
            onBlur={() => {
              sethasFocus(false);
            }}
            onReset={() => {
              setSearch(null);
            }}
            onChange={(text) => {
              setSearch(text.target.value);
            }}
          />
          {search && <Hits className="absolute" hitComponent={SearchResults} />}
        </InstantSearch>
      </div>
    </div>
  );
}
Example #12
Source File: index.js    From learningHub with MIT License 5 votes vote down vote up
export default function SearchComponent({ indices, collapse, hitsAsGrid }) {
  const ref = createRef();

  const [query, setQuery] = useState(``);

  const [focus, setFocus] = useState(false);

  const searchClient = algoliasearch(
    config.header.search.algoliaAppId,
    config.header.search.algoliaSearchKey
  );

  useClickOutside(ref, () => setFocus(false));
  const displayResult = query.length > 0 && focus ? 'showResults' : 'hideResults';

  return (
    <InstantSearch
      searchClient={searchClient}
      indexName={indices[0].name}
      onSearchStateChange={({ query }) => setQuery(query)}
      root={{ Root, props: { ref } }}
    >
      <Input onFocus={() => setFocus(true)} {...{ collapse, focus }} />
      <HitsWrapper
        className={'hitWrapper ' + displayResult}
        show={query.length > 0 && focus}
        asGrid={hitsAsGrid}
      >
        {indices.map(({ name, title, hitComp, type }) => {
          return (
            <Index key={name} indexName={name}>
              <Results />
              <Hits hitComponent={hitComps[hitComp](() => setFocus(false))} />
            </Index>
          );
        })}
        <PoweredBy />
      </HitsWrapper>
      <Configure hitsPerPage={5} />
    </InstantSearch>
  );
}
Example #13
Source File: index.js    From climatescape.org with MIT License 5 votes vote down vote up
export default function Search() {
  const [query, setQuery] = useState("")
  const [focused, setFocused] = useState(false)
  const [activeHit, setActiveHit] = useState(0)
  const [openActiveHit, setOpenActiveHit] = useState(false)
  const ref = useRef(null)
  useClickOutside(ref, () => setFocused(false))

  const searchClient = useMemo(
    () =>
      client(
        algoliasearch(
          process.env.GATSBY_ALGOLIA_APP_ID,
          process.env.GATSBY_ALGOLIA_SEARCH_KEY
        )
      ),
    []
  )

  const handleNavigateResults = direction => {
    setActiveHit(activeHit + direction)
  }

  const handleSearchStateChange = ({ query: newQuery }) => {
    setQuery(newQuery)
    setActiveHit(0)
  }

  return (
    <InstantSearch
      searchClient={searchClient}
      indexName="Pages"
      onSearchStateChange={handleSearchStateChange}
    >
      <Configure hitsPerPage={8} />
      <div className="sm:relative w-full" ref={ref}>
        <SearchBox
          onFocus={() => setFocused(true)}
          onNavigate={handleNavigateResults}
          onEnter={() => setOpenActiveHit(true)}
        />
        {query && focused && (
          <Hits
            activeHit={activeHit}
            onChangeActiveHit={setActiveHit}
            openActiveHit={openActiveHit}
          />
        )}
      </div>
    </InstantSearch>
  )
}
Example #14
Source File: index.js    From website with MIT License 5 votes vote down vote up
export default function Search({ indices, collapse, hitsAsGrid }) {
  const [query, setQuery] = useState(``)
  const [setFocus] = useState(false)
  const searchClient = algoliasearch(
    "V0X7Z4KE9D",
    "544bec33383dc791bcbca3e1ceaec11b"
  )
  return (
    <InstantSearch
      searchClient={searchClient}
      indexName={indices[0].name}
      onSearchStateChange={({ query }) => {
        if (typeof query !== "undefined") {
          setQuery(query)
        }
      }}
    >
      <div tw="relative shadow appearance-none border rounded w-full py-3 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-inner rounded-r-none">
        <SearchBox
          tw="w-full px-8"
          translations={{
            placeholder: "Find analysis tools, formatters, and linters...",
          }}
          startValue=""
          submit={
            <svg
              xmlns="http://www.w3.org/2000/svg"
              width="16"
              height="16"
              viewBox="0 0 18 18"
            >
              <g
                fill="none"
                fillRule="evenodd"
                stroke="currentColor"
                strokeLinecap="round"
                strokeLinejoin="round"
                strokeWidth="1.67"
                transform="translate(1 1)"
              >
                <circle cx="7.11" cy="7.11" r="7.11" />
                <path d="M16 16l-3.87-3.87" />
              </g>
            </svg>
          }
        />
      </div>
      {query && (
        <HitsWrapper
          show={query.length > 0}
          asGrid="false"
          tw="max-h-screen overflow-scroll border shadow bg-white absolute w-full"
        >
          {indices.map(({ name, title, hitComp }) => (
            <Index key={name} indexName={name}>
              <Results>
                <Hits hitComponent={hitComps[hitComp](() => setFocus(false))} />
              </Results>
            </Index>
          ))}
          <PoweredBy />
        </HitsWrapper>
      )}
    </InstantSearch>
  )
}
Example #15
Source File: Search.js    From adarshaacharya.com.np with MIT License 5 votes vote down vote up
Search = ({ props }) => {
  const { location } = props;

  const [searchState, setSearchState] = React.useState(
    urlToSearchState(location)
  );

  const onSearchStateChange = updatedSearchState => {
    setSearchState(updatedSearchState);
  };

  const searchClient = algoliasearch(
    process.env.GATSBY_ALGOLIA_APP_ID,
    process.env.GATSBY_ALGOLIA_SEARCH_KEY
  );

  return (
    <StyledSearch>
      <InstantSearch
        indexName={process.env.GATSBY_ALGOLIA_INDEX_NAME}
        searchClient={searchClient}
        searchState={searchState}
        onSearchStateChange={onSearchStateChange}
      >
        <SearchBox
          translations={{
            placeholder: 'Search by title, tags or description..',
          }}
        />

        {searchState && searchState.query ? (
          <>
            <Stats
              translations={{
                stats(nbHits) {
                  return `${nbHits} Results found`;
                },
              }}
            />

            <Hits hitComponent={Hit} />
          </>
        ) : (
          <Posts />
        )}
      </InstantSearch>
    </StyledSearch>
  );
}
Example #16
Source File: search.js    From Nextjs-ja-translation-docs with MIT License 5 votes vote down vote up
function Search(props) {
  return (
    <InstantSearch indexName="nextjs_docs" searchClient={searchClient}>
      <Configure hitsPerPage={8} />
      <AutoComplete {...props} />
    </InstantSearch>
  );
}
Example #17
Source File: index.js    From website with MIT License 5 votes vote down vote up
NavSearchBarDropdownList = () => {
  const inputRef = useRef(null);
  const [isOpen, setIsOpen] = useState(false);

  return (
    <InstantSearch searchClient={searchClient} indexName="wishes">
      <Popover
        isOpen={isOpen}
        position={['bottom']}
        disableReposition
        onClickOutside={() => setIsOpen(false)}
        containerStyle={{
          zIndex: 1000,
          width: '350px',
          boxShadow: '0 8px 13px 0 rgba(44, 44, 45, 0.27)',
          borderRadius: '5px',
          position: 'fixed',
        }}
        align="start"
        transitionDuration={0.1}
        content={({ position, nudgedLeft, nudgedTop, targetRect, popoverRect }) => {
          return (
            <ContentContainer>
              <>
                <Index indexName="wishes">
                  <Container>
                    <Text weight="bold">Wishes</Text>
                  </Container>

                  <CustomHits type="wishes" />
                  <Configure hitsPerPage={MAXIMUM_SEARCH_DESKTOP} />
                </Index>

                <Index indexName="donations">
                  <Container>
                    <Text weight="bold">Donations</Text>
                  </Container>

                  <CustomHits type="donations" />
                  <Configure hitsPerPage={MAXIMUM_SEARCH_DESKTOP} />
                </Index>
              </>
            </ContentContainer>
          );
        }}
      >
        <div onClick={() => setIsOpen(true)}>
          <CustomSearchBox inputRef={inputRef} />
        </div>
      </Popover>
    </InstantSearch>
  );
}
Example #18
Source File: index.js    From website with MIT License 5 votes vote down vote up
OrganizationWishes = ({ organization }) => {
  const user = useUser();
  const category = {
    id: '',
    name: 'All wishes',
  };

  return (
    <InstantSearch searchClient={searchClient} indexName="wishes">
      <ViewAllWishesContainer>
        <Grid
          columnGap="20px"
          desktop={{
            columns: '1fr 6fr',
          }}
          rows="1fr auto"
        >
          <GridSectionContainer>
            <WishesSortFilterPanel category={null} />
          </GridSectionContainer>

          <GridSectionContainer>
            <BlackText style={{ marginBottom: '10px' }} size="large">
              All Wishes
            </BlackText>

            {/* Algolia */}
            <Configure
              filters={getNpoWishes(organization.id)}
              hitsPerPage={WISHES_BATCH_SIZE}
              aroundRadius={10000}
              enablePersonalization={true}
              userToken={user?.userId}
              clickAnalytics={true}
            />
            <WishesContainer>
              {/* Desktop,Tablet,Mobile has infinite scrolling  */}
              <WishesInfiniteHit category={category} minHitsPerPage={WISHES_BATCH_SIZE} />
            </WishesContainer>
          </GridSectionContainer>
        </Grid>
      </ViewAllWishesContainer>
    </InstantSearch>
  );
}
Example #19
Source File: index.js    From website with MIT License 5 votes vote down vote up
ViewCategoryPage = ({ categoryDetails, sortByQuery }) => {
  const user = useUser();
  const category = categoryDetails;
  const [sortBy, setSortBy] = useState(sortByQuery ? sortByQuery : wishesSortByRule().defaultRefinement);
  const [latLngFilter, setLatLngFilter] = useState('');

  const onLatLngUpdated = (latLng) => {
    setLatLngFilter(latLng);
  };

  return (
    <InstantSearch searchClient={searchClient} indexName="wishes">
      <ViewCategoryContainer>
        <Categories type="wishes" />

        <Grid
          columnGap="20px"
          desktop={{
            columns: '1fr 6fr',
          }}
          rows="1fr auto"
        >
          <GridSectionContainer>
            <WishesSortFilterPanel
              sortItems={wishesSortByRule().items}
              sortDefaultRefinement={sortBy}
              category={category}
              onLatLngUpdated={onLatLngUpdated}
            />
          </GridSectionContainer>

          <GridSectionContainer>
            <BlackText style={{ marginBottom: '10px' }} size="large">
              {category.name}
            </BlackText>

            {/* Algolia */}
            <Configure
              filters={getByCategoryIdAndStatusAndNotExpired(category.id, 'pending', Date.now())}
              hitsPerPage={WISHES_BATCH_SIZE}
              aroundLatLng={latLngFilter}
              aroundRadius={10000}
              enablePersonalization={true}
              userToken={user?.userId}
              clickAnalytics={true}
            />
            <WishesContainer>
              {/* Desktop,Tablet,Mobile has infinite scrolling  */}
              <WishesInfiniteHit category={category} minHitsPerPage={WISHES_BATCH_SIZE} />
            </WishesContainer>
          </GridSectionContainer>
        </Grid>
      </ViewCategoryContainer>
    </InstantSearch>
  );
}
Example #20
Source File: index.js    From website with MIT License 5 votes vote down vote up
ViewAllWishesPage = ({ sortByQuery, query = '' }) => {
  const user = useUser();
  const [sortBy, setSortBy] = useState(sortByQuery ? sortByQuery : wishesSortByRule().defaultRefinement);
  const category = {
    id: '',
    name: 'All wishes',
  };
  const [latLngFilter, setLatLngFilter] = useState('');

  const onLatLngUpdated = (latLng) => {
    setLatLngFilter(latLng);
  };

  return (
    <InstantSearch searchClient={searchClient} indexName="wishes">
      <ViewAllWishesContainer>
        <Categories type="wishes" />

        <BlackText style={{ marginTop: '20px' }} size="large">
          {query ? `Search results for "${query}"` : null}
        </BlackText>
        <Grid
          columnGap="20px"
          desktop={{
            columns: '1fr 6fr',
          }}
          rows="1fr auto"
        >
          <GridSectionContainer>
            <WishesSortFilterPanel
              sortItems={wishesSortByRule().items}
              sortDefaultRefinement={sortBy}
              category={null}
              onLatLngUpdated={onLatLngUpdated}
            />
          </GridSectionContainer>

          <GridSectionContainer>
            <BlackText style={{ marginBottom: '10px' }} size="large">
              All Wishes
            </BlackText>

            {/* Algolia */}
            <Configure
              filters={getByStatusAndNotExpired('pending', Date.now())}
              hitsPerPage={WISHES_BATCH_SIZE}
              query={query}
              aroundLatLng={latLngFilter}
              aroundRadius={10000}
              enablePersonalization={true}
              userToken={user?.userId}
              clickAnalytics={true}
            />
            <WishesContainer>
              {/* Desktop,Tablet,Mobile has infinite scrolling  */}
              <WishesInfiniteHit category={category} minHitsPerPage={WISHES_BATCH_SIZE} />
            </WishesContainer>
          </GridSectionContainer>
        </Grid>
      </ViewAllWishesContainer>
    </InstantSearch>
  );
}
Example #21
Source File: index.js    From website with MIT License 5 votes vote down vote up
ViewCategoryPage = ({ categoryDetails, sortByQuery }) => {
  const user = useUser();
  const category = categoryDetails;
  const [sortBy, setSortBy] = useState(sortByQuery ? sortByQuery : donationsSortByRule().defaultRefinement);
  const [latLngFilter, setLatLngFilter] = useState('');

  const onLatLngUpdated = (latLng) => {
    setLatLngFilter(latLng);
  };

  return (
    <InstantSearch searchClient={searchClient} indexName="donations">
      <ViewCategoryContainer>
        <Categories type="donations" />

        <Grid
          columnGap="20px"
          desktop={{
            columns: '1fr 6fr',
          }}
          rows="1fr auto"
        >
          <GridSectionContainer>
            <DonationsSortFilterPanel
              sortItems={donationsSortByRule().items}
              sortDefaultRefinement={sortBy}
              category={category}
              onLatLngUpdated={onLatLngUpdated}
            />
          </GridSectionContainer>

          <GridSectionContainer>
            <BlackText style={{ marginBottom: '10px' }} size="large">
              {category.name}
            </BlackText>

            {/* Algolia */}
            <Configure
              filters={getByCategoryIdAndStatus(category.id, 'pending')}
              hitsPerPage={DONATIONS_BATCH_SIZE}
              aroundLatLng={latLngFilter}
              aroundRadius={10000}
              enablePersonalization={true}
              userToken={user?.userId}
              clickAnalytics={true}
            />
            <DonationsContainer>
              {/* Desktop,Tablet,Mobile has infinite scrolling  */}
              <DonationsInfiniteHit category={category} minHitsPerPage={DONATIONS_BATCH_SIZE} />
            </DonationsContainer>
          </GridSectionContainer>
        </Grid>
      </ViewCategoryContainer>
    </InstantSearch>
  );
}
Example #22
Source File: index.js    From website with MIT License 5 votes vote down vote up
ViewAllDonationsPage = ({ sortByQuery, query = '' }) => {
  const user = useUser();
  const [sortBy, setSortBy] = useState(sortByQuery ? sortByQuery : donationsSortByRule().defaultRefinement);
  const category = {
    id: '',
    name: 'All donations',
  };
  const [latLngFilter, setLatLngFilter] = useState('');

  const onLatLngUpdated = (latLng) => {
    setLatLngFilter(latLng);
  };

  return (
    <InstantSearch searchClient={searchClient} indexName="donations">
      <ViewAllDonationsContainer>
        <Categories type="donations" />

        <BlackText style={{ marginTop: '10px' }} size="large">
          {query ? `Search results for "${query}"` : null}
        </BlackText>

        <Grid
          columnGap="20px"
          desktop={{
            columns: '1fr 6fr',
          }}
          rows="1fr auto"
        >
          <GridSectionContainer>
            <DonationsSortFilterPanel
              sortItems={donationsSortByRule().items}
              sortDefaultRefinement={sortBy}
              category={null}
              onLatLngUpdated={onLatLngUpdated}
            />
          </GridSectionContainer>

          <GridSectionContainer>
            <BlackText style={{ marginBottom: '10px' }} size="large">
              {category.name}
            </BlackText>

            {/* Algolia */}
            <Configure
              filters={getByStatus('pending')}
              hitsPerPage={DONATIONS_BATCH_SIZE}
              query={query}
              aroundLatLng={latLngFilter}
              aroundRadius={10000}
              enablePersonalization={true}
              userToken={user?.userId}
              clickAnalytics={true}
            />
            <DonationsContainer>
              {/* Desktop,Tablet,Mobile has infinite scrolling  */}
              <DonationsInfiniteHit category={category} minHitsPerPage={DONATIONS_BATCH_SIZE} />
            </DonationsContainer>
          </GridSectionContainer>
        </Grid>
      </ViewAllDonationsContainer>
    </InstantSearch>
  );
}
Example #23
Source File: NpoOrganizationDropdownField.js    From website with MIT License 5 votes vote down vote up
NpoOrganizationDropdownField = ({ onSelected, error, label, disabled, value }) => {
  const inputRef = useRef(null);
  const [isOpen, setIsOpen] = useState(false);
  const [selected, setSelected] = useState('');

  useEffect(() => {
    setSelected(value);
  }, [value]);

  return (
    <InstantSearch searchClient={searchClient} indexName="organizations">
      <Popover
        isOpen={isOpen}
        position={['bottom']}
        disableReposition
        onClickOutside={() => {
          setIsOpen(false);
        }}
        containerStyle={{
          zIndex: 1000,
          width: '300px',
          boxShadow: '0 8px 13px 0 rgba(44, 44, 45, 0.27)',
          borderRadius: '5px',
          position: 'fixed',
          maxHeight: '400px',
          overflowY: 'auto',
        }}
        align="start"
        transitionDuration={0.1}
        content={({ position, nudgedLeft, nudgedTop, targetRect, popoverRect }) => {
          return (
            <ContentContainer>
              <>
                <Index indexName="organizations">
                  <CustomHits
                    onClick={(name) => {
                      onSelected(name);
                      setSelected(name);
                      setIsOpen(false);
                    }}
                  />
                  <Configure hitsPerPage={8} />
                </Index>
              </>
            </ContentContainer>
          );
        }}
      >
        <div onClick={() => setIsOpen(true)}>
          <CustomSearchBox inputRef={inputRef} error={error} label={label} disabled={disabled} value={selected} />
        </div>
      </Popover>
    </InstantSearch>
  );
}
Example #24
Source File: WishesViewCategoryPage.js    From website with MIT License 5 votes vote down vote up
ViewCategoryPage = ({ categoryDetails, sortByQuery }) => {
  const user = useUser();
  const category = categoryDetails;
  const [sortBy, setSortBy] = useState(sortByQuery ? sortByQuery : wishesSortByRule().defaultRefinement);
  const [latLngFilter, setLatLngFilter] = useState('');

  const onLatLngUpdated = (latLng) => {
    setLatLngFilter(latLng);
  };

  return (
    <InstantSearch searchClient={searchClient} indexName="wishes">
      <ViewCategoryContainer>
        <Categories type="wishes" />

        <Grid
          columnGap="20px"
          desktop={{
            columns: '1fr 6fr',
          }}
          rows="1fr auto"
        >
          <GridSectionContainer>
            <WishesSortFilterPanel
              sortItems={wishesSortByRule().items}
              sortDefaultRefinement={sortBy}
              category={category}
              onLatLngUpdated={onLatLngUpdated}
            />
          </GridSectionContainer>

          <GridSectionContainer>
            <BlackText style={{ marginBottom: '10px' }} size="large">
              {category.name}
            </BlackText>

            {/* Algolia */}
            <Configure
              filters={getByCategoryIdAndStatusAndNotExpired(category.id, 'pending', Date.now())}
              hitsPerPage={WISHES_BATCH_SIZE}
              aroundLatLng={latLngFilter}
              aroundRadius={10000}
              enablePersonalization={true}
              userToken={user?.userId}
              clickAnalytics={true}
            />
            <WishesContainer>
              {/* Desktop,Tablet,Mobile has infinite scrolling  */}
              <WishesInfiniteHit category={category} minHitsPerPage={WISHES_BATCH_SIZE} />
            </WishesContainer>
          </GridSectionContainer>
        </Grid>
      </ViewCategoryContainer>
    </InstantSearch>
  );
}
Example #25
Source File: ViewAllWishesPage.js    From website with MIT License 5 votes vote down vote up
ViewAllWishesPage = ({ sortByQuery, query = '' }) => {
  const user = useUser();
  const [sortBy, setSortBy] = useState(sortByQuery ? sortByQuery : wishesSortByRule().defaultRefinement);
  const category = {
    id: '',
    name: 'All wishes',
  };
  const [latLngFilter, setLatLngFilter] = useState('');

  const onLatLngUpdated = (latLng) => {
    setLatLngFilter(latLng);
  };

  return (
    <InstantSearch searchClient={searchClient} indexName="wishes">
      <ViewAllWishesContainer>
        <Categories type="wishes" />

        <BlackText style={{ marginTop: '20px' }} size="large">
          {query ? `Search results for "${query}"` : null}
        </BlackText>
        <Grid
          columnGap="20px"
          desktop={{
            columns: '1fr 6fr',
          }}
          rows="1fr auto"
        >
          <GridSectionContainer>
            <WishesSortFilterPanel
              sortItems={wishesSortByRule().items}
              sortDefaultRefinement={sortBy}
              category={null}
              onLatLngUpdated={onLatLngUpdated}
            />
          </GridSectionContainer>

          <GridSectionContainer>
            <BlackText style={{ marginBottom: '10px' }} size="large">
              All Wishes
            </BlackText>

            {/* Algolia */}
            <Configure
              filters={getByStatusAndNotExpired('pending', Date.now())}
              hitsPerPage={WISHES_BATCH_SIZE}
              query={query}
              aroundLatLng={latLngFilter}
              aroundRadius={10000}
              enablePersonalization={true}
              userToken={user?.userId}
              clickAnalytics={true}
            />
            <WishesContainer>
              {/* Desktop,Tablet,Mobile has infinite scrolling  */}
              <WishesInfiniteHit category={category} minHitsPerPage={WISHES_BATCH_SIZE} />
            </WishesContainer>
          </GridSectionContainer>
        </Grid>
      </ViewAllWishesContainer>
    </InstantSearch>
  );
}
Example #26
Source File: DonationsViewCategoryPage.js    From website with MIT License 5 votes vote down vote up
ViewCategoryPage = ({ categoryDetails, sortByQuery }) => {
  const user = useUser();
  const category = categoryDetails;
  const [sortBy, setSortBy] = useState(sortByQuery ? sortByQuery : donationsSortByRule().defaultRefinement);
  const [latLngFilter, setLatLngFilter] = useState('');

  const onLatLngUpdated = (latLng) => {
    setLatLngFilter(latLng);
  };

  return (
    <InstantSearch searchClient={searchClient} indexName="donations">
      <ViewCategoryContainer>
        <Categories type="donations" />

        <Grid
          columnGap="20px"
          desktop={{
            columns: '1fr 6fr',
          }}
          rows="1fr auto"
        >
          <GridSectionContainer>
            <DonationsSortFilterPanel
              sortItems={donationsSortByRule().items}
              sortDefaultRefinement={sortBy}
              category={category}
              onLatLngUpdated={onLatLngUpdated}
            />
          </GridSectionContainer>

          <GridSectionContainer>
            <BlackText style={{ marginBottom: '10px' }} size="large">
              {category.name}
            </BlackText>

            {/* Algolia */}
            <Configure
              filters={getByCategoryIdAndStatus(category.id, 'pending')}
              hitsPerPage={DONATIONS_BATCH_SIZE}
              aroundLatLng={latLngFilter}
              aroundRadius={10000}
              enablePersonalization={true}
              userToken={user?.userId}
              clickAnalytics={true}
            />
            <DonationsContainer>
              {/* Desktop,Tablet,Mobile has infinite scrolling  */}
              <DonationsInfiniteHit category={category} minHitsPerPage={DONATIONS_BATCH_SIZE} />
            </DonationsContainer>
          </GridSectionContainer>
        </Grid>
      </ViewCategoryContainer>
    </InstantSearch>
  );
}
Example #27
Source File: AlgoliaProductList.jsx    From emprezzo with MIT License 4 votes vote down vote up
AlgoliaProductList = ({ defaultFilter, defaultSearchTerm, itemsPerPage, hideLeftPanel, hideCTAButton, showClearFilter, facetsToShow, showSearchBox, showSearchSuggestions, searchIndexName, enableShopProductSwitch, enableCart, noResultMessage }) => {

  const [currentIndexName, setCurrentIndexName] = React.useState(searchIndexName || `empProducts`)
  const changeCurrentIndexName = (e) => { setCurrentIndexName(e.target.value); setCurrentSuggestionIndexName(getSuggestionIndex(e.target.value)); setSuggestionQuery(''); }

  const getSuggestionIndex = (mainIndexName) => {
    if (mainIndexName == 'empProducts') return ('empProducts_query_suggestions');
    if (mainIndexName == 'uncommonry') return ('uncommonry_query_suggestions')
  }
  const [currentSuggestionIndexName, setCurrentSuggestionIndexName] = React.useState(getSuggestionIndex(currentIndexName))
  const [suggestionQuery, setSuggestionQuery] = React.useState();

  const algoliaClient = algoliasearch(
    process.env.GATSBY_ALGOLIA_APP_ID,
    process.env.GATSBY_ALGOLIA_SEARCH_KEY
  );
  const searchClient = {
    search(requests) {
      if (requests.length > 0 && defaultSearchTerm) requests[0].params.query = defaultSearchTerm
      return algoliaClient.search(requests);
    },
  };
  noResultMessage = noResultMessage || `No result found`;
  enableCart = enableCart || false;
  itemsPerPage = itemsPerPage || 12;
  
  aa('init', {
    appId: process.env.GATSBY_ALGOLIA_APP_ID,
    apiKey: process.env.GATSBY_ALGOLIA_SEARCH_KEY
  });

  const [currentHitComponent, setCurrentHitComponent] = React.useState();
  React.useEffect(() => {
    if (currentIndexName == 'empProducts') setCurrentHitComponent(() => connectHitInsights(aa)(AlgoliaProductItem));
    if (currentIndexName == 'uncommonry') setCurrentHitComponent(() => connectHitInsights(aa)(AlgoliaUncommonryItem));
    if (currentIndexName == 'emails') setCurrentHitComponent(() => connectHitInsights(aa)(AlgoliaEmailsItem));
  }, [currentIndexName]);

  const AlgoliaSuggestions = ({ hit }) => {
    return (
      <a href="javascript:" onClick={() => setSuggestionQuery(hit.query)}>{hit.query}</a>
    );
  }

  return (
    <SearchWrapper>
      {!enableCart &&
        <Global
          styles={css`
            .cart-section {
              display: none;
            }
        `}
        />
      }
      <InstantSearch indexName={currentIndexName} searchClient={searchClient}>
        <VirtualSearchBox defaultRefinement={suggestionQuery} />
        {!hideLeftPanel &&
          <LeftPanel>

            {showClearFilter &&
              <ClearRefinements />
            }
            {facetsToShow && facetsToShow.indexOf("category") >= 0 &&
              <>
                <FilterHeading>Category</FilterHeading>
                <RefinementList attribute="shopCategory" showMore='true' limit='5' />
              </>
            }
            {facetsToShow && facetsToShow.indexOf("brands") >= 0 && currentIndexName != 'uncommonry' &&
              <>
                <FilterHeading>Brands</FilterHeading>
                <RefinementList attribute="shopName" showMore='true' limit='5' />
              </>
            }
            {facetsToShow && facetsToShow.indexOf("payments") >= 0 && currentIndexName == 'uncommonry' &&
              <>
                <FilterHeading>Payments</FilterHeading>
                <RefinementList
                  attribute="shopifyPay"
                  transformItems={items =>
                    items.filter(item => (item.label == '1')).map(item => ({
                      ...item,
                      label: "Shop Pay",
                    }))
                  }
                />
                <RefinementList
                  attribute="paypal"
                  transformItems={items =>
                    items.filter(item => (item.label == '1')).map(item => ({
                      ...item,
                      label: "Paypal",
                    }))
                  }
                />
                <RefinementList
                  attribute="applePay"
                  transformItems={items =>
                    items.filter(item => (item.label == '1')).map(item => ({
                      ...item,
                      label: "Apple Pay",
                    }))
                  }
                />
                <RefinementList
                  attribute="amazonPay"
                  transformItems={items =>
                    items.filter(item => (item.label == '1')).map(item => ({
                      ...item,
                      label: "Amazon Pay",
                    }))
                  }
                />
              </>
            }
            {facetsToShow && facetsToShow.indexOf("pricerangeslider") >= 0 && currentIndexName == 'uncommonry' &&
              <>
                <FilterHeading>Average Price</FilterHeading>
                <AlgoliaRangeSlider attribute="price" />
              </>
            }
            {facetsToShow && facetsToShow.indexOf("prices") >= 0 && currentIndexName == 'empProducts' &&
              <>
                <FilterHeading>Prices</FilterHeading>
                <NumericMenu
                  attribute="price"
                  items={[
                    { label: 'All' },
                    { label: 'Under $50', end: 50 },
                    { label: '$50 - $100', start: 50, end: 100 },
                    { label: '$100 - $200', start: 100, end: 200 },
                    { label: '$200+', start: 200 },
                  ]}
                />
              </>
            }
            {/*
            {facetsToShow && facetsToShow.indexOf("giftcard") >= 0 && currentIndexName == 'empProducts' &&
              <>
                <FilterHeading>Gift Card</FilterHeading>
                <RefinementList
                  attribute="name"
                  transformItems={items =>
                    items.filter(item => (item.label.toLowerCase().indexOf('gift') >= 0))
                  }
                />
              </>
            }
            {facetsToShow && facetsToShow.indexOf("gifimage") >= 0 && currentIndexName == 'empProducts' &&
              <>
                <FilterHeading>GIF</FilterHeading>
                <RefinementList
                  attribute="imageURL"
                  transformItems={items =>
                    items.filter(item => (item.label.indexOf('.gif') >= 0)).map(item => ({
                      ...item,
                      label: "GIF",
                    }))
                  }
                />
              </>
            }
            */}

            {facetsToShow && facetsToShow.indexOf("storeoffers") >= 0 &&
              <>
                <FilterHeading>Store Offers</FilterHeading>
                <RefinementList
                  attribute="freeShipMin"
                  transformItems={items =>
                    items.filter(item => (item.label == 0)).map(item => ({
                      ...item,
                      label: "Free Shipping",
                    }))
                  }
                />
                <RefinementList
                  attribute="returnShipFree"
                  transformItems={items =>
                    items.filter(item => (item.label == 'Yes')).map(item => ({
                      ...item,
                      label: "Free Returns",
                    }))
                  }
                />
              </>
            }
          </LeftPanel>
        }
        <RightPanel>
          <Configure clickAnalytics={true} hitsPerPage={itemsPerPage} filters={defaultFilter} />
          <div class="searchline">
            <div class="indexSelect">
              {enableShopProductSwitch &&
                <div style={{ paddingBottom: '0.75rem' }}>
                  <select value={currentIndexName} onChange={changeCurrentIndexName}>
                    <option value="uncommonry">Shops</option>
                    <option value="empProducts">Products</option>
                  </select>
                </div>
              }
            </div>
            {facetsToShow && facetsToShow.indexOf("onsale") >= 0 &&
              <div class="saleFacet">
                <RefinementList
                  attribute="onSale"
                  transformItems={items =>
                    items.filter(item => (item.label == '1')).map(item => ({
                      ...item,
                      label: "On Sale",
                    }))
                  }
                />
              </div>
            }
          <div class="searchContainer">
            {showSearchBox &&
              <>
                <SearchBox defaultRefinement={suggestionQuery} />
              </>
            }<br style={{ clear: 'both' }} />
  {showSearchSuggestions && currentSuggestionIndexName &&
    <span style={{ 'font-weight': 'bold', 'padding': '0 1em 1em 0' }}>Trending </span>
  }
            {showSearchSuggestions && currentSuggestionIndexName &&

              <div className="suggestions">

                <InstantSearch
                  searchClient={searchClient}
                  indexName={currentSuggestionIndexName}
                >
                  <Configure hitsPerPage={5} />
                  <InfiniteHits hitComponent={AlgoliaSuggestions} />
                </InstantSearch>
              </div>
            }
            </div>
            {!hideCTAButton &&
              <div class="giftCard">
                <BuyGiftCard />
              </div>
            }
          </div>

          <AlgoliaStateResults noResultMessage={noResultMessage} />
          <Hits hitComponent={currentHitComponent} />
          <Pagination />
        </RightPanel>
      </InstantSearch>
    </SearchWrapper>
  );
}
Example #28
Source File: index.js    From website with MIT License 4 votes vote down vote up
TopWishes = ({ numberOfPosts, numberOfCategories }) => {
  const router = useRouter();
  const [topCategories, setTopCategories] = useState([]);

  useEffect(() => {
    getAllCategories().then((categories) => {
      getTopNCategoriesFromAlgoliaWithExpireDateTime('wishes').then(({ hits, facets }) => {
        if (facets['categories.id'] === undefined || Object.keys(facets['categories.id']).length === 0) {
          return;
        }
        const sorted = sortObjectEntries(facets['categories.id']);
        if (sorted.length >= numberOfCategories) {
          const topNCategoriesIds = sorted.slice(0, numberOfCategories);
          const topNCategories = categories.filter((category) => {
            if (topNCategoriesIds.includes(category.id)) {
              return true;
            }
            return false;
          });
          setTopCategories(topNCategories);
        } else if (sorted.length > 0 && sorted.length < numberOfCategories) {
          const topCategories = categories.filter((category) => {
            if (sorted.includes(category.id)) {
              return true;
            }
            return false;
          });
          setTopCategories(topCategories);
        }
      });
    });
  }, []);

  const getAllCategories = async () => {
    const rawCategories = await api.categories.getAll().catch((err) => console.error(err));
    return rawCategories.docs.map((doc) => doc.data());
  };

  const TopWishesColumn = ({ hits, category }) => {
    const categoryHref = `/wishes/category/${category.id}`;
    const handleViewAllButton = (event) => {
      event.preventDefault();
      router.push(categoryHref);
    };
    return (
      <WishesColumn key={category.id}>
        <CategoryHeader title={category.name}></CategoryHeader>
        {hits.map((wish) => {
          const wishPostHref = `/wishes/${wish.objectID}`;
          const profileHref = `/profile/${wish.user.userId}`;
          return (
            <GroupWishCard
              key={`${category.id}-${wish.objectID}`}
              name={wish.organization.name}
              title={wish.title}
              description={wish.description}
              imageUrl={wish.user.profileImageUrl}
              postedDateTime={wish.postedDateTime}
              postHref={wishPostHref}
              profileHref={profileHref}
              categoryId={category.id}
              categoryName={category.name}
            />
          );
        })}
        <ViewAllButtonContainer>
          <Button size="small" asComponent={GreySubtleButton} onClick={handleViewAllButton}>
            <BlackText size="small">View all</BlackText>
          </Button>
        </ViewAllButtonContainer>
      </WishesColumn>
    );
  };

  const TopCategories = connectHits(TopWishesColumn);

  return (
    <Stack desktop={{ direction: 'row' }} direction="column" align="start" spacing="extraLoose">
      {topCategories.map((category) => (
        <InstantSearch key={category.id} searchClient={searchClient} indexName="wishes">
          <TopCategories category={category} />
          <Configure
            filters={getByCategoryIdAndStatusAndNotExpired(category.id, 'pending', Date.now())}
            hitsPerPage={numberOfPosts}
          />
        </InstantSearch>
      ))}
    </Stack>
  );
}
Example #29
Source File: index.js    From website with MIT License 4 votes vote down vote up
TopDonations = ({ numberOfPosts, numberOfCategories }) => {
  const router = useRouter();
  const [topCategories, setTopCategories] = useState([]);

  useEffect(() => {
    getTopNCategories().then((categories) => {
      getTopNCategoriesFromAlgolia('donations').then(({ hits, facets }) => {
        if (facets['categories.id'] === undefined || Object.keys(facets['categories.id']).length === 0) {
          return;
        }
        const sorted = sortObjectEntries(facets['categories.id']);
        if (sorted.length >= numberOfCategories) {
          const topNCategoriesIds = sorted.slice(0, numberOfCategories);
          const topNCategories = categories.filter((category) => {
            if (topNCategoriesIds.includes(category.id)) {
              return true;
            }
            return false;
          });
          setTopCategories(topNCategories);
        } else if (sorted.length > 0 && sorted.length < numberOfCategories) {
          const topCategories = categories.filter((category) => {
            if (sorted.includes(category.id)) {
              return true;
            }
            return false;
          });
          setTopCategories(topCategories);
        }
      });
    });
  }, []);

  const getTopNCategories = async () => {
    const rawCategories = await api.categories.getAll().catch((err) => console.error(err));
    return rawCategories.docs.map((doc) => doc.data());
  };

  const TopDonationsRow = ({ hits, category }) => {
    const categoryHref = `/donations/category/${category.id}`;
    const handleViewAllButton = (event) => {
      event.preventDefault();
      router.push(categoryHref);
    };
    const getScrollableWidth = () => document.getElementById(category.id).clientWidth;
    const handleScrollLeft = () => (document.getElementById(category.id).scrollLeft -= getScrollableWidth());
    const handleScrollRight = () => (document.getElementById(category.id).scrollLeft += getScrollableWidth());
    return (
      <TopDonationCardsContainer key={category.id}>
        <CategoryHeader>
          <LeftAnchor>
            <Text size="normal" weight="bold">
              {category.name}
            </Text>
          </LeftAnchor>
          <RightAnchor>
            <Button size="small" asComponent={GreySubtleButton} onClick={handleViewAllButton}>
              <BlackText size="small">View all</BlackText>
            </Button>
          </RightAnchor>
        </CategoryHeader>
        <CarouselContainer>
          <Desktop>
            <CarouselScrollButton direction="left" size="normal" onClickHandler={handleScrollLeft} />
          </Desktop>
          <DonationsRow id={category.id} className="scrollableDonation">
            <Stack direction="row" align="start" spacing="extraLoose">
              {hits.map((donation) => {
                const donationPostHref = `/donations/${donation.objectID}`;
                const profileHref = `/profile/${donation.user.userId}`;
                const validPeriod = `${getFormattedDate(donation.validPeriodFrom)} - ${getFormattedDate(
                  donation.validPeriodTo
                )}`;
                return (
                  <DonationCard
                    key={`${category.id}-${donation.objectID}`}
                    name={donation.user.userName}
                    title={donation.title}
                    description={donation.description}
                    profileImageUrl={donation.user.profileImageUrl}
                    postedDateTime={donation.postedDateTime}
                    coverImageUrl={donation.coverImageUrl}
                    postHref={donationPostHref}
                    profileHref={profileHref}
                    validPeriod={validPeriod}
                    itemCondition={donation.itemCondition}
                    categoryId={category.id}
                    categoryName={category.name}
                  ></DonationCard>
                );
              })}
            </Stack>
          </DonationsRow>
          <Desktop>
            <CarouselScrollButton direction="right" size="normal" onClickHandler={handleScrollRight} />
          </Desktop>
        </CarouselContainer>
      </TopDonationCardsContainer>
    );
  };

  const TopCategories = connectHits(TopDonationsRow);

  return (
    <Stack direction="column" align="start" spacing="natural">
      {topCategories.map((category) => (
        <InstantSearch key={category.id} searchClient={searchClient} indexName="donations">
          <TopCategories category={category} />
          <Configure filters={getByCategoryIdAndStatus(category.id, 'pending')} hitsPerPage={numberOfPosts} />
        </InstantSearch>
      ))}
    </Stack>
  );
}