Skip to content

Commit

Permalink
Merge pull request #627 from nwplus/daniel/attended-events
Browse files Browse the repository at this point in the history
Attended Events component
  • Loading branch information
daniel-panhead authored Oct 31, 2024
2 parents afb3bf6 + 0d266e8 commit e6e5cdc
Show file tree
Hide file tree
Showing 8 changed files with 245 additions and 17 deletions.
5 changes: 5 additions & 0 deletions src/assets/checkmark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
83 changes: 83 additions & 0 deletions src/components/Rewards/AttendedEvents.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import styled, { useTheme } from 'styled-components'
import { TagLegendContainer, TagLegends } from '../Schedule/Tag'
import { H1 } from '../Typography'
import AttendedEventsCard from './AttendedEventsCard'
import { EVENT_TYPES } from '../Schedule/Constants'
import { getEvents } from '../../utility/firebase'
import { useHackathon } from '../../utility/HackathonProvider'
import { useEffect } from 'react'
import { useState } from 'react'

const AttendedEventsContainer = styled.div`
display: flex;
flex-direction: column;
gap: 0.75em;
`

const AttendedEventsHeader = styled.div`
display: flex;
flex-direction: column;
`

const TagLegendsContainer = styled(TagLegendContainer)`
justify-content: start;
padding-right: 0;
`

const EventsList = styled.div`
display: flex;
flex-direction: column;
gap: 0.75em;
overflow-y: scroll;
width: 85%;
${p => p.theme.mediaQueries.mobile} {
width: 100%;
}
`

const AttendedEvents = ({ userDetails }) => {
const { dbHackathonName } = useHackathon()
const theme = useTheme()
const event_type = EVENT_TYPES(theme)
const [events, setEvents] = useState([])

useEffect(() => {
// prettier insisted on the semicolon
;(async () => {
if (userDetails && dbHackathonName) {
console.log(userDetails)
const eventIds = userDetails.dayOf.events.map(event => event.eventId)
const events = await getEvents(dbHackathonName)
const filteredEvents = events.filter(event => eventIds.includes(event.key))
setEvents(filteredEvents)
}
})()
}, [userDetails, dbHackathonName])

return (
<AttendedEventsContainer>
<AttendedEventsHeader>
<H1>Attended events</H1>
<TagLegendsContainer>
<TagLegends theme={theme} />
</TagLegendsContainer>
</AttendedEventsHeader>
{userDetails && (
<EventsList>
{events.map((event, i) => (
<AttendedEventsCard
key={i}
name={event.title}
time={new Date(event.date.seconds * 1000).toLocaleString()}
points={event.points}
color={event_type[event.type]?.colour ?? 'gray'}
/>
))}
</EventsList>
)}
</AttendedEventsContainer>
)
}

export default AttendedEvents
86 changes: 86 additions & 0 deletions src/components/Rewards/AttendedEventsCard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import styled from 'styled-components'
import { StyledSVG } from '../Schedule/Tag'
import { P } from '../Typography'
import Icon from '../../assets/checkmark.svg?react'

const AttendedEventsCardContainer = styled.div`
display: flex;
align-items: center;
gap: 1em;
color: ${p => p.theme.colors.cardText};
background: ${p => p.theme.colors.backgroundTertiary};
border-radius: 5px;
padding: 0.875em 1em;
`

const EventDetailsContainer = styled.div`
flex-grow: 1;
display: flex;
justify-content: space-between;
gap: 2em;
align-items: center;
`

const TagPointsContainer = styled.div`
display: flex;
flex-direction: column;
align-items: end;
`

const CheckmarkSVG = styled(Icon)`
fill: ${props => props.color};
${p => p.theme.mediaQueries.mobile} {
height: 0.75em;
width: 0.75em;
}
`

const EventDetails = styled.div`
display: flex;
flex-direction: column;
`

const EventName = styled(P)`
margin: 0;
font-weight: 700;
`

const EventTime = styled(P)`
margin: 0;
font-size: 0.875em;
`

const PointsText = styled(P)`
font-weight: 700;
color: ${props => props.color};
font-size: 0.875em;
margin: 0;
`

/**
* @typedef {{name: string, time: string, points: number, color: string}} AttendedEventsCardProps
*/

/**
* @param {AttendedEventsCardProps} param0
*/
const AttendedEventsCard = ({ name, time, points, color }) => {
return (
<AttendedEventsCardContainer>
<CheckmarkSVG color={color} />
<EventDetailsContainer>
<EventDetails>
<EventName>{name}</EventName>
<EventTime>{time}</EventTime>
</EventDetails>
<TagPointsContainer>
<StyledSVG color={color} />
<PointsText color={color}>{points} pts earned</PointsText>
</TagPointsContainer>
</EventDetailsContainer>
</AttendedEventsCardContainer>
)
}

