Skip to content

Commit

Permalink
New team page (#59)
Browse files Browse the repository at this point in the history
* New team page

* Add team to output jsons

* Add save shortcut to all forms

* Add save shortcut to all forms
  • Loading branch information
HugoGresse authored Nov 5, 2023
1 parent 329ff6f commit 54868c0
Show file tree
Hide file tree
Showing 22 changed files with 418 additions and 9 deletions.
Binary file modified bun.lockb
Binary file not shown.
4 changes: 4 additions & 0 deletions firestore.rules
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ service cloud.firestore {
allow read: if authenticated() && isAdmin(eventData(eventId));
allow write: if authenticated() && isAdmin(eventData(eventId));
}
match /team/{memberId} {
allow read: if authenticated() && isAdmin(eventData(eventId));
allow write: if authenticated() && isAdmin(eventData(eventId));
}
match /schedule/{scheduleId} {
allow read: if authenticated() && isAdmin(eventData(eventId));
allow write: if authenticated() && isAdmin(eventData(eventId));
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"react-dropzone": "^14.2.3",
"react-hook-form": "^7.47.0",
"react-hook-form-mui": "^6.5.4",
"react-hotkeys-hook": "^4.4.1",
"react-redux": "^8.1.3",
"use-firebase-auth": "^3.0.0",
"uuid": "^9.0.1",
Expand Down
16 changes: 16 additions & 0 deletions src/components/form/SaveShortcut.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { useHotkeys } from 'react-hotkeys-hook'
import { useRef } from 'react'

export const SaveShortcut = () => {
const ref = useRef(null)
useHotkeys(['ctrl+s', 'meta+s'], (event) => {
event.preventDefault()
// @ts-ignore
const form = ref.current?.closest('form')
if (form) {
form.dispatchEvent(new Event('submit', { cancelable: true, bubbles: true }))
}
})

return <div ref={ref}></div>
}
11 changes: 11 additions & 0 deletions src/events/actions/getTeam.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { TeamMember } from '../../types'
import { getDocs } from 'firebase/firestore'
import { collections } from '../../services/firebase'

export const getTeam = async (eventId: string): Promise<TeamMember[]> => {
const snapshots = await getDocs(collections.team(eventId))

return snapshots.docs.map((snapshot) => ({
...snapshot.data(),
}))
}
4 changes: 4 additions & 0 deletions src/events/actions/updateWebsiteActions/generateStaticJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import { getSessions } from '../sessions/getSessions'
import { getSpeakers } from '../getSpeakers'
import { getSponsors } from '../getSponsors'
import { generateOpenFeedbackJson } from './generateOpenFeedbackJson'
import { getTeam } from '../getTeam'

export const generateStaticJson = async (event: Event) => {
const sessions = await getSessions(event.id)
const speakers = await getSpeakers(event.id)
const sponsors = await getSponsors(event.id)
const team = await getTeam(event.id)

const openFeedbackOutput = generateOpenFeedbackJson(event, sessions, speakers)

Expand Down Expand Up @@ -85,13 +87,15 @@ export const generateStaticJson = async (event: Event) => {
})),
sessions: outputSessions,
sponsors: outputSponsor,
team: team,
generatedAt: new Date().toISOString(),
}
const outputPrivate = {
event: outputEvent,
speakers: speakers,
sessions: outputSessionsPrivate,
sponsors: outputSponsor,
team: team,
generatedAt: new Date().toISOString(),
}

Expand Down
28 changes: 25 additions & 3 deletions src/events/page/EventRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ import { FirestoreQueryLoaderAndErrorDisplay } from '../../components/FirestoreQ
import { Event } from '../../types'
import { SuspenseLoader } from '../../components/SuspenseLoader'

