Fix support messaging

This commit is contained in:
Hazem Krimi
2023-05-23 20:44:31 +01:00
parent 055ad3a61e
commit 032137e004
10 changed files with 259 additions and 193 deletions
+2 -2
View File
@@ -136,7 +136,7 @@ const App = () => {
}
/>
<Route
path='/support/:project'
path='/support/:projectId'
element={
<Protected>
<Support />
@@ -144,7 +144,7 @@ const App = () => {
}
/>
<Route
path='/support/:project/:id'
path='/support/:projectId/:threadId'
element={
<Protected>
<Support />
+7 -11
View File
@@ -7,7 +7,7 @@ import { Wrapper } from './styles';
import {
GetProjectThreadsQuery,
GetProjectThreadsQueryVariables,
ThreadObject,
Support,
} from '../../graphql/types.support';
import { GET_PROJECT_THREADS } from '../../graphql/chat.api.support';
import { Add, Empty } from '../../assets';
@@ -21,7 +21,7 @@ const MessagingSidebar = ({ onClose }: MessagingSidebarProps) => {
const role = useReactiveVar(roleVar);
const location = useLocation();
const navigate = useNavigate();
const [projectThreads, setProjectThreads] = useState<Array<ThreadObject>>();
const [projectThreads, setProjectThreads] = useState<Array<Support>>();
useEffect(() => {
(async () => {
@@ -32,15 +32,13 @@ const MessagingSidebar = ({ onClose }: MessagingSidebarProps) => {
>({
query: GET_PROJECT_THREADS,
variables: {
projectId: location.pathname.split('/')[2]!,
projectId: location.pathname.split('/')[2] as string,
},
fetchPolicy: 'network-only',
});
setProjectThreads(threads?.data?.getProjectThreads!);
setProjectThreads(threads?.data?.threads!);
}
})();
// eslint-disable-next-line
}, [location.pathname]);
return (
@@ -55,7 +53,7 @@ const MessagingSidebar = ({ onClose }: MessagingSidebarProps) => {
>
<Box flexGrow='1'>
<Text variant='title' weight='bold' color='white'>
Messaging Support
Support
</Text>
</Box>
<Button
@@ -65,7 +63,7 @@ const MessagingSidebar = ({ onClose }: MessagingSidebarProps) => {
iconLeft={<Add />}
onClick={() => {
onClose();
navigate(`/support-messaging/${location.pathname.split('/')[2]}`);
navigate(`/support/${location.pathname.split('/')[2]}`);
}}
/>
</Box>
@@ -86,9 +84,7 @@ const MessagingSidebar = ({ onClose }: MessagingSidebarProps) => {
onClick={() => {
onClose();
navigate(
`/support-messaging/${location.pathname.split('/')[2]}/${
thread.id
}`
`/support/${location.pathname.split('/')[2]}/${thread.id}`
);
}}
>
+13 -9
View File
@@ -2,11 +2,12 @@ import gql from 'graphql-tag';
export const GET_PROJECT_THREADS = gql`
query GetProjectThreads($projectId: String!) {
getProjectThreads(projectId: $projectId) {
threads(projectId: $projectId) {
id
title
threadDescription
userMessages {
id
username
text
}
@@ -16,11 +17,12 @@ export const GET_PROJECT_THREADS = gql`
export const GET_THREAD_BY_ID = gql`
query GetThreadById($threadId: String!) {
getThreadById(threadId: $threadId) {
thread(threadId: $threadId) {
id
title
threadDescription
userMessages {
id
username
text
}
@@ -47,22 +49,24 @@ export const CREATE_THREAD = gql`
projectId: $projectId
title: $title
threadDescription: $threadDescription
)
) {
id
}
}
`;
export const SEND_MSG = gql`
mutation SendMsg($threadId: String!, $username: String!, $msg: String!) {
sendMsg(threadId: $threadId, username: $username, msg: $msg)
mutation SendMessage($threadId: String!, $username: String!, $text: String!) {
sendMessage(threadId: $threadId, username: $username, text: $text)
}
`;
export const CONNECT_STREAM = gql`
subscription ConnectStream($mutationType: MutationType) {
connectStream(mutationType: $mutationType) {
export const MESSAGES_SUBSCRIPTION = gql`
subscription messagesSubscription {
messages {
mutationType
id
userMessage {
userMessages {
id
username
text
+53 -57
View File
@@ -1,4 +1,6 @@
/* eslint-disable */
export type Maybe<T> = T | null;
export type InputMaybe<T> = Maybe<T>;
export type Exact<T extends { [key: string]: unknown }> = {
[K in keyof T]: T[K];
};
@@ -19,80 +21,78 @@ export type Scalars = {
export type MutationRoot = {
__typename?: 'MutationRoot';
createThread: Scalars['ID'];
deleteThread: ThreadObject;
sendMsg: Scalars['ID'];
createThread: Support;
deleteThread?: Maybe<Support>;
sendMessage: Scalars['ID'];
};
export type MutationRootCreateThreadArgs = {
projectId: Scalars['String'];
title: Scalars['String'];
threadDescription: Scalars['String'];
title: Scalars['String'];
};
export type MutationRootDeleteThreadArgs = {
threadId: Scalars['String'];
};
export type MutationRootSendMsgArgs = {
export type MutationRootSendMessageArgs = {
text: Scalars['String'];
threadId: Scalars['String'];
username: Scalars['String'];
msg: Scalars['String'];
};
export type MutationType = 'CREATED';
export enum MutationType {
Created = 'CREATED',
}
export type QueryRoot = {
__typename?: 'QueryRoot';
messages: Array<UserMessage>;
getProjectThreads: Array<ThreadObject>;
getThreadById: ThreadObject;
messages?: Maybe<Array<UserMessages>>;
thread?: Maybe<Support>;
threads?: Maybe<Array<Support>>;
};
export type QueryRootMessagesArgs = {
threadId: Scalars['String'];
threadId: Scalars['ID'];
};
export type QueryRootGetProjectThreadsArgs = {
projectId: Scalars['String'];
export type QueryRootThreadArgs = {
threadId: Scalars['ID'];
};
export type QueryRootGetThreadByIdArgs = {
threadId: Scalars['String'];
export type QueryRootThreadsArgs = {
projectId: Scalars['ID'];
};
export type StreamChanged = {
__typename?: 'StreamChanged';
mutationType: MutationType;
id: Scalars['ID'];
userMessage?: Maybe<UserMessageObject>;
mutationType: MutationType;
userMessages?: Maybe<UserMessages>;
};
export type SubscriptionRoot = {
__typename?: 'SubscriptionRoot';
connectStream: StreamChanged;
interval: Scalars['Int'];
messages: StreamChanged;
};
export type SubscriptionRootConnectStreamArgs = {
mutationType?: Maybe<MutationType>;
export type SubscriptionRootIntervalArgs = {
n?: Scalars['Int'];
};
export type ThreadObject = {
__typename?: 'ThreadObject';
id: Scalars['String'];
title: Scalars['String'];
export type Support = {
__typename?: 'Support';
id: Scalars['ID'];
projectId: Scalars['ID'];
threadDescription: Scalars['String'];
userMessages: Array<UserMessage>;
title: Scalars['String'];
userMessages: Array<UserMessages>;
};
export type UserMessage = {
__typename?: 'UserMessage';
username: Scalars['String'];
text: Scalars['String'];
};
export type UserMessageObject = {
__typename?: 'UserMessageObject';
export type UserMessages = {
__typename?: 'UserMessages';
id: Scalars['String'];
username: Scalars['String'];
text: Scalars['String'];
@@ -103,15 +103,15 @@ export type GetProjectThreadsQueryVariables = Exact<{
}>;
export type GetProjectThreadsQuery = { __typename?: 'QueryRoot' } & {
getProjectThreads: Array<
{ __typename?: 'ThreadObject' } & Pick<
ThreadObject,
'id' | 'title' | 'threadDescription'
threads: Array<
{ __typename?: 'Support' } & Pick<
Support,
'id' | 'title' | 'projectId' | 'threadDescription' | 'userMessages'
> & {
userMessages: Array<
{ __typename?: 'UserMessage' } & Pick<
UserMessage,
'username' | 'text'
UserMessages,
'id' | 'username' | 'text'
>
>;
}
@@ -123,12 +123,12 @@ export type GetThreadByIdQueryVariables = Exact<{
}>;
export type GetThreadByIdQuery = { __typename?: 'QueryRoot' } & {
getThreadById: { __typename?: 'ThreadObject' } & Pick<
ThreadObject,
'id' | 'title' | 'threadDescription'
thread: { __typename?: 'Support' } & Pick<
Support,
'id' | 'title' | 'projectId' | 'threadDescription' | 'userMessages'
> & {
userMessages: Array<
{ __typename?: 'UserMessage' } & Pick<UserMessage, 'username' | 'text'>
{ __typename?: 'UserMessages' } & Pick<UserMessages, 'id' | 'username' | 'text'>
>;
};
};
@@ -139,7 +139,7 @@ export type MessagesQueryVariables = Exact<{
export type MessagesQuery = { __typename?: 'QueryRoot' } & {
messages: Array<
{ __typename?: 'UserMessage' } & Pick<UserMessage, 'username' | 'text'>
{ __typename?: 'UserMessages' } & Pick<UserMessages, 'username' | 'text' | 'id'>
>;
};
@@ -157,28 +157,24 @@ export type CreateThreadMutation = { __typename?: 'MutationRoot' } & Pick<
export type SendMsgMutationVariables = Exact<{
threadId: Scalars['String'];
username: Scalars['String'];
msg: Scalars['String'];
text: Scalars['String'];
}>;
export type SendMsgMutation = { __typename?: 'MutationRoot' } & Pick<
MutationRoot,
'sendMsg'
'sendMessage'
>;
export type ConnectStreamSubscriptionVariables = Exact<{
mutationType?: Maybe<MutationType>;
}>;
export type ConnectStreamSubscription = { __typename?: 'SubscriptionRoot' } & {
connectStream: { __typename?: 'StreamChanged' } & Pick<
export type MessagesSubscription = { __typename?: 'SubscriptionRoot' } & {
messages: { __typename?: 'StreamChanged' } & Pick<
StreamChanged,
'mutationType' | 'id'
'mutationType'
> & {
userMessage?: Maybe<
{ __typename?: 'UserMessageObject' } & Pick<
UserMessageObject,
userMessages?: Maybe<
{ __typename?: 'UserMessages' } & Pick<
UserMessages,
'id' | 'username' | 'text'
>
>;
>;
};
};
+14 -12
View File
@@ -1,13 +1,14 @@
import React from 'react';
import * as ReactDOMClient from 'react-dom/client';
import { GraphQLWsLink } from '@apollo/client/link/subscriptions';
import { createClient } from 'graphql-ws';
import {
ApolloClient,
InMemoryCache,
createHttpLink,
ApolloProvider,
split,
HttpLink,
} from '@apollo/client';
import { WebSocketLink } from '@apollo/client/link/ws';
import { getMainDefinition } from '@apollo/client/utilities';
import { setContext } from '@apollo/client/link/context';
import { ThemeProvider } from 'styled-components';
@@ -17,20 +18,19 @@ import App from './App';
import GlobalStyles from './GlobalStyles';
import reportWebVitals from './reportWebVitals';
const httpLinkMain = createHttpLink({
const httpLinkMain = new HttpLink({
uri: import.meta.env.VITE_GRAPHQL_API,
});
const httpLinkSupport = createHttpLink({
const httpLinkSupport = new HttpLink({
uri: import.meta.env.VITE_GRAPHQL_SUPPORT_API,
});
const wsLink = new WebSocketLink({
uri: `${import.meta.env.VITE_GRAPHQL_SUPPORT_SUBSCRIPTIONS_API}`,
options: {
reconnect: true,
},
});
const wsLink = new GraphQLWsLink(
createClient({
url: `${import.meta.env.VITE_GRAPHQL_SUPPORT_SUBSCRIPTIONS_API}`,
})
);
const splitLink = split(
({ query }) => {
@@ -69,7 +69,9 @@ let root: ReactDOMClient.Root | null = null;
document.addEventListener('DOMContentLoaded', () => {
if (!root) {
root = ReactDOMClient.createRoot(document.querySelector('#app') as HTMLElement);
root = ReactDOMClient.createRoot(
document.querySelector('#app') as HTMLElement
);
root.render(
<React.StrictMode>
@@ -84,7 +86,7 @@ document.addEventListener('DOMContentLoaded', () => {
</ThemeProvider>
</ApolloProvider>
</React.StrictMode>
)
);
}
});
+31 -40
View File
@@ -6,56 +6,53 @@ import { useState, useEffect } from 'react';
import { roleVar, userVar } from '../../graphql/state';
import { Wrapper } from './styles';
import {
ConnectStreamSubscription,
ConnectStreamSubscriptionVariables,
CreateThreadMutation,
CreateThreadMutationVariables,
GetThreadByIdQuery,
GetThreadByIdQueryVariables,
MessagesQuery,
MessagesQueryVariables,
MessagesSubscription,
SendMsgMutation,
SendMsgMutationVariables,
ThreadObject,
UserMessageObject,
Support as SupportType,
UserMessages,
} from '../../graphql/types.support';
import { Box, Button, Input, TextArea, Text } from '../../components';
import { Send, ThreadClient, ThreadProductOwner } from '../../assets';
import {
CONNECT_STREAM,
CREATE_THREAD,
GET_THREAD_BY_ID,
MESSAGES,
MESSAGES_SUBSCRIPTION,
SEND_MSG,
} from '../../graphql/chat.api.support';
import { theme } from '../../themes';
import { clientSupport } from '../..';
const Support = () => {
const { project, id } = useParams<{ id: string; project: string }>();
const { projectId, threadId } = useParams<{ projectId: string, threadId: string }>();
const role = useReactiveVar(roleVar);
const currentUser = useReactiveVar(userVar);
const navigate = useNavigate();
const [thread, setThread] = useState<ThreadObject>();
const [messages, setMessages] = useState<Array<UserMessageObject>>([]);
const [addedMessages, setAddedMessages] = useState<Array<UserMessageObject>>(
[]
);
const [thread, setThread] = useState<SupportType>();
const [messages, setMessages] = useState<Array<UserMessages>>([]);
const [addedMessages, setAddedMessages] = useState<Array<UserMessages>>([]);
useEffect(() => {
(async () => {
if (id) {
if (threadId) {
const threadResult = await clientSupport.query<
GetThreadByIdQuery,
GetThreadByIdQueryVariables
>({
query: GET_THREAD_BY_ID,
variables: {
threadId: id!,
threadId: threadId!,
},
});
setThread(threadResult?.data?.getThreadById);
setThread(threadResult?.data?.thread);
const messagesResult = await clientSupport.query<
MessagesQuery,
@@ -63,41 +60,37 @@ const Support = () => {
>({
query: MESSAGES,
variables: {
threadId: id!,
threadId: threadId!,
},
fetchPolicy: 'network-only',
});
setMessages(
Array.from(messagesResult?.data?.messages).map((message, index) => ({
text: message.text,
username: message.username,
id: index.toString(),
}))
Array.from(messagesResult?.data?.messages).map(
(message: UserMessages) => ({
text: message.text,
username: message.username,
id: message.id,
})
)
);
const messageSubscriber = clientSupport.subscribe<
ConnectStreamSubscription,
ConnectStreamSubscriptionVariables
clientSupport.subscribe<
MessagesSubscription
>({
query: CONNECT_STREAM,
variables: {
mutationType: 'CREATED',
},
});
messageSubscriber.subscribe(({ data }) => {
query: MESSAGES_SUBSCRIPTION,
}).subscribe(({ data }) => {
setAddedMessages((prevMessages) => [
...prevMessages,
{
id: messages.length.toString(),
username: data?.connectStream?.userMessage?.username!,
text: data?.connectStream?.userMessage?.text!,
id: data?.messages?.userMessages?.id!,
username: data?.messages?.userMessages?.username!,
text: data?.messages?.userMessages?.text!,
},
]);
});
}
})();
}, [id]);
}, [threadId]);
const createThreadForm = useFormik({
initialValues: {
@@ -115,14 +108,12 @@ const Support = () => {
>({
mutation: CREATE_THREAD,
variables: {
projectId: project as string,
projectId: projectId as string,
title,
threadDescription: description,
},
});
navigate(
`/support/${project}/${createdThread.data?.createThread}`
);
navigate(`/support/${projectId}/${createdThread.data?.createThread.id}`);
},
});
@@ -137,9 +128,9 @@ const Support = () => {
await clientSupport.mutate<SendMsgMutation, SendMsgMutationVariables>({
mutation: SEND_MSG,
variables: {
threadId: id as string,
threadId: threadId as string,
username: `${currentUser?.firstName} ${currentUser?.lastName}`,
msg,
text: msg,
},
});
resetForm();