- Update the look and feel of the chat message list (prevents breaking when zoomed in and out like previous implementation)

Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
Dave Richer
2024-01-16 14:02:54 -05:00
parent 0d0f24802f
commit b6b445dc21
2 changed files with 101 additions and 104 deletions

View File

@@ -1,120 +1,116 @@
import {Badge, List, Space, Tag} from "antd";
import {Badge, Card, List, Space, Tag} from "antd";
import React from "react";
import { connect } from "react-redux";
import {
AutoSizer,
CellMeasurer,
CellMeasurerCache,
List as VirtualizedList,
} from "react-virtualized";
import { createStructuredSelector } from "reselect";
import { setSelectedConversation } from "../../redux/messaging/messaging.actions";
import { selectSelectedConversation } from "../../redux/messaging/messaging.selectors";
import { TimeAgoFormatter } from "../../utils/DateFormatter";
import {connect} from "react-redux";
import {AutoSizer, CellMeasurer, CellMeasurerCache, List as VirtualizedList,} from "react-virtualized";
import {createStructuredSelector} from "reselect";
import {setSelectedConversation} from "../../redux/messaging/messaging.actions";
import {selectSelectedConversation} from "../../redux/messaging/messaging.selectors";
import {TimeAgoFormatter} from "../../utils/DateFormatter";
import PhoneFormatter from "../../utils/PhoneFormatter";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
import OwnerNameDisplay, {OwnerNameDisplayFunction} from "../owner-name-display/owner-name-display.component";
import _ from "lodash";
import "./chat-conversation-list.styles.scss";
const mapStateToProps = createStructuredSelector({
selectedConversation: selectSelectedConversation,
selectedConversation: selectSelectedConversation,
});
const mapDispatchToProps = (dispatch) => ({
setSelectedConversation: (conversationId) =>
dispatch(setSelectedConversation(conversationId)),
setSelectedConversation: (conversationId) =>
dispatch(setSelectedConversation(conversationId)),
});
function ChatConversationListComponent({
conversationList,
selectedConversation,
setSelectedConversation,
loadMoreConversations,
}) {
const cache = new CellMeasurerCache({
fixedWidth: true,
defaultHeight: 60,
});
conversationList,
selectedConversation,
setSelectedConversation,
loadMoreConversations,
}) {
const cache = new CellMeasurerCache({
fixedWidth: true,
defaultHeight: 60,
});
const rowRenderer = ({index, key, style, parent}) => {
const item = conversationList[index];
const cardContentRight =
<TimeAgoFormatter>{item.updated_at}</TimeAgoFormatter>;
const cardContentLeft = item.job_conversations.length > 0
? item.job_conversations.map((j, idx) => (
<Tag key={idx}>{j.job.ro_number}</Tag>
))
: null;
const names = <>{_.uniq(item.job_conversations.map((j, idx) =>
OwnerNameDisplayFunction(j.job)
))}</>
const cardTitle = <>
{item.label && <Tag color="blue">{item.label}</Tag>}
{item.job_conversations.length > 0 ? (
<Space direction="vertical">
{names}
</Space>
) : (
<Space>
<PhoneFormatter>{item.phone_num}</PhoneFormatter>
</Space>
)}
</>
const cardExtra = <Badge count={item.messages_aggregate.aggregate.count || 0}/>
const cardStyle = index % 2 === 0 ? {backgroundColor: '#f0f2f5'} : {backgroundColor: '#ffffff'};
return (
<CellMeasurer
key={key}
cache={cache}
parent={parent}
columnIndex={0}
rowIndex={index}
>
<List.Item
onClick={() => setSelectedConversation(item.id)}
style={style}
className={`chat-list-item
${
item.id === selectedConversation
? "chat-list-selected-conversation"
: null
}`}
>
<Card style={cardStyle} bordered={false} size="small" extra={cardExtra} title={cardTitle}>
<div style={{display: 'inline-block', width: '70%', textAlign: 'left'}}>
{cardContentLeft}
</div>
<div style={{display: 'inline-block',width: '30%', textAlign: 'right'}}>{cardContentRight}</div>
</Card>
</List.Item>
</CellMeasurer>
);
};
const rowRenderer = ({ index, key, style, parent }) => {
const item = conversationList[index];
return (
<CellMeasurer
key={key}
cache={cache}
parent={parent}
columnIndex={0}
rowIndex={index}
>
<List.Item
onClick={() => setSelectedConversation(item.id)}
style={style}
className={`chat-list-item
${
item.id === selectedConversation
? "chat-list-selected-conversation"
: null
}`}
>
<Space style={{padding: '12px 24px'}} size={"large"}>
<Space>
{item.label && <Space>{item.label}</Space>}
{item.job_conversations.length > 0 ? (
<Space direction="vertical">
{item.job_conversations.map((j, idx) => (
<OwnerNameDisplay key={idx} ownerObject={j.job} />
))}
</Space>
) : (
<Space>
<PhoneFormatter>{item.phone_num}</PhoneFormatter>
</Space>
<div className="chat-list-container">
<AutoSizer>
{({height, width}) => (
<VirtualizedList
height={height}
width={width}
rowCount={conversationList.length}
rowHeight={cache.rowHeight}
rowRenderer={rowRenderer}
onScroll={({scrollTop, scrollHeight, clientHeight}) => {
if (scrollTop + clientHeight === scrollHeight) {
loadMoreConversations();
}
}}
/>
)}
</Space>
<Space direction="vertical">
<Space>
{item.job_conversations.length > 0
? item.job_conversations.map((j, idx) => (
<Tag key={idx}>{j.job.ro_number}</Tag>
))
: null}
</Space>
<Space>
<TimeAgoFormatter>{item.updated_at}</TimeAgoFormatter>
</Space>
</Space>
<Space>
<Badge count={item.messages_aggregate.aggregate.count || 0} />
</Space>
</Space>
</List.Item>
</CellMeasurer>
</AutoSizer>
</div>
);
};
return (
<div className="chat-list-container">
<AutoSizer>
{({ height, width }) => (
<VirtualizedList
height={height}
width={width}
rowCount={conversationList.length}
rowHeight={cache.rowHeight}
rowRenderer={rowRenderer}
onScroll={({ scrollTop, scrollHeight, clientHeight }) => {
if (scrollTop + clientHeight === scrollHeight) {
loadMoreConversations();
}
}}
/>
)}
</AutoSizer>
</div>
);
}
export default connect(
mapStateToProps,
mapDispatchToProps
mapStateToProps,
mapDispatchToProps
)(ChatConversationListComponent);