Prepare final project submission
This commit is contained in:
parent
7c6fed961e
commit
f4a55882ac
1
.env.example
Normal file
1
.env.example
Normal file
@ -0,0 +1 @@
|
|||||||
|
TM_API_KEY=your_ticketmaster_api_key
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1,3 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
|
.DS_Store
|
||||||
|
__MACOSX/
|
||||||
47
README.md
47
README.md
@ -45,24 +45,33 @@ cd AISE_FS26-FrontendEntwicklungProjekt
|
|||||||
npm install
|
npm install
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. Umgebungsvariable konfigurieren
|
### 3. Umgebungsvariablen / Ticketmaster API
|
||||||
|
|
||||||
Erstelle eine `.env`-Datei im Projektstamm:
|
Für die Bewertung enthält die Abgabe bereits eine vorkonfigurierte `.env`-Datei, sodass die Anwendung ohne zusätzliche Konfiguration gestartet werden kann.
|
||||||
|
|
||||||
|
In einer regulären Installation muss eine eigene `.env`-Datei im Projektstamm erstellt werden:
|
||||||
|
|
||||||
```env
|
```env
|
||||||
TM_API_KEY=dein_ticketmaster_api_key
|
TM_API_KEY=your_ticketmaster_api_key
|
||||||
```
|
```
|
||||||
|
|
||||||
Den API-Key erhältst du kostenlos unter [developer.ticketmaster.com](https://developer.ticketmaster.com).
|
Ein kostenloser API-Key kann über das Ticketmaster Developer Portal bezogen werden:
|
||||||
*(Zum Testen ist im Repository vorübergehend ein Key hinterlegt.)*
|
|
||||||
|
https://developer.ticketmaster.com/
|
||||||
|
|
||||||
|
Zusätzlich ist eine `.env.example`-Datei enthalten, welche die erwartete Struktur der Umgebungsvariablen dokumentiert.
|
||||||
|
|
||||||
### 4. Backend-Server starten
|
### 4. Backend-Server starten
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
node server/server.js
|
npm start
|
||||||
```
|
```
|
||||||
|
|
||||||
Ausgabe: `Server läuft auf http://localhost:3000`
|
Ausgabe:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Server läuft auf http://localhost:3000
|
||||||
|
```
|
||||||
|
|
||||||
### 5. Frontend öffnen
|
### 5. Frontend öffnen
|
||||||
|
|
||||||
@ -124,26 +133,26 @@ Alle KI-generierten Vorschläge wurden kritisch geprüft, angepasst und manuell
|
|||||||
|
|
||||||
## Selbstreflexion
|
## Selbstreflexion
|
||||||
|
|
||||||
**Herausforderungen:**
|
### Herausforderungen
|
||||||
|
|
||||||
- **Externe API-Integration**: Die Ticketmaster-API hat eine komplexe, verschachtelte JSON-Struktur. Das Mapping auf ein einfaches Datenmodell erforderte sorgfältige Analyse und optionale Chaining (`?.`).
|
* **Frontend-Backend-Integration:** Die Kommunikation zwischen Frontend, Backend und Ticketmaster API musste zuverlässig koordiniert werden.
|
||||||
- **Modulstruktur ohne Framework**: Die klare Trennung in `api/`, `services/`, `ui/` ohne ein Framework erforderte bewusste Architekturentscheidungen.
|
* **Verschachtelte Ticketmaster-Daten:** Die komplexe JSON-Struktur der API erforderte eine zusätzliche Service-Schicht zur Datenaufbereitung.
|
||||||
- **Statuscode-Konventionen**: Die korrekte Verwendung von HTTP-Statuscodes (201 für Ressource-Erstellung, 200 für erfolgreichen GET) musste erst explizit reflektiert werden.
|
* **Modularisierung:** Mit wachsendem Funktionsumfang wurde eine klare Trennung der Verantwortlichkeiten immer wichtiger.
|
||||||
- **XSS-Bewusstsein**: Das Risiko von `innerHTML` mit externen Daten war nicht von Anfang an präsent und wurde erst im Code-Review erkannt.
|
|
||||||
|
|
||||||
**Lerneffekte:**
|
### Lerneffekte
|
||||||
|
|
||||||
- Tiefes Verständnis für Async/Await und Fehlerbehandlung in JavaScript
|
* **Integration erhöht die Komplexität:** Mehrere Systeme müssen konsistent zusammenarbeiten.
|
||||||
- Sensibilisierung für OWASP-Risiken bereits beim Schreiben von Frontend-Code
|
* **Kleine Änderungen können grosse Auswirkungen haben:** Sichere Praktiken wie die Verwendung von `textContent` helfen, Fehler und Sicherheitsrisiken zu vermeiden.
|
||||||
- Wert von semantischem HTML5 und Accessibility für Barrierefreiheit und SEO
|
* **Modulare Architektur verbessert die Wartbarkeit:** Klare Strukturen erleichtern Entwicklung, Fehlersuche und Erweiterungen.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Gruppenmitglieder und Rollen
|
## Gruppenmitglieder und Rollen
|
||||||
|
|
||||||
| Name | Rolle | Schwerpunkte |
|
| Name | Rolle | Schwerpunkte |
|
||||||
|---|---|---|
|
| --------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------- |
|
||||||
| **Nicola Augsburger** | Frontend & Backend | Einladungssystem (Frontend + Backend), Authentifizierung, App-Architektur
|
| **Nicola Augsburger** | Frontend & Backend | Einladungssystem (Frontend + Backend), Authentifizierung, App-Architektur |
|
||||||
| **Karolina Thöny-Tyganova** | Frontend & API | Ticketmaster-API-Integration, Suchfunktion, Filterlogik | Event-Karten-Komponente, CSS-Styling, Responsives Layout |
|
| **Karolina Thöny-Tyganova** | Frontend & API | Ticketmaster-API-Integration, Suchfunktion, Filterlogik, Event-Karten-Komponente, CSS-Styling, Responsives Layout |
|
||||||
|
|
||||||
|
|
||||||
Die individuelle Beteiligung ist in den Git-Commits auf [gitea.fhgr.ch](https://gitea.fhgr.ch/augsbunicola/AISE_FS26-FrontendEntwicklungProjekt) nachvollziehbar.
|
Die individuelle Beteiligung ist in den Git-Commits auf [gitea.fhgr.ch](https://gitea.fhgr.ch/augsbunicola/AISE_FS26-FrontendEntwicklungProjekt) nachvollziehbar.
|
||||||
@ -247,22 +247,22 @@
|
|||||||
margin-bottom: 0.35rem;
|
margin-bottom: 0.35rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-input {
|
.auth-modal-body .form-control.auth-input {
|
||||||
border: 1.5px solid var(--color-border) !important;
|
border: 1.5px solid var(--color-border);
|
||||||
border-radius: var(--radius-sm) !important;
|
border-radius: var(--radius-sm);
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
height: 42px;
|
height: 42px;
|
||||||
color: var(--color-text);
|
color: var(--color-text);
|
||||||
background: var(--color-bg) !important;
|
background: var(--color-bg);
|
||||||
transition: border-color var(--transition), box-shadow var(--transition);
|
transition: border-color var(--transition), box-shadow var(--transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-input:focus {
|
.auth-modal-body .form-control.auth-input:focus {
|
||||||
border-color: var(--color-accent) !important;
|
border-color: var(--color-accent);
|
||||||
box-shadow: 0 0 0 3px rgba(13, 148, 136, 0.15) !important;
|
box-shadow: 0 0 0 3px rgba(13, 148, 136, 0.15);
|
||||||
outline: none;
|
outline: none;
|
||||||
background: var(--color-surface) !important;
|
background: var(--color-surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-error {
|
.auth-error {
|
||||||
|
|||||||
@ -25,7 +25,6 @@ export async function fetchEvents(city) {
|
|||||||
return data._embedded?.events || [];
|
return data._embedded?.events || [];
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Fehler beim Laden der Events:", error);
|
|
||||||
// Fehler nach oben weitergeben, damit app.js ihn dem Nutzer anzeigen kann
|
// Fehler nach oben weitergeben, damit app.js ihn dem Nutzer anzeigen kann
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -133,7 +133,6 @@ modalLoginBtn.addEventListener("click", async () => {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
loginError.textContent = "Verbindungsfehler. Ist der Server erreichbar?";
|
loginError.textContent = "Verbindungsfehler. Ist der Server erreichbar?";
|
||||||
loginError.hidden = false;
|
loginError.hidden = false;
|
||||||
console.error("Login-Fehler:", err);
|
|
||||||
} finally {
|
} finally {
|
||||||
modalLoginBtn.disabled = false;
|
modalLoginBtn.disabled = false;
|
||||||
modalLoginBtn.textContent = "Anmelden";
|
modalLoginBtn.textContent = "Anmelden";
|
||||||
@ -192,7 +191,6 @@ modalRegBtn.addEventListener("click", async () => {
|
|||||||
registerError.hidden = false;
|
registerError.hidden = false;
|
||||||
modalRegBtn.disabled = false;
|
modalRegBtn.disabled = false;
|
||||||
modalRegBtn.textContent = "Konto erstellen";
|
modalRegBtn.textContent = "Konto erstellen";
|
||||||
console.error("Registrierungs-Fehler:", err);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -245,7 +243,6 @@ async function handleSearch() {
|
|||||||
renderEventList(filtered, eventListEl);
|
renderEventList(filtered, eventListEl);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showError(eventListEl, "Fehler beim Laden der Events. Bitte erneut versuchen.");
|
showError(eventListEl, "Fehler beim Laden der Events. Bitte erneut versuchen.");
|
||||||
console.error("Such-Fehler:", err);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,7 +384,6 @@ async function loadInvitations() {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showError(container, "Fehler beim Laden der Einladungen.");
|
showError(container, "Fehler beim Laden der Einladungen.");
|
||||||
console.error("Einladungs-Fehler:", err);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,7 +483,6 @@ async function respondToInvitation(id, action, card) {
|
|||||||
errEl.className = "text-danger small mt-1";
|
errEl.className = "text-danger small mt-1";
|
||||||
errEl.textContent = "Fehler beim Antworten auf die Einladung.";
|
errEl.textContent = "Fehler beim Antworten auf die Einladung.";
|
||||||
card.appendChild(errEl);
|
card.appendChild(errEl);
|
||||||
console.error("Antwort-Fehler:", err);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -512,7 +507,6 @@ async function deleteInvitation(id, card) {
|
|||||||
errEl.className = "text-danger small mt-1";
|
errEl.className = "text-danger small mt-1";
|
||||||
errEl.textContent = "Fehler beim Löschen der Einladung.";
|
errEl.textContent = "Fehler beim Löschen der Einladung.";
|
||||||
card.appendChild(errEl);
|
card.appendChild(errEl);
|
||||||
console.error("Lösch-Fehler:", err);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -188,7 +188,6 @@ function createInviteForm(event, card) {
|
|||||||
sendBtn.disabled = false;
|
sendBtn.disabled = false;
|
||||||
sendBtn.textContent = "Senden";
|
sendBtn.textContent = "Senden";
|
||||||
showCardMessage(card, err.message || "Fehler beim Senden der Einladung.", "danger");
|
showCardMessage(card, err.message || "Fehler beim Senden der Einladung.", "danger");
|
||||||
console.error("Einladungs-Fehler:", err);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "aise_fs26-frontendentwicklungprojekt",
|
"name": "aise_fs26-frontendentwicklungprojekt",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "Frontend Project for cds-208 at FHGR Collaborators: Pascal Schieman, Nicola Augsburger, Karolina Thöny-Tyganova ## Project Description **Find your next event in seconds.** Encore is a modern event discovery frontend that brings Ticketmaster events directly to users through a clean, intelligent interface. Instead of sifting through cluttered listings, users can instantly browse concerts, sports, theater, and entertainment by location, date, and category—then dive into event details to make informed decisions fast.",
|
"description": "Frontend Project for cds-208 at FHGR Collaborators: Nicola Augsburger, Karolina Thöny-Tyganova ## Project Description **Find your next event in seconds.** Encore is a modern event discovery frontend that brings Ticketmaster events directly to users through a clean, intelligent interface. Instead of sifting through cluttered listings, users can instantly browse concerts, sports, theater, and entertainment by location, date, and category—then dive into event details to make informed decisions fast.",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node server/server.js"
|
"start": "node server/server.js"
|
||||||
|
|||||||
@ -52,7 +52,6 @@ app.get("/api/events", async (req, res) => {
|
|||||||
|
|
||||||
res.json(data);
|
res.json(data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Ticketmaster-Fehler:", error);
|
|
||||||
res.status(500).json({ message: "Fehler beim Laden der Events" });
|
res.status(500).json({ message: "Fehler beim Laden der Events" });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user