export default AttendedEventsCard
10 changes: 7 additions & 3 deletions src/components/Schedule/Schedule.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ScrollbarLike } from '../Common'
import { H1 } from '../Typography'
import { EVENT_GAP, MOBILE_HOUR_HEIGHT } from './Constants'
import Event from './Event'
import { TagLegend } from './Tag'
import { TagLegends, TagLegendContainer } from './Tag'
import { TimelineColumn } from './Timeline'
import { useTheme } from 'styled-components'

Expand Down Expand Up @@ -312,7 +312,9 @@ const Schedule = ({ events, hackathonStart, hackathonEnd }) => {
<OverflowContainer>
<HeaderContainer>
<Header>Day-Of-Events Schedule</Header>
<TagLegend theme={theme} />
<TagLegendContainer>
<TagLegends theme={theme} />
</TagLegendContainer>
</HeaderContainer>
<DayLabelContainer>
<DayLabel style={{ opacity: isSunday ? 0 : 1 }}>Saturday</DayLabel>
Expand All @@ -339,7 +341,9 @@ const Schedule = ({ events, hackathonStart, hackathonEnd }) => {
<MobileOverflowContainer>
<HeaderContainer>
<Header>Day-Of-Events Schedule</Header>
<TagLegend theme={theme} />
<TagLegendContainer>
<TagLegends theme={theme} />
</TagLegendContainer>
</HeaderContainer>
<MobileScrollableContainer>
<ScheduleFlexContainer>
Expand Down
22 changes: 9 additions & 13 deletions src/components/Schedule/Tag.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,13 @@ export const StyledSVG = styled(Icon)`
}
`

export const TagLegend = ({ theme }) => {
return (
<TagLegendContainer>
{Object.entries(EVENT_TYPES(theme)).map(([key, event_type], i) => {
return (
<React.Fragment key={key}>
<StyledSVG color={event_type.colour} />
<Tag>{event_type.label}</Tag>
</React.Fragment>
)
})}
</TagLegendContainer>
)
export const TagLegends = ({ theme }) => {
return Object.entries(EVENT_TYPES(theme)).map(([key, event_type], i) => {
return (
<React.Fragment key={key}>
<StyledSVG color={event_type.colour} />
<Tag>{event_type.label}</Tag>
</React.Fragment>
)
})
}
48 changes: 47 additions & 1 deletion src/containers/Rewards.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,49 @@
const Rewards = () => {}
import styled from 'styled-components'
import AttendedEvents from '../components/Rewards/AttendedEvents'
import { useAuth } from '../utility/Auth'
import { getUserApplication } from '../utility/firebase'
import { useHackathon } from '../utility/HackathonProvider'
import { useState } from 'react'
import { useEffect } from 'react'

const RewardsContainer = styled.div`
display: flex;
height: 100%;
width: 100%;
${p => p.theme.mediaQueries.mobile} {
flex-direction: column;
}
`

const RewardsSummaryContainer = styled.div`
display: flex;
flex-direction: column;
flex-basis: 35%;
flex-shrink: 0;
`

const RewardsContentContainer = styled.div``

const Rewards = () => {
const { user } = useAuth()
const { dbHackathonName } = useHackathon()
const [userDetails, setUserDetails] = useState(null)

useEffect(() => {
getUserApplication(user.uid, dbHackathonName).then(user => {
setUserDetails(user)
})
}, [user, dbHackathonName])

return (
<RewardsContainer>
<RewardsSummaryContainer>
<AttendedEvents userDetails={userDetails} />
</RewardsSummaryContainer>
<RewardsContentContainer></RewardsContentContainer>
</RewardsContainer>
)
}

export default Rewards
1 change: 1 addition & 0 deletions src/utility/Auth.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Spinner from '../components/Loading'
import { useLocation } from 'wouter'
import { useHackathon } from './HackathonProvider'

/** @type {React.Context<{isAuthed: boolean, user: firebase.User | null, setUser: React.Dispatch<React.SetStateAction<firebase.User | null>>, logout: () => Promise<void>}>} */
const AuthContext = createContext()

export function useAuth() {
Expand Down
7 changes: 7 additions & 0 deletions src/utility/firebase.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ export const applicantsRef = dbHackathonName => {
export const projectsRef = dbHackathonName => {
return db.collection(DB_COLLECTION).doc(dbHackathonName).collection('Projects')
}
export const eventsRef = dbHackathonName => {
return db.collection(DB_COLLECTION).doc(dbHackathonName).collection('Events')
}
export const announcementsRef = dbHackathonName => {
return db.collection(DB_COLLECTION).doc(dbHackathonName).collection('Announcements')
}
Expand All @@ -51,6 +54,10 @@ export const getLivesiteDoc = callback => {
})
}

export const getEvents = async dbHackathonName => {
return (await eventsRef(dbHackathonName).get()).docs.map(doc => doc.data())
}

const createNewApplication = async (user, dbHackathonName) => {
analytics.logEvent(ANALYTICS_EVENTS.signup, { userId: user.uid })
const userId = {
Expand Down

0 comments on commit e6e5cdc

Please sign in to comment.