frontend/src/chat/ChatMessage.tsx
2024-12-09 17:26:12 -06:00

208 lines
6 KiB
TypeScript

import {
Avatar,
Box,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
Grid2 as Grid,
IconButton,
ListItemIcon,
ListItemText,
Menu,
MenuItem,
Theme,
Typography
} from "@mui/material";
import { MoreVert, Person, Delete as DeleteIcon, } from "@mui/icons-material";
import moment from "moment-timezone";
import { useGlobalState, useNoteAPI, useSnackbar } from "providers";
import React, { useState } from "react";
import { pond } from "protobuf-ts/pond";
import { red } from "@mui/material/colors";
import { makeStyles } from "@mui/styles";
import CancelSubmit from "common/CancelSubmit";
import { getThemeType } from "theme/themeType";
interface Props {
index: number;
chat: pond.Chat;
attachments?: pond.FileReference[];
removeNoteMethod: (index: number) => void;
}
const useStyles = makeStyles((theme: Theme) => ({
red: {
color: red["500"]
},
oddGrid: {
backgroundColor: theme.palette.background.paper,
padding: theme.spacing(1)
},
evenGrid: {
backgroundColor: getThemeType() === "light" ? theme.palette.background.default : undefined,
padding: theme.spacing(1)
},
userAvatar: {
width: 36,
height: 36,
marginLeft: theme.spacing(1),
marginRight: theme.spacing(2),
}
}))
/**
* 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 [dialog, setDialog] = useState(false);
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const avatar = props.chat.profile?.avatar
const name = props.chat.profile?.name
const timestamp = props.chat.note?.settings?.timestamp ? props.chat.note?.settings?.timestamp : undefined
const generatePermissions = () => {
let perms: pond.Permission[] = []
if (Array.isArray(props.chat.permissions)) {
perms = props.chat.permissions.map((perm: unknown) => {
const mappedPerm = pond.Permission[perm as keyof typeof pond.Permission];
return mappedPerm; // Return null for invalid keys
}).filter(Boolean); // Optionally filter out any null values
} else {
console.error("data.permissions is not an array or does not exist");
perms = [];
}
return perms
}
const permissions = generatePermissions()
const deleteMessage = () => {
if (!props.chat?.note?.settings) return
setAnchorEl(null);
noteAPI
.removeNote(props.chat.note.settings.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 messageMenu = () => {
return (
<Menu
id="groupMenu"
anchorEl={anchorEl}
open={Boolean(anchorEl)}
onClose={() => setAnchorEl(null)}
keepMounted
>
<MenuItem dense onClick={openDialog}>
<ListItemIcon>
<DeleteIcon className={classes.red} />
</ListItemIcon>
<ListItemText>Delete Message</ListItemText>
</MenuItem>
</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>
<CancelSubmit
onCancel={closeDialog}
onSubmit={deleteMessage}
submitText="Delete"
/>
</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>
{avatar ? (
<Avatar alt={name} src={avatar} className={classes.userAvatar}>
{!avatar && name}
</Avatar>
) : (
<Avatar alt={name} className={classes.userAvatar}>
<Person />
</Avatar>
)}
</Grid>
<Grid container direction="column" justifyContent="space-between" size={{ xs:10 }} >
<Grid container direction="row" alignContent={"center"} spacing={1} >
<Grid>
<Typography color="textPrimary">
{name}
</Typography>
</Grid>
<Grid justifyContent={"center"}>
<Typography variant="caption" color="textSecondary">
{moment.unix(timestamp ? timestamp/1000: 0)
.tz(user.settings.timezone ? user.settings.timezone : "Canada/Central")
.format("MMMM Do YYYY, h:mm:ss a")}
</Typography>
</Grid>
</Grid>
<Grid size={{ xs: 12 }}>
<Typography variant="body2" whiteSpace={"pre-line"}>
{props.chat.note?.settings?.content}
</Typography>
{/*load files and display attached images below the message */}
</Grid>
</Grid>
<Grid padding={1}>
{/* delete button */}
{permissions.includes(pond.Permission.PERMISSION_WRITE) ? (
<IconButton
onClick={(event: React.MouseEvent<HTMLButtonElement>) =>
setAnchorEl(event.currentTarget)
}>
<MoreVert />
</IconButton>
) : (
// <span>
// <Tooltip title="No permissions to edit or delete" disableInteractive>
<IconButton disabled>
<MoreVert />
</IconButton>
// </Tooltip>
// </span>
)}
</Grid>
</Grid>
{deleteDialog()}
{messageMenu()}
</Box>
);
}