Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

[Reclamação] Faltou a resolução

Há apenas uma parte falando sobre adicionar na interface de IEventoFiltro, porém não tem a implementação para fazê-la funcionar.

Eu implementei assim:

selectors.ts

import { selector } from "recoil";
import { IEvento } from "../interfaces/IEvento";
import { filtroEventosState, listaEventosState } from "./atom";

export const eventosFiltradosState = selector<IEvento[]>({
  key: "eventosFiltradosState",
  get: ({ get }) => {
    const todosEventos = get(listaEventosState);
    const filtro = get(filtroEventosState);

    const eventos = todosEventos.filter((evt) => {
      if (filtro.data) {
        const ehOMesmoDia = filtro.data.toISOString().slice(0, 10) === evt.inicio.toISOString().slice(0, 10);

        return filtro.estado !== "ambos"
          ? filtro.estado === "completos"
            ? ehOMesmoDia && evt.completo
            : ehOMesmoDia && !evt.completo
          : ehOMesmoDia;
      }

      if (filtro.estado === "completos") return evt.completo;

      if (filtro.estado === "incompletos") return !evt.completo;

      return true;
    });

    return eventos;
  },
});

Filtro/index.tsx

import React, { useState } from "react";
import { useSetRecoilState } from "recoil";
import { IFiltroEventos } from "../../common/interfaces/IFiltro";
import { filtroEventosState } from "../../common/stores/atom";
import style from "./Filtro.module.scss";

const Filtro = () => {
  const [data, setData] = useState("");
  const [estado, setEstado] = useState<"ambos" | "incompletos" | "completos">("ambos");

  const setFiltroEvento = useSetRecoilState(filtroEventosState);

  const submeterForm = (evento: React.FormEvent<HTMLFormElement>) => {
    evento.preventDefault();

    const filtro: IFiltroEventos = {};

    if (!data && !estado) {
      filtro.data = null;
      filtro.estado = null;
    }

    if (data && !estado) filtro.data = new Date(data);

    if (estado && !data) filtro.estado = estado;

    filtro.data = new Date(data);
    filtro.estado = estado;

    setFiltroEvento(filtro);
  };

  return (
    <form className={style.Filtro} onSubmit={submeterForm}>
      <div>
        <h3 className={style.titulo}>Filtrar por data</h3>
        <input
          type="date"
          name="data"
          className={style.input}
          onChange={(evento) => setData(evento.target.value)}
          placeholder="Por data"
          value={data}
        />
      </div>
      <div>
        <h3>Filtrar por estado:</h3>
        <label>
          Ambos:
          <input type="radio" name="estado" value={estado} onChange={() => setEstado("ambos")} />
        </label>
        <label>
          Completos:
          <input type="radio" name="estado" value={estado} onChange={() => setEstado("completos")} />
        </label>
        <label>
          Incompletos:
          <input type="radio" name="estado" value={estado} onChange={() => setEstado("incompletos")} />
        </label>
      </div>

      <button className={style.botao}>Filtrar</button>
    </form>
  );
};

export default Filtro;

Queria saber como o professor implementou.

2 respostas
solução!

Salve, Levi!

A falta da resolução aqui foi proposital! Minha ideia por trás dessa atividade era mesmo instigar soluções diferentes.

A única coisa que eu mudaria, talvez, seria extrair a lista de possíveis estados para uma const e fazer um .map ao invés de colocar todos os radios manualmente.

A nível de UX/UI, eu colocaria dentro de um <select> com as opções ao invés de colocar todos os radios ocupado espaço na tela. Mas é mais questão de gosto mesmo :)

Bons estudos!

Vou aproveitar esse tópico já aberto para compartilhar minha solução, pode ser? Ao invés de usar operador lógico && no seletor, eu encadeei uma nova chamada de filter. E usei um <select>:


seletores/index.ts

import { selector } from "recoil";
import { filtroDeEventosState, listaDeEventosState } from "../atom";

export const eventosFiltradosState = selector({
  key: 'eventosFiltradosState',
  get: ({ get }) => {
    const filtro = get(filtroDeEventosState);
    const todosEventos = get(listaDeEventosState);
    const eventos = todosEventos.filter(evento => {
      if (!filtro.data) {
        return true;
      }
      const ehMesmoDia = filtro.data.toISOString().slice(0, 10) === evento.inicio.toISOString().slice(0,10);
      return ehMesmoDia;
    }).filter(evento => {
      if (!filtro.status) {
        return true;
      }
      switch(filtro.status) {
        case "completas":
          return evento.completo === true;
        case "incompletas":
          return evento.completo === false;
        default:
          return true;
      }
    });
    return eventos;
  }
})

componentes/Filtro/index.tsx

import React, { useState } from 'react';
import { useSetRecoilState } from 'recoil';
import { IFiltroDeEventos } from '../../interfaces/IFiltroDeEventos';
import { filtroDeEventosState } from '../../state/atom';
import style from './Filtro.module.scss';

const Filtro: React.FC = () => {

  const [data, setData] = useState('');
  const [status, setStatus] = useState('');
  const setFiltroDeEvento = useSetRecoilState<IFiltroDeEventos>(filtroDeEventosState);

  const submeterForm = (evento: React.FormEvent<HTMLFormElement>) => {
    evento.preventDefault()
    const filtro: IFiltroDeEventos = {}
    if (data) {
      filtro.data = new Date(data);
    } else {
      filtro.data = null;
    }
    if (status) {
      filtro.status = status;
    } else {
      filtro.status = 'todas';
    }

    setFiltroDeEvento(filtro);
  }

  return (<form className={style.Filtro} onSubmit={submeterForm}>
    <h3 className={style.titulo}>Filtrar por data</h3>
    <input 
      type="date" 
      name="data"
      className={style.input}
      onChange={evento => {setData(evento.target.value)}} 
      placeholder="Por data"
      value={data} />

    <h3 className={style.titulo}>Filtrar por status</h3>
    <select 
      name="status"
      onChange={evento => {setStatus(evento.target.value)}}
      value={status}
    >
      <option value="todas">Todas</option>
      <option value="completas">Completas</option>
      <option value="incompletas">Incompletas</option>
    </select>

    <button className={style.botao}>
      Filtrar
    </button>

  </form>)
}

export default Filtro

Eu fiquei na dúvida se a ordem dos filter faz diferença, mas acredito que não.