Skip to content

Commit 4a56d3f

Browse files
committed
feat: improve search functionality and display talks sorted by room and time
1 parent a08f5c1 commit 4a56d3f

1 file changed

Lines changed: 49 additions & 70 deletions

File tree

src/app/talks/page.js

Lines changed: 49 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Link from "next/link";
66
import allTalks from "@/data/talks";
77
import cityData from "@/data/cities";
88
import EmptyState from "@/components/EmptyState";
9+
import { FaSearch } from "react-icons/fa";
910

1011
export default function TalksPage() {
1112
const [selectedCity, setSelectedCity] = useState("");
@@ -25,18 +26,18 @@ export default function TalksPage() {
2526
const filteredTalks = allTalks.filter((talk) => {
2627
const cityInfo = cityData[talk.city];
2728
const searchTerms = debouncedSearch.toLowerCase();
28-
29+
2930
const cityMatch = !selectedCity || talk.city === selectedCity;
30-
const categoryMatch =
31-
!selectedCategory || talk.category === selectedCategory;
32-
const dateMatch = selectedDay ? cityInfo.date === selectedDay : true;
33-
31+
const categoryMatch = !selectedCategory || talk.category === selectedCategory;
32+
const dateMatch = selectedDay ? cityInfo?.date === selectedDay : true;
33+
3434
const searchMatch =
3535
talk.title.toLowerCase().includes(searchTerms) ||
3636
talk.description.toLowerCase().includes(searchTerms) ||
37-
talk.tags?.some((tag) => tag.toLowerCase().includes(searchTerms)) ||
38-
talk.speaker.name.toLowerCase().includes(searchTerms);
39-
37+
(talk.tags && talk.tags.some(tag => tag.toLowerCase().includes(searchTerms))) ||
38+
(talk.speaker?.name && talk.speaker.name.toLowerCase().includes(searchTerms)) ||
39+
(talk.speakers && talk.speakers.some(s => s.name.toLowerCase().includes(searchTerms)));
40+
4041
return cityMatch && categoryMatch && dateMatch && searchMatch;
4142
});
4243

@@ -99,7 +100,8 @@ export default function TalksPage() {
99100
))}
100101
</div>
101102
</div>
102-
{/* Filtros de charlas */}
103+
104+
{/* Filtros de charlas (estructura original) */}
103105
<div className="mb-8 backdrop-blur-sm rounded-lg p-4 md:p-6">
104106
<div className="flex flex-col md:flex-row gap-4 md:items-center justify-between">
105107
<div className="flex items-center gap-2 flex-wrap">
@@ -125,7 +127,6 @@ export default function TalksPage() {
125127
<option value="tecnica">Técnica</option>
126128
<option value="comunidad">Comunidad</option>
127129
<option value="caso-de-exito">Caso de Éxito</option>
128-
<option value="keynote">Keynote</option>
129130
</select>
130131
</div>
131132
<div className="relative">
@@ -136,73 +137,51 @@ export default function TalksPage() {
136137
onChange={(e) => setSearchQuery(e.target.value)}
137138
className="text-py-text border border-py-text/20 rounded pl-9 pr-3 py-1.5 w-full md:w-64 text-sm focus:outline-none focus:ring-2 focus:ring-py-green"
138139
/>
139-
<svg
140-
xmlns="http://www.w3.org/2000/svg"
141-
className="h-4 w-4 absolute left-3 top-2 text-py-text/60"
142-
fill="none"
143-
viewBox="0 0 24 24"
144-
stroke="currentColor"
145-
>
146-
<path
147-
strokeLinecap="round"
148-
strokeLinejoin="round"
149-
strokeWidth={2}
150-
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
151-
/>
152-
</svg>
140+
<FaSearch className="h-4 w-4 absolute left-3 top-2 text-py-text/60" />
153141
</div>
154142
</div>
155143
</div>
156144

157-
{/* Renderizado de charlas */}
145+
{/* Renderizado agrupado por sala */}
158146
{filteredTalks.length > 0 ? (
159-
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
160-
{filteredTalks.map((talk) => {
161-
const cityInfo = cityData[talk.city];
162-
return (
163-
<TalkCard
164-
key={talk.id}
165-
talk={{
166-
...talk,
167-
date: cityInfo.date,
168-
location: cityInfo.name,
169-
cityInfo: cityInfo,
170-
}}
171-
/>
172-
);
173-
})}
174-
</div>
147+
Object.entries(
148+
filteredTalks.reduce((acc, talk) => {
149+
const room = talk.room || "Sala no asignada";
150+
if (!acc[room]) acc[room] = [];
151+
acc[room].push(talk);
152+
return acc;
153+
}, {})
154+
).map(([roomName, talksInRoom]) => {
155+
// Ordena por hora dentro de la sala
156+
const sortedTalks = talksInRoom.sort((a, b) =>
157+
a.time.localeCompare(b.time)
158+
);
159+
160+
return (
161+
<div key={roomName} className="mb-12">
162+
<h2 className="text-xl font-bold mb-4 text-py-green">{roomName}</h2>
163+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
164+
{sortedTalks.map((talk) => {
165+
const cityInfo = cityData[talk.city];
166+
return (
167+
<TalkCard
168+
key={talk.id}
169+
talk={{
170+
...talk,
171+
date: cityInfo.date,
172+
location: cityInfo.name,
173+
cityInfo: cityInfo,
174+
}}
175+
/>
176+
);
177+
})}
178+
</div>
179+
</div>
180+
);
181+
})
175182
) : (
176183
<EmptyState context="global" />
177184
)}
178-
179-
{/* TODO: API para que funcione: */}
180-
{/* Subscribe for updates */}
181-
{/* <div className="mt-16 bg-green-800/30 backdrop-blur-sm rounded-lg p-6 md:p-8">
182-
<div className="max-w-4xl mx-auto">
183-
<div className="flex flex-col md:flex-row md:items-center justify-between gap-6">
184-
<div>
185-
<h3 className="text-xl md:text-2xl font-bold mb-2">
186-
¿Quieres recibir actualizaciones?
187-
</h3>
188-
<p className="text-sm md:text-base text-white/80">
189-
Suscríbete para recibir notificaciones sobre nuevas charlas y
190-
cambios en el programa.
191-
</p>
192-
</div>
193-
<div className="flex flex-col sm:flex-row gap-3">
194-
<input
195-
type="email"
196-
placeholder="Tu correo electrónico"
197-
className="bg-black/30 text-white border border-white/20 rounded px-4 py-2 w-full sm:w-64 text-sm focus:outline-none focus:ring-2 focus:ring-green-500"
198-
/>
199-
<button className="btn-primary whitespace-nowrap py-2">
200-
Suscribirse
201-
</button>
202-
</div>
203-
</div>
204-
</div>
205-
</div> */}
206185
</div>
207186
);
208-
}
187+
}

0 commit comments

Comments
 (0)