const EventSponsors = lazy(() =>
import('./sponsors/EventSponsors').then((module) => ({ default: module.EventSponsors }))
)
const EventSettings = lazy(() =>
import('./settings/EventSettings').then((module) => ({ default: module.EventSettings }))
)
Expand All @@ -27,9 +24,16 @@ const EventSpeakers = lazy(() =>
const EventSpeaker = lazy(() => import('./speakers/EventSpeaker').then((module) => ({ default: module.EventSpeaker })))
const NewSession = lazy(() => import('./sessions/NewSession').then((module) => ({ default: module.NewSession })))
const NewSpeaker = lazy(() => import('./speakers/NewSpeaker').then((module) => ({ default: module.NewSpeaker })))
const EventSponsors = lazy(() =>
import('./sponsors/EventSponsors').then((module) => ({ default: module.EventSponsors }))
)
const NewSponsor = lazy(() => import('./sponsors/NewSponsor').then((module) => ({ default: module.NewSponsor })))
const Sponsor = lazy(() => import('./sponsors/Sponsor').then((module) => ({ default: module.Sponsor })))

const EventTeam = lazy(() => import('./team/EventTeam').then((module) => ({ default: module.EventTeam })))
const NewMember = lazy(() => import('./team/NewMember').then((module) => ({ default: module.NewMember })))
const EventMember = lazy(() => import('./team/EventMember').then((module) => ({ default: module.EventMember })))

export const EventRouter = () => {
const [_, params] = useRoute('/events/:eventId/:subRoute*')
const event = useEvent(params?.eventId)
Expand Down Expand Up @@ -71,6 +75,24 @@ export const EventRouter = () => {
</Route>
</Switch>

<Route path="/team">
<Suspense fallback={<SuspenseLoader />}>
<EventTeam event={eventData} />
</Suspense>
</Route>
<Switch>
<Route path="/team/new">
<Suspense fallback={<SuspenseLoader />}>
<NewMember event={eventData} />
</Suspense>
</Route>
<Route path="/team/:id">
<Suspense fallback={<SuspenseLoader />}>
<EventMember event={eventData} />
</Suspense>
</Route>
</Switch>

<Route path="/sessions">
<Suspense fallback={<SuspenseLoader />}>
<EventSessions event={eventData} />
Expand Down
14 changes: 13 additions & 1 deletion src/events/page/EventScreenMenuItems.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { ListItemButton, ListItemIcon, ListItemText } from '@mui/material'
import * as React from 'react'
import { Icon } from '@mdi/react'
import { mdiAccountVoice, mdiCalendarWeekend, mdiCashMultiple, mdiCogBox, mdiPresentation } from '@mdi/js'
import {
mdiAccountMultiple,
mdiAccountVoice,
mdiCalendarWeekend,
mdiCashMultiple,
mdiCogBox,
mdiPresentation,
} from '@mdi/js'
import { useRoute } from 'wouter'
import { LinkBehavior } from '../../components/CCLink'

Expand All @@ -26,6 +33,11 @@ export const Menu = [
icon: mdiCashMultiple,
name: 'Sponsors',
},
{
href: '/team',
icon: mdiAccountMultiple,
name: 'Team',
},
{
href: '/sessions',
icon: mdiPresentation,
Expand Down
2 changes: 2 additions & 0 deletions src/events/page/sessions/EventSessionForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useSpeakers } from '../../../services/hooks/useSpeakersMap'
import LoadingButton from '@mui/lab/LoadingButton'
import { ImageTextFieldElement } from '../../../components/form/ImageTextFieldElement'
import { useLocation } from 'wouter'
import { SaveShortcut } from '../../../components/form/SaveShortcut'

export type EventSessionFormProps = {
event: Event
Expand Down Expand Up @@ -287,6 +288,7 @@ export const EventSessionForm = ({ event, session, onSubmit }: EventSessionFormP
</LoadingButton>
</Grid>
</Grid>
<SaveShortcut />
</FormContainer>
)
}
2 changes: 2 additions & 0 deletions src/events/page/settings/EventSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
useFirestoreDocumentDeletion,
useFirestoreDocumentMutation,
} from '../../../services/hooks/firestoreMutationHooks'
import { SaveShortcut } from '../../../components/form/SaveShortcut'

const schema = yup
.object({
Expand Down Expand Up @@ -172,6 +173,7 @@ export const EventSettings = ({ event }: EventSettingsProps) => {
</Grid>
</Grid>
</Card>
{!deleteOpen && !reImportOpen && <SaveShortcut />}
</FormContainer>

<Box mt={2}>
Expand Down
2 changes: 2 additions & 0 deletions src/events/page/speakers/EventSpeakerForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Grid } from '@mui/material'
import LoadingButton from '@mui/lab/LoadingButton'
import { SpeakerSocialFields } from './SpeakerSocials'
import { ImageTextFieldElement } from '../../../components/form/ImageTextFieldElement'
import { SaveShortcut } from '../../../components/form/SaveShortcut'

export type EventSpeakerFormProps = {
event: Event
Expand Down Expand Up @@ -165,6 +166,7 @@ export const EventSpeakerForm = ({ speaker, onSubmit, event }: EventSpeakerFormP
</LoadingButton>
</Grid>
</Grid>
<SaveShortcut />
</FormContainer>
)
}
2 changes: 2 additions & 0 deletions src/events/page/sponsors/components/SponsorForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { FormContainer, TextFieldElement, useForm } from 'react-hook-form-mui'
import { Grid } from '@mui/material'
import LoadingButton from '@mui/lab/LoadingButton'
import { ImageTextFieldElement } from '../../../../components/form/ImageTextFieldElement'
import { SaveShortcut } from '../../../../components/form/SaveShortcut'

export type SponsorFormProps = {
event: Event
Expand Down Expand Up @@ -92,6 +93,7 @@ export const SponsorForm = ({ event, sponsor, onSubmit }: SponsorFormProps) => {
{sponsor ? 'Save' : 'Add sponsor'}
</LoadingButton>
</Grid>
<SaveShortcut />
</FormContainer>
)
}
55 changes: 55 additions & 0 deletions src/events/page/team/EventMember.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import * as React from 'react'
import { Box, Button, Card, Container, Link, Typography } from '@mui/material'
import { ArrowBack } from '@mui/icons-material'
import { useLocation, useRoute } from 'wouter'
import { doc } from 'firebase/firestore'
import { collections } from '../../../services/firebase'
import { FirestoreQueryLoaderAndErrorDisplay } from '../../../components/FirestoreQueryLoaderAndErrorDisplay'
import { MemberForm } from './components/MemberForm'
import { useFirestoreDocumentMutation } from '../../../services/hooks/firestoreMutationHooks'
import { useTeam } from '../../../services/hooks/useTeam'
import { Event, TeamMember } from '../../../types'

export type EventMemberProps = {
event: Event
}
export const EventMember = ({ event }: EventMemberProps) => {
const [_, params] = useRoute('/:routeName/:memberId*')
const members = useTeam(event.id)
const [_2, setLocation] = useLocation()

const memberId = params?.memberId

const mutation = useFirestoreDocumentMutation(doc(collections.team(event.id), memberId))

if (members.isLoading || !members.data) {
return <FirestoreQueryLoaderAndErrorDisplay hookResult={members} />
}

const member = members.data.find((s: TeamMember) => s.id === memberId)

if (!member) {
setLocation('/team')
}

return (
<Container maxWidth="lg" sx={{ mt: 4, mb: 4 }} key={memberId}>
<Box display="flex" justifyContent="space-between" mt={2}>
<Button startIcon={<ArrowBack />} component={Link} href="/team">
All members
</Button>
</Box>
<Card sx={{ paddingX: 2 }}>
<Typography variant="h2">{member.name}</Typography>

<MemberForm
event={event}
member={member}
onSubmit={async (data) => {
await mutation.mutate(data)
}}
/>
</Card>
</Container>
)
}
38 changes: 38 additions & 0 deletions src/events/page/team/EventTeam.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Event, TeamMember } from '../../../types'
import * as React from 'react'
import { FirestoreQueryLoaderAndErrorDisplay } from '../../../components/FirestoreQueryLoaderAndErrorDisplay'
import { Box, Button, Card, Container, Typography } from '@mui/material'
import { useTeam } from '../../../services/hooks/useTeam'
import { Member } from './components/Member'

export type EventTeamProps = {
event: Event
}
export const EventTeam = ({ event }: EventTeamProps) => {
const team = useTeam(event.id)

const teamData = team.data || []

if (team.isLoading) {
return <FirestoreQueryLoaderAndErrorDisplay hookResult={team} />
}

return (
<Container maxWidth="lg" sx={{ mt: 4, mb: 4 }}>
<Box display="flex" justifyContent="space-between" alignItems="center" marginBottom={1}>
<Typography>{team.data?.length} members</Typography>
<Box marginY={2}>
<Button href={`/team/new`}>Add member</Button>
</Box>
</Box>
<Card sx={{ padding: 2, minHeight: '50vh', display: 'flex', flexDirection: 'column', flexFlow: 'row' }}>
{teamData.map((member: TeamMember) => (
<Member key={member.id} member={member} event={event} />
))}
</Card>
<Box marginY={2}>
<Button href={`/team/new`}>Add member</Button>
</Box>
</Container>
)
}
41 changes: 41 additions & 0 deletions src/events/page/team/NewMember.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as React from 'react'
import { useLocation } from 'wouter'
import { collections } from '../../../services/firebase'
import { Button, Card, Container, Typography } from '@mui/material'
import { ArrowBack } from '@mui/icons-material'
import { Event } from '../../../types'
import { MemberForm } from './components/MemberForm'
import { useFirestoreCollectionMutation } from '../../../services/hooks/firestoreMutationHooks'
import { slugify } from '../../../utils/slugify'

export type NewMemberProps = {
event: Event
}
export const NewMember = ({ event }: NewMemberProps) => {
const [_, setLocation] = useLocation()
const mutation = useFirestoreCollectionMutation(collections.team(event.id))

return (
<Container maxWidth="lg" sx={{ mt: 4, mb: 4 }}>
<Button href="/team" startIcon={<ArrowBack />}>
Cancel
</Button>
<Card sx={{ paddingX: 2 }}>
<Typography variant="h2">New member</Typography>

<MemberForm
event={event}
onSubmit={(member) => {
return mutation.mutate(member, slugify(member.name)).then(() => {
setLocation('/team')
})
}}
/>

{mutation.isError && (
<Typography color="error">Error while adding member: {mutation.error?.message}</Typography>
)}
</Card>
</Container>
)
}
Loading

0 comments on commit 54868c0

Please sign in to comment.