agx-chat-web 1.1.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -49
- package/dist/agx-chat.esm.js +1 -1
- package/dist/agx-chat.esm.js.map +1 -1
- package/dist/{agx-chat.min.js → agx-chat.umd.js} +2 -2
- package/dist/agx-chat.umd.js.map +1 -0
- package/dist/esm/app/Messenger/components/IncomingMessage/IncomingMessage.js +7 -3
- package/dist/esm/app/Messenger/components/IncomingMessage/IncomingMessage.js.map +1 -1
- package/dist/esm/app/Messenger/components/InputFile/InputFile.js +3 -1
- package/dist/esm/app/Messenger/components/InputFile/InputFile.js.map +1 -1
- package/dist/esm/app/Messenger/components/RenderFileIcon/RenderFileIcon.js +8 -0
- package/dist/esm/app/Messenger/components/RenderFileIcon/RenderFileIcon.js.map +1 -1
- package/dist/esm/app/Messenger/components/SendMessageForm/SendMessageForm.js +30 -8
- package/dist/esm/app/Messenger/components/SendMessageForm/SendMessageForm.js.map +1 -1
- package/dist/esm/app/Messenger/components/SenderMessages/SenderMessages.js +11 -8
- package/dist/esm/app/Messenger/components/SenderMessages/SenderMessages.js.map +1 -1
- package/dist/esm/app/Messenger/icons/CSVFileIcon.d.ts +4 -0
- package/dist/esm/app/Messenger/icons/CSVFileIcon.js +7 -0
- package/dist/esm/app/Messenger/icons/CSVFileIcon.js.map +1 -0
- package/dist/esm/app/Messenger/icons/MP4FileIcon.d.ts +4 -0
- package/dist/esm/app/Messenger/icons/MP4FileIcon.js +7 -0
- package/dist/esm/app/Messenger/icons/MP4FileIcon.js.map +1 -0
- package/package.json +91 -91
- package/src/__tests__/app/Messenger/classes/slaCalculations.spec.ts +122 -122
- package/src/app/ChatProvider/ChatProvider.tsx +20 -20
- package/src/app/Messenger/classes/slaCalculations.ts +197 -197
- package/src/app/Messenger/components/ChatButton/ChatButton.tsx +64 -64
- package/src/app/Messenger/components/ChatTabs/ChatTabs.less +18 -18
- package/src/app/Messenger/components/ChatTabs/ChatTabs.tsx +32 -32
- package/src/app/Messenger/components/DocMessage/DocMessage.less +71 -71
- package/src/app/Messenger/components/DocMessage/DocMessage.tsx +50 -50
- package/src/app/Messenger/components/ImagesContainer/ImagesContainer.less +79 -79
- package/src/app/Messenger/components/ImagesContainer/ImagesContainer.tsx +51 -51
- package/src/app/Messenger/components/IncomingMessage/IncomingMessage.tsx +170 -166
- package/src/app/Messenger/components/InfiniteScroll/InfiniteScroll.tsx +80 -80
- package/src/app/Messenger/components/InputFile/InputFile.tsx +147 -145
- package/src/app/Messenger/components/InputFile/inputFile.less +59 -59
- package/src/app/Messenger/components/MessageBallon/MessageBalloon.tsx +100 -100
- package/src/app/Messenger/components/MessengerAvatar/MessengerAvatar.tsx +29 -29
- package/src/app/Messenger/components/MessengerThemeWrapper/MessengerThemeWrapper.tsx +62 -62
- package/src/app/Messenger/components/RenderFileIcon/RenderFileIcon.tsx +40 -34
- package/src/app/Messenger/components/SearchInput/SearchInput.less +45 -45
- package/src/app/Messenger/components/SearchInput/SearchInput.tsx +77 -77
- package/src/app/Messenger/components/Select/Select.less +22 -22
- package/src/app/Messenger/components/Select/Select.tsx +56 -56
- package/src/app/Messenger/components/SendMessageForm/SendMessageForm.tsx +254 -234
- package/src/app/Messenger/components/SenderMessages/SenderMessages.tsx +91 -89
- package/src/app/Messenger/components/SystemMessage/SystemMessage.tsx +25 -25
- package/src/app/Messenger/components/TextArea/TextArea.tsx +35 -35
- package/src/app/Messenger/components/TextArea/Textarea.less +22 -22
- package/src/app/Messenger/components/Tooltip/Tooltip.less +27 -27
- package/src/app/Messenger/components/Tooltip/Tooltip.tsx +17 -17
- package/src/app/Messenger/hooks/useConversations.tsx +143 -143
- package/src/app/Messenger/hooks/useMessages.tsx +49 -49
- package/src/app/Messenger/hooks/useThemes.tsx +14 -14
- package/src/app/Messenger/icons/AttachFileIcon.tsx +20 -20
- package/src/app/Messenger/icons/CSVFileIcon.tsx +26 -0
- package/src/app/Messenger/icons/CloseIcon.tsx +20 -20
- package/src/app/Messenger/icons/DOCFileIcon.tsx +54 -54
- package/src/app/Messenger/icons/DownloadMinimalistIcon.tsx +37 -37
- package/src/app/Messenger/icons/EmptyIcon.tsx +20 -20
- package/src/app/Messenger/icons/MP4FileIcon.tsx +26 -0
- package/src/app/Messenger/icons/MessageIcon.tsx +27 -27
- package/src/app/Messenger/icons/PDFFileIcon.tsx +54 -54
- package/src/app/Messenger/icons/ReadIcon.tsx +18 -18
- package/src/app/Messenger/icons/SearchIcon.tsx +20 -20
- package/src/app/Messenger/icons/TimerIcon.tsx +18 -18
- package/src/app/Messenger/icons/TrashIcon.tsx +21 -21
- package/src/app/Messenger/views/Messenger.less +623 -623
- package/src/app/Messenger/views/MessengerList.tsx +170 -170
- package/src/app/Messenger/views/MessengerListItem.tsx +178 -178
- package/src/app/Messenger/views/MessengerMessages.tsx +414 -414
- package/src/app/Messenger/views/NewFormChat.tsx +145 -145
- package/src/app/i18n/index.ts +36 -36
- package/src/app/i18n/locales/en.json +64 -64
- package/src/app/i18n/locales/pt.json +64 -64
- package/src/assets/right-arrow.svg +9 -9
- package/src/index.ts +23 -23
- package/src/react-app-env.d.ts +19 -19
- package/src/setupTests.ts +5 -5
- package/src/styles/abstracts/animations.less +8 -8
- package/src/styles/abstracts/mixins.less +5 -5
- package/src/styles/abstracts/variables.less +31 -31
- package/src/styles/base/base.less +6 -6
- package/src/styles/index.less +5 -5
- package/src/types.ts +174 -174
- package/dist/agx-chat.min.js.map +0 -1
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import useTheme from '../../hooks/useThemes'
|
|
3
|
-
import { IInconmingMessage } from 'types'
|
|
4
|
-
|
|
5
|
-
function SystemMessage ({ date, message, formatDate, id }: IInconmingMessage) {
|
|
6
|
-
const { theme } = useTheme()
|
|
7
|
-
|
|
8
|
-
return (
|
|
9
|
-
<div className='messenger__messages-row--system' id={id}>
|
|
10
|
-
<div
|
|
11
|
-
className='messenger__messages-received messenger__messages-received--system'
|
|
12
|
-
style={{ background: theme?.messengerSystemColor }}
|
|
13
|
-
>
|
|
14
|
-
<span>
|
|
15
|
-
<p className='messenger__message'>{message}</p>
|
|
16
|
-
<p className='messenger__message--date'>
|
|
17
|
-
{formatDate(date) ?? new Date(date).toString()}
|
|
18
|
-
</p>
|
|
19
|
-
</span>
|
|
20
|
-
</div>
|
|
21
|
-
</div>
|
|
22
|
-
)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export default SystemMessage
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import useTheme from '../../hooks/useThemes'
|
|
3
|
+
import { IInconmingMessage } from 'types'
|
|
4
|
+
|
|
5
|
+
function SystemMessage ({ date, message, formatDate, id }: IInconmingMessage) {
|
|
6
|
+
const { theme } = useTheme()
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<div className='messenger__messages-row--system' id={id}>
|
|
10
|
+
<div
|
|
11
|
+
className='messenger__messages-received messenger__messages-received--system'
|
|
12
|
+
style={{ background: theme?.messengerSystemColor }}
|
|
13
|
+
>
|
|
14
|
+
<span>
|
|
15
|
+
<p className='messenger__message'>{message}</p>
|
|
16
|
+
<p className='messenger__message--date'>
|
|
17
|
+
{formatDate(date) ?? new Date(date).toString()}
|
|
18
|
+
</p>
|
|
19
|
+
</span>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default SystemMessage
|
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import useTheme from '../../hooks/useThemes'
|
|
3
|
-
interface IProps {
|
|
4
|
-
label: string
|
|
5
|
-
onChange: (value: string) => void
|
|
6
|
-
name: string
|
|
7
|
-
placeholder: string
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function Textarea ({ name, placeholder, label, onChange }: IProps) {
|
|
11
|
-
const { theme } = useTheme()
|
|
12
|
-
return (
|
|
13
|
-
<div className='text-area'>
|
|
14
|
-
<label
|
|
15
|
-
htmlFor={name}
|
|
16
|
-
className='text-area__label'
|
|
17
|
-
style={{ color: theme.newChatFormTexts }}
|
|
18
|
-
>
|
|
19
|
-
{label}
|
|
20
|
-
</label>
|
|
21
|
-
<textarea
|
|
22
|
-
style={{
|
|
23
|
-
backgroundColor: theme.inputBg,
|
|
24
|
-
color: theme.newChatFormTexts,
|
|
25
|
-
}}
|
|
26
|
-
name={name}
|
|
27
|
-
placeholder={placeholder}
|
|
28
|
-
className='text-area__input'
|
|
29
|
-
onChange={(e) => onChange(e.target.value)}
|
|
30
|
-
/>
|
|
31
|
-
</div>
|
|
32
|
-
)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export default Textarea
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import useTheme from '../../hooks/useThemes'
|
|
3
|
+
interface IProps {
|
|
4
|
+
label: string
|
|
5
|
+
onChange: (value: string) => void
|
|
6
|
+
name: string
|
|
7
|
+
placeholder: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function Textarea ({ name, placeholder, label, onChange }: IProps) {
|
|
11
|
+
const { theme } = useTheme()
|
|
12
|
+
return (
|
|
13
|
+
<div className='text-area'>
|
|
14
|
+
<label
|
|
15
|
+
htmlFor={name}
|
|
16
|
+
className='text-area__label'
|
|
17
|
+
style={{ color: theme.newChatFormTexts }}
|
|
18
|
+
>
|
|
19
|
+
{label}
|
|
20
|
+
</label>
|
|
21
|
+
<textarea
|
|
22
|
+
style={{
|
|
23
|
+
backgroundColor: theme.inputBg,
|
|
24
|
+
color: theme.newChatFormTexts,
|
|
25
|
+
}}
|
|
26
|
+
name={name}
|
|
27
|
+
placeholder={placeholder}
|
|
28
|
+
className='text-area__input'
|
|
29
|
+
onChange={(e) => onChange(e.target.value)}
|
|
30
|
+
/>
|
|
31
|
+
</div>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default Textarea
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
.text-area {
|
|
2
|
-
margin-bottom: 1rem;
|
|
3
|
-
width: 100%;
|
|
4
|
-
|
|
5
|
-
&__label {
|
|
6
|
-
color: @title-form-color;
|
|
7
|
-
font-weight: bold;
|
|
8
|
-
margin: 0.5rem;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
&__input {
|
|
12
|
-
border: 1.5px solid hsl(0, 0%, 80%);
|
|
13
|
-
border-radius: 4px;
|
|
14
|
-
margin-top: 0.5rem;
|
|
15
|
-
padding: 4px 8px;
|
|
16
|
-
width: 100%;
|
|
17
|
-
|
|
18
|
-
&:focus {
|
|
19
|
-
outline: #2684ff 2px solid !important;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
1
|
+
.text-area {
|
|
2
|
+
margin-bottom: 1rem;
|
|
3
|
+
width: 100%;
|
|
4
|
+
|
|
5
|
+
&__label {
|
|
6
|
+
color: @title-form-color;
|
|
7
|
+
font-weight: bold;
|
|
8
|
+
margin: 0.5rem;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
&__input {
|
|
12
|
+
border: 1.5px solid hsl(0, 0%, 80%);
|
|
13
|
+
border-radius: 4px;
|
|
14
|
+
margin-top: 0.5rem;
|
|
15
|
+
padding: 4px 8px;
|
|
16
|
+
width: 100%;
|
|
17
|
+
|
|
18
|
+
&:focus {
|
|
19
|
+
outline: #2684ff 2px solid !important;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
.tooltip {
|
|
2
|
-
position: relative;
|
|
3
|
-
display: inline-block;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
.tooltip__text {
|
|
7
|
-
visibility: hidden;
|
|
8
|
-
background-color: black;
|
|
9
|
-
color: #fff;
|
|
10
|
-
text-align: center;
|
|
11
|
-
border-radius: 5px;
|
|
12
|
-
padding: 5px;
|
|
13
|
-
position: absolute;
|
|
14
|
-
z-index: 1;
|
|
15
|
-
bottom: 125%;
|
|
16
|
-
left: -40%;
|
|
17
|
-
margin-left: -60px;
|
|
18
|
-
opacity: 0;
|
|
19
|
-
transition:
|
|
20
|
-
opacity 0.3s,
|
|
21
|
-
visibility 0.3s;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
.tooltip:hover .tooltip__text {
|
|
25
|
-
visibility: visible;
|
|
26
|
-
opacity: 1;
|
|
27
|
-
}
|
|
1
|
+
.tooltip {
|
|
2
|
+
position: relative;
|
|
3
|
+
display: inline-block;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.tooltip__text {
|
|
7
|
+
visibility: hidden;
|
|
8
|
+
background-color: black;
|
|
9
|
+
color: #fff;
|
|
10
|
+
text-align: center;
|
|
11
|
+
border-radius: 5px;
|
|
12
|
+
padding: 5px;
|
|
13
|
+
position: absolute;
|
|
14
|
+
z-index: 1;
|
|
15
|
+
bottom: 125%;
|
|
16
|
+
left: -40%;
|
|
17
|
+
margin-left: -60px;
|
|
18
|
+
opacity: 0;
|
|
19
|
+
transition:
|
|
20
|
+
opacity 0.3s,
|
|
21
|
+
visibility 0.3s;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.tooltip:hover .tooltip__text {
|
|
25
|
+
visibility: visible;
|
|
26
|
+
opacity: 1;
|
|
27
|
+
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import React, { ReactNode } from 'react'
|
|
2
|
-
|
|
3
|
-
interface ToolTipProps {
|
|
4
|
-
text: string
|
|
5
|
-
children: ReactNode
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const ToolTip: React.FC<ToolTipProps> = ({ text, children }) => {
|
|
9
|
-
return (
|
|
10
|
-
<div className='tooltip'>
|
|
11
|
-
{children}
|
|
12
|
-
<div className='tooltip__text'>{text}</div>
|
|
13
|
-
</div>
|
|
14
|
-
)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export default ToolTip
|
|
1
|
+
import React, { ReactNode } from 'react'
|
|
2
|
+
|
|
3
|
+
interface ToolTipProps {
|
|
4
|
+
text: string
|
|
5
|
+
children: ReactNode
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const ToolTip: React.FC<ToolTipProps> = ({ text, children }) => {
|
|
9
|
+
return (
|
|
10
|
+
<div className='tooltip'>
|
|
11
|
+
{children}
|
|
12
|
+
<div className='tooltip__text'>{text}</div>
|
|
13
|
+
</div>
|
|
14
|
+
)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default ToolTip
|
|
@@ -1,143 +1,143 @@
|
|
|
1
|
-
import { useState } from 'react'
|
|
2
|
-
import { IList } from 'types'
|
|
3
|
-
|
|
4
|
-
type _viewDesktop = 'empty' | 'messages' | 'newChat'
|
|
5
|
-
type _viewMobile = 'list' | 'messages'
|
|
6
|
-
|
|
7
|
-
export const useConversations = () => {
|
|
8
|
-
const SLICE = 15
|
|
9
|
-
const [sliceCount, setSliceCount] = useState(SLICE)
|
|
10
|
-
const [conversations, setConversations] = useState<IList[]>([])
|
|
11
|
-
const [currentChat, setCurrentChat] = useState<IList>()
|
|
12
|
-
const [viewDesktop, setViewDesktop] = useState<_viewDesktop>('empty')
|
|
13
|
-
const [viewMobile, setViewMobile] = useState<'list' | 'messages'>('list')
|
|
14
|
-
|
|
15
|
-
const changeViewDesktop = (view: _viewDesktop) => {
|
|
16
|
-
setViewDesktop(view)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const changeViewMobile = (view: _viewMobile) => {
|
|
20
|
-
setViewMobile(view)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const selectChat = (chat: IList) => {
|
|
24
|
-
setCurrentChat(chat)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const onIntersect = () => {
|
|
28
|
-
setSliceCount((prev) => {
|
|
29
|
-
const count = prev + SLICE
|
|
30
|
-
return count
|
|
31
|
-
})
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const hasNext = () => {
|
|
35
|
-
return conversations.length >= sliceCount
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const resetConversations = () => {
|
|
39
|
-
setConversations([])
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const mapConversationsUnread = (prev: IList[]) => (id: string) => {
|
|
43
|
-
return (prev || []).map((conversation) => {
|
|
44
|
-
if (conversation?._id === id) {
|
|
45
|
-
return {
|
|
46
|
-
...conversation,
|
|
47
|
-
totalUnreadMessages: 0,
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return conversation
|
|
52
|
-
})
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const reorderConversations = (conversations: IList[], ticketId?: string) => {
|
|
56
|
-
const index = conversations.findIndex(
|
|
57
|
-
(conversation) => conversation._id === ticketId
|
|
58
|
-
)
|
|
59
|
-
if (index !== -1) {
|
|
60
|
-
const conversationToMove = conversations.splice(index, 1)[0]
|
|
61
|
-
conversations.unshift(conversationToMove)
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const mapConversationsIncrementUnread =
|
|
66
|
-
(prev: IList[], ticketId?: string) => (id: string) => {
|
|
67
|
-
const updatedConversations = (prev || []).map((conversation) => {
|
|
68
|
-
if (conversation._id === id) {
|
|
69
|
-
return {
|
|
70
|
-
...conversation,
|
|
71
|
-
totalUnreadMessages:
|
|
72
|
-
ticketId === id ? 0 : conversation.totalUnreadMessages + 1,
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return conversation
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
reorderConversations(updatedConversations, ticketId)
|
|
79
|
-
|
|
80
|
-
return updatedConversations
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const setAsRead = (id: string) => {
|
|
84
|
-
setConversations((prev) => mapConversationsUnread(prev)(id))
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const addConversations = (
|
|
88
|
-
conversations: IList[],
|
|
89
|
-
goToNewConversation?: (chat: IList) => void
|
|
90
|
-
) => {
|
|
91
|
-
setConversations(conversations)
|
|
92
|
-
|
|
93
|
-
if (goToNewConversation) goToNewConversation(conversations[0])
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const addOneUnreadToTicket = (ticketId: string, currentChat?: string) => {
|
|
97
|
-
setConversations((prev) => {
|
|
98
|
-
return mapConversationsIncrementUnread(prev, currentChat)(ticketId)
|
|
99
|
-
})
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const removeClosedConversation = (ticketId: string) => {
|
|
103
|
-
const filtred = conversations.filter(
|
|
104
|
-
(conversation) => conversation._id !== ticketId
|
|
105
|
-
)
|
|
106
|
-
addConversations(filtred)
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const closeIfIsCurrent = (ticketId: string) => {
|
|
110
|
-
if (ticketId === currentChat?._id) {
|
|
111
|
-
changeViewDesktop('empty')
|
|
112
|
-
changeViewMobile('list')
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const onCloseChat = (ticketId: string) => {
|
|
117
|
-
removeClosedConversation(ticketId)
|
|
118
|
-
closeIfIsCurrent(ticketId)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const reset = () => {
|
|
122
|
-
setSliceCount(SLICE)
|
|
123
|
-
resetConversations()
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return {
|
|
127
|
-
onIntersect,
|
|
128
|
-
reset,
|
|
129
|
-
conversations,
|
|
130
|
-
hasNext,
|
|
131
|
-
addConversations,
|
|
132
|
-
addOneUnreadToTicket,
|
|
133
|
-
setAsRead,
|
|
134
|
-
sliceCount,
|
|
135
|
-
currentChat,
|
|
136
|
-
selectChat,
|
|
137
|
-
onCloseChat,
|
|
138
|
-
changeViewDesktop,
|
|
139
|
-
viewDesktop,
|
|
140
|
-
changeViewMobile,
|
|
141
|
-
viewMobile,
|
|
142
|
-
}
|
|
143
|
-
}
|
|
1
|
+
import { useState } from 'react'
|
|
2
|
+
import { IList } from 'types'
|
|
3
|
+
|
|
4
|
+
type _viewDesktop = 'empty' | 'messages' | 'newChat'
|
|
5
|
+
type _viewMobile = 'list' | 'messages'
|
|
6
|
+
|
|
7
|
+
export const useConversations = () => {
|
|
8
|
+
const SLICE = 15
|
|
9
|
+
const [sliceCount, setSliceCount] = useState(SLICE)
|
|
10
|
+
const [conversations, setConversations] = useState<IList[]>([])
|
|
11
|
+
const [currentChat, setCurrentChat] = useState<IList>()
|
|
12
|
+
const [viewDesktop, setViewDesktop] = useState<_viewDesktop>('empty')
|
|
13
|
+
const [viewMobile, setViewMobile] = useState<'list' | 'messages'>('list')
|
|
14
|
+
|
|
15
|
+
const changeViewDesktop = (view: _viewDesktop) => {
|
|
16
|
+
setViewDesktop(view)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const changeViewMobile = (view: _viewMobile) => {
|
|
20
|
+
setViewMobile(view)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const selectChat = (chat: IList) => {
|
|
24
|
+
setCurrentChat(chat)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const onIntersect = () => {
|
|
28
|
+
setSliceCount((prev) => {
|
|
29
|
+
const count = prev + SLICE
|
|
30
|
+
return count
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const hasNext = () => {
|
|
35
|
+
return conversations.length >= sliceCount
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const resetConversations = () => {
|
|
39
|
+
setConversations([])
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const mapConversationsUnread = (prev: IList[]) => (id: string) => {
|
|
43
|
+
return (prev || []).map((conversation) => {
|
|
44
|
+
if (conversation?._id === id) {
|
|
45
|
+
return {
|
|
46
|
+
...conversation,
|
|
47
|
+
totalUnreadMessages: 0,
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return conversation
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const reorderConversations = (conversations: IList[], ticketId?: string) => {
|
|
56
|
+
const index = conversations.findIndex(
|
|
57
|
+
(conversation) => conversation._id === ticketId
|
|
58
|
+
)
|
|
59
|
+
if (index !== -1) {
|
|
60
|
+
const conversationToMove = conversations.splice(index, 1)[0]
|
|
61
|
+
conversations.unshift(conversationToMove)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const mapConversationsIncrementUnread =
|
|
66
|
+
(prev: IList[], ticketId?: string) => (id: string) => {
|
|
67
|
+
const updatedConversations = (prev || []).map((conversation) => {
|
|
68
|
+
if (conversation._id === id) {
|
|
69
|
+
return {
|
|
70
|
+
...conversation,
|
|
71
|
+
totalUnreadMessages:
|
|
72
|
+
ticketId === id ? 0 : conversation.totalUnreadMessages + 1,
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return conversation
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
reorderConversations(updatedConversations, ticketId)
|
|
79
|
+
|
|
80
|
+
return updatedConversations
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const setAsRead = (id: string) => {
|
|
84
|
+
setConversations((prev) => mapConversationsUnread(prev)(id))
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const addConversations = (
|
|
88
|
+
conversations: IList[],
|
|
89
|
+
goToNewConversation?: (chat: IList) => void
|
|
90
|
+
) => {
|
|
91
|
+
setConversations(conversations)
|
|
92
|
+
|
|
93
|
+
if (goToNewConversation) goToNewConversation(conversations[0])
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const addOneUnreadToTicket = (ticketId: string, currentChat?: string) => {
|
|
97
|
+
setConversations((prev) => {
|
|
98
|
+
return mapConversationsIncrementUnread(prev, currentChat)(ticketId)
|
|
99
|
+
})
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const removeClosedConversation = (ticketId: string) => {
|
|
103
|
+
const filtred = conversations.filter(
|
|
104
|
+
(conversation) => conversation._id !== ticketId
|
|
105
|
+
)
|
|
106
|
+
addConversations(filtred)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const closeIfIsCurrent = (ticketId: string) => {
|
|
110
|
+
if (ticketId === currentChat?._id) {
|
|
111
|
+
changeViewDesktop('empty')
|
|
112
|
+
changeViewMobile('list')
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const onCloseChat = (ticketId: string) => {
|
|
117
|
+
removeClosedConversation(ticketId)
|
|
118
|
+
closeIfIsCurrent(ticketId)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const reset = () => {
|
|
122
|
+
setSliceCount(SLICE)
|
|
123
|
+
resetConversations()
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
onIntersect,
|
|
128
|
+
reset,
|
|
129
|
+
conversations,
|
|
130
|
+
hasNext,
|
|
131
|
+
addConversations,
|
|
132
|
+
addOneUnreadToTicket,
|
|
133
|
+
setAsRead,
|
|
134
|
+
sliceCount,
|
|
135
|
+
currentChat,
|
|
136
|
+
selectChat,
|
|
137
|
+
onCloseChat,
|
|
138
|
+
changeViewDesktop,
|
|
139
|
+
viewDesktop,
|
|
140
|
+
changeViewMobile,
|
|
141
|
+
viewMobile,
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -1,49 +1,49 @@
|
|
|
1
|
-
import { useState } from 'react'
|
|
2
|
-
import { IMessages, ISocketMessage } from 'types'
|
|
3
|
-
|
|
4
|
-
export const useMessages = () => {
|
|
5
|
-
const [messages, setMessages] = useState<IMessages[]>([])
|
|
6
|
-
const [totalMessages, setTotalMessages] = useState<number>(0)
|
|
7
|
-
|
|
8
|
-
const addMessages = (messages: IMessages[]) => {
|
|
9
|
-
setMessages(messages)
|
|
10
|
-
}
|
|
11
|
-
const addTotalMessages = (total: number) => {
|
|
12
|
-
setTotalMessages(total)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const incrementMessages = (ticket: ISocketMessage, currentChatId: string) => {
|
|
16
|
-
const existentMessage = messages.find(
|
|
17
|
-
(item) => item.messagecode === ticket.message.messagecode
|
|
18
|
-
)
|
|
19
|
-
if (ticket.message.ticketId === currentChatId && !existentMessage) {
|
|
20
|
-
addMessages([...messages, ticket.message])
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const updateMesssagesAsRead = (
|
|
25
|
-
ticket: ISocketMessage,
|
|
26
|
-
currentChatId: string
|
|
27
|
-
) => {
|
|
28
|
-
if (ticket.markAsRead || currentChatId === ticket?.message?.ticketId) {
|
|
29
|
-
const readMessages = messages.map((message) => ({
|
|
30
|
-
...message,
|
|
31
|
-
everybodyHasRead: true,
|
|
32
|
-
}))
|
|
33
|
-
addMessages(readMessages)
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const hasOlderMessages = () => {
|
|
38
|
-
return messages.length > 9 && messages.length < totalMessages
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return {
|
|
42
|
-
addMessages,
|
|
43
|
-
messages,
|
|
44
|
-
incrementMessages,
|
|
45
|
-
updateMesssagesAsRead,
|
|
46
|
-
addTotalMessages,
|
|
47
|
-
hasOlderMessages,
|
|
48
|
-
}
|
|
49
|
-
}
|
|
1
|
+
import { useState } from 'react'
|
|
2
|
+
import { IMessages, ISocketMessage } from 'types'
|
|
3
|
+
|
|
4
|
+
export const useMessages = () => {
|
|
5
|
+
const [messages, setMessages] = useState<IMessages[]>([])
|
|
6
|
+
const [totalMessages, setTotalMessages] = useState<number>(0)
|
|
7
|
+
|
|
8
|
+
const addMessages = (messages: IMessages[]) => {
|
|
9
|
+
setMessages(messages)
|
|
10
|
+
}
|
|
11
|
+
const addTotalMessages = (total: number) => {
|
|
12
|
+
setTotalMessages(total)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const incrementMessages = (ticket: ISocketMessage, currentChatId: string) => {
|
|
16
|
+
const existentMessage = messages.find(
|
|
17
|
+
(item) => item.messagecode === ticket.message.messagecode
|
|
18
|
+
)
|
|
19
|
+
if (ticket.message.ticketId === currentChatId && !existentMessage) {
|
|
20
|
+
addMessages([...messages, ticket.message])
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const updateMesssagesAsRead = (
|
|
25
|
+
ticket: ISocketMessage,
|
|
26
|
+
currentChatId: string
|
|
27
|
+
) => {
|
|
28
|
+
if (ticket.markAsRead || currentChatId === ticket?.message?.ticketId) {
|
|
29
|
+
const readMessages = messages.map((message) => ({
|
|
30
|
+
...message,
|
|
31
|
+
everybodyHasRead: true,
|
|
32
|
+
}))
|
|
33
|
+
addMessages(readMessages)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const hasOlderMessages = () => {
|
|
38
|
+
return messages.length > 9 && messages.length < totalMessages
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
addMessages,
|
|
43
|
+
messages,
|
|
44
|
+
incrementMessages,
|
|
45
|
+
updateMesssagesAsRead,
|
|
46
|
+
addTotalMessages,
|
|
47
|
+
hasOlderMessages,
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { useContext } from 'react'
|
|
2
|
-
import { MessageThemeContext } from '../components/MessengerThemeWrapper/MessengerThemeWrapper'
|
|
3
|
-
|
|
4
|
-
const useTheme = () => {
|
|
5
|
-
const context = useContext(MessageThemeContext)
|
|
6
|
-
|
|
7
|
-
if (context === undefined) {
|
|
8
|
-
throw new Error('useTheme must be used within a ThemeProvider')
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
return context
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export default useTheme
|
|
1
|
+
import { useContext } from 'react'
|
|
2
|
+
import { MessageThemeContext } from '../components/MessengerThemeWrapper/MessengerThemeWrapper'
|
|
3
|
+
|
|
4
|
+
const useTheme = () => {
|
|
5
|
+
const context = useContext(MessageThemeContext)
|
|
6
|
+
|
|
7
|
+
if (context === undefined) {
|
|
8
|
+
throw new Error('useTheme must be used within a ThemeProvider')
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return context
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default useTheme
|