1import EditIcon from '@mui/icons-material/Edit';
2import HistoryIcon from '@mui/icons-material/History';
3import IconButton from '@mui/material/IconButton';
4import Paper from '@mui/material/Paper';
5import Tooltip from '@mui/material/Tooltip/Tooltip';
6import makeStyles from '@mui/styles/makeStyles';
7import * as React from 'react';
8import { useState } from 'react';
9
10import Author, { Avatar } from 'src/components/Author';
11import Content from 'src/components/Content';
12import Date from 'src/components/Date';
13import IfLoggedIn from 'src/components/IfLoggedIn/IfLoggedIn';
14
15import { BugFragment } from './Bug.generated';
16import EditCommentForm from './EditCommentForm';
17import { AddCommentFragment } from './MessageCommentFragment.generated';
18import { CreateFragment } from './MessageCreateFragment.generated';
19import MessageHistoryDialog from './MessageHistoryDialog';
20
21const useStyles = makeStyles((theme) => ({
22 author: {
23 fontWeight: 'bold',
24 color: theme.palette.info.contrastText,
25 },
26 container: {
27 display: 'flex',
28 },
29 avatar: {
30 marginTop: 2,
31 },
32 bubble: {
33 flex: 1,
34 marginLeft: theme.spacing(1),
35 minWidth: 0,
36 },
37 header: {
38 ...theme.typography.body1,
39 padding: '0.5rem 1rem',
40 borderBottom: `1px solid ${theme.palette.divider}`,
41 display: 'flex',
42 borderTopRightRadius: theme.shape.borderRadius,
43 borderTopLeftRadius: theme.shape.borderRadius,
44 backgroundColor: theme.palette.info.main,
45 color: theme.palette.info.contrastText,
46 },
47 title: {
48 flex: 1,
49 },
50 tag: {
51 ...theme.typography.button,
52 color: '#888',
53 border: '#ddd solid 1px',
54 padding: '0 0.5rem',
55 fontSize: '0.75rem',
56 borderRadius: 2,
57 marginLeft: '0.5rem',
58 },
59 body: {
60 overflow: 'auto',
61 ...theme.typography.body2,
62 paddingLeft: theme.spacing(1),
63 paddingRight: theme.spacing(1),
64 },
65 headerActions: {
66 color: theme.palette.info.contrastText,
67 padding: '0rem',
68 marginLeft: theme.spacing(1),
69 fontSize: '0.75rem',
70 '&:hover': {
71 backgroundColor: 'inherit',
72 },
73 },
74}));
75
76type HistBtnProps = {
77 bugId: string;
78 commentId: string;
79};
80function HistoryMenuToggleButton({ bugId, commentId }: HistBtnProps) {
81 const classes = useStyles();
82 const [open, setOpen] = React.useState(false);
83
84 const handleClickOpen = () => {
85 setOpen(true);
86 };
87
88 const handleClose = () => {
89 setOpen(false);
90 };
91
92 return (
93 <div>
94 <IconButton
95 aria-label="more"
96 aria-controls="long-menu"
97 aria-haspopup="true"
98 onClick={handleClickOpen}
99 className={classes.headerActions}
100 size="large"
101 >
102 <HistoryIcon />
103 </IconButton>
104 {
105 // Render CustomizedDialogs on open to prevent fetching the history
106 // before opening the history menu.
107 open && (
108 <MessageHistoryDialog
109 bugId={bugId}
110 commentId={commentId}
111 open={open}
112 onClose={handleClose}
113 />
114 )
115 }
116 </div>
117 );
118}
119
120type Props = {
121 bug: BugFragment;
122 op: AddCommentFragment | CreateFragment;
123};
124function Message({ bug, op }: Props) {
125 const classes = useStyles();
126 const [editMode, switchToEditMode] = useState(false);
127 const [comment, setComment] = useState(op);
128
129 const editComment = (id: String) => {
130 switchToEditMode(true);
131 };
132
133 function readMessageView() {
134 return (
135 <Paper elevation={1} className={classes.bubble}>
136 <header className={classes.header}>
137 <div className={classes.title}>
138 <Author className={classes.author} author={comment.author} />
139 <span> commented </span>
140 <Date date={comment.createdAt} />
141 </div>
142 {comment.edited && (
143 <HistoryMenuToggleButton bugId={bug.id} commentId={comment.id} />
144 )}
145 <IfLoggedIn>
146 {() => (
147 <Tooltip title="Edit Message" placement="top" arrow={true}>
148 <IconButton
149 disableRipple
150 className={classes.headerActions}
151 aria-label="edit message"
152 onClick={() => editComment(comment.id)}
153 size="large"
154 >
155 <EditIcon />
156 </IconButton>
157 </Tooltip>
158 )}
159 </IfLoggedIn>
160 </header>
161 <section className={classes.body}>
162 {comment.message !== '' ? (
163 <Content markdown={comment.message} />
164 ) : (
165 <Content markdown="*No description provided.*" />
166 )}
167 </section>
168 </Paper>
169 );
170 }
171
172 function editMessageView() {
173 const cancelEdition = () => {
174 switchToEditMode(false);
175 };
176
177 const onPostSubmit = (comment: AddCommentFragment | CreateFragment) => {
178 setComment(comment);
179 switchToEditMode(false);
180 };
181
182 return (
183 <div className={classes.bubble}>
184 <EditCommentForm
185 bug={bug}
186 onCancel={cancelEdition}
187 onPostSubmit={onPostSubmit}
188 comment={comment}
189 />
190 </div>
191 );
192 }
193
194 return (
195 <article className={classes.container}>
196 <Avatar author={comment.author} className={classes.avatar} />
197 {editMode ? editMessageView() : readMessageView()}
198 </article>
199 );
200}
201
202export default Message;