Initial project setup with HTML structure, modular JS, and Ticketmaster event fetching #1
0
css/components.css
Normal file
0
css/components.css
Normal file
14
css/main.css
Normal file
14
css/main.css
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
.event-card {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 1rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-card__title {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-card__date {
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
98
index.html
Normal file
98
index.html
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
|
<title>Encore – Discover Events</title>
|
||||||
|
|
||||||
|
<!-- CSS -->
|
||||||
|
<link rel="stylesheet" href="css/main.css">
|
||||||
|
|
||||||
|
<!-- Bootstrap (optional CSS framework) -->
|
||||||
|
<link
|
||||||
|
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"
|
||||||
|
rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<!-- HEADER -->
|
||||||
|
<header class="site-header">
|
||||||
|
<nav class="container d-flex justify-content-between align-items-center">
|
||||||
|
|
||||||
|
<h1 class="site-logo">Encore</h1>
|
||||||
|
|
||||||
|
<ul class="nav">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="index.html">Home</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#">Events</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- MAIN CONTENT -->
|
||||||
|
<main class="container mt-4">
|
||||||
|
|
||||||
|
<!-- SEARCH / FILTER SECTION -->
|
||||||
|
<section class="event-search mb-4">
|
||||||
|
|
||||||
|
<h2>Find Events</h2>
|
||||||
|
|
||||||
|
<div class="d-flex gap-2">
|
||||||
|
|
||||||
|
<input
|
||||||
|
id="city-input"
|
||||||
|
type="text"
|
||||||
|
class="form-control"
|
||||||
|
placeholder="Enter city (e.g. Zurich)"
|
||||||
|
>
|
||||||
|
|
||||||
|
<button
|
||||||
|
id="load-events"
|
||||||
|
class="btn btn-primary"
|
||||||
|
>
|
||||||
|
Search
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- EVENTS LIST -->
|
||||||
|
<section class="events">
|
||||||
|
|
||||||
|
<h2>Upcoming Events</h2>
|
||||||
|
|
||||||
|
<div id="event-list" class="events__list">
|
||||||
|
<p class="text-muted">Search for events to begin.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</main>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- FOOTER -->
|
||||||
|
<footer class="site-footer text-center mt-5 p-3">
|
||||||
|
|
||||||
|
<p>© 2026 Encore – Event Discovery</p>
|
||||||
|
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- JS -->
|
||||||
|
<script type="module" src="js/app.js"></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
21
js/api/ticketmaster.js
Normal file
21
js/api/ticketmaster.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
const API_KEY = "0FLYFe9BnzGlk2OPHrWleCulNzHpWgtC";
|
||||||
|
|
||||||
|
export async function fetchEvents(city) {
|
||||||
|
const url = `https://app.ticketmaster.com/discovery/v2/events.json?apikey=${API_KEY}&city=${city}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(url);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("API request failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
return data._embedded?.events || [];
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching events:", error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
39
js/app.js
Normal file
39
js/app.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { fetchEvents } from "./api/ticketmaster.js";
|
||||||
|
import { createEventCard } from "./ui/eventCard.js";
|
||||||
|
|
||||||
|
const button = document.querySelector("#load-events");
|
||||||
|
const container = document.querySelector("#event-list");
|
||||||
|
const cityInput = document.querySelector("#city-input");
|
||||||
|
|
||||||
|
button.addEventListener("click", async () => {
|
||||||
|
|
||||||
|
const city = cityInput.value.trim();
|
||||||
|
|
||||||
|
if (!city) {
|
||||||
|
container.innerHTML = "Please enter a city.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
container.innerHTML = "Loading events...";
|
||||||
|
|
||||||
|
const events = await fetchEvents(city);
|
||||||
|
|
||||||
|
container.innerHTML = "";
|
||||||
|
|
||||||
|
if (events.length === 0) {
|
||||||
|
container.innerHTML = "No events found.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
events.forEach(event => {
|
||||||
|
const card = createEventCard(event);
|
||||||
|
container.appendChild(card);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
cityInput.addEventListener("keydown", (event) => {
|
||||||
|
if (event.key === "Enter") {
|
||||||
|
button.click();
|
||||||
|
}
|
||||||
|
});
|
||||||
12
js/services/eventService.js
Normal file
12
js/services/eventService.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { fetchEvents } from "../api/ticketmaster.js";
|
||||||
|
|
||||||
|
export async function getEvents(city) {
|
||||||
|
const events = await fetchEvents(city);
|
||||||
|
|
||||||
|
return events.map(event => ({
|
||||||
|
id: event.id,
|
||||||
|
name: event.name,
|
||||||
|
date: event.dates.start.localDate,
|
||||||
|
venue: event._embedded?.venues[0]?.name
|
||||||
|
}));
|
||||||
|
}
|
||||||
17
js/ui/eventCard.js
Normal file
17
js/ui/eventCard.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
export function createEventCard(event) {
|
||||||
|
|
||||||
|
const article = document.createElement("article");
|
||||||
|
article.className = "event-card";
|
||||||
|
|
||||||
|
const name = event.name;
|
||||||
|
const date = event.dates.start.localDate;
|
||||||
|
const venue = event._embedded?.venues[0]?.name;
|
||||||
|
|
||||||
|
article.innerHTML = `
|
||||||
|
<h3 class="event-card__title">${name}</h3>
|
||||||
|
<p class="event-card__date">${date}</p>
|
||||||
|
<p class="event-card__venue">${venue}</p>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return article;
|
||||||
|
}
|
||||||
0
js/ui/eventList.js
Normal file
0
js/ui/eventList.js
Normal file
0
js/ui/filters.js
Normal file
0
js/ui/filters.js
Normal file
3
js/utils/helpers.js
Normal file
3
js/utils/helpers.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export function formatDate(date) {
|
||||||
|
return new Date(date).toLocaleDateString();
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user