added chat drawer

This commit is contained in:
Carter 2024-12-04 10:41:46 -06:00
parent 7c3b0a3ab0
commit 1a9ee12533
7 changed files with 196 additions and 110 deletions

View file

@ -23,3 +23,16 @@ html, body, #root {
margin: 0;
padding: 0;
}
/* styles.css or a CSS module */
.MuiDialog-root {
z-index: 1500 !important;
}
.MuiDrawer-root {
z-index: 1300 !important;
}
.MuiMenu-root {
z-index: 1400 !important; /* Ensure it's above the drawer */
}

View file

@ -2,6 +2,7 @@ import { Chat as ChatIcon, ChevronRight } from "@mui/icons-material";
import { Box, Drawer, IconButton, Theme, Tooltip, Typography } from "@mui/material";
import { makeStyles } from "@mui/styles";
import Chat from "chat/Chat";
import { ChatDrawer } from "chat/ChatDrawer";
import { useMobile } from "hooks";
import { Team, User } from "models";
import moment from "moment";
@ -36,7 +37,8 @@ const useStyles = makeStyles((theme: Theme) => ({
padding: theme.spacing(1),
height: "100%",
minWidth: theme.spacing(54),
maxWidth: theme.spacing(54)
maxWidth: theme.spacing(54),
zIndex: 1000000000000
},
chatDrawerMobile: {
padding: theme.spacing(1),
@ -119,22 +121,29 @@ export default function HeaderButtons(props: Props) {
<>
{chatButton()}
{team && team.settings && team.settings.key && (
<Drawer
anchor="right"
<ChatDrawer
open={chatDrawerOpen}
onClose={() => setChatDrawerOpen(false)}
style={{ height: "100%", maxWidth: "100%" }}
title={team.settings.name ? team.settings.name + "Chat" : "Chat"}>
<div className={isMobile ? classes.chatDrawerMobile : classes.chatDrawer}>
<div className={classes.drawerHeader}>
<IconButton onClick={() => setChatDrawerOpen(false)}>
<ChevronRight />
</IconButton>
<Typography>{team.name()} Chat</Typography>
</div>
<Chat objectKey={team.settings.key} type={pond.NoteType.NOTE_TYPE_TEAM} />
</div>
</Drawer>
team={team}
/>
// <Drawer
// anchor="right"
// open={chatDrawerOpen}
// sx={{ zIndex: 10000 }}
// onClose={() => setChatDrawerOpen(false)}
// style={{ height: "100%", maxWidth: "100%" }}
// title={team.settings.name ? team.settings.name + "Chat" : "Chat"}>
// <div className={isMobile ? classes.chatDrawerMobile : classes.chatDrawer}>
// <div className={classes.drawerHeader}>
// <IconButton onClick={() => setChatDrawerOpen(false)}>
// <ChevronRight />
// </IconButton>
// <Typography>{team.name()} Chat</Typography>
// </div>
// <Chat objectKey={team.settings.key} type={pond.NoteType.NOTE_TYPE_TEAM} />
// </div>
// </Drawer>
)}
</>
)

View file

@ -1,4 +1,4 @@
import { Box, CircularProgress } from "@mui/material";
import { Box, CircularProgress, Theme } from "@mui/material";
import { useGlobalState, useNoteAPI, useTeamAPI } from "providers";
import React from "react";
import { useCallback } from "react";
@ -9,6 +9,7 @@ import ChatOutput from "./ChatOutput";
import { Note } from "models";
import { pond } from "protobuf-ts/pond";
import moment from "moment-timezone";
import { makeStyles } from "@mui/styles";
interface Props {
objectKey: string;
@ -26,6 +27,7 @@ export default function Chat(props: Props) {
const [attachmentMap, setAttachmentMap] = useState<Map<string, pond.FileReference[]>>(new Map());
const teamAPI = useTeamAPI();
// const classes = useStyles();
const loadNotes = useCallback(() => {
let currentNotes: Note[] = notes;
@ -36,7 +38,6 @@ export default function Chat(props: Props) {
if (resp.data.notes.length < 1) {
return;
}
setTotalMessages(resp.data.total);
let tempNotes: Note[] = [];
let tempAttachmentMap: Map<string, pond.FileReference[]> = attachmentMap;

61
src/chat/ChatDrawer.tsx Normal file
View file

@ -0,0 +1,61 @@
import { ChevronRight } from "@mui/icons-material";
import { Box, Drawer, IconButton, Theme, Typography } from "@mui/material";
import { makeStyles } from "@mui/styles";
import { useMobile } from "hooks";
import { Team } from "models";
import { pond } from "protobuf-ts/pond";
import Chat from "./Chat";
const useStyles = makeStyles((theme: Theme) => {
return ({
chatDrawer: {
backgroundColor: theme.palette.background.default,
// padding: theme.spacing(1),
height: "100%",
minWidth: theme.spacing(54),
maxWidth: theme.spacing(54),
// zIndex: 1000000000000,
// zIndex: theme.zIndex.drawer,
},
chatDrawerMobile: {
backgroundColor: theme.palette.background.default,
// padding: theme.spacing(1),
height: "auto",
width: "100%"
},
drawerHeader: {
display: "flex",
alignItems: "center",
padding: theme.spacing(1),
// necessary for content to be below app bar
...theme.mixins.toolbar,
justifyContent: "flex-start"
}
});
});
interface Props {
open: boolean;
onClose: () => void;
team: Team;
}
export function ChatDrawer(props: Props) {
const { open, onClose, team } = props;
const isMobile = useMobile();
const classes = useStyles()
return (
<Drawer open={open} onClose={onClose} anchor="right" sx={{ zIndex: 10000 }}>
<Box className={isMobile ? classes.chatDrawerMobile : classes.chatDrawer}>
<Box className={classes.drawerHeader}>
<IconButton onClick={onClose}>
<ChevronRight />
</IconButton>
<Typography>{team.name()} Chat</Typography>
</Box>
<Chat objectKey={team.settings.key} type={pond.NoteType.NOTE_TYPE_TEAM} />
</Box>
</Drawer>
)
}

View file

@ -1,4 +1,5 @@
import {
Box,
Button,
//DialogActions,
//DialogContent,
@ -31,12 +32,22 @@ const useStyles = makeStyles((theme: Theme) => ({
margin: 8,
marginRight: 12
},
textAreaBox: {
width: "100%",
padding: theme.spacing(1),
paddingTop: theme.spacing(0),
},
textAreaClass: {
backgroundColor: getThemeType() === "light" ? "rgb(245, 245, 245)" : "rgb(50, 50, 50)",
borderColor: getThemeType() === "light" ? "rgb(255, 255, 255)" : "rgb(60, 60, 60)",
color: getThemeType() === "light" ? "rgb(10, 10, 10)" : "rgb(245, 245, 245)",
padding: theme.spacing(1),
// backgroundColor: getThemeType() === "light" ? "rgb(245, 245, 245)" : "rgb(50, 50, 50)",
// borderColor: getThemeType() === "light" ? "rgb(255, 255, 255)" : "rgb(60, 60, 60)",
// color: getThemeType() === "light" ? "rgb(10, 10, 10)" : "rgb(245, 245, 245)",
backgroundColor: theme.palette.background.paper,
borderColor: theme.palette.background.default,
color: theme.palette.text.primary,
borderRadius: "5px",
width: "100%"
width: "100%",
}
}))
@ -104,20 +115,19 @@ export default function ChatInput(props: Props) {
let newNote = Note.create();
newNote.settings.objectKey = objectKey;
newNote.settings.userId = user.id();
//newNote.settings.objectType = pond.NoteType.NOTE_TYPE_TEAM not using type at the moment
if (type) {
newNote.settings.objectType = type;
}
newNote.settings.timestamp = Date.now();
newNote.settings.content = message;
noteAPI
.addNote(newNote.settings, Array.from(uploadedFiles.keys()))
.then(resp => {
newNote.settings.key = resp.data.note
props.newNoteMethod(newNote);
openSnack("Message Sent");
})
.catch(err => {
.catch(_err => {
openSnack("Message Failed to send");
});
}
@ -175,19 +185,21 @@ export default function ChatInput(props: Props) {
justifyContent="space-between"
spacing={1}
style={{ marginTop: theme.spacing(1) }}>
<Grid>
{/* <Grid>
<Button onClick={validateMessage} variant="contained" color="primary">
<ChatIcon />
</Button>
</Grid>
<Grid size={{ xs: 9 }} >
<TextareaAutosize
</Grid> */}
<Grid size={{ xs: 12 }} >
<Box className={classes.textAreaBox}>
<textarea
value={message}
className={classes.textAreaClass}
onChange={e => setMessage(e.target.value)}
onKeyDown={onKeyDown}
onKeyUp={onKeyUp}
/>
</Box>
</Grid>
{/* <Grid item xs={2}>
<IconButton

View file

@ -7,12 +7,11 @@ import {
DialogContent,
DialogTitle,
Grid2 as Grid,
List,
ListItem,
ListItemButton,
IconButton,
ListItemIcon,
ListItemText,
Menu,
MenuItem,
Theme,
Typography
} from "@mui/material";
@ -39,21 +38,26 @@ interface Props {
attachments?: pond.FileReference[];
removeNoteMethod: (index: number) => void;
}
const useStyles = makeStyles((_theme: Theme) => ({
const useStyles = makeStyles((theme: Theme) => ({
red: {
color: red["500"]
},
oddGrid: {
backgroundColor: getThemeType() === "light" ? "rgb(245, 245, 245)" : "rgb(50, 50, 50)",
backgroundColor: theme.palette.background.paper,
padding: 4
},
evenGrid: {
backgroundColor: getThemeType() === "light" ? "rgb(235, 235, 235)" : "rgb(60, 60, 60)",
backgroundColor: theme.palette.background.default,
padding: 4
},
textContainer: {
padding: theme.spacing(1),
},
userAvatar: {
width: 36,
height: 36
height: 36,
marginLeft: theme.spacing(1),
marginRight: theme.spacing(2),
}
}))
@ -83,14 +87,14 @@ export default function ChatMessage(props: Props) {
.then(resp => {
setPermissions(resp.permissions);
})
.catch(err => {});
.catch(_err => {});
userAPI
.getProfile(props.note.settings.userId)
.then(resp => {
setName(resp.name);
setAvatar(resp.avatar);
})
.catch(err => {});
.catch(_err => {});
}, [props.note, userAPI, user]);
useEffect(() => {
@ -101,11 +105,11 @@ export default function ChatMessage(props: Props) {
setAnchorEl(null);
noteAPI
.removeNote(props.note.key())
.then(resp => {
.then(_resp => {
openSnack("Message Deleted");
props.removeNoteMethod(props.index);
})
.catch(err => {
.catch(_err => {
openSnack("Failed to delete Message");
});
closeDialog();
@ -174,27 +178,14 @@ export default function ChatMessage(props: Props) {
anchorEl={anchorEl}
open={Boolean(anchorEl)}
onClose={() => setAnchorEl(null)}
keepMounted>
<List>
<ListItemButton onClick={openDialog}>
keepMounted
>
<MenuItem dense 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>
</MenuItem>
</Menu>
);
};
@ -226,8 +217,6 @@ export default function ChatMessage(props: Props) {
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}
@ -237,47 +226,38 @@ export default function ChatMessage(props: Props) {
<Person />
</Avatar>
)}
</Box>
</Grid>
<Grid size={{ xs: 12 }}>
<Box marginLeft="5px">
<Grid container direction="column" style={{ margin: "5px" }}>
<Grid container direction="column" justifyContent="space-between" size={{ xs:10 }} >
<Grid container direction="row" alignContent={"center"} spacing={1} >
<Grid>
<Grid container direction="row">
<Grid>
<Typography variant="subtitle2" color="textPrimary">
<Typography color="textPrimary">
{name}
</Typography>
</Grid>
<Box marginRight={1} marginLeft={1}>
<Grid>
<Grid justifyContent={"center"}>
<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">
<Typography variant="body2">
{props.note.content()}
</Typography>
{/*load files and display attached images below the message */}
</Grid>
</Grid>
</Box>
</Grid>
<Grid>
<Grid padding={1}>
{/* delete button */}
{permissions.includes(pond.Permission.PERMISSION_WRITE) && (
<Button
<IconButton
onClick={(event: React.MouseEvent<HTMLButtonElement>) =>
setAnchorEl(event.currentTarget)
}>
<MoreVert />
</Button>
</IconButton>
)}
</Grid>
</Grid>

View file

@ -120,6 +120,16 @@ function options(themeType: "light" | "dark"): ThemeOptions {
styleOverrides: {
paperFullScreen: {
overflowX: "hidden"
},
root: {
zIndex: 1500
}
},
},
MuiDrawer: {
styleOverrides: {
root: {
zIndex: 1300
}
},
},