src/components/Search/SearchResultsListItem.tsx (132 lines of code) (raw):
import { Fragment } from 'react';
import AccessTimeOutlinedIcon from '@mui/icons-material/AccessTimeOutlined';
import MailOutlineOutlinedIcon from '@mui/icons-material/MailOutlineOutlined';
import Checkbox from '@mui/material/Checkbox';
import ListItem from '@mui/material/ListItem';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import Radio from '@mui/material/Radio';
import Typography from '@mui/material/Typography';
import { style } from 'typestyle';
import DateTimeDisplay from './DateTimeDisplay';
import { Spacing } from '../../styles';
import type { Changeset } from '../../types/state';
import { truncateHash, getLatestCommitMessage } from '../../utils/helpers';
interface SearchResultsListItemProps {
index: number;
item: Changeset;
isChecked: boolean;
onToggle: (item: Changeset) => void;
listItemComponent?: 'checkbox' | 'radio';
}
const styles = {
listItemButton: style({
paddingTop: 0,
$nest: {
'.MuiListItem-root': {
alignItems: 'flex-start',
},
'.search-revision-item-icon': {
minWidth: '0',
},
'.MuiListItemText-primary': {
display: 'flex',
justifyContent: 'space-between',
flexWrap: 'wrap',
},
'.info-caption': {
flexWrap: 'wrap',
$nest: {
svg: {
marginRight: `${Spacing.xSmall}px`,
fontSize: '1rem',
},
'.item-author': {
marginRight: `${Spacing.xSmall + 1}px`,
},
},
},
},
}),
};
function SearchResultsListItem({
index,
item,
isChecked,
onToggle,
listItemComponent,
}: SearchResultsListItemProps) {
const ListItemComponent = listItemComponent === 'radio' ? Radio : Checkbox;
const revisionHash = truncateHash(item.revision);
const commitMessage = getLatestCommitMessage(item);
const itemDate = new Date(item.push_timestamp * 1000);
const onToggleAction = () => {
onToggle(item);
};
return (
<>
<ListItemButton
key={item.id}
onClick={onToggleAction}
className={`${styles.listItemButton} ${
isChecked ? 'item-selected' : ''
}`}
>
<ListItem
className='search-revision-item search-revision'
disablePadding
>
<ListItemIcon className='search-revision-item-icon search-revision'>
<ListItemComponent
className='search-revision-item-checkbox'
edge='start'
tabIndex={-1}
disableRipple
data-testid={`checkbox-${index}`}
checked={isChecked}
/>
</ListItemIcon>
<ListItemText
className='search-revision-item-text'
primary={
<Fragment>
<Typography
sx={{ display: 'inline' }}
component='span'
variant='body2'
color='text.primary'
alignItems='center'
className='revision-hash'
>
{revisionHash}
</Typography>
<div className='info-caption'>
<div className='info-caption-item item-author'>
{' '}
<MailOutlineOutlinedIcon
className='mail-icon'
fontSize='small'
/>{' '}
{item.author}
</div>
<div className='info-caption-item item-time'>
<AccessTimeOutlinedIcon
className='time-icon'
fontSize='small'
/>
<DateTimeDisplay itemDate={itemDate} />
</div>
</div>
</Fragment>
}
secondary={`${commitMessage} `}
primaryTypographyProps={{ noWrap: true }}
secondaryTypographyProps={{ noWrap: true }}
/>
</ListItem>
</ListItemButton>
</>
);
}
export default SearchResultsListItem;