Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | import { ListItemAvatar, ListItemButton, ListItemProps, ListItemText, Skeleton, } from "@mui/material"; import makeStyles from "@mui/styles/makeStyles"; import Avatar from "components/Avatar"; import { MuteIcon } from "components/Icons"; import { useAuthContext } from "features/auth/AuthProvider"; import { controlMessage, groupChatTitleText, isControlMessage, messageTargetId, } from "features/messages/utils"; import { useLiteUsers } from "features/userQueries/useLiteUsers"; import { useTranslation } from "i18n"; import { MESSAGES } from "i18n/namespaces"; import { GroupChat } from "proto/conversations_pb"; import React from "react"; import { firstName } from "utils/names"; const useStyles = makeStyles((theme) => ({ titlePadding: { marginInlineEnd: theme.spacing(1) }, muteIcon: { verticalAlign: "middle" }, unread: { fontWeight: "bold" }, })); export interface GroupChatListItemProps extends ListItemProps { groupChat: GroupChat.AsObject; } export default function GroupChatListItem({ groupChat, className, }: GroupChatListItemProps) { const { t } = useTranslation(MESSAGES); const classes = useStyles(); const currentUserId = useAuthContext().authState.userId!; const latestMessageAuthorId = groupChat.latestMessage?.authorUserId; const isUnreadClass = groupChat.lastSeenMessageId !== groupChat.latestMessage?.messageId ? classes.unread : ""; //It is possible the last message is sent by someone who has left //so include it just in case const groupChatMembersQuery = useLiteUsers([ ...groupChat.memberUserIdsList, latestMessageAuthorId, ]); //the avatar is of the latest message author (if it's not the logged in user), //otherwise any user that's not the logged in user, otherwise logged in user const avatarUserId = latestMessageAuthorId !== null && latestMessageAuthorId !== currentUserId ? latestMessageAuthorId : groupChat.memberUserIdsList.find((id) => id !== currentUserId) ?? currentUserId; //title is the chat title, or all the member's names except current user joined together const title = groupChatTitleText( groupChat, groupChatMembersQuery, currentUserId ); //text is the control message text or message text let text = ""; const authorName = firstName( groupChatMembersQuery.data?.get(groupChat.latestMessage?.authorUserId)?.name ); if (groupChat.latestMessage && isControlMessage(groupChat.latestMessage)) { const targetName = firstName( groupChatMembersQuery.data?.get(messageTargetId(groupChat.latestMessage)) ?.name ); text = controlMessage({ user: authorName, target_user: targetName, t, message: groupChat.latestMessage, }); } else { text = `${authorName}: ${groupChat.latestMessage?.text?.text || ""}`; } return ( <ListItemButton className={className}> <ListItemAvatar> {groupChatMembersQuery.isLoading ? ( <Skeleton /> ) : ( <Avatar user={groupChatMembersQuery.data?.get(avatarUserId)} isProfileLink={false} /> )} </ListItemAvatar> { //When we want more than primary and secondary (host Request status, etc) //They can also take react nodes. But change typography component using props } <ListItemText primary={ groupChatMembersQuery.isLoading ? ( <Skeleton /> ) : ( <> <span className={classes.titlePadding}>{title}</span> {groupChat.muteInfo?.muted && ( <MuteIcon className={classes.muteIcon} /> )} </> ) } secondary={groupChatMembersQuery.isLoading ? <Skeleton /> : text} primaryTypographyProps={{ noWrap: true, className: isUnreadClass }} secondaryTypographyProps={{ noWrap: true, className: isUnreadClass }} /> </ListItemButton> ); } |