index.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. import { makeStyles } from "@material-ui/core/styles";
  2. import { styled } from '@mui/material/styles';
  3. import { useState } from "react";
  4. import ListItemText from '@mui/material/ListItemText';
  5. import Button from '@mui/material/Button';
  6. import ContentCopyIcon from '@mui/icons-material/ContentCopy';
  7. import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
  8. import Menu from '@mui/material/Menu';
  9. import MenuItem from '@mui/material/MenuItem';
  10. import Divider from '@mui/material/Divider';
  11. import CheckBoxIcon from '@mui/icons-material/CheckBox';
  12. import Checkbox from '@mui/material/Checkbox';
  13. import PushPinIcon from '@mui/icons-material/PushPin';
  14. import CloseIcon from '@mui/icons-material/Close';
  15. import { CopyToClipboard } from 'react-copy-to-clipboard';
  16. import { removeMessageById,updateMessageById,pinMessageById } from "../../../../../../api-data";
  17. import { firstLetter,slicedWord,timeStampMessage,copied,emojisArr } from '../../../../../../helpers'
  18. const StyledMenu = styled((props:any) => (
  19. <Menu
  20. elevation={0}
  21. anchorOrigin={{
  22. vertical: 'top',
  23. horizontal: 'right',
  24. }}
  25. transformOrigin={{
  26. vertical: 'bottom',
  27. horizontal: 'right',
  28. }}
  29. {...props}
  30. />
  31. ))(({ theme }:any) => ({
  32. '& .MuiPaper-root': {
  33. borderRadius: 10,
  34. marginTop: theme.spacing(0),
  35. minWidth: 220,
  36. color:
  37. theme.palette.mode === 'light' ? 'rgb(55, 65, 81)' : theme.palette.grey[500],
  38. boxShadow:
  39. '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',
  40. '& .MuiMenu-list': {
  41. padding: '4px 4px',
  42. },
  43. '& .MuiMenuItem-root': {
  44. marginBottom: theme.spacing(1),
  45. '& .MuiSvgIcon-root': {
  46. fontSize: 21,
  47. color: theme.palette.text.secondary,
  48. marginRight: theme.spacing(2),
  49. }
  50. },
  51. },
  52. }));
  53. const useStyles = makeStyles({
  54. container: {
  55. display: "flex",
  56. justifyContent: "flex-start",
  57. borderRadius: 7,
  58. },
  59. wrapper: {
  60. position: 'relative',
  61. display: 'flex',
  62. alignItems: 'center',
  63. alignContent: 'center',
  64. maxWidth: 450,
  65. minWidth:200,
  66. padding: "10px",
  67. paddingBottom:18,
  68. backgroundColor: "#ffffff",
  69. border: "1px solid #f0f0f0",
  70. borderRadius: 7,
  71. },
  72. message: {
  73. wordBreak:'break-word',
  74. textAlign: "left",
  75. font: "400 .9em 'Open Sans', sans-serif",
  76. "&:after": {
  77. content: "''",
  78. position: "absolute",
  79. width: "0",
  80. height: "0",
  81. borderBottom: "15px solid #ffffff",
  82. borderLeft: "15px solid transparent",
  83. borderRight: "15px solid transparent",
  84. bottom: '0px',
  85. left: "-15px"
  86. },
  87. "&:before": {
  88. content: "''",
  89. position: "absolute",
  90. width: "0",
  91. height: "0",
  92. borderBottom: "17px solid #ffffff",
  93. borderLeft: "16px solid transparent",
  94. borderRight: "16px solid transparent",
  95. bottom: "-1px",
  96. left: "-17px"
  97. }
  98. },
  99. messageActive: {
  100. wordBreak:'break-word',
  101. textAlign: "left",
  102. font: "400 .9em 'Open Sans', sans-serif",
  103. "&:after": {
  104. content: "''",
  105. position: "absolute",
  106. width: "0",
  107. height: "0",
  108. borderBottom: "15px solid #babdbc",
  109. borderLeft: "15px solid transparent",
  110. borderRight: "15px solid transparent",
  111. bottom: '0px',
  112. left: "-15px"
  113. },
  114. "&:before": {
  115. content: "''",
  116. position: "absolute",
  117. width: "0",
  118. height: "0",
  119. borderBottom: "17px solid #babdbc",
  120. borderLeft: "16px solid transparent",
  121. borderRight: "16px solid transparent",
  122. bottom: "-1px",
  123. left: "-17px"
  124. }
  125. },
  126. copyIcon: {
  127. color: '#b56ff7',
  128. cursor: 'pointer',
  129. marginRight: 7,
  130. '&:hover': {
  131. color: '#9c3bf8',
  132. },
  133. },
  134. time: {
  135. position: "absolute",
  136. fontSize: ".65em",
  137. fontWeight:600,
  138. bottom: 6,
  139. right: 6,
  140. color: '#414141',
  141. padding: 3,
  142. borderRadius: 5,
  143. },
  144. captionWrapper: {
  145. position: "absolute",
  146. fontSize: ".85em",
  147. color: '#414141',
  148. maxWidth:'80%',
  149. fontWeight:600,
  150. bottom: -30,
  151. left: 6,
  152. borderRadius: 5,
  153. wordBreak:'break-word',
  154. textAlign: "left",
  155. font: "400 .9em 'Open Sans', sans-serif",
  156. backgroundColor: '#deffa9',
  157. padding:10,
  158. "&:after": {
  159. content: "''",
  160. position: "absolute",
  161. width: "0",
  162. height: "0",
  163. borderBottom: "15px solid #deffa9",
  164. borderLeft: "15px solid transparent",
  165. borderRight: "15px solid transparent",
  166. bottom: '0px',
  167. left: "-15px"
  168. },
  169. "&:before": {
  170. content: "''",
  171. position: "absolute",
  172. width: "0",
  173. height: "0",
  174. borderBottom: "17px solid #deffa9",
  175. borderLeft: "16px solid transparent",
  176. borderRight: "16px solid transparent",
  177. bottom: "-1px",
  178. left: "-17px"
  179. }
  180. },
  181. modalDelete: {
  182. background: '#ffffff',
  183. position: 'absolute',
  184. content:'',
  185. width: '20%',
  186. height:'auto',
  187. left: '40%',
  188. bottom: '48.5%',
  189. borderRadius: 10,
  190. padding: 10,
  191. display: 'flex',
  192. flexDirection:'column'
  193. },
  194. overlay: {
  195. position: 'fixed',
  196. top: 0,
  197. left: 0,
  198. width: '100vw',
  199. height: '100vh',
  200. zIndex: 100,
  201. backgroundColor: 'rgba(104, 105, 104, 0.6)',
  202. overflowY: 'hidden',
  203. },
  204. emojiTitle: {
  205. position: "absolute",
  206. fontSize: "1.7em",
  207. fontWeight:600,
  208. bottom: 0,
  209. right: -40,
  210. },
  211. emojiCompanionTitle: {
  212. position: "absolute",
  213. fontSize: "1.7em",
  214. fontWeight:600,
  215. bottom: '2rem',
  216. right: -40,
  217. },
  218. emoji: {
  219. cursor: 'pointer',
  220. fontSize: '1.7rem',
  221. transition: 'all 0.3s',
  222. '&:hover': {
  223. transform: 'scale(1.5)'
  224. }
  225. },
  226. emojiActive: {
  227. cursor: 'pointer',
  228. fontSize: '1.2rem',
  229. animation: `$emoji 0.6s ease-out`,
  230. animationDirection: 'forwards',
  231. animationIterationCount: 1,
  232. },
  233. '@keyframes emoji': {
  234. '5%': { transform: 'translateY(1rem)'},
  235. '10%': { transform: 'translateY(0) scale(1)',opacity: 1},
  236. '50%': { transform: 'translateY(-4rem) scale(1.5) rotateY(90deg)'},
  237. '80%': {opacity: 0},
  238. '100%': {transform: 'translateY(-8rem) scale(2) rotateY(180deg)',opacity: 0},
  239. },
  240. iconClose: {
  241. '&:hover': {
  242. transform: 'rotate(180deg)',
  243. transition: 'all 250ms ease-out ',
  244. }
  245. },
  246. });
  247. const label = { inputProps: { 'aria-label': 'Checkbox demo' } };
  248. interface IMessageLeftText {
  249. message:string,
  250. name:string,
  251. lastName:string,
  252. createdAt: string,
  253. caption: string,
  254. emoji: string,
  255. emojiCompanion: string,
  256. pinned: boolean,
  257. isSomeSelected: boolean,
  258. isSelected:(_id:string) => boolean,
  259. handleSelected: (_id:string) => void,
  260. _id:string
  261. }
  262. const MessageLeftText = ({message,name,lastName,createdAt,caption,emoji,emojiCompanion,pinned,isSomeSelected,isSelected,handleSelected,_id}:IMessageLeftText) => {
  263. const classes = useStyles();
  264. const [anchorEl, setAnchorEl] = useState<any>(null);
  265. const [selected, setSelected] = useState<boolean>(false);
  266. const [modal,setModal] = useState<boolean>(false)
  267. const open = Boolean(anchorEl);
  268. const checked = isSelected(_id)
  269. const handleClose = (type: string | undefined): void => {
  270. if (type === 'copy') copied('Message')
  271. if (type === 'delete') setModal(true)
  272. setAnchorEl(null)
  273. setSelected(false)
  274. }
  275. const handleDeleteModal = (e: any) => {
  276. const id = e.target.id
  277. if (id === 'overlay' || id === 'cancel') return setModal(false)
  278. if (id === 'delete') {
  279. removeMessageById(_id)
  280. setModal(false)
  281. }
  282. }
  283. const handleContextMenu = (e: React.MouseEvent<HTMLDivElement>):void => {
  284. e.preventDefault()
  285. setAnchorEl(e.currentTarget)
  286. setSelected(true)
  287. }
  288. const handleEmojiMenu = ({ target }: any): void => {
  289. const idEmoji = target.id
  290. if (idEmoji === emoji) {updateMessageById(_id,'')
  291. } else updateMessageById(_id,idEmoji)
  292. }
  293. return (
  294. <div className={classes.container} style={{ marginBottom: caption ? 45 : 15}}>
  295. {isSomeSelected&&<Checkbox {...label} checked={checked} onClick={() => handleSelected(_id)}/>}
  296. <div onContextMenu={(e) => handleContextMenu(e)} className={classes.wrapper}
  297. style={{backgroundColor:selected?'#babdbc':undefined,
  298. border:selected?'#babdbc':undefined,pointerEvents:isSomeSelected?'none':'auto'}}>
  299. <CopyToClipboard onCopy={() => copied('Message')} text={message}>
  300. <ContentCopyIcon className={classes.copyIcon} fontSize='large'/>
  301. </CopyToClipboard>
  302. <ListItemText className={selected?classes.messageActive:classes.message}
  303. primary={`${firstLetter(name)}${slicedWord(name, 15, 1)}
  304. ${firstLetter(lastName)}${slicedWord(lastName, 15, 1)}`}
  305. primaryTypographyProps={{color: "#0379af"}}
  306. secondary={message}
  307. secondaryTypographyProps={{ color: "#0e0d0d" }} />
  308. <div className={classes.time}>{timeStampMessage(createdAt)}</div>
  309. {emojiCompanion && <div className={classes.emojiCompanionTitle}>{emojisArr[Number(emojiCompanion)]}</div>}
  310. {emoji && <div className={classes.emojiTitle}>{emojisArr[Number(emoji)]}</div>}
  311. {caption&&<div className={classes.captionWrapper}>{caption}</div>}
  312. <StyledMenu id="demo-positioned-menu" aria-labelledby="demo-positioned-button"
  313. anchorEl={anchorEl} open={open} onClose={handleClose}>
  314. <MenuItem onClick={handleEmojiMenu} style={{ cursor: 'none' }} >
  315. {emojisArr.map((el:string, i:number) =>
  316. <div key={el} className={emoji === String(i)?classes.emojiActive:classes.emoji} id={String(i)}>{el}</div>)}
  317. </MenuItem>
  318. <Divider/>
  319. <CopyToClipboard onCopy={() => handleClose('copy')} text={message}>
  320. <MenuItem>
  321. <ContentCopyIcon />
  322. Copy message
  323. </MenuItem>
  324. </CopyToClipboard>
  325. <MenuItem onClick={() => {
  326. pinMessageById(_id, !pinned)
  327. handleClose(undefined)
  328. }}>
  329. {pinned ?
  330. <CloseIcon className={classes.iconClose} /> :
  331. <PushPinIcon />}
  332. {pinned?'Unpin message':'Pin message'}
  333. </MenuItem>
  334. <MenuItem onClick={() => {
  335. handleSelected(_id)
  336. handleClose(undefined)
  337. }}>
  338. <CheckBoxIcon />
  339. Select message
  340. </MenuItem>
  341. <MenuItem style={{color:'#f02a2a'}} onClick={() => handleClose('delete')}>
  342. <DeleteOutlineIcon style={{color:'#f02a2a'}}/>
  343. Delete message
  344. </MenuItem>
  345. </StyledMenu>
  346. {modal &&
  347. <div onClick={handleDeleteModal} className={classes.overlay} id='overlay'>
  348. <div className={classes.modalDelete}>
  349. <h3 style={{color: '#2c2c2c'}}>Delete message</h3>
  350. <p style={{ color: '#050505' }}>Are you sure you want to delete message?</p>
  351. <Button id='delete' variant="text" color="error" style={{fontWeight:500,fontSize:22}}>
  352. DELETE MESSAGE
  353. </Button>
  354. <Button id='cancel' variant="text" style={{fontWeight:500,fontSize:22}}>
  355. CANCEL
  356. </Button>
  357. </div>
  358. </div>}
  359. </div>
  360. </div>
  361. )};
  362. export default MessageLeftText