Merge pull request 'Added date and category filtering' (#3) from feature/date-category-filter into main
Reviewed-on: #3
This commit is contained in:
commit
08e457ad96
@ -89,14 +89,18 @@ footer {
|
|||||||
|
|
||||||
.search__controls {
|
.search__controls {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search__controls input {
|
.search__controls input,
|
||||||
|
.search__controls select {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
min-width: 120px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search__controls button {
|
.search__controls button {
|
||||||
width: 150px;
|
flex: 0 0 auto;
|
||||||
|
min-width: 120px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#event-list {
|
#event-list {
|
||||||
|
|||||||
19
index.html
19
index.html
@ -42,12 +42,13 @@
|
|||||||
<main class="container mt-4">
|
<main class="container mt-4">
|
||||||
|
|
||||||
<!-- SEARCH / FILTER SECTION -->
|
<!-- SEARCH / FILTER SECTION -->
|
||||||
<section class="event-search mb-4">
|
<section class="search mb-4">
|
||||||
|
|
||||||
<h2>Find Events</h2>
|
<h2>Find Events</h2>
|
||||||
|
|
||||||
<div class="search__controls">
|
<div class="search__controls">
|
||||||
|
|
||||||
|
<!-- City -->
|
||||||
<input
|
<input
|
||||||
id="city-input"
|
id="city-input"
|
||||||
type="text"
|
type="text"
|
||||||
@ -55,6 +56,22 @@
|
|||||||
placeholder="Enter city (e.g. Zurich)"
|
placeholder="Enter city (e.g. Zurich)"
|
||||||
>
|
>
|
||||||
|
|
||||||
|
<!-- Date -->
|
||||||
|
<label>From</label>
|
||||||
|
<input id="date-from" type="date">
|
||||||
|
|
||||||
|
<label>To</label>
|
||||||
|
<input id="date-to" type="date">
|
||||||
|
|
||||||
|
<!-- Category -->
|
||||||
|
<select id="category-input" class="form-control">
|
||||||
|
<option value="">All categories</option>
|
||||||
|
<option value="music">Music</option>
|
||||||
|
<option value="sports">Sports</option>
|
||||||
|
<option value="arts & theatre">Arts & Theatre</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- Button -->
|
||||||
<button
|
<button
|
||||||
id="load-events"
|
id="load-events"
|
||||||
class="btn btn-primary"
|
class="btn btn-primary"
|
||||||
|
|||||||
51
js/app.js
51
js/app.js
@ -1,13 +1,22 @@
|
|||||||
import { fetchEvents } from "./api/ticketmaster.js";
|
import { fetchEvents } from "./api/ticketmaster.js";
|
||||||
import { createEventCard } from "./ui/eventCard.js";
|
import { renderEventList } from "./ui/eventList.js";
|
||||||
|
import { getFilters } from "./ui/filters.js";
|
||||||
|
|
||||||
const button = document.querySelector("#load-events");
|
const button = document.querySelector("#load-events");
|
||||||
const container = document.querySelector("#event-list");
|
const container = document.querySelector("#event-list");
|
||||||
const cityInput = document.querySelector("#city-input");
|
const cityInput = document.querySelector("#city-input");
|
||||||
|
|
||||||
button.addEventListener("click", async () => {
|
button.addEventListener("click", handleSearch);
|
||||||
|
|
||||||
const city = cityInput.value.trim();
|
cityInput.addEventListener("keydown", (event) => {
|
||||||
|
if (event.key === "Enter") {
|
||||||
|
handleSearch();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function handleSearch() {
|
||||||
|
|
||||||
|
const { city, dateFrom, dateTo, category } = getFilters();
|
||||||
|
|
||||||
if (!city) {
|
if (!city) {
|
||||||
container.innerHTML = "Please enter a city.";
|
container.innerHTML = "Please enter a city.";
|
||||||
@ -18,22 +27,28 @@ button.addEventListener("click", async () => {
|
|||||||
|
|
||||||
const events = await fetchEvents(city);
|
const events = await fetchEvents(city);
|
||||||
|
|
||||||
container.innerHTML = "";
|
const filteredEvents = applyFilters(events, dateFrom, dateTo, category);
|
||||||
|
|
||||||
if (events.length === 0) {
|
renderEventList(filteredEvents, container);
|
||||||
container.innerHTML = "No events found.";
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
events.forEach(event => {
|
function applyFilters(events, dateFrom, dateTo, category) {
|
||||||
const card = createEventCard(event);
|
|
||||||
container.appendChild(card);
|
return events.filter(event => {
|
||||||
|
|
||||||
|
const eventDate = event.dates.start.localDate;
|
||||||
|
|
||||||
|
const eventCategory =
|
||||||
|
event.classifications?.[0]?.segment?.name?.toLowerCase();
|
||||||
|
|
||||||
|
const matchDateFrom = dateFrom ? eventDate >= dateFrom : true;
|
||||||
|
const matchDateTo = dateTo ? eventDate <= dateTo : true;
|
||||||
|
|
||||||
|
const matchCategory = category
|
||||||
|
? eventCategory === category
|
||||||
|
: true;
|
||||||
|
|
||||||
|
return matchDateFrom && matchDateTo && matchCategory;
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
}
|
||||||
|
|
||||||
cityInput.addEventListener("keydown", (event) => {
|
|
||||||
if (event.key === "Enter") {
|
|
||||||
button.click();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@ -1,17 +1,38 @@
|
|||||||
export function createEventCard(event) {
|
export function createEventCard(event) {
|
||||||
|
|
||||||
const article = document.createElement("article");
|
const article = document.createElement("article");
|
||||||
article.className = "event-card";
|
article.className = "event-card";
|
||||||
|
|
||||||
const name = event.name;
|
const name = event.name;
|
||||||
const date = event.dates.start.localDate;
|
|
||||||
const venue = event._embedded?.venues[0]?.name;
|
// DATE
|
||||||
|
const rawDate = event.dates?.start?.localDate;
|
||||||
article.innerHTML = `
|
const formattedDate = rawDate
|
||||||
<h3 class="event-card__title">${name}</h3>
|
? new Date(rawDate).toLocaleDateString("de-CH", {
|
||||||
<p class="event-card__date">${date}</p>
|
day: "2-digit",
|
||||||
<p class="event-card__venue">${venue}</p>
|
month: "2-digit",
|
||||||
`;
|
year: "numeric"
|
||||||
|
})
|
||||||
return article;
|
: "Date not available";
|
||||||
}
|
|
||||||
|
// TIME
|
||||||
|
const rawTime = event.dates?.start?.localTime;
|
||||||
|
const formattedTime = rawTime
|
||||||
|
? rawTime.slice(0, 5)
|
||||||
|
: "";
|
||||||
|
|
||||||
|
// Combine date + time
|
||||||
|
const dateTime = formattedTime
|
||||||
|
? `${formattedDate}, ${formattedTime}`
|
||||||
|
: formattedDate;
|
||||||
|
|
||||||
|
const venue = event._embedded?.venues[0]?.name || "Unknown venue";
|
||||||
|
|
||||||
|
article.innerHTML = `
|
||||||
|
<h3 class="event-card__title">${name}</h3>
|
||||||
|
<p class="event-card__date">${dateTime}</p>
|
||||||
|
<p class="event-card__venue">${venue}</p>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return article;
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
import { createEventCard } from "./eventCard.js";
|
||||||
|
|
||||||
|
export function renderEventList(events, container) {
|
||||||
|
|
||||||
|
container.innerHTML = "";
|
||||||
|
|
||||||
|
if (events.length === 0) {
|
||||||
|
container.innerHTML = "No events found.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
events.forEach(event => {
|
||||||
|
const card = createEventCard(event);
|
||||||
|
container.appendChild(card);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
export function getFilters() {
|
||||||
|
const city = document.querySelector("#city-input").value.trim();
|
||||||
|
const dateFrom = document.querySelector("#date-from").value;
|
||||||
|
const dateTo = document.querySelector("#date-to").value;
|
||||||
|
const category = document.querySelector("#category-input").value;
|
||||||
|
|
||||||
|
return { city, dateFrom, dateTo, category };
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user