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: () => {},
});
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[]>([]);
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("&");
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]);
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);
};
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.
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.
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,
};
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>
);
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);
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);
};
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 });