Skip to content

Commit

Permalink
Merge pull request #485 from gladly-team/jtan/shortcut-icon
Browse files Browse the repository at this point in the history
Adding Shortcut Add Icon
  • Loading branch information
jedtan authored Jul 6, 2023
2 parents d58d5d0 + ede840d commit e7b676f
Show file tree
Hide file tree
Showing 3 changed files with 218 additions and 0 deletions.
112 changes: 112 additions & 0 deletions src/components/ShortcutIcon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/* eslint-disable jsx-a11y/mouse-events-have-key-events */
// TODO: @jtan Adjust for Accessibility
import React, { useState } from 'react'
import { makeStyles } from '@material-ui/core/styles'
import PropTypes from 'prop-types'
import Typography from '@material-ui/core/Typography'
import clsx from 'clsx'
import IconButton from '@material-ui/core/IconButton'
import Fade from '@material-ui/core/Fade'
import DeleteIcon from '@material-ui/icons/Delete'
import EditIcon from '@material-ui/icons/Edit'
import Link from 'src/components/Link'

const useStyles = makeStyles((theme) => ({
button: {
height: '150px',
width: '96px',
maxWidth: '96px',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
borderRadius: '10px',
padding: theme.spacing(1),
},
hover: {
backgroundColor: 'rgba(0,0,0,0.5)',
},
buttons: {
display: 'flex',
flexDirection: 'row',
color: 'white',
width: '100%',
justifyContent: 'space-between',
},
miniButton: {
width: '24px',
height: '24px',
'&:hover': {
color: 'white',
},
},
letterIcon: {
width: '70px',
height: '70px',
borderRadius: '100%',
backgroundColor: 'white',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: 'black',
marginTop: theme.spacing(1),
marginBottom: theme.spacing(1),
},
overflow: {
overflow: 'hidden',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
maxWidth: '100%',
paddingLeft: theme.spacing(1),
paddingRight: theme.spacing(1),
color: 'white',
},
}))
const ShortcutIcon = ({ onEdit, onDelete, text, url }) => {
const getFirstTwoLetters = (str) => {
const words = str.split(' ')
const firstLetters = words.map((word) => word.charAt(0))
return firstLetters.slice(0, 2).join('')
}
const [hover, setHover] = useState(false)
const classes = useStyles()
const firstLettersText = getFirstTwoLetters(text)
return (
<Link to={url}>
<div
className={hover ? clsx(classes.button, classes.hover) : classes.button}
onMouseOver={() => setHover(true)}
onMouseOut={() => setHover(false)}
>
<Fade in={hover}>
<div className={classes.buttons}>
<IconButton className={classes.miniButton} onClick={onDelete}>
<DeleteIcon />
</IconButton>
<IconButton className={classes.miniButton} onClick={onEdit}>
<EditIcon />
</IconButton>
</div>
</Fade>
<div className={classes.letterIcon}>
<Typography variant="h6">{firstLettersText}</Typography>
</div>
<Typography className={classes.overflow}>{text}</Typography>
</div>
</Link>
)
}

ShortcutIcon.propTypes = {
onEdit: PropTypes.func,
onDelete: PropTypes.func,
text: PropTypes.string.isRequired,
url: PropTypes.string.isRequired,
}

ShortcutIcon.defaultProps = {
onEdit: () => {},
onDelete: () => {},
}

export default ShortcutIcon
24 changes: 24 additions & 0 deletions src/components/ShortcutIcon.stories.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react'
import ShortcutIcon from './ShortcutIcon'

export default {
title: 'Components/ShortcutIcon',
component: ShortcutIcon,
parameters: {
backgrounds: {
default: 'grey',
values: [
{ name: 'grey', value: '#F2F2F2' },
{ name: 'black', value: '#000000' },
],
},
},
}

const Template = (args) => <ShortcutIcon {...args} />

export const basic = Template.bind({})
basic.args = {
text: 'Google Googledy',
url: 'https://www.google.com',
}
82 changes: 82 additions & 0 deletions src/components/__tests__/ShortcutIcon.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import React from 'react'
import { mount, shallow } from 'enzyme'
import Fade from '@material-ui/core/Fade'
import Link from 'src/components/Link'
import Typography from '@material-ui/core/Typography'
import IconButton from '@material-ui/core/IconButton'

const getMockProps = () => ({
text: 'Google Googledy',
url: 'https://www.google.com',
onEdit: jest.fn(),
onDelete: jest.fn(),
})

describe('ShortcutIcon component', () => {
it('renders without error', () => {
const ShortcutIcon = require('src/components/ShortcutIcon').default
const mockProps = getMockProps()
expect(() => {
shallow(<ShortcutIcon {...mockProps} />)
}).not.toThrow()
})

it('has a link with url property', () => {
const ShortcutIcon = require('src/components/ShortcutIcon').default
const mockProps = getMockProps()
const wrapper = mount(<ShortcutIcon {...mockProps} />)
expect(wrapper.find(Link).prop('to')).toEqual(mockProps.url)
})

it('displays abbreviated version of link name along with full title', () => {
const ShortcutIcon = require('src/components/ShortcutIcon').default
const mockProps = getMockProps()
const wrapper = mount(<ShortcutIcon {...mockProps} />)
expect(wrapper.find(Typography).first().text()).toEqual('GG')
expect(wrapper.find(Typography).at(1).text()).toEqual(mockProps.text)
})

it('displays edit and delete buttons on hover', () => {
const ShortcutIcon = require('src/components/ShortcutIcon').default
const mockProps = getMockProps()
const wrapper = mount(<ShortcutIcon {...mockProps} />)

expect(wrapper.find(Fade).prop('in')).toEqual(false)

wrapper.find(Fade).simulate('mouseover')

expect(wrapper.find(Fade).prop('in')).toEqual(true)
})

it('calls edit and delete button on clicks', () => {
const ShortcutIcon = require('src/components/ShortcutIcon').default
const mockProps = getMockProps()
const wrapper = mount(<ShortcutIcon {...mockProps} />)

wrapper.find(Fade).simulate('mouseover')

wrapper.find(IconButton).first().simulate('click')
expect(mockProps.onDelete).toHaveBeenCalled()

wrapper.find(IconButton).at(1).simulate('click')
expect(mockProps.onEdit).toHaveBeenCalled()
})

it('default handlers do not throw', () => {
const ShortcutIcon = require('src/components/ShortcutIcon').default
const mockProps = getMockProps()
delete mockProps.onDelete
delete mockProps.onEdit
const wrapper = mount(<ShortcutIcon {...mockProps} />)

wrapper.find(Fade).simulate('mouseover')

expect(() => {
wrapper.find(IconButton).first().simulate('click')
}).not.toThrow()

expect(() => {
wrapper.find(IconButton).at(1).simulate('click')
}).not.toThrow()
})
})

1 comment on commit e7b676f

@vercel
Copy link

@vercel vercel bot commented on e7b676f Jul 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.