team chat is now functional
This commit is contained in:
parent
ba77dbc710
commit
7c3b0a3ab0
13 changed files with 1004 additions and 41 deletions
288
src/chat/ChatMessage.tsx
Normal file
288
src/chat/ChatMessage.tsx
Normal file
|
|
@ -0,0 +1,288 @@
|
|||
import {
|
||||
Avatar,
|
||||
Box,
|
||||
Button,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
Grid2 as Grid,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Menu,
|
||||
Theme,
|
||||
Typography
|
||||
} from "@mui/material";
|
||||
import { MoreVert, Person, Delete as DeleteIcon, } from "@mui/icons-material";
|
||||
import moment from "moment-timezone";
|
||||
import { useGlobalState, useNoteAPI, useSnackbar, useUserAPI } from "providers";
|
||||
import React, { useState } from "react";
|
||||
// import { getThemeType } from "theme";
|
||||
// import { red } from "@material-ui/core/colors";
|
||||
import { useEffect } from "react";
|
||||
import { noteScope } from "models/Scope";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { useCallback } from "react";
|
||||
import { Note } from "models";
|
||||
import { red } from "@mui/material/colors";
|
||||
import { getThemeType } from "theme/themeType";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
//import ImageViewer from "common/ImageViewer";
|
||||
//import ResponsiveDialog from "common/ResponsiveDialog";
|
||||
|
||||
interface Props {
|
||||
index: number;
|
||||
note: Note;
|
||||
attachments?: pond.FileReference[];
|
||||
removeNoteMethod: (index: number) => void;
|
||||
}
|
||||
const useStyles = makeStyles((_theme: Theme) => ({
|
||||
red: {
|
||||
color: red["500"]
|
||||
},
|
||||
oddGrid: {
|
||||
backgroundColor: getThemeType() === "light" ? "rgb(245, 245, 245)" : "rgb(50, 50, 50)",
|
||||
padding: 4
|
||||
},
|
||||
evenGrid: {
|
||||
backgroundColor: getThemeType() === "light" ? "rgb(235, 235, 235)" : "rgb(60, 60, 60)",
|
||||
padding: 4
|
||||
},
|
||||
userAvatar: {
|
||||
width: 36,
|
||||
height: 36
|
||||
}
|
||||
}))
|
||||
|
||||
/**
|
||||
* Takes in a note and renders it
|
||||
* handles deleting of the note
|
||||
* @param props Note object
|
||||
*/
|
||||
export default function ChatMessage(props: Props) {
|
||||
const classes = useStyles();
|
||||
const [{ user }] = useGlobalState();
|
||||
const noteAPI = useNoteAPI();
|
||||
const { openSnack } = useSnackbar();
|
||||
const [permissions, setPermissions] = useState<pond.Permission[]>([]);
|
||||
const userAPI = useUserAPI();
|
||||
const [dialog, setDialog] = useState(false);
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||
//const [fileListOpen, setFileListOpen] = useState(false);
|
||||
|
||||
const [name, setName] = useState("");
|
||||
const [avatar, setAvatar] = useState("");
|
||||
|
||||
const loadPermissions = useCallback(() => {
|
||||
let scope = noteScope(props.note.key());
|
||||
userAPI
|
||||
.getUser(user.id(), scope)
|
||||
.then(resp => {
|
||||
setPermissions(resp.permissions);
|
||||
})
|
||||
.catch(err => {});
|
||||
userAPI
|
||||
.getProfile(props.note.settings.userId)
|
||||
.then(resp => {
|
||||
setName(resp.name);
|
||||
setAvatar(resp.avatar);
|
||||
})
|
||||
.catch(err => {});
|
||||
}, [props.note, userAPI, user]);
|
||||
|
||||
useEffect(() => {
|
||||
loadPermissions();
|
||||
}, [loadPermissions]);
|
||||
|
||||
const deleteMessage = () => {
|
||||
setAnchorEl(null);
|
||||
noteAPI
|
||||
.removeNote(props.note.key())
|
||||
.then(resp => {
|
||||
openSnack("Message Deleted");
|
||||
props.removeNoteMethod(props.index);
|
||||
})
|
||||
.catch(err => {
|
||||
openSnack("Failed to delete Message");
|
||||
});
|
||||
closeDialog();
|
||||
};
|
||||
|
||||
const openDialog = () => {
|
||||
setDialog(true);
|
||||
};
|
||||
|
||||
const closeDialog = () => {
|
||||
setDialog(false);
|
||||
};
|
||||
|
||||
// const uploadedImages = () => {
|
||||
// return (
|
||||
// <Grid container direction="row">
|
||||
// {props.attachments?.map(attachment => {
|
||||
// if (attachment.metadata && attachment.metadata.contentType.split("/")[0] === "image") {
|
||||
// return (
|
||||
// <Grid item xs={4} key={attachment.uuid}>
|
||||
// <ImageViewer image={attachment} width={"100%"} />
|
||||
// </Grid>
|
||||
// );
|
||||
// } else {
|
||||
// return undefined;
|
||||
// }
|
||||
// })}
|
||||
// </Grid>
|
||||
// );
|
||||
// };
|
||||
|
||||
// const fileListDialog = () => {
|
||||
// return (
|
||||
// <ResponsiveDialog
|
||||
// open={fileListOpen}
|
||||
// onClose={() => {
|
||||
// setFileListOpen(false);
|
||||
// }}>
|
||||
// <DialogTitle>Message Attachments</DialogTitle>
|
||||
// <DialogContent>
|
||||
// {props.attachments &&
|
||||
// props.attachments.map(file => {
|
||||
// if (file.metadata && file.metadata.contentType.includes("image/")) {
|
||||
// //if the file is an image
|
||||
// return (
|
||||
// <Box margin={2} key={file.uuid}>
|
||||
// <ImageViewer image={file} width={"100%"} />
|
||||
// </Box>
|
||||
// );
|
||||
// } else {
|
||||
// return undefined;
|
||||
// }
|
||||
// })}
|
||||
// </DialogContent>
|
||||
// <DialogActions>
|
||||
// <Button onClick={() => setFileListOpen(false)}>Close</Button>
|
||||
// </DialogActions>
|
||||
// </ResponsiveDialog>
|
||||
// );
|
||||
// };
|
||||
|
||||
const messageMenu = () => {
|
||||
return (
|
||||
<Menu
|
||||
id="groupMenu"
|
||||
anchorEl={anchorEl}
|
||||
open={Boolean(anchorEl)}
|
||||
onClose={() => setAnchorEl(null)}
|
||||
keepMounted>
|
||||
<List>
|
||||
<ListItemButton onClick={openDialog}>
|
||||
<ListItemIcon>
|
||||
<DeleteIcon className={classes.red} />
|
||||
</ListItemIcon>
|
||||
<ListItemText>Delete Message</ListItemText>
|
||||
</ListItemButton>
|
||||
{/* {props.attachments && props.attachments.length > 0 && (
|
||||
<ListItem
|
||||
button
|
||||
onClick={() => {
|
||||
setFileListOpen(true);
|
||||
}}>
|
||||
<ListItemIcon>
|
||||
<Visibility />
|
||||
</ListItemIcon>
|
||||
<ListItemText>View Attachments</ListItemText>
|
||||
</ListItem>
|
||||
)} */}
|
||||
</List>
|
||||
</Menu>
|
||||
);
|
||||
};
|
||||
|
||||
const deleteDialog = () => {
|
||||
return (
|
||||
<Dialog open={dialog} onClose={closeDialog}>
|
||||
<DialogTitle>Delete Message?</DialogTitle>
|
||||
<DialogContent>Are you sure you wish to delete this message</DialogContent>
|
||||
|
||||
<DialogActions>
|
||||
<Button onClick={closeDialog} color="primary">
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={deleteMessage} color="primary">
|
||||
Delete
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box style={{ width: "100%" }}>
|
||||
<Grid
|
||||
wrap="nowrap"
|
||||
container
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
className={props.index % 2 === 0 ? classes.oddGrid : classes.evenGrid}>
|
||||
<Grid>
|
||||
<Box marginLeft="5px">
|
||||
{/* avatar */}
|
||||
{avatar ? (
|
||||
<Avatar alt={name} src={avatar} className={classes.userAvatar}>
|
||||
{!avatar && name}
|
||||
</Avatar>
|
||||
) : (
|
||||
<Avatar alt={name} className={classes.userAvatar}>
|
||||
<Person />
|
||||
</Avatar>
|
||||
)}
|
||||
</Box>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12 }}>
|
||||
<Box marginLeft="5px">
|
||||
<Grid container direction="column" style={{ margin: "5px" }}>
|
||||
<Grid>
|
||||
<Grid container direction="row">
|
||||
<Grid>
|
||||
<Typography variant="subtitle2" color="textPrimary">
|
||||
{name}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Box marginRight={1} marginLeft={1}>
|
||||
<Grid>
|
||||
<Typography variant="caption" color="textSecondary">
|
||||
{moment(props.note.date())
|
||||
.tz(user.settings.timezone)
|
||||
.format("MMMM Do YYYY, h:mm:ss a")}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid>
|
||||
<Typography style={{ whiteSpace: "pre-wrap" }} variant="caption">
|
||||
{props.note.content()}
|
||||
</Typography>
|
||||
{/*load files and display attached images below the message */}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</Grid>
|
||||
<Grid>
|
||||
{/* delete button */}
|
||||
{permissions.includes(pond.Permission.PERMISSION_WRITE) && (
|
||||
<Button
|
||||
onClick={(event: React.MouseEvent<HTMLButtonElement>) =>
|
||||
setAnchorEl(event.currentTarget)
|
||||
}>
|
||||
<MoreVert />
|
||||
</Button>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
{deleteDialog()}
|
||||
{messageMenu()}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue