Skip to content
This repository has been archived by the owner on Jul 25, 2023. It is now read-only.

Commit

Permalink
Merge pull request #7 from OnrampLab/issue-6-lazy-loading-conversations
Browse files Browse the repository at this point in the history
Issue 6 lazy loading conversations
  • Loading branch information
kenpingshu authored Nov 15, 2019
2 parents 39512c8 + 6aa2b49 commit 50bfb45
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 89 deletions.
170 changes: 96 additions & 74 deletions src/modules/conversations/components/ConversationsSidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,93 +1,115 @@
import React, { useState } from 'react';
import React, { useContext, useState } from 'react';
import { Drawer, Layout, List, Menu } from 'antd';
import { useSelector } from 'react-redux';
import { CheckCircle, Heart, RefreshCcw, Star } from 'react-feather';
import distanceInWordsToNow from 'date-fns/distance_in_words_to_now';
import { LeadAvatar } from '@onr/conversations';
import {
LeadAvatar,
ConversationsService,
ConversationsMainPageConsumer,
} from '@onr/conversations';
import ConversationsMainPageContext from '@onr/conversations/pages/ConversationsMainPageContext';

const { Sider } = Layout;

interface ConversationsSidebarProps {
conversationsData: any;
onConversationSelected: any;
}

export const ConversationsSidebar: React.FC<ConversationsSidebarProps> = ({
conversationsData,
onConversationSelected,
}: ConversationsSidebarProps) => {
export const ConversationsSidebar: React.FC = () => {
const isMobile = useSelector((store: any) => store.wrapper.mobile);
const [messages, setMessages] = useState(false);
const [selectedIndex, setSelectedIndex] = useState(0);
const { setSelectedIndex, conversationsResponse, setConversationsResponse } = useContext(
ConversationsMainPageContext,
);

const changeIndex = (index: number) => {
setSelectedIndex(index);
onConversationSelected(index);
};
const onListScroll = async e => {
const element = e.target;
if (element.scrollHeight - element.scrollTop === element.clientHeight) {
const nextPageResponse = await ConversationsService.getConversations({
campaignId: '1',
params: {
page: conversationsResponse.meta.current_page + 1,
},
});
nextPageResponse.data = conversationsResponse.data.concat(nextPageResponse.data);
setConversationsResponse(nextPageResponse);
}
};
const conversations = (
<div
css={`
display: flex;
flex: 1;
flex-direction: column;
height: 100%;
overflow: hidden;
border-right: 1px solid rgba(0, 0, 0, 0.05);
`}
>
<Menu mode="horizontal" className="border-0 m-auto">
<Menu.Item key="read">
<a href="javascript:;">
<CheckCircle size={20} strokeWidth={1} />
</a>
</Menu.Item>
<Menu.Item key="favorite">
<a href="javascript:;">
<Heart size={20} strokeWidth={1} />
</a>
</Menu.Item>
<Menu.Item key="star">
<a href="javascript:;">
<Star size={20} strokeWidth={1} />
</a>
</Menu.Item>
<Menu.Item key="refresh">
<a href="javascript:;">
<RefreshCcw size={20} strokeWidth={1} />
</a>
</Menu.Item>
</Menu>
<List
className="scroll-y flex-1 bg-transparent px-3 py-1"
dataSource={conversationsData}
itemLayout="horizontal"
renderItem={(item, index) => (
<List.Item
onClick={changeIndex.bind(null, index)}
style={{
backgroundColor: selectedIndex === index ? '#e6f7ff' : '',
}}
className={`${selectedIndex === index ? '' : 'border-0'} rounded border-0 p-3`}
<ConversationsMainPageConsumer>
{({ selectedIndex, conversationsResponse }) => {
return (
<div
css={`
display: flex;
flex: 1;
flex-direction: column;
height: 100%;
overflow: hidden;
border-right: 1px solid rgba(0, 0, 0, 0.05);
`}
>
<List.Item.Meta
avatar={<LeadAvatar name={item.lead.phone} />}
title={
<small
css={`
display: flex;
width: 100%;
`}
<Menu mode="horizontal" className="border-0 m-auto">
<Menu.Item key="read">
<a href="javascript:;">
<CheckCircle size={20} strokeWidth={1} />
</a>
</Menu.Item>
<Menu.Item key="favorite">
<a href="javascript:;">
<Heart size={20} strokeWidth={1} />
</a>
</Menu.Item>
<Menu.Item key="star">
<a href="javascript:;">
<Star size={20} strokeWidth={1} />
</a>
</Menu.Item>
<Menu.Item key="refresh">
<a href="javascript:;">
<RefreshCcw size={20} strokeWidth={1} />
</a>
</Menu.Item>
</Menu>
<List
className="scroll-y flex-1 bg-transparent px-3 py-1"
dataSource={conversationsResponse.data}
itemLayout="horizontal"
onScroll={onListScroll}
renderItem={(item, index) => (
<List.Item
onClick={changeIndex.bind(null, index)}
style={{
backgroundColor: selectedIndex === index ? '#e6f7ff' : '',
}}
className={`${selectedIndex === index ? '' : 'border-0'} rounded border-0 p-3`}
>
<span>{item.lead.phone}</span>
<span className="mr-auto" />
<span>{item.latest_message && distanceInWordsToNow(new Date(item.latest_message.created_at))}</span>
</small>
}
description={item.latest_message && item.latest_message.content}
<List.Item.Meta
avatar={<LeadAvatar name={item.lead.phone} />}
title={
<small
css={`
display: flex;
width: 100%;
`}
>
<span>{item.lead.phone}</span>
<span className="mr-auto" />
<span>
{item.latest_message &&
distanceInWordsToNow(new Date(item.latest_message.created_at))}
</span>
</small>
}
description={item.latest_message && item.latest_message.content}
/>
</List.Item>
)}
/>
</List.Item>
)}
/>
</div>
</div>
);
}}
</ConversationsMainPageConsumer>
);
return (
<>
Expand Down
35 changes: 20 additions & 15 deletions src/modules/conversations/pages/ConversationsMainPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,41 @@ import {
ConversationsService,
} from '@onr/conversations';

import { ConversationsMainPageProvider } from './ConversationsMainPageContext';

const ConversationsComponent: React.FC = () => {
const [selectedIndex, setSelectedIndex] = useState(0);
const [conversationsData, setConversationsData] = useState([]);
const [conversationsResponse, setConversationsResponse] = useState({ data: [], meta: {} });
const fetchConversations = async (campaignId: string) => {
const response = await ConversationsService.getConversations({ campaignId });
return response;
};
const onConversationSelected = (index: number) => {
setSelectedIndex(index);
};

useEffect(() => {
(async function() {
const conversationsResponse = await fetchConversations('1');
setConversationsData(conversationsResponse.data);
setConversationsResponse(conversationsResponse);
})();
}, []);

return (
<>
<Layout className="fill-workspace rounded shadow-sm overflow-hidden">
<FilterSidebar />
<ConversationsSidebar
conversationsData={conversationsData}
onConversationSelected={onConversationSelected}
/>
{conversationsData[selectedIndex] && (
<ChatRoom conversation={conversationsData[selectedIndex]} />
)}
</Layout>
<ConversationsMainPageProvider
value={{
selectedIndex: selectedIndex,
setSelectedIndex: setSelectedIndex,
conversationsResponse: conversationsResponse,
setConversationsResponse: setConversationsResponse,
}}
>
<Layout className="fill-workspace rounded shadow-sm overflow-hidden">
<FilterSidebar />
<ConversationsSidebar />
{conversationsResponse.data[selectedIndex] && (
<ChatRoom conversation={conversationsResponse.data[selectedIndex]} />
)}
</Layout>
</ConversationsMainPageProvider>
</>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from 'react';

const ConversationsMainPageContext = React.createContext({});

export const ConversationsMainPageProvider = ConversationsMainPageContext.Provider;
export const ConversationsMainPageConsumer = ConversationsMainPageContext.Consumer;
export default ConversationsMainPageContext;
1 change: 1 addition & 0 deletions src/modules/conversations/pages/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './ConversationsMainPage';
export * from './ConversationsMainPageContext';

0 comments on commit 50bfb45

Please sign in to comment.