blob: a92cf83d79be483e122c5d6cbe00885e61133080 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
import { Calendar } from "./Icons";
const API_URL = import.meta.env.VITE_API_URL;
interface Event {
id: number;
title: string;
description?: string;
date: Date;
host_id: number;
image_url?: string;
host: {
id: number;
name: string;
email: string;
};
rsvps: {
id: number;
name: string;
email: string;
}[];
}
const loadEventsData = async (): Promise<Event[]> => {
try {
const response = await fetch(`${API_URL}/events`);
return response.json();
} catch (e) {
console.error(e);
return [];
}
};
export const EventModal = (event: Event) => {
const formId = `rsvp-form-${event.id}`;
const modalId = `modal-event-${event.id}`;
return `<dialog id="${modalId}">
<article>
<header>
<button
aria-label="Close"
rel="prev"
data-target="${modalId}"
class="toggle-modal"
></button>
<h3>RSVP to ${event.title}</h3>
</header>
<form id="${formId}" data-modal="${modalId}"
action="${API_URL}/events/${event.id}/rsvp"
method="POST"
>
<label for="rsvp-name-${event.id}">Name:
<input type="text" id="rsvp-name-${event.id}" class="rsvp-name" name="name" required />
</label>
<label for="rsvp-email-${event.id}">Email:
<input type="email" id="rsvp-email-${event.id}" class="rsvp-email" name="email" required />
</label>
</form>
<footer>
<button
role="button"
class="toggle-modal cancel"
data-target="${modalId}"
>Cancel</button>
<button id="submit-${formId}" role="button" form="${formId}" type="submit">Submit RSVP</button>
</footer>
</article>
</dialog>`;
};
export const EventCard = (e: Event) => {
const eventDate = new Date(e.date);
const isPast = eventDate < new Date();
return `
<article class="event" >
<header>
${e.image_url && `<img src=${e.image_url} alt="${e.title} thumbnail" />`}
</header>
<main>
<h4>${e.title}</h4>
<p>${Calendar} ${eventDate.toLocaleDateString()}</p>
<p>Host: ${e.host?.name || `User ${e.host_id}`}</p>
${e.description ? `<p>${e.description}</p>` : ""}
</main>
<footer>
<span>
${e.rsvps?.length || 0} ${isPast ? "went" : "going"}
</span>
${
!isPast
? `
<button role="button" data-target="modal-event-${e.id}" class="toggle-modal"
title="RSVP to ${e.title}"
>
RSVP
</button>`
: ""
}
</footer>
${EventModal(e)}
</article>
`;
};
export const EventsSection = (title: string, events: Event[]) => {
return `
<section class='events'>
<h2>${title} events </h2>
<div role = "group">
${events.map((e) => EventCard(e)).join("") || "No events"}
</div>
</section>`;
};
// IIFE to asynchronously load the Event data before exporting the component
// https://developer.mozilla.org/en-US/docs/Glossary/IIFE
export const Events = await (async () => {
const all = await loadEventsData();
const past = all.filter((e) => new Date(e.date) < new Date());
const upcoming = all.filter((e) => new Date(e.date) > new Date());
return `
${EventsSection("Upcoming", upcoming)}
${EventsSection("Past", past)}
`;
})();
|