Skip to content
This repository has been archived by the owner on Sep 18, 2023. It is now read-only.

Commit

Permalink
refactor(views/SignIn): split component and hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
sbolel committed Jul 26, 2023
1 parent 0f04d86 commit cd98a48
Show file tree
Hide file tree
Showing 7 changed files with 517 additions and 243 deletions.
83 changes: 83 additions & 0 deletions src/components/PasswordVisibilityToggle.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// PasswordVisibilityToggle.test.tsx
import { act, render, fireEvent, waitFor } from '@testing-library/react'
import PasswordVisibilityToggle from './PasswordVisibilityToggle'

describe('PasswordVisibilityToggle', () => {
let setShowPassword: jest.Mock

beforeEach(() => {
jest.resetAllMocks()
setShowPassword = jest.fn()
})

it('renders without crashing', () => {
const { getByRole } = render(
<PasswordVisibilityToggle
showPassword={false}
setShowPassword={setShowPassword}
/>
)
expect(getByRole('button')).toBeInTheDocument()
})

it('changes icon when clicked', async () => {
const { getByRole, rerender } = render(
<PasswordVisibilityToggle
showPassword={false}
setShowPassword={setShowPassword}
/>
)
const button = getByRole('button')
await act(async () => {
fireEvent.click(button)
})
waitFor(() => {
expect(setShowPassword).toHaveBeenCalledWith(true)
})
rerender(
<PasswordVisibilityToggle
showPassword={true}
setShowPassword={setShowPassword}
/>
)
await act(async () => {
fireEvent.click(button)
})
waitFor(() => {
expect(setShowPassword).toHaveBeenCalledWith(false)
})
})

it('calls setShowPassword with correct argument when clicked', async () => {
const { getByRole } = render(
<PasswordVisibilityToggle
showPassword={false}
setShowPassword={setShowPassword}
/>
)
const button = getByRole('button')
await act(async () => {
fireEvent.click(button)
})
waitFor(() => {
expect(setShowPassword).toHaveBeenCalledWith(true)
})
})

it('prevents default on mouse down', async () => {
const { getByRole } = render(
<PasswordVisibilityToggle
showPassword={false}
setShowPassword={setShowPassword}
/>
)
const button = getByRole('button')
const preventDefault = jest.fn()
await act(async () => {
fireEvent.mouseDown(button, { preventDefault })
})
waitFor(() => {
expect(preventDefault).toHaveBeenCalled()
})
})
})
38 changes: 38 additions & 0 deletions src/components/PasswordVisibilityToggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* @module sbom-harbor-ui/components/PasswordVisibilityToggle.tsx
*/
import React from 'react'
import IconButton from '@mui/material/IconButton'
import InputAdornment from '@mui/material/InputAdornment'
import VisibilityOutline from '@mui/icons-material/Visibility'
import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'

interface PasswordVisibilityToggleProps {
showPassword: boolean
setShowPassword: (value: boolean) => void
}

const PasswordVisibilityToggle: React.FC<PasswordVisibilityToggleProps> = ({
showPassword,
setShowPassword,
}) => {
const handleClick = React.useCallback(
() => setShowPassword(!showPassword),
[showPassword, setShowPassword]
)

return (
<InputAdornment position="end">
<IconButton
edge="end"
onMouseDown={(e) => e.preventDefault()}
onClick={handleClick}
aria-label={showPassword ? 'Hide password' : 'Show password'}
>
{showPassword ? <VisibilityOutline /> : <VisibilityOffIcon />}
</IconButton>
</InputAdornment>
)
}

export default PasswordVisibilityToggle
5 changes: 5 additions & 0 deletions src/theme/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1091,6 +1091,10 @@ theme = createTheme(theme, {
'& .MuiTypography-root': {
marginBottom: 0,
},

'& .MuiFormControlLabel-label': {
color: theme.palette.text.primary,
},
},
},
},
Expand All @@ -1113,6 +1117,7 @@ theme = createTheme(theme, {
lineHeight: '1.125rem',
fontWeight: theme.typography.fontWeightRegular,
color: theme.palette.text.secondary,

'&.Mui-error': {
color: 'rgba(255, 77, 73, 1)',
},
Expand Down
34 changes: 27 additions & 7 deletions src/views/SignIn/SignIn.components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,50 @@ export const LoginIllustrationWrapper = styled(Box)<BoxProps>(({ theme }) => ({
},
}))

export const RightWrapper = styled(Box)<BoxProps>(({ theme }) => ({
export const RightWrapper = styled(Box, {
shouldForwardProp: (prop) => prop !== 'hidden',
})<BoxProps>(({ theme, hidden }) => ({
width: '100%',
marginLeft: 'auto',
marginRight: theme.spacing(16),
[theme.breakpoints.up('md')]: {
maxWidth: 400,
maxWidth: `min(450px, 40vw)`,
},
[theme.breakpoints.up('lg')]: {
maxWidth: 450,
maxWidth: 500,
},
...(!hidden && { borderLeft: `1px solid ${theme.palette.divider}` }),
}))

export const BoxWrapper = styled(Box)<BoxProps>(({ theme }) => ({
width: '100%',
[theme.breakpoints.down('sm')]: {
padding: theme.spacing(4),
},
}))

export const CenteredFlexBox = styled(Box)<BoxProps>(({ theme }) => ({
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
[theme.breakpoints.down('xs')]: {
flexDirection: 'column',
},
}))

export const VerticalCenteredFlexBox = styled(Box)<BoxProps>(({ theme }) => ({
[theme.breakpoints.down('md')]: {
maxWidth: 400,
position: 'absolute',
top: '50%',
transform: 'translateY(-50%)',
margin: 'auto',
padding: theme.spacing(4),
},
}))

export const FormControlLabel = styled(
MuiFormControlLabel
)<FormControlLabelProps>(({ theme }) => ({
'& .MuiFormControlLabel-label': {
fontSize: '0.875rem',
color: theme.palette.text.secondary,
fontSize: theme.typography.body2.fontSize,
},
}))
Loading

0 comments on commit cd98a48

Please sign in to comment.