Skip to content

Commit b5266c2

Browse files
committed
(refacto) add RoomContent component
1 parent fe32731 commit b5266c2

File tree

2 files changed

+348
-282
lines changed

2 files changed

+348
-282
lines changed
Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
<template>
2+
<div class="vac-room-container">
3+
<slot name="room-list-item" v-bind="{ room }">
4+
<div
5+
v-if="room.avatar"
6+
class="vac-room-avatar"
7+
:style="{ 'background-image': `url('${room.avatar}')` }"
8+
/>
9+
<div class="vac-name-container vac-text-ellipsis">
10+
<div class="vac-title-container">
11+
<div
12+
v-if="userStatus"
13+
class="vac-state-circle"
14+
:class="{ 'vac-state-online': userStatus === 'online' }"
15+
/>
16+
<div class="vac-room-name vac-text-ellipsis">
17+
{{ room.roomName }}
18+
</div>
19+
<div v-if="room.lastMessage" class="vac-text-date">
20+
{{ room.lastMessage.timestamp }}
21+
</div>
22+
</div>
23+
<div
24+
class="vac-text-last"
25+
:class="{
26+
'vac-message-new':
27+
room.lastMessage && room.lastMessage.new && !typingUsers
28+
}"
29+
>
30+
<span v-if="isMessageCheckmarkVisible(room)">
31+
<slot name="checkmark-icon" v-bind="room.lastMessage">
32+
<svg-icon
33+
:name="
34+
room.lastMessage.distributed
35+
? 'double-checkmark'
36+
: 'checkmark'
37+
"
38+
:param="room.lastMessage.seen ? 'seen' : ''"
39+
class="vac-icon-check"
40+
/>
41+
</slot>
42+
</span>
43+
<div
44+
v-if="
45+
room.lastMessage &&
46+
!room.lastMessage.deleted &&
47+
room.lastMessage.file &&
48+
room.lastMessage.file.audio
49+
"
50+
class="vac-text-ellipsis"
51+
>
52+
<slot name="microphone-icon">
53+
<svg-icon name="microphone" class="vac-icon-microphone" />
54+
</slot>
55+
{{ formattedDuration(room.lastMessage.file.duration) }}
56+
</div>
57+
<format-message
58+
v-else-if="room.lastMessage"
59+
:content="getLastMessage(room)"
60+
:deleted="!!room.lastMessage.deleted && !typingUsers"
61+
:users="room.users"
62+
:linkify="false"
63+
:text-formatting="textFormatting"
64+
:single-line="true"
65+
>
66+
<template #deleted-icon="data">
67+
<slot name="deleted-icon" v-bind="data" />
68+
</template>
69+
</format-message>
70+
<div
71+
v-if="!room.lastMessage && typingUsers"
72+
class="vac-text-ellipsis"
73+
>
74+
{{ typingUsers }}
75+
</div>
76+
<div class="vac-room-options-container">
77+
<div v-if="room.unreadCount" class="vac-room-badge">
78+
{{ room.unreadCount }}
79+
</div>
80+
<slot name="room-list-options" v-bind="{ room }">
81+
<div
82+
v-if="roomActions.length"
83+
class="vac-svg-button vac-list-room-options"
84+
@click.stop="roomMenuOpened = room.roomId"
85+
>
86+
<slot name="room-list-options-icon">
87+
<svg-icon name="dropdown" param="room" />
88+
</slot>
89+
</div>
90+
<transition v-if="roomActions.length" name="vac-slide-left">
91+
<div
92+
v-if="roomMenuOpened === room.roomId"
93+
v-click-outside="closeRoomMenu"
94+
class="vac-menu-options"
95+
>
96+
<div class="vac-menu-list">
97+
<div v-for="action in roomActions" :key="action.name">
98+
<div
99+
class="vac-menu-item"
100+
@click.stop="roomActionHandler(action, room)"
101+
>
102+
{{ action.title }}
103+
</div>
104+
</div>
105+
</div>
106+
</div>
107+
</transition>
108+
</slot>
109+
</div>
110+
</div>
111+
</div>
112+
</slot>
113+
</div>
114+
</template>
115+
116+
<script>
117+
import vClickOutside from 'v-click-outside'
118+
119+
import SvgIcon from '../../components/SvgIcon'
120+
import FormatMessage from '../../components/FormatMessage'
121+
122+
import typingText from '../../utils/typingText'
123+
124+
export default {
125+
name: 'RoomsContent',
126+
components: {
127+
SvgIcon,
128+
FormatMessage
129+
},
130+
131+
directives: {
132+
clickOutside: vClickOutside.directive
133+
},
134+
135+
props: {
136+
currentUserId: { type: [String, Number], required: true },
137+
room: { type: Object, required: true },
138+
textFormatting: { type: Boolean, required: true },
139+
textMessages: { type: Object, required: true },
140+
roomActions: { type: Array, required: true }
141+
},
142+
143+
data() {
144+
return {
145+
roomMenuOpened: null
146+
}
147+
},
148+
149+
computed: {
150+
userStatus() {
151+
if (!this.room.users || this.room.users.length !== 2) return
152+
153+
const user = this.room.users.find(u => u._id !== this.currentUserId)
154+
if (user.status) return user.status.state
155+
156+
return null
157+
},
158+
typingUsers() {
159+
return typingText(this.room, this.currentUserId, this.textMessages)
160+
}
161+
},
162+
163+
watch: {},
164+
165+
methods: {
166+
getLastMessage(room) {
167+
const isTyping = this.typingUsers
168+
if (isTyping) return isTyping
169+
170+
const content = room.lastMessage.deleted
171+
? this.textMessages.MESSAGE_DELETED
172+
: room.lastMessage.content
173+
174+
if (room.users.length <= 2) {
175+
return content
176+
}
177+
178+
const user = room.users.find(
179+
user => user._id === room.lastMessage.sender_id
180+
)
181+
182+
if (room.lastMessage.username) {
183+
return `${room.lastMessage.username} - ${content}`
184+
} else if (!user || user._id === this.currentUserId) {
185+
return content
186+
}
187+
188+
return `${user.username} - ${content}`
189+
},
190+
formattedDuration(s) {
191+
s = Math.round(s)
192+
return (s - (s %= 60)) / 60 + (s > 9 ? ':' : ':0') + s
193+
},
194+
isMessageCheckmarkVisible(room) {
195+
return (
196+
!this.typingUsers &&
197+
room.lastMessage &&
198+
!room.lastMessage.deleted &&
199+
room.lastMessage.sender_id === this.currentUserId &&
200+
(room.lastMessage.saved ||
201+
room.lastMessage.distributed ||
202+
room.lastMessage.seen)
203+
)
204+
},
205+
roomActionHandler(action, room) {
206+
this.closeRoomMenu()
207+
this.$emit('room-action-handler', { action, roomId: room.roomId })
208+
},
209+
closeRoomMenu() {
210+
this.roomMenuOpened = null
211+
}
212+
}
213+
}
214+
</script>
215+
216+
<style lang="scss" scoped>
217+
.vac-room-container {
218+
display: flex;
219+
flex: 1;
220+
align-items: center;
221+
}
222+
223+
.vac-name-container {
224+
flex: 1;
225+
}
226+
227+
.vac-text-ellipsis {
228+
white-space: nowrap;
229+
overflow: hidden;
230+
text-overflow: ellipsis;
231+
}
232+
233+
.vac-title-container {
234+
display: flex;
235+
align-items: center;
236+
line-height: 25px;
237+
}
238+
239+
.vac-state-circle {
240+
width: 9px;
241+
height: 9px;
242+
border-radius: 50%;
243+
background-color: var(--chat-room-color-offline);
244+
margin-right: 6px;
245+
transition: 0.3s;
246+
}
247+
248+
.vac-state-online {
249+
background-color: var(--chat-room-color-online);
250+
}
251+
252+
.vac-room-name {
253+
flex: 1;
254+
color: var(--chat-room-color-username);
255+
font-weight: 500;
256+
}
257+
258+
.vac-text-date {
259+
margin-left: 5px;
260+
font-size: 11px;
261+
color: var(--chat-room-color-timestamp);
262+
}
263+
264+
.vac-text-last {
265+
display: flex;
266+
align-items: center;
267+
font-size: 12px;
268+
line-height: 19px;
269+
color: var(--chat-room-color-message);
270+
}
271+
272+
.vac-message-new {
273+
color: var(--chat-room-color-username);
274+
font-weight: 500;
275+
}
276+
277+
.vac-icon-check {
278+
display: flex;
279+
vertical-align: middle;
280+
height: 14px;
281+
width: 14px;
282+
margin-top: -2px;
283+
margin-right: 2px;
284+
}
285+
286+
.vac-icon-microphone {
287+
height: 15px;
288+
width: 15px;
289+
vertical-align: middle;
290+
margin: -3px 1px 0 -2px;
291+
fill: var(--chat-room-color-message);
292+
}
293+
294+
.vac-room-options-container {
295+
display: flex;
296+
margin-left: auto;
297+
}
298+
299+
.vac-room-badge {
300+
background-color: var(--chat-room-bg-color-badge);
301+
color: var(--chat-room-color-badge);
302+
font-size: 11px;
303+
font-weight: 500;
304+
height: 13px;
305+
width: auto;
306+
min-width: 13px;
307+
margin-left: 5px;
308+
border-radius: 50%;
309+
display: flex;
310+
align-items: center;
311+
justify-content: center;
312+
padding: 3px;
313+
}
314+
315+
.vac-list-room-options {
316+
height: 19px;
317+
width: 19px;
318+
align-items: center;
319+
margin-left: 5px;
320+
}
321+
322+
@media only screen and (max-width: 768px) {
323+
}
324+
</style>

0 commit comments

Comments
 (0)