using chats instead of notes for the chat
This commit is contained in:
parent
9ec1956687
commit
cf45fcb98a
9 changed files with 201 additions and 284 deletions
2
package-lock.json
generated
2
package-lock.json
generated
|
|
@ -4220,7 +4220,7 @@
|
||||||
},
|
},
|
||||||
"node_modules/protobuf-ts": {
|
"node_modules/protobuf-ts": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#81a4e3f24369057b3d022ae0a8ef3e5fab58ea09",
|
"resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#8c31044c11d0b97c40a253cc917a333f33c3cdf4",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"protobufjs": "^6.8.8"
|
"protobufjs": "^6.8.8"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ export default function UserWrapper(props: Props) {
|
||||||
let user_id = or(useAuth.user?.sub, "")
|
let user_id = or(useAuth.user?.sub, "")
|
||||||
|
|
||||||
const loadUser = useCallback(() => {
|
const loadUser = useCallback(() => {
|
||||||
|
if (!userAPI.getUserWithTeam) return;
|
||||||
if (hasFetched.current) return;
|
if (hasFetched.current) return;
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
userAPI.getUserWithTeam(user_id).then(resp => {
|
userAPI.getUserWithTeam(user_id).then(resp => {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,16 @@ import { createRoot } from 'react-dom/client'
|
||||||
import './index.css'
|
import './index.css'
|
||||||
import App from './App.tsx'
|
import App from './App.tsx'
|
||||||
|
|
||||||
|
// I don't consider providing a disabled button to a Tooltip an error.
|
||||||
|
// console.error = (message) => {
|
||||||
|
// if (message.includes('You are providing a disabled `button` child to the Tooltip component.')) {
|
||||||
|
// return; // Suppress specific warning
|
||||||
|
// }
|
||||||
|
// console.error(message); // Other warnings still show
|
||||||
|
// console.info(message, "error"); // Other warnings still show
|
||||||
|
|
||||||
|
// };
|
||||||
|
|
||||||
createRoot(document.getElementById('root')!).render(
|
createRoot(document.getElementById('root')!).render(
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
<App />
|
<App />
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { Box, CircularProgress, Theme } from "@mui/material";
|
import { Box, CircularProgress } from "@mui/material";
|
||||||
import { useGlobalState, useNoteAPI, useTeamAPI } from "providers";
|
import { useGlobalState, useNoteAPI, useTeamAPI } from "providers";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useCallback } from "react";
|
import { useCallback } from "react";
|
||||||
|
|
@ -9,7 +9,6 @@ import ChatOutput from "./ChatOutput";
|
||||||
import { Note } from "models";
|
import { Note } from "models";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
import { makeStyles } from "@mui/styles";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
objectKey: string;
|
objectKey: string;
|
||||||
|
|
@ -17,95 +16,73 @@ interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Chat(props: Props) {
|
export default function Chat(props: Props) {
|
||||||
const [notes, setNotes] = useState<Note[]>([]);
|
const [chats, setChats] = useState<pond.Chat[]>([]);
|
||||||
const { objectKey, type } = props;
|
const { objectKey, type } = props;
|
||||||
const noteAPI = useNoteAPI();
|
const noteAPI = useNoteAPI();
|
||||||
const [notesLoaded, setNotesLoaded] = useState<boolean>(false);
|
const [loaded, setLoaded] = useState<boolean>(false);
|
||||||
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
const [totalMessages, setTotalMessages] = useState(0);
|
const [totalMessages, setTotalMessages] = useState(0);
|
||||||
const [scrollPos, setScrollPos] = useState(0);
|
const [scrollPos, setScrollPos] = useState(0);
|
||||||
const [{ team }] = useGlobalState();
|
const [{ user }] = useGlobalState();
|
||||||
const [attachmentMap, setAttachmentMap] = useState<Map<string, pond.FileReference[]>>(new Map());
|
const [attachmentMap, setAttachmentMap] = useState<Map<string, pond.FileReference[]>>(new Map());
|
||||||
|
|
||||||
const teamAPI = useTeamAPI();
|
|
||||||
// const classes = useStyles();
|
|
||||||
|
|
||||||
const loadNotes = useCallback(() => {
|
useEffect(() => {
|
||||||
let currentNotes: Note[] = notes;
|
console.log(totalMessages)
|
||||||
noteAPI
|
}, [totalMessages])
|
||||||
.listNotes(15, currentNotes.length, "desc", "timestamp", objectKey)
|
|
||||||
.then(resp => {
|
|
||||||
setNotesLoaded(true);
|
|
||||||
if (resp.data.notes.length < 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setTotalMessages(resp.data.total);
|
|
||||||
let tempNotes: Note[] = [];
|
|
||||||
let tempAttachmentMap: Map<string, pond.FileReference[]> = attachmentMap;
|
|
||||||
resp.data.notes.forEach(note => {
|
|
||||||
let n = Note.any(note);
|
|
||||||
tempNotes.push(n);
|
|
||||||
let refList = resp.data.attachments[n.key()];
|
|
||||||
if (refList) {
|
|
||||||
tempAttachmentMap.set(n.key(), refList.refs);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
setScrollPos(tempNotes.length);
|
|
||||||
currentNotes = currentNotes.concat(tempNotes);
|
|
||||||
currentNotes.reverse();
|
|
||||||
setNotes(currentNotes);
|
|
||||||
setAttachmentMap(tempAttachmentMap);
|
|
||||||
|
|
||||||
if (type) {
|
const loadChats = () => {
|
||||||
// Setting the note type for future use
|
setLoading(true)
|
||||||
currentNotes.forEach(note => {
|
noteAPI.listChats(10, chats.length, "desc", "timestamp", objectKey).then(resp => {
|
||||||
if (note.settings.objectType === pond.NoteType.NOTE_TYPE_UNKNOWN && type) {
|
setChats(resp.data.chats ? resp.data.chats.reverse().concat(chats) : [])
|
||||||
note.settings.objectType = type;
|
setTotalMessages(resp.data.total)
|
||||||
noteAPI.updateNote(note.settings);
|
}).finally(() => {
|
||||||
}
|
setLoading(false)
|
||||||
});
|
setLoaded(true)
|
||||||
|
|
||||||
// Update new chat viewed timestamp
|
|
||||||
if (type === pond.NoteType.NOTE_TYPE_TEAM) {
|
|
||||||
team.preferences.chatViewedTimestamp = moment().toISOString();
|
|
||||||
teamAPI.updatePreferences(team.key(), team.preferences);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch(_err => {});
|
}
|
||||||
}, [noteAPI, objectKey, notes, type, team, teamAPI, attachmentMap]);
|
|
||||||
|
|
||||||
const removeNote = (index: number) => {
|
const removeNote = (index: number) => {
|
||||||
let n = notes;
|
let c = chats
|
||||||
setTotalMessages(totalMessages - 1);
|
setTotalMessages(totalMessages - 1);
|
||||||
n.splice(index, 1);
|
c.splice(index, 1);
|
||||||
setNotes([...n]);
|
setChats([...c])
|
||||||
};
|
};
|
||||||
|
|
||||||
const showNewNotes = (newNote: Note) => {
|
const showNewNotes = (newNote: Note) => {
|
||||||
let n = notes;
|
let note = pond.Note.create({
|
||||||
n.push(newNote);
|
settings: newNote.settings,
|
||||||
setScrollPos(n.length);
|
status: newNote.status,
|
||||||
setNotes([...n]);
|
})
|
||||||
|
let profile = pond.UserProfile.create({
|
||||||
|
name: user.name(),
|
||||||
|
avatar: user.settings.avatar,
|
||||||
|
})
|
||||||
|
let permissions = [
|
||||||
|
pond.Permission.PERMISSION_READ,
|
||||||
|
pond.Permission.PERMISSION_WRITE,
|
||||||
|
]
|
||||||
|
let c = chats;
|
||||||
|
c.push({
|
||||||
|
note: note,
|
||||||
|
profile: profile,
|
||||||
|
permissions: permissions
|
||||||
|
} as any)
|
||||||
|
setChats([...c])
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!notesLoaded) {
|
loadChats()
|
||||||
loadNotes();
|
}, []);
|
||||||
}
|
|
||||||
// setNotesLoaded(true);
|
|
||||||
}, [notesLoaded, loadNotes]);
|
|
||||||
|
|
||||||
const loadMore = () => {
|
const loadMore = () => {
|
||||||
let n = notes;
|
loadChats();
|
||||||
n.reverse();
|
|
||||||
setNotes(n);
|
|
||||||
loadNotes();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{!notesLoaded ? (
|
{ loading && !loaded ? (
|
||||||
<Box marginTop={"51%"} marginLeft={"44%"}>
|
<Box width="100%" height="100%" alignContent={"center"} textAlign={"center"} >
|
||||||
<CircularProgress />
|
<CircularProgress />
|
||||||
</Box>
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
|
|
@ -114,7 +91,7 @@ export default function Chat(props: Props) {
|
||||||
<ChatOutput
|
<ChatOutput
|
||||||
totalMessages={totalMessages}
|
totalMessages={totalMessages}
|
||||||
attachmentMap={attachmentMap}
|
attachmentMap={attachmentMap}
|
||||||
messages={notes}
|
messages={chats}
|
||||||
scrollPos={scrollPos}
|
scrollPos={scrollPos}
|
||||||
removeNoteMethod={removeNote}
|
removeNoteMethod={removeNote}
|
||||||
loadMore={loadMore}
|
loadMore={loadMore}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,6 @@
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Button,
|
|
||||||
//DialogActions,
|
|
||||||
//DialogContent,
|
|
||||||
//DialogTitle,
|
|
||||||
Grid2 as Grid,
|
Grid2 as Grid,
|
||||||
//IconButton,
|
|
||||||
TextareaAutosize,
|
|
||||||
Theme,
|
Theme,
|
||||||
Typography,
|
Typography,
|
||||||
useTheme
|
useTheme
|
||||||
|
|
@ -15,10 +9,8 @@ import {
|
||||||
import { useGlobalState, useNoteAPI, useSnackbar } from "providers";
|
import { useGlobalState, useNoteAPI, useSnackbar } from "providers";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
// import { getThemeType } from "theme";
|
// import { getThemeType } from "theme";
|
||||||
import ChatIcon from "@mui/icons-material/Chat";
|
|
||||||
import { Note } from "models";
|
import { Note } from "models";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { getThemeType } from "theme/themeType";
|
|
||||||
import { makeStyles } from "@mui/styles";
|
import { makeStyles } from "@mui/styles";
|
||||||
//import { AttachFile } from "@material-ui/icons";
|
//import { AttachFile } from "@material-ui/icons";
|
||||||
//import ResponsiveDialog from "common/ResponsiveDialog";
|
//import ResponsiveDialog from "common/ResponsiveDialog";
|
||||||
|
|
@ -134,47 +126,6 @@ export default function ChatInput(props: Props) {
|
||||||
clearEntry();
|
clearEntry();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Dialog to select attachments
|
|
||||||
* postponing note attachments until notes can be overhauled to be more in line with the rest of the objects
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
// const attachmentDialog = () => {
|
|
||||||
// return (
|
|
||||||
// <ResponsiveDialog
|
|
||||||
// open={attachmentDialogOpen}
|
|
||||||
// onClose={() => {
|
|
||||||
// setAttachmentDialogOpen(false);
|
|
||||||
// }}>
|
|
||||||
// <DialogTitle>Add Attachments</DialogTitle>
|
|
||||||
// <DialogContent>
|
|
||||||
// <FileUploader
|
|
||||||
// uploadStart={() => {
|
|
||||||
// setUploadingFile(true);
|
|
||||||
// }}
|
|
||||||
// uploadEnd={(fileID, fileName) => {
|
|
||||||
// setUploadingFile(false);
|
|
||||||
// if (fileID && fileName) {
|
|
||||||
// let f = cloneDeep(uploadedFiles);
|
|
||||||
// f.set(fileID, fileName);
|
|
||||||
// setUploadedFiles(f);
|
|
||||||
// }
|
|
||||||
// }}
|
|
||||||
// />
|
|
||||||
// </DialogContent>
|
|
||||||
// <DialogActions>
|
|
||||||
// <Button
|
|
||||||
// disabled={uploadingFile}
|
|
||||||
// onClick={() => {
|
|
||||||
// setAttachmentDialogOpen(false);
|
|
||||||
// }}>
|
|
||||||
// Close
|
|
||||||
// </Button>
|
|
||||||
// </DialogActions>
|
|
||||||
// </ResponsiveDialog>
|
|
||||||
// );
|
|
||||||
// };
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Grid
|
<Grid
|
||||||
|
|
@ -185,11 +136,6 @@ export default function ChatInput(props: Props) {
|
||||||
justifyContent="space-between"
|
justifyContent="space-between"
|
||||||
spacing={1}
|
spacing={1}
|
||||||
style={{ marginTop: theme.spacing(1) }}>
|
style={{ marginTop: theme.spacing(1) }}>
|
||||||
{/* <Grid>
|
|
||||||
<Button onClick={validateMessage} variant="contained" color="primary">
|
|
||||||
<ChatIcon />
|
|
||||||
</Button>
|
|
||||||
</Grid> */}
|
|
||||||
<Grid size={{ xs: 12 }} >
|
<Grid size={{ xs: 12 }} >
|
||||||
<Box className={classes.textAreaBox}>
|
<Box className={classes.textAreaBox}>
|
||||||
<textarea
|
<textarea
|
||||||
|
|
@ -201,15 +147,6 @@ export default function ChatInput(props: Props) {
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Grid>
|
</Grid>
|
||||||
{/* <Grid item xs={2}>
|
|
||||||
<IconButton
|
|
||||||
onClick={() => {
|
|
||||||
setAttachmentDialogOpen(true);
|
|
||||||
}}
|
|
||||||
color="primary">
|
|
||||||
<AttachFile />
|
|
||||||
</IconButton>
|
|
||||||
</Grid> */}
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<Typography>{Array.from(uploadedFiles.values()).toString()}</Typography>
|
<Typography>{Array.from(uploadedFiles.values()).toString()}</Typography>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
|
|
|
||||||
|
|
@ -17,24 +17,15 @@ import {
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { MoreVert, Person, Delete as DeleteIcon, } from "@mui/icons-material";
|
import { MoreVert, Person, Delete as DeleteIcon, } from "@mui/icons-material";
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
import { useGlobalState, useNoteAPI, useSnackbar, useUserAPI } from "providers";
|
import { useGlobalState, useNoteAPI, useSnackbar } from "providers";
|
||||||
import React, { useState } from "react";
|
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 { pond } from "protobuf-ts/pond";
|
||||||
import { useCallback } from "react";
|
|
||||||
import { Note } from "models";
|
|
||||||
import { red } from "@mui/material/colors";
|
import { red } from "@mui/material/colors";
|
||||||
import { getThemeType } from "theme/themeType";
|
|
||||||
import { makeStyles } from "@mui/styles";
|
import { makeStyles } from "@mui/styles";
|
||||||
//import ImageViewer from "common/ImageViewer";
|
|
||||||
//import ResponsiveDialog from "common/ResponsiveDialog";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
index: number;
|
index: number;
|
||||||
note: Note;
|
chat: pond.Chat;
|
||||||
attachments?: pond.FileReference[];
|
attachments?: pond.FileReference[];
|
||||||
removeNoteMethod: (index: number) => void;
|
removeNoteMethod: (index: number) => void;
|
||||||
}
|
}
|
||||||
|
|
@ -44,11 +35,13 @@ const useStyles = makeStyles((theme: Theme) => ({
|
||||||
},
|
},
|
||||||
oddGrid: {
|
oddGrid: {
|
||||||
backgroundColor: theme.palette.background.paper,
|
backgroundColor: theme.palette.background.paper,
|
||||||
padding: 4
|
// padding: 4,
|
||||||
|
padding: theme.spacing(1)
|
||||||
},
|
},
|
||||||
evenGrid: {
|
evenGrid: {
|
||||||
backgroundColor: theme.palette.background.default,
|
// backgroundColor: theme.palette.background.default,
|
||||||
padding: 4
|
// padding: 4
|
||||||
|
padding: theme.spacing(1)
|
||||||
},
|
},
|
||||||
textContainer: {
|
textContainer: {
|
||||||
padding: theme.spacing(1),
|
padding: theme.spacing(1),
|
||||||
|
|
@ -61,6 +54,8 @@ const useStyles = makeStyles((theme: Theme) => ({
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes in a note and renders it
|
* Takes in a note and renders it
|
||||||
* handles deleting of the note
|
* handles deleting of the note
|
||||||
|
|
@ -71,40 +66,33 @@ export default function ChatMessage(props: Props) {
|
||||||
const [{ user }] = useGlobalState();
|
const [{ user }] = useGlobalState();
|
||||||
const noteAPI = useNoteAPI();
|
const noteAPI = useNoteAPI();
|
||||||
const { openSnack } = useSnackbar();
|
const { openSnack } = useSnackbar();
|
||||||
const [permissions, setPermissions] = useState<pond.Permission[]>([]);
|
|
||||||
const userAPI = useUserAPI();
|
|
||||||
const [dialog, setDialog] = useState(false);
|
const [dialog, setDialog] = useState(false);
|
||||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||||
//const [fileListOpen, setFileListOpen] = useState(false);
|
|
||||||
|
|
||||||
const [name, setName] = useState("");
|
const avatar = props.chat.profile?.avatar
|
||||||
const [avatar, setAvatar] = useState("");
|
const name = props.chat.profile?.name
|
||||||
|
const timestamp = props.chat.note?.settings?.timestamp ? props.chat.note?.settings?.timestamp : undefined
|
||||||
|
|
||||||
const loadPermissions = useCallback(() => {
|
const generatePermissions = () => {
|
||||||
let scope = noteScope(props.note.key());
|
let perms: pond.Permission[] = []
|
||||||
userAPI
|
if (Array.isArray(props.chat.permissions)) {
|
||||||
.getUser(user.id(), scope)
|
perms = props.chat.permissions.map((perm: unknown) => {
|
||||||
.then(resp => {
|
const mappedPerm = pond.Permission[perm as keyof typeof pond.Permission];
|
||||||
setPermissions(resp.permissions);
|
return mappedPerm; // Return null for invalid keys
|
||||||
})
|
}).filter(Boolean); // Optionally filter out any null values
|
||||||
.catch(_err => {});
|
} else {
|
||||||
userAPI
|
console.error("data.permissions is not an array or does not exist");
|
||||||
.getProfile(props.note.settings.userId)
|
perms = [];
|
||||||
.then(resp => {
|
}
|
||||||
setName(resp.name);
|
return perms
|
||||||
setAvatar(resp.avatar);
|
}
|
||||||
})
|
const permissions = generatePermissions()
|
||||||
.catch(_err => {});
|
|
||||||
}, [props.note, userAPI, user]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
loadPermissions();
|
|
||||||
}, [loadPermissions]);
|
|
||||||
|
|
||||||
const deleteMessage = () => {
|
const deleteMessage = () => {
|
||||||
|
if (!props.chat?.note?.settings) return
|
||||||
setAnchorEl(null);
|
setAnchorEl(null);
|
||||||
noteAPI
|
noteAPI
|
||||||
.removeNote(props.note.key())
|
.removeNote(props.chat.note.settings.key)
|
||||||
.then(_resp => {
|
.then(_resp => {
|
||||||
openSnack("Message Deleted");
|
openSnack("Message Deleted");
|
||||||
props.removeNoteMethod(props.index);
|
props.removeNoteMethod(props.index);
|
||||||
|
|
@ -123,54 +111,6 @@ export default function ChatMessage(props: Props) {
|
||||||
setDialog(false);
|
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 = () => {
|
const messageMenu = () => {
|
||||||
return (
|
return (
|
||||||
<Menu
|
<Menu
|
||||||
|
|
@ -236,28 +176,36 @@ export default function ChatMessage(props: Props) {
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid justifyContent={"center"}>
|
<Grid justifyContent={"center"}>
|
||||||
<Typography variant="caption" color="textSecondary">
|
<Typography variant="caption" color="textSecondary">
|
||||||
{moment(props.note.date())
|
{moment.unix(timestamp ? timestamp/1000: 0)
|
||||||
.tz(user.settings.timezone)
|
.tz(user.settings.timezone ? user.settings.timezone : "Canada/Central")
|
||||||
.format("MMMM Do YYYY, h:mm:ss a")}
|
.format("MMMM Do YYYY, h:mm:ss a")}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid size={{ xs: 12 }}>
|
<Grid size={{ xs: 12 }}>
|
||||||
<Typography variant="body2" whiteSpace={"pre-line"}>
|
<Typography variant="body2" whiteSpace={"pre-line"}>
|
||||||
{props.note.content()}
|
{props.chat.note?.settings?.content}
|
||||||
</Typography>
|
</Typography>
|
||||||
{/*load files and display attached images below the message */}
|
{/*load files and display attached images below the message */}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid padding={1}>
|
<Grid padding={1}>
|
||||||
{/* delete button */}
|
{/* delete button */}
|
||||||
{permissions.includes(pond.Permission.PERMISSION_WRITE) && (
|
{permissions.includes(pond.Permission.PERMISSION_WRITE) ? (
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={(event: React.MouseEvent<HTMLButtonElement>) =>
|
onClick={(event: React.MouseEvent<HTMLButtonElement>) =>
|
||||||
setAnchorEl(event.currentTarget)
|
setAnchorEl(event.currentTarget)
|
||||||
}>
|
}>
|
||||||
<MoreVert />
|
<MoreVert />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
) : (
|
||||||
|
// <span>
|
||||||
|
// <Tooltip title="No permissions to edit or delete" disableInteractive>
|
||||||
|
<IconButton disabled>
|
||||||
|
<MoreVert />
|
||||||
|
</IconButton>
|
||||||
|
// </Tooltip>
|
||||||
|
// </span>
|
||||||
)}
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import { useEffect, useRef } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
import ChatMessage from "./ChatMessage";
|
import ChatMessage from "./ChatMessage";
|
||||||
import { Box, Button } from "@mui/material";
|
import { Box, Button, ListItemButton } from "@mui/material";
|
||||||
|
|
||||||
import { Note } from "models";
|
// import { Note } from "models";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
messages: Note[];
|
messages: pond.Chat[];
|
||||||
attachmentMap?: Map<string, pond.FileReference[]>;
|
attachmentMap?: Map<string, pond.FileReference[]>;
|
||||||
totalMessages: number;
|
totalMessages: number;
|
||||||
scrollPos: number;
|
scrollPos: number;
|
||||||
|
|
@ -54,33 +54,31 @@ export default function ChatOutput(props: Props) {
|
||||||
let display = props.messages.map((curMessage, index) => (
|
let display = props.messages.map((curMessage, index) => (
|
||||||
<div key={index}>
|
<div key={index}>
|
||||||
<ChatMessage
|
<ChatMessage
|
||||||
note={curMessage}
|
chat={curMessage}
|
||||||
index={index}
|
index={index}
|
||||||
attachments={props.attachmentMap?.get(curMessage.key())}
|
// attachments={props.attachmentMap?.get(curMessage.note?.settings?.key)}
|
||||||
removeNoteMethod={props.removeNoteMethod}
|
removeNoteMethod={props.removeNoteMethod}
|
||||||
/>
|
/>
|
||||||
{props.scrollPos !== 0 && index === props.scrollPos && <ScrollTo />}
|
{/* {props.scrollPos !== 0 && index === props.scrollPos && <ScrollTo />} */}
|
||||||
|
<ScrollTo />
|
||||||
</div>
|
</div>
|
||||||
));
|
));
|
||||||
return display;
|
return display;
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box style={{
|
||||||
//height="85%"
|
|
||||||
// height="auto"
|
|
||||||
style={{
|
|
||||||
overflowY: "scroll",
|
overflowY: "scroll",
|
||||||
overflowX: "hidden",
|
overflowX: "hidden",
|
||||||
// borderRadius: "4px"
|
|
||||||
}}>
|
}}>
|
||||||
{props.messages.length < props.totalMessages && (
|
{props.messages.length < props.totalMessages && (
|
||||||
<div style={{ textAlign: "center" }}>
|
<ListItemButton onClick={seeMore} sx={{ justifyContent: "center"}}>
|
||||||
<Button onClick={seeMore}>See More</Button>
|
<Button >See More</Button>
|
||||||
</div>
|
</ListItemButton>
|
||||||
)}
|
)}
|
||||||
{displayMessages()}
|
{displayMessages()}
|
||||||
{props.scrollPos === 0 && <ScrollTo />}
|
{props.scrollPos === 0 && <ScrollTo />}
|
||||||
|
{/* <ScrollTo/> */}
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,15 @@ import ObjectUsers from "user/ObjectUsers";
|
||||||
import UserAvatar from "user/UserAvatar";
|
import UserAvatar from "user/UserAvatar";
|
||||||
import { or } from "utils/types";
|
import { or } from "utils/types";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme: Theme) => ({
|
interface StylesProps {
|
||||||
|
isMobile: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const useStyles = makeStyles<Theme, StylesProps>((theme: Theme) => {
|
||||||
|
// const isMobile = useMobile()
|
||||||
|
return ({
|
||||||
avatar: {
|
avatar: {
|
||||||
|
// margin: theme.spacing(2),
|
||||||
width: theme.spacing(4),
|
width: theme.spacing(4),
|
||||||
height: theme.spacing(4)
|
height: theme.spacing(4)
|
||||||
},
|
},
|
||||||
|
|
@ -30,7 +37,10 @@ const useStyles = makeStyles((theme: Theme) => ({
|
||||||
color: getSignatureAccentColour(),
|
color: getSignatureAccentColour(),
|
||||||
},
|
},
|
||||||
card: {
|
card: {
|
||||||
height: theme.spacing(72)
|
height: theme.spacing(72),
|
||||||
|
},
|
||||||
|
cardMobile: {
|
||||||
|
height: theme.spacing(48)
|
||||||
},
|
},
|
||||||
container: {
|
container: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
|
@ -53,13 +63,15 @@ const useStyles = makeStyles((theme: Theme) => ({
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
textOverflow: 'ellipsis',
|
textOverflow: 'ellipsis',
|
||||||
},
|
},
|
||||||
}));
|
});
|
||||||
|
});
|
||||||
|
|
||||||
export default function TeamPage() {
|
export default function TeamPage() {
|
||||||
const teamAPI = useTeamAPI();
|
const teamAPI = useTeamAPI();
|
||||||
const userAPI = useUserAPI();
|
const userAPI = useUserAPI();
|
||||||
const snackbar = useSnackbar()
|
const snackbar = useSnackbar()
|
||||||
const classes = useStyles();
|
const isMobile = useMobile();
|
||||||
|
const classes = useStyles({isMobile});
|
||||||
const { state } = useLocation();
|
const { state } = useLocation();
|
||||||
// const { teamID } = useParams<{ teamID: string }>() as { teamID: string };
|
// const { teamID } = useParams<{ teamID: string }>() as { teamID: string };
|
||||||
const { teamID } = useParams<{ teamID: string }>();
|
const { teamID } = useParams<{ teamID: string }>();
|
||||||
|
|
@ -71,7 +83,6 @@ export default function TeamPage() {
|
||||||
const [userDialog, setUserDialog] = useState(false)
|
const [userDialog, setUserDialog] = useState(false)
|
||||||
const teamKey = teamID ? teamID : "";
|
const teamKey = teamID ? teamID : "";
|
||||||
|
|
||||||
const isMobile = useMobile();
|
|
||||||
|
|
||||||
const getTeam = () => {
|
const getTeam = () => {
|
||||||
if (teamKey.length < 1) return
|
if (teamKey.length < 1) return
|
||||||
|
|
@ -119,7 +130,7 @@ export default function TeamPage() {
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (state.team) return
|
if (state && state.team) return
|
||||||
getTeam();
|
getTeam();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
@ -213,12 +224,12 @@ export default function TeamPage() {
|
||||||
/>
|
/>
|
||||||
<Grid2 container spacing={1}>
|
<Grid2 container spacing={1}>
|
||||||
<Grid2 size={{ xs: 12, sm: 6 }}>
|
<Grid2 size={{ xs: 12, sm: 6 }}>
|
||||||
<Card className={classes.card}>
|
<Card className={ isMobile ? classes.cardMobile : classes.card }>
|
||||||
<Chat objectKey={team.key()} />
|
<Chat objectKey={team.key()} />
|
||||||
</Card>
|
</Card>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<Grid2 size={{ xs: 12, sm: 6 }}>
|
<Grid2 size={{ xs: 12, sm: 6 }}>
|
||||||
<Card className={classes.card}>
|
<Card className={ isMobile ? classes.cardMobile : classes.card }>
|
||||||
|
|
||||||
</Card>
|
</Card>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,15 @@ export interface INoteAPIContext {
|
||||||
asRoot?: boolean,
|
asRoot?: boolean,
|
||||||
as?: string
|
as?: string
|
||||||
) => Promise<AxiosResponse<pond.ListNotesResponse>>;
|
) => Promise<AxiosResponse<pond.ListNotesResponse>>;
|
||||||
|
listChats: (
|
||||||
|
limit: number,
|
||||||
|
offset: number,
|
||||||
|
order?: "asc" | "desc",
|
||||||
|
orderBy?: string,
|
||||||
|
search?: string,
|
||||||
|
asRoot?: boolean,
|
||||||
|
as?: string
|
||||||
|
) => Promise<AxiosResponse<pond.ListChatsResponse>>;
|
||||||
removeNote: (noteID: string) => Promise<AxiosResponse<pond.RemoveBinResponse>>;
|
removeNote: (noteID: string) => Promise<AxiosResponse<pond.RemoveBinResponse>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,12 +81,38 @@ export default function NoteProvider(props: PropsWithChildren<Props>) {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const listChats = (
|
||||||
|
limit: number,
|
||||||
|
offset: number,
|
||||||
|
order?: "asc" | "desc",
|
||||||
|
orderBy?: string,
|
||||||
|
search?: string,
|
||||||
|
asRoot?: boolean,
|
||||||
|
as?: string
|
||||||
|
) => {
|
||||||
|
return get<pond.ListChatsResponse>(
|
||||||
|
pondURL(
|
||||||
|
"/chats" +
|
||||||
|
"?limit=" +
|
||||||
|
limit +
|
||||||
|
"&offset=" +
|
||||||
|
offset +
|
||||||
|
("&order=" + (order ? order : "asc")) +
|
||||||
|
("&by=" + (orderBy ? orderBy : "key")) +
|
||||||
|
(search ? "&search=" + search : "") +
|
||||||
|
(asRoot ? "&asRoot=" + asRoot.toString() : "") +
|
||||||
|
(as ? "&as=" + as : "")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NoteAPIContext.Provider
|
<NoteAPIContext.Provider
|
||||||
value={{
|
value={{
|
||||||
addNote,
|
addNote,
|
||||||
getNote,
|
getNote,
|
||||||
updateNote,
|
updateNote,
|
||||||
|
listChats,
|
||||||
listNotes,
|
listNotes,
|
||||||
removeNote
|
removeNote
|
||||||
}}>
|
}}>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue