photum/frontend/components/EventFiltersBar.tsx
João Vitor 8016a0298e feat: Melhorias na tabela de eventos e formulários
- Adiciona coluna de Cidade com ordenação independente na tabela de eventos
- Implementa ordenação clicável em todas as colunas (nome, tipo, data, horário, cidade, local, status)
- Remove dependência de estado para filtro de cidade
- Adiciona exibição de curso/turma no modal de detalhes do evento
- Torna campo curso/turma obrigatório no formulário de solicitação de evento
- Remove campo de imagem de capa do formulário
- Corrige importação de getActiveCoursesByInstitutionId no Dashboard
2025-12-08 09:11:05 -03:00

224 lines
8.1 KiB
TypeScript

import React from 'react';
import { Calendar, MapPin, Clock, Filter, X } from 'lucide-react';
export interface EventFilters {
date: string;
city: string;
state: string;
timeRange: string;
type: string;
}
interface EventFiltersBarProps {
filters: EventFilters;
onFilterChange: (filters: EventFilters) => void;
availableCities: string[];
availableStates: string[];
availableTypes: string[];
}
export const EventFiltersBar: React.FC<EventFiltersBarProps> = ({
filters,
onFilterChange,
availableCities,
availableStates,
availableTypes,
}) => {
const handleReset = () => {
onFilterChange({
date: '',
city: '',
state: '',
timeRange: '',
type: '',
});
};
const hasActiveFilters = Object.values(filters).some(value => value !== '');
const timeRanges = [
{ value: '', label: 'Todos os horários' },
{ value: 'morning', label: 'Manhã (06:00 - 12:00)' },
{ value: 'afternoon', label: 'Tarde (12:00 - 18:00)' },
{ value: 'evening', label: 'Noite (18:00 - 23:59)' },
];
return (
<div className="bg-white rounded-lg border border-gray-200 p-4 shadow-sm">
<div className="flex items-center justify-between mb-4">
<div className="flex items-center gap-2">
<Filter size={18} className="text-brand-gold" />
<h3 className="font-semibold text-gray-800">Filtros Avançados</h3>
</div>
{hasActiveFilters && (
<button
onClick={handleReset}
className="flex items-center gap-1 text-sm text-gray-600 hover:text-brand-gold transition-colors"
>
<X size={16} />
Limpar filtros
</button>
)}
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-3">
{/* Filtro por Data */}
<div className="flex flex-col">
<label className="text-xs font-medium text-gray-600 mb-1 flex items-center gap-1">
<Calendar size={14} className="text-brand-gold" />
Data
</label>
<input
type="date"
value={filters.date}
onChange={(e) => onFilterChange({ ...filters, date: e.target.value })}
className="px-3 py-2 border border-gray-300 rounded text-sm focus:outline-none focus:border-brand-gold transition-colors"
/>
</div>
{/* Filtro por Estado */}
<div className="flex flex-col">
<label className="text-xs font-medium text-gray-600 mb-1 flex items-center gap-1">
<MapPin size={14} className="text-brand-gold" />
Estado
</label>
<select
value={filters.state}
onChange={(e) => onFilterChange({ ...filters, state: e.target.value })}
className="px-3 py-2 border border-gray-300 rounded text-sm focus:outline-none focus:border-brand-gold transition-colors bg-white"
>
<option value="">Todos os estados</option>
{availableStates.map((state) => (
<option key={state} value={state}>
{state}
</option>
))}
</select>
</div>
{/* Filtro por Cidade */}
<div className="flex flex-col">
<label className="text-xs font-medium text-gray-600 mb-1 flex items-center gap-1">
<MapPin size={14} className="text-brand-gold" />
Cidade
</label>
<select
value={filters.city}
onChange={(e) => onFilterChange({ ...filters, city: e.target.value })}
className="px-3 py-2 border border-gray-300 rounded text-sm focus:outline-none focus:border-brand-gold transition-colors bg-white"
>
<option value="">Todas as cidades</option>
{availableCities.map((city) => (
<option key={city} value={city}>
{city}
</option>
))}
</select>
</div>
{/* Filtro por Horário */}
<div className="flex flex-col">
<label className="text-xs font-medium text-gray-600 mb-1 flex items-center gap-1">
<Clock size={14} className="text-brand-gold" />
Horário
</label>
<select
value={filters.timeRange}
onChange={(e) => onFilterChange({ ...filters, timeRange: e.target.value })}
className="px-3 py-2 border border-gray-300 rounded text-sm focus:outline-none focus:border-brand-gold transition-colors bg-white"
>
{timeRanges.map((range) => (
<option key={range.value} value={range.value}>
{range.label}
</option>
))}
</select>
</div>
{/* Filtro por Tipo */}
<div className="flex flex-col">
<label className="text-xs font-medium text-gray-600 mb-1 flex items-center gap-1">
<Filter size={14} className="text-brand-gold" />
Tipo de Evento
</label>
<select
value={filters.type}
onChange={(e) => onFilterChange({ ...filters, type: e.target.value })}
className="px-3 py-2 border border-gray-300 rounded text-sm focus:outline-none focus:border-brand-gold transition-colors bg-white"
>
<option value="">Todos os tipos</option>
{availableTypes.map((type) => (
<option key={type} value={type}>
{type}
</option>
))}
</select>
</div>
</div>
{/* Active Filters Display */}
{hasActiveFilters && (
<div className="mt-3 pt-3 border-t border-gray-100">
<div className="flex flex-wrap gap-2">
<span className="text-xs text-gray-500">Filtros ativos:</span>
{filters.date && (
<span className="inline-flex items-center gap-1 px-2 py-1 bg-brand-gold/10 text-brand-gold text-xs rounded">
Data: {new Date(filters.date + 'T00:00:00').toLocaleDateString('pt-BR')}
<button
onClick={() => onFilterChange({ ...filters, date: '' })}
className="hover:text-brand-black"
>
<X size={12} />
</button>
</span>
)}
{filters.state && (
<span className="inline-flex items-center gap-1 px-2 py-1 bg-brand-gold/10 text-brand-gold text-xs rounded">
Estado: {filters.state}
<button
onClick={() => onFilterChange({ ...filters, state: '', city: '' })}
className="hover:text-brand-black"
>
<X size={12} />
</button>
</span>
)}
{filters.city && (
<span className="inline-flex items-center gap-1 px-2 py-1 bg-brand-gold/10 text-brand-gold text-xs rounded">
Cidade: {filters.city}
<button
onClick={() => onFilterChange({ ...filters, city: '' })}
className="hover:text-brand-black"
>
<X size={12} />
</button>
</span>
)}
{filters.timeRange && (
<span className="inline-flex items-center gap-1 px-2 py-1 bg-brand-gold/10 text-brand-gold text-xs rounded">
{timeRanges.find(r => r.value === filters.timeRange)?.label}
<button
onClick={() => onFilterChange({ ...filters, timeRange: '' })}
className="hover:text-brand-black"
>
<X size={12} />
</button>
</span>
)}
{filters.type && (
<span className="inline-flex items-center gap-1 px-2 py-1 bg-brand-gold/10 text-brand-gold text-xs rounded">
Tipo: {filters.type}
<button
onClick={() => onFilterChange({ ...filters, type: '' })}
className="hover:text-brand-black"
>
<X size={12} />
</button>
</span>
)}
</div>
</div>
)}
</div>
);
};