- 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:
@@ -1,120 +1,116 @@
|
|||||||
import {Badge, List, Space, Tag} from "antd";
|
import {Badge, Card, List, Space, Tag} from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { connect } from "react-redux";
|
import {connect} from "react-redux";
|
||||||
import {
|
import {AutoSizer, CellMeasurer, CellMeasurerCache, List as VirtualizedList,} from "react-virtualized";
|
||||||
AutoSizer,
|
import {createStructuredSelector} from "reselect";
|
||||||
CellMeasurer,
|
import {setSelectedConversation} from "../../redux/messaging/messaging.actions";
|
||||||
CellMeasurerCache,
|
import {selectSelectedConversation} from "../../redux/messaging/messaging.selectors";
|
||||||
List as VirtualizedList,
|
import {TimeAgoFormatter} from "../../utils/DateFormatter";
|
||||||
} 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 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";
|
import "./chat-conversation-list.styles.scss";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
selectedConversation: selectSelectedConversation,
|
selectedConversation: selectSelectedConversation,
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
setSelectedConversation: (conversationId) =>
|
setSelectedConversation: (conversationId) =>
|
||||||
dispatch(setSelectedConversation(conversationId)),
|
dispatch(setSelectedConversation(conversationId)),
|
||||||
});
|
});
|
||||||
|
|
||||||
function ChatConversationListComponent({
|
function ChatConversationListComponent({
|
||||||
conversationList,
|
conversationList,
|
||||||
selectedConversation,
|
selectedConversation,
|
||||||
setSelectedConversation,
|
setSelectedConversation,
|
||||||
loadMoreConversations,
|
loadMoreConversations,
|
||||||
}) {
|
}) {
|
||||||
const cache = new CellMeasurerCache({
|
const cache = new CellMeasurerCache({
|
||||||
fixedWidth: true,
|
fixedWidth: true,
|
||||||
defaultHeight: 60,
|
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 (
|
return (
|
||||||
<CellMeasurer
|
<div className="chat-list-container">
|
||||||
key={key}
|
<AutoSizer>
|
||||||
cache={cache}
|
{({height, width}) => (
|
||||||
parent={parent}
|
<VirtualizedList
|
||||||
columnIndex={0}
|
height={height}
|
||||||
rowIndex={index}
|
width={width}
|
||||||
>
|
rowCount={conversationList.length}
|
||||||
<List.Item
|
rowHeight={cache.rowHeight}
|
||||||
onClick={() => setSelectedConversation(item.id)}
|
rowRenderer={rowRenderer}
|
||||||
style={style}
|
onScroll={({scrollTop, scrollHeight, clientHeight}) => {
|
||||||
className={`chat-list-item
|
if (scrollTop + clientHeight === scrollHeight) {
|
||||||
${
|
loadMoreConversations();
|
||||||
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>
|
|
||||||
)}
|
)}
|
||||||
</Space>
|
</AutoSizer>
|
||||||
<Space direction="vertical">
|
</div>
|
||||||
<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>
|
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
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(
|
export default connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
mapDispatchToProps
|
mapDispatchToProps
|
||||||
)(ChatConversationListComponent);
|
)(ChatConversationListComponent);
|
||||||
|
|||||||
@@ -7,10 +7,11 @@
|
|||||||
border: 1px solid gainsboro;
|
border: 1px solid gainsboro;
|
||||||
}
|
}
|
||||||
.chat-list-item {
|
.chat-list-item {
|
||||||
|
.ant-card-head {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
&:hover {
|
&:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: #ff7a00;
|
color: #ff7a00;
|
||||||
}
|
}
|
||||||
|
|
||||||
border-bottom: 1px solid gainsboro;
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user