Message.tsx

  1import React, { useState } from 'react';
  2
  3import IconButton from '@material-ui/core/IconButton';
  4import Paper from '@material-ui/core/Paper';
  5import Tooltip from '@material-ui/core/Tooltip/Tooltip';
  6import { makeStyles } from '@material-ui/core/styles';
  7import EditIcon from '@material-ui/icons/Edit';
  8import HistoryIcon from '@material-ui/icons/History';
  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    ...theme.typography.body2,
 61    paddingLeft: theme.spacing(1),
 62    paddingRight: theme.spacing(1),
 63  },
 64  headerActions: {
 65    color: theme.palette.info.contrastText,
 66    padding: '0rem',
 67    marginLeft: theme.spacing(1),
 68    fontSize: '0.75rem',
 69    '&:hover': {
 70      backgroundColor: 'inherit',
 71    },
 72  },
 73}));
 74
 75type HistBtnProps = {
 76  bugId: string;
 77  commentId: string;
 78};
 79function HistoryMenuToggleButton({ bugId, commentId }: HistBtnProps) {
 80  const classes = useStyles();
 81  const [open, setOpen] = React.useState(false);
 82
 83  const handleClickOpen = () => {
 84    setOpen(true);
 85  };
 86
 87  const handleClose = () => {
 88    setOpen(false);
 89  };
 90
 91  return (
 92    <div>
 93      <IconButton
 94        aria-label="more"
 95        aria-controls="long-menu"
 96        aria-haspopup="true"
 97        onClick={handleClickOpen}
 98        className={classes.headerActions}
 99      >
100        <HistoryIcon />
101      </IconButton>
102      {
103        // Render CustomizedDialogs on open to prevent fetching the history
104        // before opening the history menu.
105        open && (
106          <MessageHistoryDialog
107            bugId={bugId}
108            commentId={commentId}
109            open={open}
110            onClose={handleClose}
111          />
112        )
113      }
114    </div>
115  );
116}
117
118type Props = {
119  bug: BugFragment;
120  op: AddCommentFragment | CreateFragment;
121};
122function Message({ bug, op }: Props) {
123  const classes = useStyles();
124  const [editMode, switchToEditMode] = useState(false);
125  const [comment, setComment] = useState(op);
126
127  const editComment = (id: String) => {
128    switchToEditMode(true);
129  };
130
131  function readMessageView() {
132    return (
133      <Paper elevation={1} className={classes.bubble}>
134        <header className={classes.header}>
135          <div className={classes.title}>
136            <Author className={classes.author} author={comment.author} />
137            <span> commented </span>
138            <Date date={comment.createdAt} />
139          </div>
140          {comment.edited && (
141            <HistoryMenuToggleButton bugId={bug.id} commentId={comment.id} />
142          )}
143          <IfLoggedIn>
144            {() => (
145              <Tooltip title="Edit Message" placement="top" arrow={true}>
146                <IconButton
147                  disableRipple
148                  className={classes.headerActions}
149                  aria-label="edit message"
150                  onClick={() => editComment(comment.id)}
151                >
152                  <EditIcon />
153                </IconButton>
154              </Tooltip>
155            )}
156          </IfLoggedIn>
157        </header>
158        <section className={classes.body}>
159          <Content markdown={comment.message} />
160        </section>
161      </Paper>
162    );
163  }
164
165  function editMessageView() {
166    const cancelEdition = () => {
167      switchToEditMode(false);
168    };
169
170    const onPostSubmit = (comment: AddCommentFragment | CreateFragment) => {
171      setComment(comment);
172      switchToEditMode(false);
173    };
174
175    return (
176      <div className={classes.bubble}>
177        <EditCommentForm
178          bug={bug}
179          onCancel={cancelEdition}
180          onPostSubmit={onPostSubmit}
181          comment={comment}
182        />
183      </div>
184    );
185  }
186
187  return (
188    <article className={classes.container}>
189      <Avatar author={comment.author} className={classes.avatar} />
190      {editMode ? editMessageView() : readMessageView()}
191    </article>
192  );
193}
194
195export default Message;