index.tsx 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. import { makeStyles,Typography } from '@material-ui/core'
  2. import { useState } from 'react';
  3. import { styled } from '@mui/material/styles';
  4. import Menu from '@mui/material/Menu';
  5. import MenuItem from '@mui/material/MenuItem';
  6. import NotificationsNoneIcon from '@mui/icons-material/NotificationsNone';
  7. import VolumeOffIcon from '@mui/icons-material/VolumeOff';
  8. import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
  9. import ListItemButton from '@mui/material/ListItemButton';
  10. import Avatar from '@mui/material/Avatar';
  11. import ListItemText from '@mui/material/ListItemText';
  12. import ListItemIcon from '@mui/material/ListItemIcon';
  13. import Badge from '@mui/material/Badge';
  14. import DoneAllIcon from '@mui/icons-material/DoneAll';
  15. import { muteChat } from '../../../../../api-data';
  16. import { TChat } from '../../../../../typescript/redux/chats/types';
  17. import { firstLetter, slicedWord, timeStampEU,prodBaseURL } from '../../../../../helpers';
  18. import DeleteModal from './DeleteModal';
  19. const StyledMenu = styled((props:any) => (
  20. <Menu
  21. elevation={0}
  22. anchorOrigin={{
  23. vertical: 'top',
  24. horizontal: 'right',
  25. }}
  26. transformOrigin={{
  27. vertical: 'bottom',
  28. horizontal: 'right',
  29. }}
  30. {...props}
  31. />
  32. ))(({ theme }:any) => ({
  33. '& .MuiPaper-root': {
  34. borderRadius: 10,
  35. marginTop: theme.spacing(0),
  36. minWidth: 220,
  37. color:
  38. theme.palette.mode === 'light' ? 'rgb(55, 65, 81)' : theme.palette.grey[500],
  39. boxShadow:
  40. 'rgb(255, 255, 255) 0px 0px 0px 0px, rgba(0, 0, 0, 0.05) 0px 0px 0px 1px, rgba(0, 0, 0, 0.1) 0px 10px 15px -3px, rgba(0, 0, 0, 0.05) 0px 4px 6px -2px',
  41. '& .MuiMenu-list': {
  42. padding: '8px 8px',
  43. },
  44. '& .MuiMenuItem-root': {
  45. marginBottom: theme.spacing(1),
  46. '& .MuiSvgIcon-root': {
  47. fontSize: 21,
  48. color: theme.palette.text.secondary,
  49. marginRight: theme.spacing(4),
  50. }
  51. },
  52. },
  53. }));
  54. const StyledBadge = styled(Badge)(({ theme }) => ({
  55. '& .MuiBadge-badge': {
  56. backgroundColor: '#44b700',
  57. color: '#44b700',
  58. boxShadow: `0 0 0 2px ${theme.palette.background.paper}`,
  59. '&::after': {
  60. position: 'absolute',
  61. top: 0,
  62. left: 0,
  63. width: '100%',
  64. height: '100%',
  65. borderRadius: '50%',
  66. animation: 'ripple 1.2s infinite ease-in-out',
  67. border: '1px solid currentColor',
  68. content: '""',
  69. },
  70. },
  71. '@keyframes ripple': {
  72. '0%': {
  73. transform: 'scale(.8)',
  74. opacity: 1,
  75. },
  76. '100%': {
  77. transform: 'scale(2.4)',
  78. opacity: 0,
  79. },
  80. },
  81. }));
  82. const useStyles = makeStyles({
  83. listItemInnerText: {
  84. display: 'flex',
  85. alignContent: 'center',
  86. alignItems: 'center',
  87. flexWrap: 'nowrap',
  88. },
  89. listItemInnerText__icon: {
  90. marginLeft: 5,
  91. color: '#959595',
  92. },
  93. listItem_iconAvatar: {
  94. marginRight:10
  95. },
  96. listItem_iconRight: {
  97. marginRight: 10,
  98. display: 'flex',
  99. alignItems: 'center',
  100. justifyContent: 'center',
  101. alignContent: 'center',
  102. flexDirection: 'column'
  103. },
  104. listItem_iconTimeChecked: {
  105. display: 'flex',
  106. flexWrap: 'nowrap',
  107. alignItems: 'center',
  108. justifyContent: 'center',
  109. alignContent: 'center',
  110. marginBottom:2
  111. },
  112. listItem_iconRightBtn: {
  113. background: '#0ac40a',
  114. borderRadius: '50%',
  115. color: '#ffffff',
  116. border: 'none',
  117. height: 24,
  118. width: 24,
  119. textAlign: 'center',
  120. display: 'flex',
  121. alignItems: 'center',
  122. justifyContent: 'center',
  123. alignContent: 'center',
  124. fontSize: 12,
  125. marginLeft: 'auto',
  126. '&:hover': {
  127. outline: 'solid 3px #3ee415',
  128. }
  129. },
  130. listItem_iconRightBtnMute: {
  131. background: '#a7aaa7',
  132. borderRadius: '50%',
  133. color: '#ffffff',
  134. border: 'none',
  135. height: 24,
  136. width: 24,
  137. textAlign: 'center',
  138. display: 'flex',
  139. alignItems: 'center',
  140. justifyContent: 'center',
  141. alignContent: 'center',
  142. fontSize: 12,
  143. marginLeft: 'auto',
  144. '&:hover': {
  145. outline: 'solid 3px #cccbcb',
  146. }
  147. },
  148. listItem_iconRightBtnHidden: {
  149. background: 'inherit',
  150. borderRadius: '50%',
  151. border: 'none',
  152. height: 24,
  153. width: 24,
  154. textAlign: 'center',
  155. display: 'flex',
  156. alignItems: 'center',
  157. justifyContent: 'center',
  158. alignContent: 'center',
  159. fontSize: 12,
  160. marginLeft: 'auto',
  161. },
  162. listItem_icon_time: {
  163. fontSize: 12,
  164. marginLeft: 5,
  165. color: '#1b1b1b'
  166. },
  167. listItem_typing: {
  168. color: '#4d4d4d',
  169. animation: 'ripple 4s infinite ease-in-out',
  170. },
  171. listItem_dots: {
  172. color: '#1b1b1b',
  173. fontWeight: 'bold',
  174. display:'inline-block',
  175. fontFamily: 'monospace',
  176. clipPath: 'inset(0 3ch 0 0)',
  177. animation: `$run 2s steps(5) infinite`,
  178. },
  179. '@keyframes run': {
  180. to: {
  181. clipPath: 'inset(0 -1ch 0 0)'
  182. },
  183. },
  184. })
  185. interface IChatItem {
  186. chat: TChat,
  187. handleListItemClick: (companionId: string) => void,
  188. handleNewMsgs: (e: any,companionId: string) => void,
  189. }
  190. const ChatItem = ({chat,handleListItemClick,handleNewMsgs}:IChatItem) => {
  191. const classes = useStyles()
  192. const [anchorEl, setAnchorEl] = useState<any>(null);
  193. const [selected, setSelected] = useState<boolean>(false);
  194. const [modal, setModal] = useState<boolean>(false);
  195. const open = Boolean(anchorEl);
  196. const { name, lastName, avatarUrl, color, companionId, mute, seen, total, watched,
  197. typing, online, lastMessage, lastMessageCreatedAt, createdAt } = chat
  198. const handleClose = (type: string | undefined): void => {
  199. if (type === 'mute') muteChat(companionId)
  200. if (type === 'delete') setModal(true)
  201. setAnchorEl(null)
  202. setSelected(false)
  203. }
  204. const handleContextMenu = (e: React.MouseEvent<HTMLDivElement>):void => {
  205. e.preventDefault()
  206. setAnchorEl(e.currentTarget)
  207. setSelected(true)
  208. }
  209. return (
  210. <div>
  211. {modal&&<DeleteModal setModal={setModal} chat={chat}/>}
  212. <ListItemButton
  213. selected={selected}
  214. onClick={() => handleListItemClick(companionId)}
  215. onContextMenu={(e) => handleContextMenu(e)}
  216. >
  217. <ListItemIcon className={classes.listItem_iconAvatar}>
  218. <StyledBadge overlap="circular" variant={online === 'true'?'dot':'standard'}
  219. anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}>
  220. <Avatar alt={name} src={avatarUrl?`${prodBaseURL}/${avatarUrl}`:undefined}
  221. sx={{ background: color, width: 54, height: 54 }}>
  222. {!avatarUrl&&`${firstLetter(name)}${firstLetter(lastName)}`}
  223. </Avatar>
  224. </StyledBadge>
  225. </ListItemIcon>
  226. <ListItemText primary={<div className={classes.listItemInnerText}>
  227. <span>{`${firstLetter(name)}${slicedWord(name, 15, 1)}
  228. ${firstLetter(lastName)}${slicedWord(lastName, 15, 1)}`}</span>
  229. {mute&&<VolumeOffIcon className={classes.listItemInnerText__icon} fontSize='small' />}</div>}
  230. secondary={typing ? <span className={classes.listItem_typing}>
  231. typing<span className={classes.listItem_dots}>...</span></span> :
  232. lastMessage ? slicedWord(lastMessage, 35) :
  233. `${firstLetter(name)}${slicedWord(name, 8, 1)} joined Telegram`}/>
  234. <ListItemIcon className={classes.listItem_iconRight}>
  235. <div className={classes.listItem_iconTimeChecked}>
  236. {watched&& <DoneAllIcon style={{ color: '#18bd03' }} fontSize='small' />}
  237. <Typography className={classes.listItem_icon_time} variant="h6" color="initial">
  238. {timeStampEU(lastMessageCreatedAt?lastMessageCreatedAt:createdAt)}
  239. </Typography>
  240. </div>
  241. {lastMessage && total > seen ? <button onClick={(e) => handleNewMsgs(e,companionId)}
  242. className={mute?classes.listItem_iconRightBtnMute:classes.listItem_iconRightBtn}>{total-seen}</button> :
  243. <button className={classes.listItem_iconRightBtnHidden}/>}
  244. </ListItemIcon>
  245. </ListItemButton>
  246. <StyledMenu
  247. id="demo-positioned-menu"
  248. aria-labelledby="demo-positioned-button"
  249. anchorEl={anchorEl}
  250. open={open}
  251. onClose={handleClose}
  252. >
  253. <MenuItem onClick={() => handleClose('mute')}>
  254. {mute ? <NotificationsNoneIcon /> : <VolumeOffIcon />}
  255. {mute ? 'Unmute chat':'Mute chat'}
  256. </MenuItem>
  257. <MenuItem style={{color:'#f02a2a'}} onClick={() => handleClose('delete')}>
  258. <DeleteOutlineIcon style={{color:'#f02a2a'}}/>
  259. Delete chat
  260. </MenuItem>
  261. </StyledMenu>
  262. </div>
  263. );
  264. }
  265. export default ChatItem