-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* added route for events page * deleted everything * Events cards (#214) * completed rough event card * possible fix * remove console log * fix padding (#213) * fix text colors for different orgs * responsive navbar (#215) * started responsive navbar * commit typing * finish navbar * move navbar styles to component level module * commit module typing * use proper color variables * use seconds for transitions * fix navlink order * fix easing functions * add css comments * Fetch data for board cards at build time server-side (#211) * fetch board data from spreadsheet and populate * moved code to api util function * isr generate date once a day * delete hardcoded data * fixed board card fetch * fixes * Update BoardAPI.ts * dumb fix * Update Navbar.module.scss (#216) * fix navbar with events tab * optional facebook url * Event filters (#219) * completed rough event card * possible fix * remove console log * fix padding (#213) * fix text colors for different orgs * responsive navbar (#215) * started responsive navbar * commit typing * finish navbar * move navbar styles to component level module * commit module typing * use proper color variables * use seconds for transitions * fix navlink order * fix easing functions * add css comments * Fetch data for board cards at build time server-side (#211) * fetch board data from spreadsheet and populate * moved code to api util function * isr generate date once a day * delete hardcoded data * fixed board card fetch * fixes * Update BoardAPI.ts * dumb fix * Update Navbar.module.scss (#216) * fix navbar with events tab * optional facebook url * close on click (#218) * add event card filters * make footer icon type pointer hi ronak - chris * breakpoint as variable * remove old files * Event details (#220) * wire up dynamic routes from api and link from corresponding card * rename /event to /events * format event name in url * mobile at 960 * event page details + calendar actions * small fixes * fix committee name and css * remove unused link for now * fix replaceAll not supported * generate and cache paths server side * add support for viewing past events * fix some comments * SEO event link previews * pass entire event directly to event card * update seo description * mobile dropdown functioning * fix 2-way binding
- Loading branch information
1 parent
9f87949
commit 70048aa
Showing
22 changed files
with
998 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import NotFoundPage from "pages/404"; | ||
import { EventObject, getAllEvents, getEvent } from "src/api/EventsAPI"; | ||
import SEO from "src/components/SEO"; | ||
import EventContent from "src/sections/event/Event.Content"; | ||
import { formatURLEventTitle, getDateTime } from "src/utils"; | ||
|
||
const EventPage: React.FC<{ event: EventObject }> = ({ event }) => { | ||
if (!event) return <NotFoundPage />; | ||
return ( | ||
<> | ||
<SEO | ||
title={event.title} | ||
path={`${formatURLEventTitle(event.title)}-${event.uuid}`} | ||
description={`${event.location} - ${getDateTime(event).time}\n\nEvent Description: ${ | ||
event.description | ||
}`} | ||
image={event.cover} | ||
/> | ||
<EventContent event={event} />; | ||
</> | ||
); | ||
}; | ||
|
||
export default EventPage; | ||
|
||
// Only render dynamic paths for actual events, don't need a fallback to generate if the link is wrong | ||
export async function getStaticPaths() { | ||
const events = await getAllEvents("future"); | ||
return { | ||
paths: events.map(event => ({ | ||
params: { | ||
key: `${formatURLEventTitle(event.title)}-${event.uuid}`, | ||
}, | ||
})), | ||
fallback: "blocking", | ||
}; | ||
} | ||
|
||
// UUID is always 36 characters long at the end of the url, use this to go to correct event details | ||
const UUID_LEN = 36; | ||
export async function getStaticProps({ params }) { | ||
const key = params.key; | ||
const uuid = key.slice(-UUID_LEN); | ||
const event = await getEvent(uuid); | ||
return { | ||
props: { | ||
event, | ||
}, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { EventsArray, getAllEvents } from "src/api/EventsAPI"; | ||
import SEO from "src/components/SEO"; | ||
import EventsContent from "src/sections/events/Events.Content"; | ||
|
||
const EventsPage: React.FC<{ futureEvents: EventsArray }> = ({ futureEvents }) => { | ||
return ( | ||
<> | ||
<SEO title="Events" path="/events" /> | ||
<EventsContent events={futureEvents} /> | ||
</> | ||
); | ||
}; | ||
|
||
export default EventsPage; | ||
|
||
export async function getStaticProps() { | ||
const futureEvents = await getAllEvents("future"); | ||
return { | ||
props: { | ||
futureEvents: futureEvents || [], | ||
}, | ||
revalidate: 1 * 60 * 60, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,6 @@ | ||
export type EventsResponse = { | ||
error: unknown; | ||
events: EventsArray; | ||
}; | ||
|
||
export type EventsArray = EventObject[]; | ||
import * as ics from "ics"; | ||
import { formatURLEventTitle } from "src/utils"; | ||
const EVENT_API = "https://api.acmucsd.com/api/v2/event"; | ||
|
||
export type EventObject = { | ||
uuid: string; | ||
|
@@ -19,30 +16,105 @@ export type EventObject = { | |
pointValue: number; | ||
requiresStaff: boolean; | ||
staffPointBonus: number; | ||
facebookUrl?: string; | ||
}; | ||
|
||
const handleErrors = (response: Response): Promise<EventsResponse> => { | ||
export type EventsArray = EventObject[]; | ||
|
||
export type EventsResponse = { | ||
error: unknown; | ||
events: EventsArray; | ||
}; | ||
|
||
export type EventResponse = { | ||
error: unknown; | ||
event: EventObject; | ||
}; | ||
|
||
const handleErrors = (response: Response) => { | ||
if (!response.ok) { | ||
throw Error(response.statusText); | ||
} | ||
return response.json(); | ||
}; | ||
|
||
const getAllEvents = async (): Promise<EventsArray | undefined> => { | ||
let apiurl = "https://api.acmucsd.com/api/v2/event/future"; | ||
|
||
// TODO: Fix test data for development purposes (images are not showing up) | ||
// if (!process.env.NODE_ENV || process.env.NODE_ENV === "development") { | ||
// apiurl = "https://testing.api.acmucsd.com/api/v2/event/future" | ||
// } | ||
const getAllEvents = async ( | ||
type: "past" | "future" | "" = "" | ||
): Promise<EventsArray | undefined> => { | ||
const api_url = `${EVENT_API}/${type}`; | ||
|
||
try { | ||
const response: Response = await fetch(apiurl); | ||
const response: Response = await fetch(api_url); | ||
const result: EventsResponse = await handleErrors(response); | ||
return result.events; | ||
} catch (error) { | ||
return undefined; | ||
} | ||
}; | ||
|
||
export { getAllEvents }; | ||
const getEvent = async (uuid: string): Promise<EventObject | undefined> => { | ||
let api_url = `${EVENT_API}/${uuid}`; | ||
|
||
try { | ||
const response: any = await fetch(api_url); | ||
const result: EventResponse = await handleErrors(response); | ||
return result.event; | ||
} catch (error) { | ||
return undefined; | ||
} | ||
}; | ||
|
||
// Referencing this answer to save text in a file and download it | ||
// https://stackoverflow.com/questions/44656610/download-a-string-as-txt-file-in-react | ||
const createDownloadFile = (textContent: string, title: string): void => { | ||
const element = document.createElement("a"); | ||
const file = new Blob([textContent], { type: "text/plain" }); | ||
element.href = URL.createObjectURL(file); | ||
element.download = `${title}.ics`; | ||
document.body.appendChild(element); | ||
element.click(); | ||
}; | ||
|
||
const downloadICS = (event: EventObject): void => { | ||
const startDate = new Date(event.start); | ||
const endDate = new Date(event.end); | ||
const duration = endDate.getTime() - startDate.getTime(); | ||
|
||
const attributes: ics.EventAttributes = { | ||
start: [ | ||
startDate.getFullYear(), | ||
startDate.getMonth() + 1, // Library is 1-indexed rather than 0-indexed | ||
startDate.getDate(), | ||
startDate.getHours(), | ||
startDate.getMinutes(), | ||
], | ||
duration: { minutes: duration / (1000 * 60) }, | ||
title: event.title, | ||
description: event.description, | ||
location: event.location, | ||
url: `https://acmucsd.com/events/${formatURLEventTitle(event.title)}-${event.uuid}`, | ||
organizer: { name: "ACM at UCSD", email: "[email protected]" }, | ||
}; | ||
|
||
const response = ics.createEvent(attributes); | ||
|
||
createDownloadFile(response.value, formatURLEventTitle(event.title)); | ||
}; | ||
|
||
// Referencing this link format - no official API documentation exists | ||
// https://github.com/InteractionDesignFoundation/add-event-to-calendar-docs/blob/main/services/google.md | ||
const saveToGoogleCal = ({ title, description, location, start, end }: EventObject): void => { | ||
const url = new URL("https://www.google.com/calendar/render?action=TEMPLATE"); | ||
const params = new URLSearchParams(url.search); | ||
params.append("text", title); | ||
params.append("details", description); | ||
params.append("location", location); | ||
const startISO = start.replaceAll("-", "").replaceAll(":", "").replaceAll(".", ""); | ||
const endISO = end.replaceAll("-", "").replaceAll(":", "").replaceAll(".", ""); | ||
params.append("dates", `${startISO}/${endISO}`); | ||
|
||
const GCAL_LINK = `${url.origin}${url.pathname}?${params.toString()}`; | ||
window.open(GCAL_LINK); | ||
}; | ||
|
||
export { getEvent, getAllEvents, downloadICS, saveToGoogleCal }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
@use "src/styles/colors" as colors; | ||
|
||
.card { | ||
width: 100%; | ||
height: 177px; | ||
background: colors.$white; | ||
box-shadow: 0px 1px 6px colors.$black; | ||
border-radius: 20px; | ||
position: relative; | ||
padding: 0.75rem; | ||
display: grid; | ||
cursor: pointer; | ||
grid-template-columns: 1fr; | ||
grid-template-rows: 2rem 1fr 20px; | ||
|
||
.cardHeader { | ||
display: flex; | ||
flex-flow: row nowrap; | ||
justify-content: flex-start; | ||
align-items: baseline; | ||
|
||
.cardDate { | ||
font-family: DM Sans; | ||
font-style: normal; | ||
font-weight: normal; | ||
font-size: 25px; | ||
line-height: 100%; | ||
color: colors.$black; | ||
margin: 0; | ||
display: inline; | ||
} | ||
.cardDay { | ||
display: inline; | ||
margin: 0 0 0 10px; | ||
font-family: DM Sans; | ||
font-style: normal; | ||
font-weight: normal; | ||
font-size: 11px; | ||
line-height: 100%; | ||
color: colors.$black; | ||
text-transform: uppercase; | ||
} | ||
} | ||
|
||
.cardBody { | ||
display: flex; | ||
flex-flow: column; | ||
justify-content: center; | ||
|
||
.eventTitle { | ||
font-family: DM Sans; | ||
font-style: normal; | ||
font-weight: bold; | ||
font-size: 15px; | ||
line-height: 110%; | ||
white-space: pre-wrap; /*keep text on one line */ | ||
overflow: hidden; /*prevent text from being shown outside the border */ | ||
text-overflow: ellipsis; /*cut off text with an ellipsis*/ | ||
max-height: 40px; | ||
margin: 0; | ||
&.general { | ||
color: colors.$blue; | ||
} | ||
&.innovate { | ||
color: colors.$purple; | ||
} | ||
&.hack { | ||
color: colors.$orange; | ||
} | ||
&.cyber { | ||
color: colors.$turquoise; | ||
} | ||
&.ai { | ||
color: colors.$red; | ||
} | ||
} | ||
.eventLocation, | ||
.eventTime { | ||
font-family: DM Sans; | ||
font-style: normal; | ||
font-weight: normal; | ||
font-size: 13px; | ||
line-height: 17px; | ||
|
||
color: colors.$black; | ||
margin: 0; | ||
} | ||
} | ||
.cardFooter { | ||
.footerIcon { | ||
width: 20px; | ||
height: 20px; | ||
|
||
filter: invert(1); | ||
margin: 0; | ||
cursor: pointer; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// AUTOGENERATED FILE -- DO NOT EDIT DIRECTLY | ||
|
||
declare namespace EventCardModuleScssNamespace { | ||
export interface IEventCardModuleScss { | ||
ai: string; | ||
card: string; | ||
cardBody: string; | ||
cardDate: string; | ||
cardDay: string; | ||
cardFooter: string; | ||
cardHeader: string; | ||
cyber: string; | ||
eventLocation: string; | ||
eventTime: string; | ||
eventTitle: string; | ||
footerIcon: string; | ||
general: string; | ||
hack: string; | ||
innovate: string; | ||
} | ||
} | ||
|
||
declare const EventCardModuleScssModule: EventCardModuleScssNamespace.IEventCardModuleScss; | ||
|
||
export = EventCardModuleScssModule; |
Oops, something went wrong.
70048aa
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs: