Skip to content
Snippets Groups Projects
Commit 975e35cd authored by Jonas Braathen's avatar Jonas Braathen
Browse files

Switch to Material UI and emotion

parent a20ebafd
No related branches found
No related tags found
1 merge request!73Switch to Material UI and emotion
Pipeline #94779 passed
Showing
with 1238 additions and 559 deletions
This diff is collapsed.
......@@ -3,6 +3,12 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@emotion/react": "^11.4.1",
"@emotion/styled": "^11.3.0",
"@mui/icons-material": "^5.0.1",
"@mui/material": "^5.0.1",
"@mui/system": "^5.0.1",
"@mui/utils": "^5.0.1",
"@navikt/fnrvalidator": "^1.1.4",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^11.2.7",
......@@ -11,7 +17,6 @@
"@types/node": "^12.20.24",
"@types/react": "^17.0.20",
"@types/react-dom": "^17.0.9",
"@types/styled-components": "^5.1.14",
"date-fns": "^2.24.0",
"http-proxy-middleware": "^2.0.1",
"i18next": "^20.6.0",
......@@ -25,7 +30,6 @@
"react-i18next": "^11.11.4",
"react-router-dom": "^5.3.0",
"react-scripts": "4.0.3",
"styled-components": "^5.3.1",
"typeface-roboto": "^1.1.13",
"typescript": "^4.4.2",
"web-vitals": "^1.1.2"
......
import styled from 'styled-components/macro'
import styled from '@emotion/styled/macro'
const Spinner = styled.div`
position: relative;
......
import styled from 'styled-components/macro'
export const Button = styled.a`
display: inline-block;
cursor: pointer;
padding: 0.6rem 0.8rem;
background: ${({ theme }) => theme.colors.main};
color: white;
border-radius: 0.5rem;
border: 2px solid white;
font-weight: 500;
font-size: 1rem;
`
export default Button
import React, { useState } from 'react'
import { useTranslation } from 'react-i18next'
import CheckIcon from '@mui/icons-material/Check'
import ClearIcon from '@mui/icons-material/Clear'
import {
Box,
Button,
Table,
TableBody,
TableRow,
TableCell,
Stack,
Divider,
} from '@mui/material'
import { appTheme, appTimezone, appVersion, appInst } from 'appConfig'
const Yes = () => <CheckIcon color="success" />
const No = () => <ClearIcon color="error" />
export const Debug = () => {
const [apiHealth, setApiHealth] = useState('not yet')
const [didContactApi, setDidContactApi] = useState(false)
......@@ -111,34 +128,43 @@ export const Debug = () => {
['Language', i18n.language],
['Theme', appTheme],
['Institution', appInst],
['API reachable?', apiHealth],
['Csrf', csrf],
['Authenticated?', isAuthenticated ? 'Authenticated' : 'Not Authenticated'],
['username', username],
['API reachable?', apiHealth === 'yes' ? <Yes /> : apiHealth],
['Authenticated?', isAuthenticated ? <Yes /> : <No />],
['Username', username],
['CSRF', csrf],
]
return (
<table>
<thead>
<strong>Debug</strong>
</thead>
<button type="button" onClick={() => getSession()}>
AM I AUTHENTICATED?
</button>
<button type="button" onClick={() => whoami()}>
WHO AM I?
</button>
<button type="button" onClick={() => logout()}>
LOGOUT
</button>
<tbody>
{d.map(([key, value]) => (
<tr>
<td>{key}</td>
<td>{value}</td>
</tr>
))}
</tbody>
</table>
<Box>
<h3>Debug</h3>
<Stack
direction="row"
spacing={1}
divider={<Divider orientation="vertical" />}
>
<Button type="button" onClick={() => getSession()}>
AM I AUTHENTICATED?
</Button>
<Button type="button" onClick={() => whoami()}>
WHO AM I?
</Button>
<Button type="button" onClick={() => logout()}>
LOGOUT
</Button>
</Stack>
<Box sx={{ maxWidth: '30rem' }}>
<Table>
<TableBody>
{d.map(([key, value]) => (
<TableRow>
<TableCell>{key}</TableCell>
<TableCell>{value}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</Box>
</Box>
)
}
......
import React, { useState } from 'react'
import styled from 'styled-components/macro'
import styled from '@emotion/styled/macro'
const DropDownMenu = styled.div`
......@@ -22,7 +22,6 @@ const DropDownList = styled.ul`
min-width: 10rem;
max-height: 50rem;
z-index: 100;
background: ${({ theme }) => theme.colors.dropDownMenuBackground};
`
interface IDropDownOption {
......
import styled from 'styled-components/macro'
import styled from '@emotion/styled/macro'
const StyledValidationError = styled.span`
color: ${({ theme }) => theme.colors.errorMessage};
color: "red"
`
export default StyledValidationError
\ No newline at end of file
import React from 'react'
import styled from 'styled-components/macro'
import styled from '@emotion/styled/macro'
import { UseFormReturn } from 'react-hook-form'
interface InputProps
......
import React from 'react'
import styled, { css } from 'styled-components/macro'
import styled from '@emotion/styled/macro'
interface IStyledLink {
external?: boolean
......@@ -9,28 +9,25 @@ interface IStyledLink {
noUnderline?: boolean
}
interface ILink {
to: string
external?: boolean
children?: React.ReactNode
marginRight?: boolean
noExternalIcon?: boolean
mail?: boolean
inheritColor?: boolean
underline?: boolean
noUnderline?: boolean
to: string
external?: boolean
children?: React.ReactNode
marginRight?: boolean
noExternalIcon?: boolean
mail?: boolean
inheritColor?: boolean
underline?: boolean
noUnderline?: boolean
}
const externalLinkIcon = (
<svg width="15.3" height="12.6" viewBox="0 0 17 14">
<g fill="#0F748D" fillRule="evenodd">
<path
d="M13.044 8.157h-.607a.3.3 0 0 0-.218.082.276.276 0 0 0-.085.208v2.907c0 .4-.148.742-.445 1.027a1.493 1.493 0 0 1-1.072.427H2.73c-.417 0-.774-.143-1.071-.427a1.371 1.371 0 0 1-.446-1.027V3.796c0-.4.149-.742.446-1.026a1.493 1.493 0 0 1 1.071-.427h6.674a.302.302 0 0 0 .218-.082.277.277 0 0 0 .085-.209v-.581a.277.277 0 0 0-.085-.21.302.302 0 0 0-.218-.08H2.73c-.752 0-1.395.255-1.93.767-.533.511-.8 1.128-.8 1.848v7.558c0 .721.267 1.337.801 1.849a2.689 2.689 0 0 0 1.93.768h7.886c.752 0 1.395-.256 1.93-.768.534-.512.8-1.128.8-1.849V8.448a.276.276 0 0 0-.085-.21.302.302 0 0 0-.218-.081z"/>
<path
d="M16.807.19a.596.596 0 0 0-.426-.173h-4.854a.596.596 0 0 0-.426.173.548.548 0 0 0-.18.409c0 .157.06.294.18.409l1.668 1.598-6.18 5.923a.281.281 0 0 0-.095.21c0 .078.031.148.094.208L7.67 9.983a.306.306 0 0 0 .436 0l6.18-5.923 1.67 1.599c.12.115.262.172.426.172a.596.596 0 0 0 .426-.172.547.547 0 0 0 .18-.409V.599a.548.548 0 0 0-.18-.409z"/>
</g>
</svg>
<svg width="15.3" height="12.6" viewBox="0 0 17 14">
<g fill="#0F748D" fillRule="evenodd">
<path d="M13.044 8.157h-.607a.3.3 0 0 0-.218.082.276.276 0 0 0-.085.208v2.907c0 .4-.148.742-.445 1.027a1.493 1.493 0 0 1-1.072.427H2.73c-.417 0-.774-.143-1.071-.427a1.371 1.371 0 0 1-.446-1.027V3.796c0-.4.149-.742.446-1.026a1.493 1.493 0 0 1 1.071-.427h6.674a.302.302 0 0 0 .218-.082.277.277 0 0 0 .085-.209v-.581a.277.277 0 0 0-.085-.21.302.302 0 0 0-.218-.08H2.73c-.752 0-1.395.255-1.93.767-.533.511-.8 1.128-.8 1.848v7.558c0 .721.267 1.337.801 1.849a2.689 2.689 0 0 0 1.93.768h7.886c.752 0 1.395-.256 1.93-.768.534-.512.8-1.128.8-1.849V8.448a.276.276 0 0 0-.085-.21.302.302 0 0 0-.218-.081z" />
<path d="M16.807.19a.596.596 0 0 0-.426-.173h-4.854a.596.596 0 0 0-.426.173.548.548 0 0 0-.18.409c0 .157.06.294.18.409l1.668 1.598-6.18 5.923a.281.281 0 0 0-.095.21c0 .078.031.148.094.208L7.67 9.983a.306.306 0 0 0 .436 0l6.18-5.923 1.67 1.599c.12.115.262.172.426.172a.596.596 0 0 0 .426-.172.547.547 0 0 0 .18-.409V.599a.548.548 0 0 0-.18-.409z" />
</g>
</svg>
)
const ExternalIcon = styled.span`
......@@ -40,23 +37,9 @@ const ExternalIcon = styled.span`
z-index: -1;
`
const baseInputStyles = css<IStyledLink>`
const StyledLink = styled.a<IStyledLink>`
display: inline-flex;
align-items: center;
color: ${(props) =>
props.external
? props.theme.linkExternalColor
: props.theme.linkInternalColor};
${(props) => (props.marginRight ? 'margin-right: 3rem;' : '')}
${(props) => (props.inheritColor ? 'color: inherit;' : '')}
${(props) => (props.underline ? 'text-decoration: underline;' : '')}
${(props) => (props.noUnderline ? ':hover { text-decoration: none };' : '')}
`
const StyledLink = styled.a<IStyledLink>`
${baseInputStyles}
`
// TODO Put back when routes are set up
// const StyledRouterLink = styled(RouterLink)`
......@@ -64,16 +47,28 @@ const StyledLink = styled.a<IStyledLink>`
// `
function Link(props: ILink) {
const { children, external, to, noExternalIcon, mail, underline, marginRight, inheritColor, noUnderline } = props
const {
children,
external,
to,
noExternalIcon,
mail,
underline,
marginRight,
inheritColor,
noUnderline,
} = props
if (mail) {
return (
<StyledLink href={`mailto:${to}`}
external={external}
underline={underline}
marginRight={marginRight}
inheritColor={inheritColor}
noUnderline={noUnderline}>
<StyledLink
href={`mailto:${to}`}
external={external}
underline={underline}
marginRight={marginRight}
inheritColor={inheritColor}
noUnderline={noUnderline}
>
{children}
</StyledLink>
)
......@@ -86,8 +81,8 @@ function Link(props: ILink) {
return (
<StyledLink
href={href}
target='_blank'
rel='noopener noreferrer'
target="_blank"
rel="noopener noreferrer"
external={external}
underline={underline}
marginRight={marginRight}
......@@ -107,13 +102,17 @@ function Link(props: ILink) {
// </StyledRouterLink>
// )
return <StyledLink
external={external}
underline={underline}
marginRight={marginRight}
inheritColor={inheritColor}
noUnderline={noUnderline}>
{children}</StyledLink>
return (
<StyledLink
external={external}
underline={underline}
marginRight={marginRight}
inheritColor={inheritColor}
noUnderline={noUnderline}
>
{children}
</StyledLink>
)
}
Link.defaultProps = {
......
......@@ -2,7 +2,7 @@ import React from 'react'
import { useTranslation } from 'react-i18next'
import Spinner from 'components/animations/spinner'
import styled from 'styled-components/macro'
import styled from '@emotion/styled/macro'
const SpinnerWrapper = styled.div`
display: flex;
......
import React from 'react'
import styled from 'styled-components/macro'
const LogoBarWrapper = styled.div`
background-color: ${(props) => props.theme.colors.secondary});
`
const LogoBar = styled.div`
margin: 0 auto;
max-width: ${({ theme }) => theme.appMaxWidth});
padding: 0 ${({ theme }) => theme.horizontalMdPadding});
`
import Box from '@mui/material/Box'
function UiBLogoBar() {
return (
<LogoBarWrapper>
<LogoBar>
<Box
sx={{
backgroundColor: 'palette.secondary',
}}
>
<Box
sx={{
margin: '0 auto',
maxWidth: 'greg.appMaxWidth',
}}
>
Insert UiB logo here
</LogoBar>
</LogoBarWrapper>
</Box>
</Box>
)
}
......
import React from 'react'
import styled from 'styled-components/macro'
import Box from '@mui/material/Box'
import { styled } from '@mui/material/styles'
import { useTranslation } from 'react-i18next'
const LogoBarWrapper = styled.div`
display: flex;
justify-content: center;
background-color: ${({ theme }) => theme.page.headerBackgroundColor};
`
type Language = {
language: string
}
const Logo = styled.div<Language>`
background: ${props => props.language === 'en' ? 'url("/uio/uio-app-logo-en.png") left center no-repeat' : 'url("/uio/uio-app-logo-nb.png") left center no-repeat'};
min-width: 20rem;
height: 2rem;
`
const Logo = styled('div')<Language>(({ language }) => ({
background:
language === 'en'
? 'url("/uio/uio-app-logo-en.png") left center no-repeat'
: 'url("/uio/uio-app-logo-nb.png") left center no-repeat',
minWidth: '20rem',
height: '2rem',
}))
function UiOLogoBar() {
const { i18n } = useTranslation(['common', 'footer'])
return (
<LogoBarWrapper>
<Box
sx={{
backgroundColor: (theme) => theme.greg.headerBackgroundColor,
display: 'flex',
justifyContent: 'center',
}}
>
<Logo language={i18n.language} />
</LogoBarWrapper>
</Box>
)
}
......
......@@ -2,25 +2,15 @@ import React from 'react'
import { Helmet } from 'react-helmet'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components/macro'
import { styled } from '@mui/material/styles'
import { Container } from '@mui/material'
const StyledPage = styled.main`
display: block;
justify-content: space-between;
margin: 0 auto;
min-width: ${(props) => props.theme.appMinWidth};
max-width: ${(props) => props.theme.appMaxWidth};
padding: ${(props) =>
`0.5rem ${props.theme.horizontalPadding} 1rem ${props.theme.horizontalPadding}`};
`
const StyledPageHeader = styled.h2`
color: ${({ theme }) => theme.page.headerColor};
font-size: 3rem;
font-weight: bold;
margin: 0rem ${({ theme }) => theme.page.horizontalPadding} 0
${({ theme }) => theme.page.horizontalPadding};
`
const StyledPageHeader = styled('h2')(({ theme }) => ({
color: theme.greg.headerTextColor,
fontSize: '3rem',
fontWeight: 'bold',
margin: '0 6.5rem 0 6.5rem',
}))
interface IPage {
children: React.ReactNode
......@@ -38,10 +28,10 @@ export default function Page(props: IPage) {
<html lang={i18n.language} />
<title>{header}</title>
</Helmet>
<StyledPage>
<Container>
<StyledPageHeader>{header}</StyledPageHeader>
{children}
</StyledPage>
</Container>
</>
)
}
......
import { createGlobalStyle } from 'styled-components/macro'
import 'typeface-roboto'
const GlobalStyle = createGlobalStyle`
html {
font-size: clamp(24px, calc(24px * 1vw), 36px);
}
body {
margin: 0;
min-height: 100vh;
font-family: 'Roboto', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
#root {
min-height: 100vh;
}
`
export default GlobalStyle
import React, { Suspense } from 'react'
import ReactDOM from 'react-dom'
import { ThemeProvider } from 'styled-components/macro'
import { ThemeProvider } from '@mui/material/styles'
import { BrowserRouter as Router } from 'react-router-dom'
import 'i18n'
import getTheme from 'themes'
import GlobalStyle from 'globalStyles'
import App from 'routes'
import Loading from 'components/loading'
import reportWebVitals from './reportWebVitals'
......@@ -15,7 +14,6 @@ function appRoot() {
return (
<React.StrictMode>
<Router>
<GlobalStyle />
<Suspense fallback={<Loading />}>
<ThemeProvider theme={getTheme()}>
<App />
......
import React from 'react'
import styled from 'styled-components/macro'
import { useTranslation } from 'react-i18next'
import { styled } from '@mui/material/styles'
import {
appStagingWarning,
appTechnicalSupportLink,
reponsibleOrganization, responsibleOrganizationLink,
} from '../../appConfig'
import Link from '../../components/link'
const FooterWrapper = styled.footer`
background: ${({ theme }) => theme.footer.backgroundColor};
height: fit-content;
padding: 0rem ${({ theme }) => theme.horizontalPadding};
margin-top: auto;
`
reponsibleOrganization,
responsibleOrganizationLink,
} from 'appConfig'
import Link from 'components/link'
const FooterSection = styled.section`
header {
margin-bottom: 0.5rem;
font-size: 1.5rem;
}
const FooterWrapper = styled('footer')(({ theme }) => ({
background: theme.greg.footerBackgroundColor,
height: 'fit-content',
padding: '0rem 6.5rem',
marginTop: 'auto',
}))
padding-left: 1rem;
`
const FooterSection = styled('section')({
header: {
marginBottom: '0.5rem',
fontSize: '1.5rem',
},
paddingLeft: '1rem',
})
const FooterSectionContent = styled.div`
font-size: 1rem;
padding-left: 0.3rem;
`
const FooterSectionContent = styled('div')({
fontSize: '1rem',
paddingLeft: '0.3rem',
})
const ContentContainer = styled.div`
width: fit-content;
color: ${({ theme }) => theme.footerTextColor};
display: flex;
flex-wrap: nowrap;
justify-content: space-between;
margin: auto;
padding-top: 1rem;
padding-right: 1rem;
padding-bottom: 1rem;
`
const ContentContainer = styled('div')(({ theme }) => ({
width: 'fit-content',
color: theme.greg.footerTextColor,
display: 'flex',
flexWrap: 'nowrap',
justifyContent: 'space-between',
margin: 'auto',
padding: '1rem 1rem 1rem 0',
}))
const Footer: React.FunctionComponent = () => {
const { t } = useTranslation(['common', 'footer'])
......@@ -79,11 +77,7 @@ const Footer: React.FunctionComponent = () => {
</FooterSection>
</ContentContainer>
</FooterWrapper>
{appStagingWarning && (
<div className='alert'>
{t('staging')}
</div>
)}
{appStagingWarning && <div className="alert">{t('staging')}</div>}
</>
)
}
......
import React from 'react'
import { Link } from 'react-router-dom'
import styled from 'styled-components/macro'
import { useTranslation } from 'react-i18next'
import LogoBar from '../../components/logobars/LogoBar'
import LanguageSelector from '../../components/languageselector'
import { styled } from '@mui/material/styles'
import Box from '@mui/material/Box'
const MainWrapper = styled.div`
color: ${({ theme }) => theme.page.headerColor};
background-color: ${({ theme }) => theme.page.headerBackgroundColor};
import LogoBar from 'components/logobars/LogoBar'
import LanguageSelector from 'components/languageselector'
a {
text-decoration: none;
const MainWrapper = styled('div')(({ theme }) => ({
color: theme.greg.headerTextColor,
backgroundColor: theme.greg.headerBackgroundColor,
&:hover,
&:focus {
text-decoration: underline;
}
}
`
a: {
textDecoration: 'none',
const Main = styled.div`
display: flex;
justify-content: space-between;
margin: 0 auto;
max-width: ${(props) => props.theme.appMaxWidth};
padding: ${(props) =>
`0.5rem ${props.theme.horizontalPadding} 1rem ${props.theme.horizontalPadding}`};
`
'&:hover, &:focus': {
textDecoration: 'underline',
},
},
}))
const Menu = styled.ul`
list-style-type: none;
`
const Main = styled('div')(({ theme }) => ({
display: 'flex',
justifyContent: 'space-between',
margin: '0 auto',
maxWidth: theme.greg.appMaxWidth,
padding: '0.5rem 6.5rem 1rem 6.5rem',
}))
const MenuItem = styled.div`
font-size: 1rem;
display: inline;
`
const Menu = styled('ul')({
listStyleType: 'none',
})
const TitleBox = styled.div`
display: flex;
flex-direction: column;
padding-left: 3rem;
`
const Title = styled.div`
color: white;
white-space: nowrap;
text-decoration: none;
font-size: 2rem;
font-weight: bold;
`
const Description = styled.div`
font-size: 1rem;
`
const MenuItem = styled('div')({
fontSize: '1rem',
display: 'inline',
})
const Header = () => {
const { t } = useTranslation('common')
......@@ -63,12 +45,30 @@ const Header = () => {
<LogoBar />
<MainWrapper>
<Main>
<TitleBox>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
paddingLeft: '3rem',
}}
>
<Link to="/">
<Title>{t('header.applicationTitle')}</Title>
<Box
sx={{
color: 'white',
whiteSpace: 'nowrap',
textDecoration: 'none',
fontSize: '2rem',
fontWeight: 'bold',
}}
>
{t('header.applicationTitle')}
</Box>
</Link>
<Description>{t('header.applicationDescription')}</Description>
</TitleBox>
<Box sx={{ fontSize: '1rem' }}>
{t('header.applicationDescription')}
</Box>
</Box>
<Menu>
<MenuItem>
<LanguageSelector />
......
import React from 'react'
import { Switch, Route } from 'react-router-dom'
import styled from 'styled-components/macro'
import { styled } from '@mui/system'
import { CssBaseline } from '@mui/material'
import Sponsor from 'routes/sponsor'
import Register from 'routes/register'
......@@ -11,33 +12,36 @@ import Footer from 'routes/components/footer'
import Header from 'routes/components/header'
import NotFound from 'routes/components/notFound'
const AppWrapper = styled.div`
display: flex;
flex-direction: column;
font-size: 1.6rem;
min-height: 100vh;
margin-top: auto;
`
const AppWrapper = styled('div')({
display: 'flex',
flexDirection: 'column',
fontSize: '1.6rem',
minHeight: '100vh',
marginTop: 'auto',
})
export default function App() {
return (
<AppWrapper>
<Header />
<Switch>
<Route exact path="/">
<FrontPage />
</Route>
<Route path="/sponsor">
<Sponsor />
</Route>
<Route path="/register">
<Register />
</Route>
<Route>
<NotFound />
</Route>
</Switch>
<Footer />
</AppWrapper>
<>
<CssBaseline />
<AppWrapper>
<Header />
<Switch>
<Route exact path="/">
<FrontPage />
</Route>
<Route path="/sponsor">
<Sponsor />
</Route>
<Route path="/register">
<Register />
</Route>
<Route>
<NotFound />
</Route>
</Switch>
<Footer />
</AppWrapper>
</>
)
}
import React from 'react'
import { render, waitFor, screen } from '@testing-library/react'
import { render, waitFor, screen } from 'test-utils'
import i18n from 'i18next'
import { ThemeProvider } from 'styled-components/macro'
import { initReactI18next } from 'react-i18next'
import userEvent from '@testing-library/user-event'
import Register from './index'
import mainTheme from '../../themes/main'
// TODO: can this be initialized in 'test-utils'? should we stub it?
// see https://react.i18next.com/misc/testing
i18n.use(initReactI18next).init({
lng: 'en',
fallbackLng: 'en',
......@@ -21,11 +21,7 @@ i18n.use(initReactI18next).init({
})
test('Validation message showing if last name is missing', async () => {
render(
<ThemeProvider theme={mainTheme}>
<Register />
</ThemeProvider>
)
render(<Register />)
const firstNameLabel = i18n.t('common:firstName').toString()
const firstNameComponent = screen.getByLabelText(firstNameLabel)
......@@ -34,7 +30,7 @@ test('Validation message showing if last name is missing', async () => {
userEvent.type(firstNameComponent, 'Test')
// Try to submit the form and check that the validation message is showing
const submitButton = screen.getByRole('button')
const submitButton = screen.getByTestId('register-submit')
userEvent.click(submitButton)
const validationLastName = i18n
......
import React from 'react'
import { useTranslation } from 'react-i18next'
import { useForm, Controller, SubmitHandler } from 'react-hook-form'
import { StyledInput, StyledLabel } from 'components/form/input'
import { Box, Button, Stack, TextField } from '@mui/material'
import DateInput from 'components/dateinput'
import Button from 'components/button'
import Page from 'components/page'
import { useForm, Controller, SubmitHandler } from 'react-hook-form'
import format from 'date-fns/format'
import { isValidFnr, postJsonOpts } from 'utils'
import StyledValidationError from '../../components/form/error'
type RegisterFormData = {
first_name: string
......@@ -49,61 +48,71 @@ export default function Register() {
return (
<Page header="Register as a guest">
<form onSubmit={onSubmit}>
<StyledLabel htmlFor="firstName">{t('common:firstName')}</StyledLabel>
<StyledInput id="firstName" {...register(`first_name`)} />
<StyledLabel htmlFor="lastName">{t('common:lastName')}</StyledLabel>
<StyledInput
id="lastName"
{...register(`last_name`, {
required: t('common:validation.lastNameRequired').toString(),
})}
/>
{errors.last_name && (
<StyledValidationError>
{errors.last_name.message}
</StyledValidationError>
)}
<StyledLabel htmlFor="dateOfBirth">
{t('common:dateOfBirth')}
</StyledLabel>
<Controller
name="date_of_birth"
control={control}
render={({ field }) => (
<DateInput
id="dateOfBirth"
customInput={<StyledInput />}
onChange={(date) => field.onChange(date)}
selected={field.value}
<Box sx={{ maxWidth: '30rem' }}>
<form onSubmit={onSubmit}>
<Stack spacing={2}>
<TextField
id="firstName"
label={t('common:firstName')}
{...register(`first_name`)}
/>
<TextField
id="lastName"
label={t('common:lastName')}
error={!!errors.last_name}
helperText={errors.last_name && errors.last_name.message}
{...register(`last_name`, {
required: t('common:validation.lastNameRequired').toString(),
})}
/>
)}
/>
<StyledLabel htmlFor="nationalIdNumber">
{t('nationalIdNumber')}
</StyledLabel>
<StyledInput
id="nationalIdNumber"
{...register('national_id_number', {
required: t(
'common:validation.nationalIdNumberRequired'
).toString(),
validate: isValidFnr,
})}
/>
{errors.national_id_number && (
<StyledValidationError>
{errors.national_id_number.message}
</StyledValidationError>
)}
{/* <Select name="gender" options={['female', 'male', 'other']} />
{/* TODO: replace with MUI datepicker? */}
<Controller
name="date_of_birth"
control={control}
render={({ field }) => (
<DateInput
id="dateOfBirth"
customInput={
<TextField
label={t('common:dateOfBirth')}
sx={{ display: 'flex' }}
/>
}
onChange={(date) => field.onChange(date)}
selected={field.value}
/>
)}
/>
<TextField
id="nationalIdNumber"
label={t('nationalIdNumber')}
error={!!errors.national_id_number}
helperText={
errors.national_id_number && errors.national_id_number.message
}
{...register('national_id_number', {
required: t(
'common:validation.nationalIdNumberRequired'
).toString(),
validate: isValidFnr,
})}
/>
{/* <Select name="gender" options={['female', 'male', 'other']} />
<Fnr name={t('common:fnr')} /> */}
<br />
<Button as="button" type="submit">
Submit
</Button>
</form>
<Button
type="submit"
data-testid="register-submit"
variant="outlined"
>
Submit
</Button>
</Stack>
</form>
</Box>
</Page>
)
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment