@rpg-engine/long-bow 0.7.22 → 0.7.24
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/dist/components/Chat/Chat.d.ts +1 -1
- package/dist/components/ChatRevamp/ChatContent.d.ts +24 -0
- package/dist/components/ChatRevamp/ChatRevamp.d.ts +1 -33
- package/dist/components/ChatRevamp/ChatTabs.d.ts +11 -0
- package/dist/components/ChatRevamp/ExpandButton.d.ts +7 -0
- package/dist/components/ChatRevamp/RecentChats.d.ts +17 -0
- package/dist/components/ChatRevamp/SearchCharacter.d.ts +1 -1
- package/dist/components/ChatRevamp/types.d.ts +33 -0
- package/dist/hooks/useChat.d.ts +19 -0
- package/dist/long-bow.cjs.development.js +341 -209
- package/dist/long-bow.cjs.development.js.map +1 -1
- package/dist/long-bow.cjs.production.min.js +1 -1
- package/dist/long-bow.cjs.production.min.js.map +1 -1
- package/dist/long-bow.esm.js +341 -209
- package/dist/long-bow.esm.js.map +1 -1
- package/dist/stories/ChatRevamp.stories.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/Chat/Chat.tsx +1 -1
- package/src/components/ChatRevamp/ChatContent.tsx +96 -0
- package/src/components/ChatRevamp/ChatRevamp.tsx +97 -408
- package/src/components/ChatRevamp/ChatTabs.tsx +51 -0
- package/src/components/ChatRevamp/ExpandButton.tsx +40 -0
- package/src/components/ChatRevamp/RecentChats.tsx +250 -0
- package/src/components/ChatRevamp/SearchCharacter.tsx +17 -20
- package/src/components/ChatRevamp/types.ts +41 -0
- package/src/hooks/useChat.ts +62 -0
- package/src/stories/Chat.stories.tsx +1 -0
- package/src/stories/ChatRevamp.stories.tsx +56 -99
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
import { uiColors } from '../../constants/uiColors';
|
|
4
|
+
|
|
5
|
+
interface ChatTabsProps {
|
|
6
|
+
tabs: { label: string; id: string }[];
|
|
7
|
+
activeTab: string;
|
|
8
|
+
onChangeTab: (tabId: string) => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const ChatTabs: React.FC<ChatTabsProps> = ({
|
|
12
|
+
tabs,
|
|
13
|
+
activeTab,
|
|
14
|
+
onChangeTab,
|
|
15
|
+
}) => (
|
|
16
|
+
<TabContainer>
|
|
17
|
+
{tabs.map((tab, index) => (
|
|
18
|
+
<Tab
|
|
19
|
+
key={`${tab.label}_${index}`}
|
|
20
|
+
active={tab.id === activeTab}
|
|
21
|
+
onPointerDown={() => onChangeTab(tab.id)}
|
|
22
|
+
>
|
|
23
|
+
{tab.label}
|
|
24
|
+
</Tab>
|
|
25
|
+
))}
|
|
26
|
+
</TabContainer>
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const TabContainer = styled.div`
|
|
30
|
+
display: flex;
|
|
31
|
+
gap: 10px;
|
|
32
|
+
align-items: center;
|
|
33
|
+
flex-grow: 1;
|
|
34
|
+
`;
|
|
35
|
+
|
|
36
|
+
const Tab = styled.button<{ active: boolean }>`
|
|
37
|
+
width: 120px;
|
|
38
|
+
color: white;
|
|
39
|
+
font-size: 0.8rem;
|
|
40
|
+
all: unset;
|
|
41
|
+
padding: 0.6rem;
|
|
42
|
+
font-size: 0.8rem;
|
|
43
|
+
border-radius: 5px 5px 0 0;
|
|
44
|
+
border-width: 0.25rem 0.25rem 0 0.25rem;
|
|
45
|
+
border-style: solid;
|
|
46
|
+
border-color: ${props =>
|
|
47
|
+
props.active ? 'rgba(198, 81, 2, 0.5)' : 'rgba(128, 128, 128, 0.5)'};
|
|
48
|
+
background-color: ${props =>
|
|
49
|
+
props.active ? uiColors.orange : 'rgba(0, 0, 0, 0.2)'};
|
|
50
|
+
color: ${props => (props.active ? 'white' : uiColors.darkGray)};
|
|
51
|
+
`;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { IoMdContract, IoMdExpand } from 'react-icons/io';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
import { uiColors } from '../../constants/uiColors';
|
|
5
|
+
|
|
6
|
+
interface ExpandButtonProps {
|
|
7
|
+
isExpanded: boolean;
|
|
8
|
+
onClick: () => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const ExpandButton: React.FC<ExpandButtonProps> = ({
|
|
12
|
+
isExpanded,
|
|
13
|
+
onClick,
|
|
14
|
+
}) => (
|
|
15
|
+
<StyledExpandButton isExpanded={isExpanded} onClick={onClick}>
|
|
16
|
+
{isExpanded ? <IoMdContract size={20} /> : <IoMdExpand size={20} />}
|
|
17
|
+
</StyledExpandButton>
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
const StyledExpandButton = styled.button<{ isExpanded: boolean }>`
|
|
21
|
+
position: absolute;
|
|
22
|
+
top: 0;
|
|
23
|
+
${({ isExpanded }) => (isExpanded ? 'right: 0' : 'left: 0')};
|
|
24
|
+
width: 30px;
|
|
25
|
+
height: 30px;
|
|
26
|
+
background-color: ${uiColors.orange};
|
|
27
|
+
color: white;
|
|
28
|
+
border: none;
|
|
29
|
+
border-radius: 50%;
|
|
30
|
+
display: flex;
|
|
31
|
+
justify-content: center;
|
|
32
|
+
align-items: center;
|
|
33
|
+
cursor: pointer;
|
|
34
|
+
transition: all 0.3s ease;
|
|
35
|
+
z-index: 10;
|
|
36
|
+
|
|
37
|
+
&:hover {
|
|
38
|
+
background-color: ${uiColors.orange};
|
|
39
|
+
}
|
|
40
|
+
`;
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { RxCross2, RxMagnifyingGlass } from 'react-icons/rx';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
import { uiColors } from '../../constants/uiColors';
|
|
5
|
+
import { uiFonts } from '../../constants/uiFonts';
|
|
6
|
+
import { Ellipsis } from '../shared/Ellipsis';
|
|
7
|
+
import { PrivateChatCharacter } from './types';
|
|
8
|
+
|
|
9
|
+
interface IRecentChatsProps {
|
|
10
|
+
showRecentChats: boolean;
|
|
11
|
+
toggleRecentChats: () => void;
|
|
12
|
+
hasUnseenMessages: boolean;
|
|
13
|
+
showSearchCharacterUI: () => void;
|
|
14
|
+
recentChatCharacters?: PrivateChatCharacter[];
|
|
15
|
+
recentSelectedChatCharacterId?: string;
|
|
16
|
+
unseenMessageCharacterIds?: string[];
|
|
17
|
+
onPreviousChatCharacterClick: (character: PrivateChatCharacter) => void;
|
|
18
|
+
onRemoveRecentChatCharacter?: (character: PrivateChatCharacter) => void;
|
|
19
|
+
isPrivate: boolean;
|
|
20
|
+
hideSearchCharacterUI: () => void; // Add this line
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const RecentChats: React.FC<IRecentChatsProps> = ({
|
|
24
|
+
showRecentChats,
|
|
25
|
+
toggleRecentChats,
|
|
26
|
+
hasUnseenMessages,
|
|
27
|
+
showSearchCharacterUI,
|
|
28
|
+
recentChatCharacters,
|
|
29
|
+
recentSelectedChatCharacterId,
|
|
30
|
+
unseenMessageCharacterIds,
|
|
31
|
+
onPreviousChatCharacterClick,
|
|
32
|
+
onRemoveRecentChatCharacter,
|
|
33
|
+
isPrivate,
|
|
34
|
+
hideSearchCharacterUI, // Add this line
|
|
35
|
+
}) => {
|
|
36
|
+
const handlePreviousChatCharacterClick = (
|
|
37
|
+
character: PrivateChatCharacter
|
|
38
|
+
) => {
|
|
39
|
+
onPreviousChatCharacterClick(character);
|
|
40
|
+
hideSearchCharacterUI(); // Call hideSearchCharacterUI here
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<RecentChatTabContainer isOpen={showRecentChats} isPrivate={isPrivate}>
|
|
45
|
+
<RecentChatTopBar>
|
|
46
|
+
<BurgerIconContainer
|
|
47
|
+
onPointerDown={toggleRecentChats}
|
|
48
|
+
hasUnseenMessages={hasUnseenMessages}
|
|
49
|
+
>
|
|
50
|
+
<BurgerLineIcon />
|
|
51
|
+
<BurgerLineIcon />
|
|
52
|
+
<BurgerLineIcon />
|
|
53
|
+
</BurgerIconContainer>
|
|
54
|
+
{showRecentChats && (
|
|
55
|
+
<SearchButton onPointerDown={showSearchCharacterUI}>
|
|
56
|
+
<RxMagnifyingGlass size={16} color={uiColors.white} />
|
|
57
|
+
</SearchButton>
|
|
58
|
+
)}
|
|
59
|
+
</RecentChatTopBar>
|
|
60
|
+
<RecentChatLogContainer isOpen={showRecentChats}>
|
|
61
|
+
{recentChatCharacters?.map(character => (
|
|
62
|
+
<ListElementContainer key={character._id}>
|
|
63
|
+
<ListElement
|
|
64
|
+
active={character._id === recentSelectedChatCharacterId}
|
|
65
|
+
onPointerDown={() => handlePreviousChatCharacterClick(character)}
|
|
66
|
+
>
|
|
67
|
+
<StatusDot
|
|
68
|
+
isUnseen={
|
|
69
|
+
unseenMessageCharacterIds?.includes(character._id) ?? false
|
|
70
|
+
}
|
|
71
|
+
/>
|
|
72
|
+
<Ellipsis maxWidth="140px" maxLines={1}>
|
|
73
|
+
{character.name}
|
|
74
|
+
</Ellipsis>
|
|
75
|
+
</ListElement>
|
|
76
|
+
<CloseButton
|
|
77
|
+
className="close-button"
|
|
78
|
+
onPointerDown={() => onRemoveRecentChatCharacter?.(character)}
|
|
79
|
+
>
|
|
80
|
+
<RxCross2 size={16} />
|
|
81
|
+
</CloseButton>
|
|
82
|
+
</ListElementContainer>
|
|
83
|
+
))}
|
|
84
|
+
</RecentChatLogContainer>
|
|
85
|
+
</RecentChatTabContainer>
|
|
86
|
+
);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const RecentChatTabContainer = styled.div<{
|
|
90
|
+
isPrivate: boolean;
|
|
91
|
+
isOpen: boolean;
|
|
92
|
+
}>`
|
|
93
|
+
display: ${props => (props.isPrivate ? 'flex' : 'none')};
|
|
94
|
+
flex-direction: column;
|
|
95
|
+
border-right: 1px solid ${uiColors.gray};
|
|
96
|
+
outline: none;
|
|
97
|
+
width: ${props => (props.isOpen ? '25%' : '30px')};
|
|
98
|
+
max-width: 200px;
|
|
99
|
+
min-width: ${props => (props.isOpen ? '180px' : '30px')};
|
|
100
|
+
transition: all 0.3s ease-in-out;
|
|
101
|
+
overflow: hidden;
|
|
102
|
+
height: 100%;
|
|
103
|
+
@media (max-width: 768px) {
|
|
104
|
+
width: ${props => (props.isOpen ? '50%' : '30px')};
|
|
105
|
+
min-width: ${props => (props.isOpen ? '150px' : '30px')};
|
|
106
|
+
}
|
|
107
|
+
`;
|
|
108
|
+
|
|
109
|
+
const RecentChatTopBar = styled.div`
|
|
110
|
+
display: flex;
|
|
111
|
+
align-items: center;
|
|
112
|
+
justify-content: space-between;
|
|
113
|
+
height: 30px;
|
|
114
|
+
flex-shrink: 0;
|
|
115
|
+
`;
|
|
116
|
+
|
|
117
|
+
const SearchButton = styled.button`
|
|
118
|
+
border: none;
|
|
119
|
+
background-color: transparent;
|
|
120
|
+
display: flex;
|
|
121
|
+
flex-direction: column;
|
|
122
|
+
align-items: flex-end;
|
|
123
|
+
gap: 2px;
|
|
124
|
+
padding: 4px;
|
|
125
|
+
position: relative;
|
|
126
|
+
`;
|
|
127
|
+
|
|
128
|
+
const BurgerIconContainer = styled.button<{ hasUnseenMessages: boolean }>`
|
|
129
|
+
border: none;
|
|
130
|
+
background-color: transparent;
|
|
131
|
+
display: flex;
|
|
132
|
+
flex-direction: column;
|
|
133
|
+
align-items: flex-end;
|
|
134
|
+
padding: 4px;
|
|
135
|
+
gap: 2px;
|
|
136
|
+
position: relative;
|
|
137
|
+
|
|
138
|
+
&:after {
|
|
139
|
+
content: '';
|
|
140
|
+
width: 6px;
|
|
141
|
+
height: 6px;
|
|
142
|
+
position: absolute;
|
|
143
|
+
top: 0;
|
|
144
|
+
right: 2px;
|
|
145
|
+
border-radius: 50%;
|
|
146
|
+
background-color: ${uiColors.lightGreen};
|
|
147
|
+
display: ${props => (props.hasUnseenMessages ? 'block' : 'none')};
|
|
148
|
+
}
|
|
149
|
+
`;
|
|
150
|
+
|
|
151
|
+
const BurgerLineIcon = styled.span`
|
|
152
|
+
width: 1rem;
|
|
153
|
+
height: 2px;
|
|
154
|
+
background-color: #ffffff;
|
|
155
|
+
`;
|
|
156
|
+
|
|
157
|
+
const RecentChatLogContainer = styled.div<{ isOpen: boolean }>`
|
|
158
|
+
display: ${props => (props.isOpen ? 'flex' : 'none')};
|
|
159
|
+
opacity: ${props => (props.isOpen ? 1 : 0)};
|
|
160
|
+
flex-direction: column;
|
|
161
|
+
gap: 0.25rem; // Reduce this from 0.5rem to 0.25rem
|
|
162
|
+
transition: opacity 0.3s ease-in-out;
|
|
163
|
+
padding: 0;
|
|
164
|
+
margin: 0;
|
|
165
|
+
overflow-y: auto;
|
|
166
|
+
flex-grow: 1;
|
|
167
|
+
height: 0;
|
|
168
|
+
|
|
169
|
+
/* Firefox */
|
|
170
|
+
scrollbar-width: thin;
|
|
171
|
+
scrollbar-color: rgba(51, 51, 51, 0.4) rgba(30, 30, 30, 0.4);
|
|
172
|
+
|
|
173
|
+
/* WebKit and Chromium-based browsers */
|
|
174
|
+
&::-webkit-scrollbar {
|
|
175
|
+
width: 8px;
|
|
176
|
+
height: 8px;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
&::-webkit-scrollbar-track {
|
|
180
|
+
background: rgba(30, 30, 30, 0.2);
|
|
181
|
+
border-radius: 4px;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
&::-webkit-scrollbar-thumb {
|
|
185
|
+
background-color: rgba(255, 102, 0, 0.5);
|
|
186
|
+
border-radius: 4px;
|
|
187
|
+
border: 2px solid rgba(30, 30, 30, 0.2);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
&::-webkit-scrollbar-thumb:hover {
|
|
191
|
+
background-color: rgba(255, 102, 0, 0.7);
|
|
192
|
+
}
|
|
193
|
+
`;
|
|
194
|
+
|
|
195
|
+
const ListElementContainer = styled.div`
|
|
196
|
+
display: flex;
|
|
197
|
+
justify-content: space-between;
|
|
198
|
+
align-items: center;
|
|
199
|
+
padding: 2px 0; // Add small vertical padding
|
|
200
|
+
`;
|
|
201
|
+
|
|
202
|
+
const ListElement = styled.button<{ active: boolean }>`
|
|
203
|
+
margin: 0 !important; // Remove vertical margins
|
|
204
|
+
font-size: ${uiFonts.size.small} !important;
|
|
205
|
+
padding: 2px;
|
|
206
|
+
all: unset;
|
|
207
|
+
color: ${props => (props.active ? uiColors.yellow : uiColors.white)};
|
|
208
|
+
width: 100%;
|
|
209
|
+
position: relative;
|
|
210
|
+
display: flex;
|
|
211
|
+
align-items: center;
|
|
212
|
+
gap: 4px;
|
|
213
|
+
|
|
214
|
+
&:hover {
|
|
215
|
+
color: #ff0;
|
|
216
|
+
}
|
|
217
|
+
max-width: calc(100% - 24px);
|
|
218
|
+
overflow: hidden;
|
|
219
|
+
text-overflow: ellipsis;
|
|
220
|
+
white-space: nowrap;
|
|
221
|
+
`;
|
|
222
|
+
|
|
223
|
+
const StatusDot = styled.span<{ isUnseen: boolean }>`
|
|
224
|
+
width: 6px;
|
|
225
|
+
height: 6px;
|
|
226
|
+
border-radius: 50%;
|
|
227
|
+
background-color: ${props =>
|
|
228
|
+
props.isUnseen ? uiColors.lightGreen : uiColors.gray};
|
|
229
|
+
display: inline-block;
|
|
230
|
+
margin-right: 6px;
|
|
231
|
+
`;
|
|
232
|
+
|
|
233
|
+
const CloseButton = styled.button`
|
|
234
|
+
all: unset;
|
|
235
|
+
font-size: ${uiFonts.size.xxsmall};
|
|
236
|
+
margin: 0 0.5rem;
|
|
237
|
+
transition: all 0.2s ease-in-out;
|
|
238
|
+
background-color: ${uiColors.red};
|
|
239
|
+
color: ${uiColors.white};
|
|
240
|
+
width: 16px;
|
|
241
|
+
height: 16px;
|
|
242
|
+
border-radius: 50%;
|
|
243
|
+
display: flex;
|
|
244
|
+
justify-content: center;
|
|
245
|
+
align-items: center;
|
|
246
|
+
&:hover {
|
|
247
|
+
background-color: ${uiColors.white};
|
|
248
|
+
color: ${uiColors.red};
|
|
249
|
+
}
|
|
250
|
+
`;
|
|
@@ -6,7 +6,7 @@ import { uiFonts } from '../../constants/uiFonts';
|
|
|
6
6
|
import { IStyles } from '../Chat/Chat';
|
|
7
7
|
import { Column } from '../shared/Column';
|
|
8
8
|
import { Ellipsis } from '../shared/Ellipsis';
|
|
9
|
-
import
|
|
9
|
+
import { PrivateChatCharacter } from './types';
|
|
10
10
|
|
|
11
11
|
interface ISearchCharacterProps {
|
|
12
12
|
onFocus?: () => void;
|
|
@@ -37,7 +37,7 @@ export const SearchCharacter = ({
|
|
|
37
37
|
const searchCharacterRef = useRef<HTMLInputElement>(null);
|
|
38
38
|
|
|
39
39
|
useEffect(() => {
|
|
40
|
-
|
|
40
|
+
const timer = setTimeout(() => {
|
|
41
41
|
if (searchCharacterRef.current) {
|
|
42
42
|
searchCharacterRef.current.focus();
|
|
43
43
|
}
|
|
@@ -52,9 +52,7 @@ export const SearchCharacter = ({
|
|
|
52
52
|
onChangeCharacterName(characterName);
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
-
const handleCharacterClick = (
|
|
56
|
-
character: PrivateChatCharacter
|
|
57
|
-
) => {
|
|
55
|
+
const handleCharacterClick = (character: PrivateChatCharacter) => {
|
|
58
56
|
if (!onCharacterClick) return;
|
|
59
57
|
setCharacterName('');
|
|
60
58
|
onCharacterClick(character);
|
|
@@ -69,23 +67,23 @@ export const SearchCharacter = ({
|
|
|
69
67
|
value={characterName}
|
|
70
68
|
ref={searchCharacterRef}
|
|
71
69
|
id="characterName"
|
|
72
|
-
name=
|
|
70
|
+
name="characterName"
|
|
73
71
|
onChange={e => {
|
|
74
72
|
setCharacterName(e.target.value);
|
|
75
73
|
onChangeCharacterName(e.target.value);
|
|
76
74
|
}}
|
|
77
|
-
placeholder=
|
|
75
|
+
placeholder="Search for a character..."
|
|
78
76
|
height={20}
|
|
79
77
|
type="text"
|
|
80
78
|
autoComplete="off"
|
|
81
79
|
onFocus={onFocus}
|
|
82
80
|
onBlur={onBlur}
|
|
83
81
|
onPointerDown={onFocus}
|
|
84
|
-
|
|
82
|
+
/>
|
|
85
83
|
</Column>
|
|
86
84
|
<Column justifyContent="flex-end">
|
|
87
85
|
<SearchButton
|
|
88
|
-
type=
|
|
86
|
+
type="submit"
|
|
89
87
|
buttonColor={styles?.buttonColor || '#005b96'}
|
|
90
88
|
buttonBackgroundColor={
|
|
91
89
|
styles?.buttonBackgroundColor || 'rgba(0,0,0,.5)'
|
|
@@ -101,28 +99,29 @@ export const SearchCharacter = ({
|
|
|
101
99
|
{recentCharacters && recentCharacters.length > 0 && (
|
|
102
100
|
<ListContainer>
|
|
103
101
|
{recentCharacters.map(character => (
|
|
104
|
-
<ListElement
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
102
|
+
<ListElement
|
|
103
|
+
onPointerDown={() => handleCharacterClick(character)}
|
|
104
|
+
key={character._id}
|
|
105
|
+
>
|
|
106
|
+
<Ellipsis maxWidth="150px" maxLines={1}>
|
|
107
|
+
{character.name}
|
|
108
|
+
</Ellipsis>
|
|
109
109
|
</ListElement>
|
|
110
110
|
))}
|
|
111
111
|
</ListContainer>
|
|
112
112
|
)}
|
|
113
|
-
|
|
113
|
+
</SearchContainer>
|
|
114
114
|
);
|
|
115
115
|
};
|
|
116
116
|
|
|
117
|
-
|
|
118
117
|
interface IButtonProps {
|
|
119
118
|
buttonColor: string;
|
|
120
119
|
buttonBackgroundColor: string;
|
|
121
120
|
}
|
|
122
121
|
|
|
123
122
|
const SearchContainer = styled.div`
|
|
124
|
-
width: 100%;
|
|
125
|
-
|
|
123
|
+
width: 100%;
|
|
124
|
+
`;
|
|
126
125
|
|
|
127
126
|
const Form = styled.form`
|
|
128
127
|
display: flex;
|
|
@@ -167,5 +166,3 @@ const ListElement = styled.li`
|
|
|
167
166
|
all: unset;
|
|
168
167
|
}
|
|
169
168
|
`;
|
|
170
|
-
|
|
171
|
-
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ICharacter,
|
|
3
|
+
IChatMessage,
|
|
4
|
+
IPrivateChatMessage,
|
|
5
|
+
ITradeChatMessage,
|
|
6
|
+
} from '@rpg-engine/shared';
|
|
7
|
+
import { IStyles } from '../Chat/Chat';
|
|
8
|
+
|
|
9
|
+
export type PrivateChatCharacter = Pick<ICharacter, '_id' | 'name'>;
|
|
10
|
+
|
|
11
|
+
export type ChatMessage =
|
|
12
|
+
| IChatMessage
|
|
13
|
+
| IPrivateChatMessage
|
|
14
|
+
| ITradeChatMessage;
|
|
15
|
+
|
|
16
|
+
export interface IChatRevampProps {
|
|
17
|
+
chatMessages: ChatMessage[];
|
|
18
|
+
onSendGlobalChatMessage: (message: string) => void;
|
|
19
|
+
onCloseButton: () => void;
|
|
20
|
+
onFocus?: () => void;
|
|
21
|
+
onBlur?: () => void;
|
|
22
|
+
styles?: IStyles;
|
|
23
|
+
tabs: { label: string; id: string }[];
|
|
24
|
+
activeTab: string;
|
|
25
|
+
onChangeTab: (tabId: string) => void;
|
|
26
|
+
privateChatCharacters?: PrivateChatCharacter[];
|
|
27
|
+
onChangeCharacterName: (characterName: string) => void;
|
|
28
|
+
onCharacterClick?: (character: PrivateChatCharacter) => void;
|
|
29
|
+
onSendPrivateChatMessage: (message: string) => void;
|
|
30
|
+
recentChatCharacters?: PrivateChatCharacter[];
|
|
31
|
+
recentSelectedChatCharacterId?: string;
|
|
32
|
+
onPreviousChatCharacterClick?: (character: PrivateChatCharacter) => void;
|
|
33
|
+
onRemoveRecentChatCharacter?: (character: PrivateChatCharacter) => void;
|
|
34
|
+
unseenMessageCharacterIds?: string[];
|
|
35
|
+
onSendTradeMessage: (message: string) => void;
|
|
36
|
+
searchCharacterUI: boolean;
|
|
37
|
+
hideSearchCharacterUI: () => void;
|
|
38
|
+
showSearchCharacterUI: () => void;
|
|
39
|
+
minimizedByDefault?: boolean;
|
|
40
|
+
autoCloseOnSend?: boolean;
|
|
41
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { PrivateChatCharacter } from '../components/ChatRevamp/types';
|
|
3
|
+
|
|
4
|
+
interface IUseChat {
|
|
5
|
+
minimizedByDefault: boolean;
|
|
6
|
+
isPrivate: boolean;
|
|
7
|
+
onChangeTab: (tabId: string) => void;
|
|
8
|
+
onPreviousChatCharacterClick?: (character: PrivateChatCharacter) => void;
|
|
9
|
+
hideSearchCharacterUI?: () => void;
|
|
10
|
+
unseenMessageCharacterIds?: string[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const useChat = ({
|
|
14
|
+
minimizedByDefault,
|
|
15
|
+
isPrivate,
|
|
16
|
+
onChangeTab,
|
|
17
|
+
onPreviousChatCharacterClick,
|
|
18
|
+
hideSearchCharacterUI,
|
|
19
|
+
unseenMessageCharacterIds,
|
|
20
|
+
}: IUseChat) => {
|
|
21
|
+
const [showRecentChats, setShowRecentChats] = useState(false);
|
|
22
|
+
const [isExpanded, setIsExpanded] = useState(!minimizedByDefault);
|
|
23
|
+
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (isPrivate) {
|
|
26
|
+
setIsExpanded(true);
|
|
27
|
+
}
|
|
28
|
+
}, [isPrivate]);
|
|
29
|
+
|
|
30
|
+
const toggleExpand = () => setIsExpanded(prev => !prev);
|
|
31
|
+
|
|
32
|
+
const toggleRecentChats = () => setShowRecentChats(prev => !prev);
|
|
33
|
+
|
|
34
|
+
const handleTabChange = (tabId: string) => {
|
|
35
|
+
if (tabId === 'private') {
|
|
36
|
+
setIsExpanded(true);
|
|
37
|
+
}
|
|
38
|
+
onChangeTab(tabId);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const handlePreviousChatCharacterClick = (
|
|
42
|
+
character: PrivateChatCharacter
|
|
43
|
+
) => {
|
|
44
|
+
if (onPreviousChatCharacterClick) {
|
|
45
|
+
onPreviousChatCharacterClick(character);
|
|
46
|
+
}
|
|
47
|
+
if (hideSearchCharacterUI) {
|
|
48
|
+
hideSearchCharacterUI();
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
showRecentChats,
|
|
54
|
+
isExpanded,
|
|
55
|
+
toggleExpand,
|
|
56
|
+
toggleRecentChats,
|
|
57
|
+
handleTabChange,
|
|
58
|
+
handlePreviousChatCharacterClick,
|
|
59
|
+
hasUnseenMessages:
|
|
60
|
+
unseenMessageCharacterIds && unseenMessageCharacterIds?.length > 0,
|
|
61
|
+
};
|
|
62
|
+
};
|