team chat is now functional

This commit is contained in:
Carter 2024-12-03 09:33:43 -06:00
parent ba77dbc710
commit 7c3b0a3ab0
13 changed files with 1004 additions and 41 deletions

288
src/chat/ChatMessage.tsx Normal file
View 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>
);
}