Skip to content

Commit

Permalink
feat(conversation): extract reused properties to composable, expose m…
Browse files Browse the repository at this point in the history
…essages in selector optionally

Signed-off-by: Maksim Sukharev <antreesy.web@gmail.com>
  • Loading branch information
Antreesy committed Feb 16, 2024
1 parent bbbb190 commit 8879269
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 207 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@ describe('Conversation.vue', () => {
testStoreConfig = cloneDeep(storeConfig)
messagesMock = jest.fn().mockReturnValue({})
testStoreConfig.modules.messagesStore.getters.messages = () => messagesMock
testStoreConfig.modules.actorStore.getters.getUserId = () => jest.fn().mockReturnValue('user-id-self')
store = new Vuex.Store(testStoreConfig)

// common defaults
item = {
token: TOKEN,
actorId: 'actor-id-1',
actorType: ATTENDEE.ACTOR_TYPE.USERS,
participants: [
],
participantType: PARTICIPANT.TYPE.USER,
Expand Down Expand Up @@ -155,7 +155,7 @@ describe('Conversation.vue', () => {
})

test('displays own last chat message with "You" as author', () => {
item.lastMessage.actorId = 'user-id-self'
item.lastMessage.actorId = 'actor-id-1'

testConversationLabel(item, 'You: hello')
})
Expand All @@ -174,7 +174,7 @@ describe('Conversation.vue', () => {

test('displays own last message with "You" author in one to one conversations', () => {
item.type = CONVERSATION.TYPE.ONE_TO_ONE
item.lastMessage.actorId = 'user-id-self'
item.lastMessage.actorId = 'actor-id-1'

testConversationLabel(item, 'You: hello')
})
Expand Down
118 changes: 13 additions & 105 deletions src/components/LeftSidebar/ConversationsList/Conversation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@

<script>
import { toRefs } from 'vue'
import { Fragment } from 'vue-frag'
import { isNavigationFailure, NavigationFailureType } from 'vue-router'
Expand All @@ -162,7 +163,8 @@ import NcListItem from '@nextcloud/vue/dist/Components/NcListItem.js'
import ConversationIcon from './../../ConversationIcon.vue'
import { CONVERSATION, PARTICIPANT, ATTENDEE } from '../../../constants.js'
import { useConversationInfo } from '../../../composables/useConversationInfo.js'
import { CONVERSATION, PARTICIPANT } from '../../../constants.js'
import { copyConversationLinkToClipboard } from '../../../services/urlService.js'
export default {
Expand Down Expand Up @@ -215,6 +217,16 @@ export default {
emits: ['click'],
setup(props) {
const { item, isSearchResult } = toRefs(props)
const { counterType, conversationInformation } = useConversationInfo({ item, isSearchResult })
return {
counterType,
conversationInformation,
}
},
data() {
return {
isDialogOpen: false,
Expand All @@ -226,18 +238,6 @@ export default {
return this.$store.getters.getMainContainerSelector()
},
counterType() {
if (this.item.unreadMentionDirect || (this.item.unreadMessages !== 0 && (
this.item.type === CONVERSATION.TYPE.ONE_TO_ONE || this.item.type === CONVERSATION.TYPE.ONE_TO_ONE_FORMER
))) {
return 'highlighted'
} else if (this.item.unreadMention) {
return 'outlined'
} else {
return ''
}
},
canFavorite() {
return this.item.participantType !== PARTICIPANT.TYPE.USER_SELF_JOINED
},
Expand Down Expand Up @@ -266,105 +266,13 @@ export default {
return this.item.canLeaveConversation
},
conversationInformation() {
// temporary item while joining
if (!this.isSearchResult && !this.item.actorId) {
return t('spreed', 'Joining conversation …')
}
if (!Object.keys(this.lastChatMessage).length) {
return ''
}
if (this.shortLastChatMessageAuthor === '') {
return this.simpleLastChatMessage
}
if (this.lastChatMessage.actorId === this.$store.getters.getUserId()) {
return t('spreed', 'You: {lastMessage}', {
lastMessage: this.simpleLastChatMessage,
}, undefined, {
escape: false,
sanitize: false,
})
}
if (this.item.type === CONVERSATION.TYPE.ONE_TO_ONE
|| this.item.type === CONVERSATION.TYPE.ONE_TO_ONE_FORMER
|| this.item.type === CONVERSATION.TYPE.CHANGELOG) {
return this.simpleLastChatMessage
}
return t('spreed', '{actor}: {lastMessage}', {
actor: this.shortLastChatMessageAuthor,
lastMessage: this.simpleLastChatMessage,
}, undefined, {
escape: false,
sanitize: false,
})
},
// Get the last message for this conversation from the message store instead
// of the conversations store. The message store is updated immediately,
// while the conversations store is refreshed every 30 seconds. This allows
// to display message previews in this component as soon as new messages are
// received by the server.
lastChatMessage() {
return this.item.lastMessage
},
dialogMessage() {
return t('spreed', 'Do you really want to delete "{displayName}"?', this.item, undefined, {
escape: false,
sanitize: false,
})
},
/**
* This is a simplified version of the last chat message.
* Parameters are parsed without markup (just replaced with the name),
* e.g. no avatars on mentions.
*
* @return {string} A simple message to show below the conversation name
*/
simpleLastChatMessage() {
if (!Object.keys(this.lastChatMessage).length) {
return ''
}
const params = this.lastChatMessage.messageParameters
let subtitle = this.lastChatMessage.message.trim()
// We don't really use rich objects in the subtitle, instead we fall back to the name of the item
Object.keys(params).forEach((parameterKey) => {
subtitle = subtitle.replace('{' + parameterKey + '}', params[parameterKey].name)
})
return subtitle
},
/**
* @return {string} Part of the name until the first space
*/
shortLastChatMessageAuthor() {
if (!Object.keys(this.lastChatMessage).length
|| this.lastChatMessage.systemMessage.length) {
return ''
}
let author = this.lastChatMessage.actorDisplayName.trim()
const spacePosition = author.indexOf(' ')
if (spacePosition !== -1) {
author = author.substring(0, spacePosition)
}
if (author.length === 0 && this.lastChatMessage.actorType === ATTENDEE.ACTOR_TYPE.GUESTS) {
return t('spreed', 'Guest')
}
return author
},
to() {
return this.item?.token
? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
:name="item.displayName"
:title="item.displayName"
:active="item.token === selectedRoom"
:bold="!!item.unreadMessages"
:counter-number="item.unreadMessages"
:bold="exposeMessages && !!item.unreadMessages"
:counter-number="exposeMessages ? item.unreadMessages : 0"
:counter-type="counterType"
@click="onClick">
<template #icon>
Expand All @@ -39,13 +39,13 @@
</template>
<script>
import { inject } from 'vue'
import { inject, toRefs } from 'vue'
import NcListItem from '@nextcloud/vue/dist/Components/NcListItem.js'
import ConversationIcon from './../../ConversationIcon.vue'
import { CONVERSATION, ATTENDEE } from '../../../constants.js'
import { useConversationInfo } from '../../../composables/useConversationInfo.js'
export default {
name: 'ConversationSearchResult',
Expand All @@ -56,6 +56,10 @@ export default {
},
props: {
exposeMessages: {
type: Boolean,
default: false,
},
item: {
type: Object,
default() {
Expand All @@ -78,106 +82,18 @@ export default {
emits: ['click'],
setup() {
setup(props) {
const { item, exposeMessages } = toRefs(props)
const selectedRoom = inject('selectedRoom', null)
const { counterType, conversationInformation } = useConversationInfo({ item, exposeMessages })
return {
selectedRoom,
counterType,
conversationInformation,
}
},
computed: {
counterType() {
if (this.item.unreadMentionDirect || (this.item.unreadMessages !== 0 && (
this.item.type === CONVERSATION.TYPE.ONE_TO_ONE || this.item.type === CONVERSATION.TYPE.ONE_TO_ONE_FORMER
))) {
return 'highlighted'
} else if (this.item.unreadMention) {
return 'outlined'
} else {
return ''
}
},
conversationInformation() {
if (!Object.keys(Object(this.item?.lastMessage)).length) {
return ''
}
if (this.shortLastChatMessageAuthor === '') {
return this.simpleLastChatMessage
}
if (this.item.lastMessage.actorId === this.item.actorId) {
return t('spreed', 'You: {lastMessage}', {
lastMessage: this.simpleLastChatMessage,
}, undefined, {
escape: false,
sanitize: false,
})
}
if (this.item.type === CONVERSATION.TYPE.ONE_TO_ONE
|| this.item.type === CONVERSATION.TYPE.ONE_TO_ONE_FORMER
|| this.item.type === CONVERSATION.TYPE.CHANGELOG) {
return this.simpleLastChatMessage
}
return t('spreed', '{actor}: {lastMessage}', {
actor: this.shortLastChatMessageAuthor,
lastMessage: this.simpleLastChatMessage,
}, undefined, {
escape: false,
sanitize: false,
})
},
/**
* This is a simplified version of the last chat message.
* Parameters are parsed without markup (just replaced with the name),
* e.g. no avatars on mentions.
*
* @return {string} A simple message to show below the conversation name
*/
simpleLastChatMessage() {
if (!Object.keys(this.item.lastMessage).length) {
return ''
}
const params = this.item.lastMessage.messageParameters
let subtitle = this.item.lastMessage.message.trim()
// We don't really use rich objects in the subtitle, instead we fall back to the name of the item
Object.keys(params).forEach((parameterKey) => {
subtitle = subtitle.replace('{' + parameterKey + '}', params[parameterKey].name)
})
return subtitle
},
/**
* @return {string} Part of the name until the first space
*/
shortLastChatMessageAuthor() {
if (!Object.keys(this.item.lastMessage).length
|| this.item.lastMessage.systemMessage.length) {
return ''
}
let author = this.item.lastMessage.actorDisplayName.trim()
const spacePosition = author.indexOf(' ')
if (spacePosition !== -1) {
author = author.substring(0, spacePosition)
}
if (author.length === 0 && this.item.lastMessage.actorType === ATTENDEE.ACTOR_TYPE.GUESTS) {
return t('spreed', 'Guest')
}
return author
},
},
methods: {
onClick() {
this.$emit('click', this.item)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
:item-size="CONVERSATION_ITEM_SIZE"
key-field="token">
<template #default="{ item }">
<ConversationSearchResult :item="item" @click="onClick" />
<ConversationSearchResult :item="item" :expose-messages="exposeMessages" @click="onClick" />
</template>
<template #after>
<LoadingPlaceholder v-if="loading" type="conversations" />
Expand Down Expand Up @@ -59,7 +59,10 @@ export default {
type: Array,
required: true,
},
exposeMessages: {
type: Boolean,
default: false,
},
loading: {
type: Boolean,
default: false,
Expand Down
Loading

0 comments on commit 8879269

Please sign in to comment.