diff --git a/frontend/public/locales/en/common.json b/frontend/public/locales/en/common.json index 3af3fd40e65906d604c1f2de4781a3f673368c7a..ef1df5b59a94021e6069b29b659d6abbd59a0aa0 100644 --- a/frontend/public/locales/en/common.json +++ b/frontend/public/locales/en/common.json @@ -1,8 +1,4 @@ { - "test": "This is a test", - "nested": { - "test": "This is a nested value" - }, "language": { "change": "Change language to {{lang}}" }, @@ -75,5 +71,7 @@ "guestRole": "Guest role", "guestPeriod":"Period", "guestDepartment": "Department" - } + }, + "yourGuests": "Your guests", + "registerNewGuest": "Register new guest" } diff --git a/frontend/public/locales/nb/common.json b/frontend/public/locales/nb/common.json index 01ca7043a75d2992dd81cd3acc3aceea4bb2c16d..76c1fc23cc72fb95ef77497473a902c2c257b8e3 100644 --- a/frontend/public/locales/nb/common.json +++ b/frontend/public/locales/nb/common.json @@ -1,8 +1,4 @@ { - "test": "Dette er en test", - "nested": { - "test": "Dette er en 'nested' verdi" - }, "language": { "change": "Bytt språk til {{lang}}" }, @@ -75,5 +71,7 @@ "guestRole": "Gjesterolle", "guestPeriod": "Periode", "guestDepartment": "Avdeling" - } + }, + "yourGuests": "Dine gjester", + "registerNewGuest": "Registrer ny gjest" } diff --git a/frontend/public/locales/nn/common.json b/frontend/public/locales/nn/common.json index c9a6efec2216e8e14cc80909990e65e7e92bbc6f..13c58859c1b8e2c5406233092b267f4e33c8d5eb 100644 --- a/frontend/public/locales/nn/common.json +++ b/frontend/public/locales/nn/common.json @@ -1,8 +1,4 @@ { - "test": "Dette er ein test", - "nested": { - "test": "Dette er ein 'nested' verdi" - }, "language": { "languageName": "Språk", "change": "Bytt språk til {{lang}}" @@ -76,5 +72,7 @@ "guestRole": "Gjesterolle", "guestPeriod": "Periode", "guestDepartment": "Avdeling" - } + }, + "yourGuests": "Dine gjestar", + "registerNewGuest": "Registrer ny gjest" } diff --git a/frontend/src/routes/components/sponsorGuestButtons.tsx b/frontend/src/routes/components/sponsorGuestButtons.tsx new file mode 100644 index 0000000000000000000000000000000000000000..f0aa91e3ae3ef36e712a8a9d5996d33bef65ad08 --- /dev/null +++ b/frontend/src/routes/components/sponsorGuestButtons.tsx @@ -0,0 +1,72 @@ +import PersonIcon from '@mui/icons-material/Person' +import { Box, IconButton, Theme } from '@mui/material' +import PersonAddIcon from '@mui/icons-material/PersonAdd' +import React from 'react' +import { useTranslation } from 'react-i18next' +import { useHistory } from 'react-router-dom' + +interface SponsorGuestButtonsProps { + yourGuestsActive?: boolean, + registerNewGuestActive?: boolean +} + +export default function SponsorGuestButtons(props: SponsorGuestButtonsProps) { + const { yourGuestsActive, registerNewGuestActive } = props + const { t } = useTranslation(['common']) + const history = useHistory() + + const goToOverview = () => { + history.push('/sponsor') + } + + const goToRegister = () => { + history.push('/register') + } + + return ( + <Box sx={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-evenly', marginBottom: '2rem' }}> + <Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}> + <IconButton onClick={goToOverview}> + <PersonIcon + fontSize='large' + sx={{ + borderRadius: '2rem', + borderStyle: 'solid', + borderColor: (theme: Theme) => yourGuestsActive ? theme.palette.primary.main : theme.greg.deactivatedColor, + fill: 'white', + backgroundColor: (theme: Theme) => yourGuestsActive ? theme.palette.primary.main : theme.greg.deactivatedColor, + }} /> + </IconButton> + <Box sx={{ + typography: 'caption', + }}> + {t('yourGuests')} + </Box> + </Box> + + <Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}> + <IconButton onClick={goToRegister}> + <PersonAddIcon + fontSize='large' + sx={{ + borderRadius: '2rem', + borderStyle: 'solid', + borderColor: (theme: Theme) => registerNewGuestActive ? theme.palette.primary.main : theme.greg.deactivatedColor, + fill: 'white', + backgroundColor: (theme: Theme) => registerNewGuestActive ? theme.palette.primary.main : theme.greg.deactivatedColor, + }} /> + </IconButton> + <Box sx={{ + typography: 'caption', + }}> + {t('registerNewGuest')} + </Box> + </Box> + </Box> + ) +} + +SponsorGuestButtons.defaultProps = { + yourGuestsActive: false, + registerNewGuestActive: false, +} diff --git a/frontend/src/routes/index.tsx b/frontend/src/routes/index.tsx index 8a6b6b8d9b83341405a0d8df3c52beac6512f26f..8ecd1892468cfa5a643ddf40632f5c5f758333fc 100644 --- a/frontend/src/routes/index.tsx +++ b/frontend/src/routes/index.tsx @@ -51,9 +51,9 @@ export default function App() { <ProtectedRoute path="/sponsor"> <Sponsor /> </ProtectedRoute> - <Route path="/register"> + <ProtectedRoute path="/register"> <Register /> - </Route> + </ProtectedRoute> <Route path="/invite/:id" component={InviteLink} /> <Route path="/invite/" component={Invite} /> <Route> diff --git a/frontend/src/routes/register/index.tsx b/frontend/src/routes/register/index.tsx index d0833f039a6e354e993ebbe64ce752abf7825e91..e7d1053e70baf38ffd8012e33f3c07fcac1a3c40 100644 --- a/frontend/src/routes/register/index.tsx +++ b/frontend/src/routes/register/index.tsx @@ -1,7 +1,7 @@ import React, { useState, useRef } from 'react' import { useTranslation } from 'react-i18next' -import { Box, Button, Step, StepLabel, Stepper } from '@mui/material' +import { Box, Button } from '@mui/material' import Page from 'components/page' import { useHistory } from 'react-router-dom' @@ -11,8 +11,8 @@ import StepPersonForm from './stepPersonForm' import { PersonFormMethods } from './personFormMethods' import { SummaryFormMethods } from './summaryFormMethods' import SubmitState from './submitState' +import SponsorGuestButtons from '../components/sponsorGuestButtons' -const steps = ['Register', 'Summary'] export default function StepRegistration() { const { t } = useTranslation(['common']) @@ -56,7 +56,7 @@ export default function StepRegistration() { } const handleForwardFromRegister = ( - updateFormData: RegisterFormData + updateFormData: RegisterFormData, ): void => { setFormData(updateFormData) setActiveStep((prevActiveStep) => prevActiveStep + 1) @@ -76,21 +76,7 @@ export default function StepRegistration() { return ( <Page> - {/* Stepper at top of wizard */} - <Stepper sx={{ paddingTop: '2rem' }} - activeStep={activeStep}> - {/* eslint-disable-next-line @typescript-eslint/no-unused-vars */} - {steps.map((label, index) => { - const stepProps = {} - const labelProps = {} - return ( - <Step key={label} {...stepProps}> - <StepLabel {...labelProps}>{label}</StepLabel> - </Step> - ) - })} - </Stepper> - + <SponsorGuestButtons registerNewGuestActive /> {/* Current page in wizard */} <Box sx={{ width: '100%' }}> {activeStep === REGISTER_STEP && ( @@ -110,7 +96,7 @@ export default function StepRegistration() { )} </Box> - <Box sx={{ display: 'flex', flexDirection: 'row', pt: 2, color: 'primary.main', paddingBottom: '1rem'}}> + <Box sx={{ display: 'flex', flexDirection: 'row', pt: 2, color: 'primary.main', paddingBottom: '1rem' }}> {activeStep === REGISTER_STEP && ( <Button data-testid='button-next' sx={{ color: 'theme.palette.secondary', mr: 1 }} diff --git a/frontend/src/routes/register/stepPersonForm.tsx b/frontend/src/routes/register/stepPersonForm.tsx index 9d0622b08e8f12bd0644a816f2738dfeda482ec4..9674d86f731df96d0b5363081c172b78dc6bcf41 100644 --- a/frontend/src/routes/register/stepPersonForm.tsx +++ b/frontend/src/routes/register/stepPersonForm.tsx @@ -158,13 +158,11 @@ const StepPersonForm = forwardRef((props: StepPersonFormProperties, ref: Ref<Per ous .sort(i18n.language === 'en' ? enSort : nbSort) .map((ou) => ( - <MenuItem value={ou.id}> + <MenuItem key={ou.id.toString()} value={ou.id}> {i18n.language === 'en' ? ou.en : ou.nb} ({ou.id}) </MenuItem> )) - ) : ( - <></> - )} + ) : ('')} </Select> </FormControl> @@ -180,6 +178,7 @@ const StepPersonForm = forwardRef((props: StepPersonFormProperties, ref: Ref<Per roleTypes.sort(roleTypeSort()) .map((roleType) => ( <MenuItem + key={roleType.id.toString()} value={roleType.id}>{i18n.language === 'en' ? roleType.name_en : roleType.name_nb}</MenuItem> )) } diff --git a/frontend/src/routes/sponsor/frontpage/index.tsx b/frontend/src/routes/sponsor/frontpage/index.tsx index 43057ae2f9d677998fd62396a99d471d6a697403..f7e6aa7f218bb5902eacc044a9d2ecfe3d9eb5ff 100644 --- a/frontend/src/routes/sponsor/frontpage/index.tsx +++ b/frontend/src/routes/sponsor/frontpage/index.tsx @@ -6,12 +6,13 @@ import { TableContainer, TableHead, TableRow, - Paper, + Paper, Accordion, AccordionSummary, AccordionDetails, } from '@mui/material' +import ExpandMoreIcon from '@mui/icons-material/ExpandMore' import Page from 'components/page' import { useTranslation } from 'react-i18next' -import { Link } from 'react-router-dom' +import SponsorGuestButtons from '../../components/sponsorGuestButtons' type PersonInfo = { name: string @@ -50,24 +51,26 @@ const PersonLine = ({ person }: PersonLineProps) => { key={person.name} sx={{ '&:last-child td, &:last-child th': { border: 0 } }} > - <TableCell component="th" scope="row"> + <TableCell component='th' scope='row'> {person.name} </TableCell> - <TableCell align="left"> + <TableCell align='left'> {i18n.language === 'en' ? person.role_en : person.role_nb} </TableCell> - <TableCell align="left">{person.period}</TableCell> - <TableCell align="left"> + <TableCell align='left'>{person.period}</TableCell> + <TableCell align='left'> {i18n.language === 'en' ? person.ou_en : person.ou_nb} </TableCell> - <TableCell align="left"> - <button type="button">{t('common:details')}</button> + <TableCell align='left'> + <button type='button'>{t('common:details')}</button> </TableCell> </TableRow> ) } const ActiveGuests = ({ persons }: GuestProps) => { + const [activeExpanded, setActiveExpanded] = useState(false) + // Only show active people let guests = persons.length > 0 ? persons : [] if (guests.length > 0) { @@ -75,38 +78,46 @@ const ActiveGuests = ({ persons }: GuestProps) => { } const [t] = useTranslation(['common']) return ( - <> - <h1>{t('common:activeGuests')}</h1> - <p>{t('common:activeGuestsDescription')}</p> - <TableContainer component={Paper}> - <Table sx={{ minWidth: 650 }} aria-label="simple table"> - <TableHead> - <TableRow> - <TableCell>{t('common:name')}</TableCell> - <TableCell align="left">{t('common:role')}</TableCell> - <TableCell align="left">{t('common:period')}</TableCell> - <TableCell align="left">{t('common:ou')}</TableCell> - <TableCell align="left">{t('common:choice')}</TableCell> - </TableRow> - </TableHead> - <TableBody> - {guests.map((person) => ( - <PersonLine person={person} /> - ))} - - <TableRow> - <TableCell> - {guests.length > 0 ? '' : t('common:noActiveGuests')} - </TableCell> - </TableRow> - </TableBody> - </Table> - </TableContainer> - </> + <Accordion expanded={activeExpanded} onChange={() => { + setActiveExpanded(!activeExpanded) + }}> + <AccordionSummary expandIcon={<ExpandMoreIcon />}> + <h4>{t('common:activeGuests')}</h4> + </AccordionSummary> + <AccordionDetails> + <p>{t('common:activeGuestsDescription')}</p> + <TableContainer component={Paper}> + <Table sx={{ minWidth: 650 }} aria-label='simple table'> + <TableHead sx={{ backgroundColor: 'primary.light' }}> + <TableRow> + <TableCell>{t('common:name')}</TableCell> + <TableCell align='left'>{t('common:role')}</TableCell> + <TableCell align='left'>{t('common:period')}</TableCell> + <TableCell align='left'>{t('common:ou')}</TableCell> + <TableCell align='left'>{t('common:choice')}</TableCell> + </TableRow> + </TableHead> + <TableBody> + {guests.map((person) => ( + <PersonLine person={person} /> + ))} + + <TableRow> + <TableCell> + {guests.length > 0 ? '' : t('common:noActiveGuests')} + </TableCell> + </TableRow> + </TableBody> + </Table> + </TableContainer> + </AccordionDetails> + </Accordion> ) } const WaitingGuests = ({ persons }: GuestProps) => { + const [waitingExpanded, setWaitingExpanded] = useState(false) + // Only show non-active people let guests = persons.length > 0 ? persons : [] if (guests.length > 0) { @@ -115,41 +126,48 @@ const WaitingGuests = ({ persons }: GuestProps) => { const [t] = useTranslation(['common']) return ( - <> - <h1>{t('common:waitingGuests')}</h1> - <p>{t('common:waitingGuestsDescription')}</p> - - <TableContainer component={Paper}> - <Table sx={{ minWidth: 650 }} aria-label="simple table"> - <TableHead> - <TableRow> - <TableCell>{t('common:name')}</TableCell> - <TableCell align="left">{t('common:role')}</TableCell> - <TableCell align="left">{t('common:period')}</TableCell> - <TableCell align="left">{t('common:ou')}</TableCell> - <TableCell align="left">{t('common:choice')}</TableCell> - </TableRow> - </TableHead> - <TableBody> - {guests.map((person) => ( - <PersonLine person={person} /> - ))} - <TableRow> - <TableCell> - {guests.length > 0 ? '' : t('common:noWaitingGuests')} - </TableCell> - </TableRow> - </TableBody> - </Table> - </TableContainer> - </> + <Accordion expanded={waitingExpanded} onChange={() => { + setWaitingExpanded(!waitingExpanded) + }} + sx={{ border: 'none' }}> + + <AccordionSummary expandIcon={<ExpandMoreIcon />}> + <h4>{t('common:waitingGuests')}</h4> + </AccordionSummary> + <AccordionDetails> + <p>{t('common:waitingGuestsDescription')}</p> + + <TableContainer component={Paper}> + <Table sx={{ minWidth: 650 }} aria-label='simple table'> + <TableHead sx={{ backgroundColor: 'primary.light' }}> + <TableRow> + <TableCell>{t('common:name')}</TableCell> + <TableCell align='left'>{t('common:role')}</TableCell> + <TableCell align='left'>{t('common:period')}</TableCell> + <TableCell align='left'>{t('common:ou')}</TableCell> + <TableCell align='left'>{t('common:choice')}</TableCell> + </TableRow> + </TableHead> + <TableBody> + {guests.map((person) => ( + <PersonLine person={person} /> + ))} + <TableRow> + <TableCell> + {guests.length > 0 ? '' : t('common:noWaitingGuests')} + </TableCell> + </TableRow> + </TableBody> + </Table> + </TableContainer> + </AccordionDetails> + </Accordion> ) } function FrontPage() { const [persons, setPersons] = useState<Array<PersonInfo>>([]) - const [t] = useTranslation(['common']) const fetchGuestsInfo = async () => { const response = await fetch('/api/ui/v1/guests/?format=json') const jsonResponse = await response.json() @@ -173,10 +191,9 @@ function FrontPage() { }, []) return ( - <Page header="Sponsor front page"> - <Link to="/register">{t('common:registerText')}</Link> + <Page> + <SponsorGuestButtons yourGuestsActive /> <WaitingGuests persons={persons} /> - <hr className="rounded" /> <ActiveGuests persons={persons} /> </Page> ) diff --git a/frontend/src/themes/index.ts b/frontend/src/themes/index.ts index a01197e633def86da817eb40c8ea9442a0beb399..d1cdfcd3867f886fcd06999949d8294dd3ffdef3 100644 --- a/frontend/src/themes/index.ts +++ b/frontend/src/themes/index.ts @@ -17,6 +17,7 @@ declare module '@mui/material/styles' { h2TextColor: string footerBackgroundColor: string footerTextColor: string + deactivatedColor: string } } // allow configuration using `createTheme` @@ -28,7 +29,8 @@ declare module '@mui/material/styles' { h1TextColor?: string h2TextColor?: string footerBackgroundColor?: string - footerTextColor?: string + footerTextColor?: string, + deactivatedColor?: string } } } diff --git a/frontend/src/themes/main.ts b/frontend/src/themes/main.ts index e07e4ce55617aa862c5b99274a6288bb084bad9c..44bd354d1d06c71c16f9b82c628b40c93381a518 100644 --- a/frontend/src/themes/main.ts +++ b/frontend/src/themes/main.ts @@ -11,11 +11,13 @@ const mainTheme: ThemeOptions = { h2TextColor: '#373F41', footerBackgroundColor: 'black', footerTextColor: 'white', + deactivatedColor: '#C9C9C9' }, palette: { primary: { - main: '#3293ED', - dark: '#1565c0' + main: '#01579B', + dark: '#1565c0', + light: '#A4C8E4', }, }, components: {