1. Primeiro, nós vamos criar um novo contexto, que será um contexto para conversarmos com o search e os filtros. Nós vamos criar um arquivo dentro de contexts e vamos chamar de QueryContext.ts, e aqui iremos criar o contexto geral das nossas querys, onde iremos modificar todos os nossos filtros

    import React from "react";
    
    interface QueryType {
      filters: string[];
      addFilter: (filter: string) => void;
    }
    
    export const QueryContext = React.createContext<QueryType>({
      filters: [],
      addFilter: () => {},
    });
    
  2. Agora que temos esse contexto criado, nós podemos ir na tela de search para criar algumas configurações. Primeiro iremos criar um useState chamado de filters

    const [filters, setFilters] = useState<string[]>([]);
    
  3. Nós iremos em seguida criar um let chamado “joinedFilters”, que serão todos os filtros que a gente for adicionando com o nosso “&” que é obrigatório para adicionarmos cada um dos parâmetros a mais

    let joinedFilters = filters.join("&");
    
  4. Vamos em seguida modificar algumas coisas. Vamos colocar o joinedFilters dentro da função getSearchedProducts, e depois criaremos um useEffect para dar o set nos filters que a gente está usando, que o primeiro sempre vai ser a nossa query. Depois, iremos criar um useEffect que vai ser chamado para chamar a função de search novamente sempre que tivermos um novo filtro adicionado.

    const handleSearch = async () => {
      const { data } = await searchService.getSearchedProducts(joinedFilters);
    
      setData(data?.products);
      setLoading(false);
    };
    
    useEffect(() => {
      setFilters([query]);
    }, [query]);
    
    useEffect(() => {
      joinedFilters && handleSearch();
    }, [joinedFilters]);
    
  5. Nós vamos agora criar uma função que irá fazer a adição do filtro. E ao mesmo que ele adiciona, ele verifica e não deixa ter nenhuma repetida. Ou seja, sempre que a gente for adicionar um filtro, vamos remover o anterior caso ele se repita.

    const addFilter = (filter: string) => {
      const newFilterParts = filter.split("=");
    
      const newFilters = filters.map((f) =>
        f.startsWith(newFilterParts[0]) ? filter : f
      );
    
      if (!newFilters.includes(filter)) {
        newFilters.push(filter);
      }
    
      setFilters(newFilters);
    };
    
  6. E nesse caso nós vamos primeiro separar os nossos filtros por “=” e depois nós vamos verificar se existe algum repetido. Se existir, ele vai ser substituído por um novo filtro, isso serve para caso o usuário faça o filtro de preço com preço X e depois mude para preço Y, e aí ele vai ter o mesmo filtro 2 vezes, que é o de preço.

  7. E aí no if, verificamos para colocar o filtro na url caso ele nunca tenha existido nela. E por fim, a gente coloca todos os filtros para o nosso state de filtros.

  8. E aí agora nós iremos criar o queyrContextValue, que será a forma que vamos distribuir os filtros para o contexto

    const addFilter = (filter: string) => {
      const newFilterParts = filter.split("=");
    
      const newFilters = filters.map((f) =>
        f.startsWith(newFilterParts[0]) ? filter : f
      );
    
      if (!newFilters.includes(filter)) {
        newFilters.push(filter);
      }
    
      setFilters(newFilters);
    };
    
    const queryContextValue = {
      filters,
      addFilter,
    };
    
  9. Agora que fizemos tudo, temos o contexto organizado e pronto para ser distribuído. Vamos então colocar ele em torno do filters.

    return (
      <Container>
        <Header />
    
        <QueryContext.Provider value={queryContextValue}>
          <Filters />
        </QueryContext.Provider>
      </Container>
    );
    
  10. Com o contexto enviado para os filtros, vamos lá pegar eles. Vamos fazer isso através do useContext

    const Filters = () => {
      const [modalVisible, setModalVisible] = useState(false);
      const [filterText, setFilterText] = useState("Mais recente");
      const [showFilters, setShowFilters] = useState(false);
      const queryContext = useContext(QueryContext);
    
  11. Agora nós já podemos usar ele. Vamos usar para as nossas funções aqui abaixo, colocando o filtro através do addFilters

    const handleBigestPrice = async () => {
      setFilterText("Maior preço");
      queryContext.addFilter("orderBy=price&direction=desc");
      setModalVisible(false);
    };
    
    const handleLowestPrice = async () => {
      setFilterText("Menor preço");
      queryContext.addFilter("orderBy=price&direction=asc");
      setModalVisible(false);
    };
    
    const handleNewest = async () => {
      setFilterText("Mais recente");
      queryContext.addFilter("orderBy=updatedAt");
      setModalVisible(false);
    };
    
  12. Podemos então testar e dar também um console.log no nosso joinedFilters para ver ele modificando de acordo com o que chamamos

    console.log({ joinedFilters });