Skip to content

Commit

Permalink
Load previous conversations within main conversation UI (#569)
Browse files Browse the repository at this point in the history
* First pass at refactoring conversations dashboard UI (WIP)

* Remove unused code

* Remove unused async

* Add ability to load previous conversation in conversation UI
  • Loading branch information
reichert621 authored Feb 12, 2021
1 parent f21099e commit 7f1f1f2
Show file tree
Hide file tree
Showing 12 changed files with 562 additions and 266 deletions.
8 changes: 8 additions & 0 deletions assets/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ body {
color: #fff;
}

.Button--faded {
opacity: 0.6;
}

.Button--faded:hover {
opacity: 1;
}

/* Mimic behavior of antd "text"-type Button */
a.RelatedCustomerConversation--link {
display: block;
Expand Down
15 changes: 6 additions & 9 deletions assets/src/components/conversations/AllConversations.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,31 @@
import React from 'react';
import {useConversations} from './ConversationsProvider';
import ConversationsContainer from './ConversationsContainer';
import ConversationsDashboard from './ConversationsDashboard';

const AllConversations = () => {
const {
loading,
currentUser,
account,
isNewUser,
all = [],
conversationsById = {},
messagesByConversation = {},
currentlyOnline = {},
fetchAllConversations,
onSelectConversation,
onUpdateConversation,
onDeleteConversation,
onSendMessage,
} = useConversations();

if (!currentUser) {
return null;
}

return (
<ConversationsContainer
<ConversationsDashboard
loading={loading}
title="All conversations"
account={account}
currentUser={currentUser}
currentlyOnline={currentlyOnline}
showGetStarted={isNewUser}
conversationIds={all}
conversationsById={conversationsById}
messagesByConversation={messagesByConversation}
fetch={fetchAllConversations}
onSelectConversation={onSelectConversation}
Expand Down
15 changes: 6 additions & 9 deletions assets/src/components/conversations/ClosedConversations.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import React from 'react';
import ConversationsContainer from './ConversationsContainer';
import ConversationsDashboard from './ConversationsDashboard';
import {useConversations} from './ConversationsProvider';

const ClosedConversations = () => {
const {
loading,
currentUser,
account,
isNewUser,
closed = [],
conversationsById = {},
messagesByConversation = {},
currentlyOnline = {},
fetchAllConversations,
fetchClosedConversations,
onSelectConversation,
Expand All @@ -29,16 +26,16 @@ const ClosedConversations = () => {
return results;
};

if (!currentUser) {
return null;
}

return (
<ConversationsContainer
<ConversationsDashboard
loading={loading}
title="Closed"
account={account}
currentUser={currentUser}
currentlyOnline={currentlyOnline}
showGetStarted={isNewUser}
conversationIds={closed}
conversationsById={conversationsById}
messagesByConversation={messagesByConversation}
fetch={fetch}
onSelectConversation={onSelectConversation}
Expand Down
180 changes: 180 additions & 0 deletions assets/src/components/conversations/ConversationContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import React from 'react';
import {Box, Flex} from 'theme-ui';
import {Conversation, Message} from '../../types';
import * as API from '../../api';
import {useConversations} from './ConversationsProvider';
import ConversationHeader from './ConversationHeader';
import ConversationMessages from './ConversationMessages';
import ConversationFooter from './ConversationFooter';
import ConversationDetailsSidebar from './ConversationDetailsSidebar';
import logger from '../../logger';

const ConversationContainer = ({
loading,
selectedConversationId,
isClosing,
setScrollRef,
onAssignUser,
onMarkPriority,
onRemovePriority,
onCloseConversation,
onReopenConversation,
onDeleteConversation,
onSendMessage,
}: {
loading: boolean;
selectedConversationId: string | null;
isClosing: boolean;
// TODO: handle scrolling within this component?
setScrollRef: (el: any) => void;
onAssignUser: (conversationId: string, userId: string) => void;
onMarkPriority: (conversationId: string) => void;
onRemovePriority: (conversationId: string) => void;
onCloseConversation: (conversationId: string) => void;
onReopenConversation: (conversationId: string) => void;
onDeleteConversation: (conversationId: string) => void;
onSendMessage: (message: Partial<Message>) => void;
}) => {
// TODO: handle loading better?
const {
currentUser,
account,
conversationsById,
messagesByConversation,
isNewUser,
isCustomerOnline,
} = useConversations();
const [history, setConversationHistory] = React.useState<Array<Conversation>>(
[]
);
const [
isLoadingPreviousConversation,
setLoadingPreviousConversation,
] = React.useState(false);
const [
hasPreviousConversations,
setHasPreviousConversations,
] = React.useState(false);

React.useEffect(() => {
setConversationHistory([]);
setLoadingPreviousConversation(false);
setHasPreviousConversations(false);

if (!selectedConversationId) {
return;
}

API.fetchPreviousConversation(selectedConversationId)
.then((conversation) => setHasPreviousConversations(!!conversation))
.catch((err) =>
logger.error('Error retrieving previous conversation:', err)
);
}, [selectedConversationId]);

const users = (account && account.users) || [];
const messages = selectedConversationId
? messagesByConversation[selectedConversationId]
: [];
const conversation = selectedConversationId
? conversationsById[selectedConversationId]
: null;
const customer = conversation ? conversation.customer : null;
const isOnline = customer ? isCustomerOnline(customer.id) : false;

const fetchPreviousConversation = async (conversationId: string) => {
if (!selectedConversationId) {
return;
}

setLoadingPreviousConversation(true);

API.fetchPreviousConversation(conversationId)
.then((conversation) => {
const previousConversationId = conversation && conversation.id;

if (previousConversationId) {
setConversationHistory([conversation, ...history]);

return API.fetchPreviousConversation(previousConversationId);
}

return null;
})
.then((conversation) => setHasPreviousConversations(!!conversation))
.catch((err) =>
logger.error('Error retrieving previous conversation:', err)
)
.finally(() => setLoadingPreviousConversation(false));
};

return (
<>
<ConversationHeader
conversation={conversation}
users={users}
onAssignUser={onAssignUser}
onMarkPriority={onMarkPriority}
onRemovePriority={onRemovePriority}
onCloseConversation={onCloseConversation}
onReopenConversation={onReopenConversation}
onDeleteConversation={onDeleteConversation}
/>
<Flex
sx={{
position: 'relative',
flex: 1,
flexDirection: 'column',
minHeight: 0,
minWidth: 640,
pr: 240, // TODO: animate this if we make it toggle-able
}}
>
<ConversationMessages
conversationId={selectedConversationId}
messages={messages}
history={history}
currentUser={currentUser}
loading={loading}
isClosing={isClosing}
isLoadingPreviousConversation={isLoadingPreviousConversation}
hasPreviousConversations={hasPreviousConversations}
// TODO: move "Getting started" UI out of this component
showGetStarted={isNewUser}
setScrollRef={setScrollRef}
onLoadPreviousConversation={fetchPreviousConversation}
/>

{conversation && (
// NB: the `key` forces a rerender so the input can clear
// any text from the last conversation and trigger autofocus
<ConversationFooter
key={conversation.id}
onSendMessage={onSendMessage}
currentUser={currentUser}
/>
)}

{customer && conversation && (
<Box
sx={{
width: 240,
height: '100%',
overflowY: 'scroll',
position: 'absolute',
right: 0,
}}
>
<ConversationDetailsSidebar
customer={customer}
isOnline={isOnline}
conversation={conversation}
/>
</Box>
)}
</Flex>
</>
);
};

export default ConversationContainer;
Loading

0 comments on commit 7f1f1f2

Please sign in to comment.