chore(pinia): migrate actor store to pinia

Signed-off-by: Dorra Jaouad <dorra.jaoued7@gmail.com>
This commit is contained in:
Dorra Jaouad 2025-06-06 14:21:55 +02:00
parent 84ea5a6ec8
commit 1b36c79d96
54 changed files with 415 additions and 369 deletions

View file

@ -47,6 +47,7 @@ import Router from './router/router.ts'
import BrowserStorage from './services/BrowserStorage.js'
import { EventBus } from './services/EventBus.ts'
import { leaveConversationSync } from './services/participantsService.js'
import { useActorStore } from './stores/actor.js'
import { useCallViewStore } from './stores/callView.ts'
import { useFederationStore } from './stores/federation.ts'
import { useSidebarStore } from './stores/sidebar.ts'
@ -80,6 +81,7 @@ export default {
federationStore: useFederationStore(),
callViewStore: useCallViewStore(),
sidebarStore: useSidebarStore(),
actorStore: useActorStore(),
}
},
@ -122,7 +124,7 @@ export default {
},
getUserId() {
return this.$store.getters.getUserId()
return this.actorStore.userId
},
isSendingMessages() {
@ -323,7 +325,7 @@ export default {
const payload = {
token: params.token,
participantIdentifier: this.$store.getters.getParticipantIdentifier(),
participantIdentifier: this.actorStore.getParticipantIdentifier,
flags,
silent: true,
recordingConsent: this.recordingConsentGiven,
@ -372,7 +374,7 @@ export default {
if (!getCurrentUser()) {
// Set the current actor/participant for guests
const conversation = this.$store.getters.conversation(this.token)
this.$store.dispatch('setCurrentParticipant', conversation)
this.actorStore.setCurrentParticipant(conversation)
}
})
@ -443,8 +445,8 @@ export default {
if (getCurrentUser()) {
console.debug('Setting current user')
this.$store.dispatch('setCurrentUser', getCurrentUser())
this.$store.dispatch('getCurrentUserTeams')
this.actorStore.setCurrentUser(getCurrentUser())
this.actorStore.getCurrentUserTeams()
} else {
console.debug('Can not set current user because it\'s a guest')
}

View file

@ -43,6 +43,7 @@ import {
import { checkBrowser } from './utils/browserCheck.ts'
import CancelableRequest from './utils/cancelableRequest.js'
import { signalingKill } from './utils/webrtc/index.js'
import { useActorStore } from './stores/actor.js'
export default {
@ -62,6 +63,7 @@ export default {
setup() {
return {
isLeavingAfterSessionIssue: useSessionIssueHandler(),
actorStore: useActorStore(),
}
},
@ -142,7 +144,7 @@ export default {
},
beforeMount() {
this.$store.dispatch('setCurrentUser', getCurrentUser())
this.actorStore.setCurrentUse(getCurrentUser())
window.addEventListener('unload', () => {
console.info('Navigating away, leaving conversation')

View file

@ -43,6 +43,7 @@ import {
leaveConversationSync,
setGuestUserName,
} from './services/participantsService.js'
import { useActorStore } from './stores/actor.js'
import { signalingKill } from './utils/webrtc/index.js'
export default {
@ -65,6 +66,7 @@ export default {
return {
isLeavingAfterSessionIssue: useSessionIssueHandler(),
actorStore: useActorStore(),
}
},
@ -127,9 +129,9 @@ export default {
const guestNickname = getGuestNickname()
if (currentUser) {
this.$store.dispatch('setCurrentUser', currentUser)
this.actorStore.setCurrentUser(currentUser)
} else if (guestNickname) {
this.$store.dispatch('setDisplayName', guestNickname)
this.actorStore.setDisplayName(guestNickname)
} else {
subscribe('talk:guest-name:added', this.showGuestMediaSettings)
}
@ -183,12 +185,12 @@ export default {
// Although the current participant is automatically added to
// the participants store it must be explicitly set in the
// actors store.
if (!this.$store.getters.getUserId()) {
if (!this.actorStore.userId) {
// Set the current actor/participant for guests
const conversation = this.$store.getters.conversation(this.token)
// Setting a guest only uses "sessionId" and "participantType".
this.$store.dispatch('setCurrentParticipant', conversation)
this.actorStore.setCurrentParticipant(conversation)
}
} catch (exception) {
window.clearInterval(this.fetchCurrentConversationIntervalId)

View file

@ -58,6 +58,7 @@ import { getPublicShareConversationData } from './services/filesIntegrationServi
import {
leaveConversationSync,
} from './services/participantsService.js'
import { useActorStore } from './stores/actor.js'
import { checkBrowser } from './utils/browserCheck.ts'
import { signalingKill } from './utils/webrtc/index.js'
@ -97,6 +98,7 @@ export default {
return {
isInCall: useIsInCall(),
isLeavingAfterSessionIssue: useSessionIssueHandler(),
actorStore: useActorStore(),
}
},
@ -223,7 +225,7 @@ export default {
// signaling server will retry the connection again and again,
// so at some point the anonymous user will have been overriden
// with the current user and the connection will succeed.
this.$store.dispatch('setCurrentUser', {
this.actorStore.setCurrentUser({
uid: data.userId,
displayName: data.displayName,
})
@ -241,12 +243,12 @@ export default {
// Although the current participant is automatically added to
// the participants store it must be explicitly set in the
// actors store.
if (!this.$store.getters.getUserId()) {
if (!this.actorStore.userId) {
// Set the current actor/participant for guests
const conversation = this.$store.getters.conversation(this.token)
// Setting a guest only uses "sessionId" and "participantType".
this.$store.dispatch('setCurrentParticipant', conversation)
this.actorStore.setCurrentParticipant(conversation)
}
} catch (exception) {
window.clearInterval(this.fetchCurrentConversationIntervalId)

View file

@ -164,6 +164,7 @@ import LocalVideo from '../shared/LocalVideo.vue'
import VideoBottomBar from '../shared/VideoBottomBar.vue'
import VideoVue from '../shared/VideoVue.vue'
import { ATTENDEE, PARTICIPANT } from '../../../constants.ts'
import { useActorStore } from '../../../stores/actor.js'
import { useCallViewStore } from '../../../stores/callView.ts'
import { placeholderImage, placeholderModel, placeholderName, placeholderSharedData } from './gridPlaceholders.ts'
@ -269,6 +270,7 @@ export default {
videosCap,
videosCapEnforced,
callViewStore: useCallViewStore(),
actorStore: useActorStore(),
}
},
@ -502,7 +504,7 @@ export default {
},
isGuestNonModerator() {
return this.$store.getters.getActorType() === ATTENDEE.ACTOR_TYPE.GUESTS
return this.actorStore.actorType === ATTENDEE.ACTOR_TYPE.GUESTS
&& this.$store.getters.conversation(this.token).participantType !== PARTICIPANT.TYPE.GUEST_MODERATOR
},

View file

@ -41,7 +41,7 @@
<AvatarWrapper :id="userId"
:token="token"
:name="displayName"
:source="actorType"
:source="actorStore.actorType"
:size="avatarSize"
:loading="isNotConnected"
disable-menu
@ -69,6 +69,7 @@ import AccountOff from 'vue-material-design-icons/AccountOff.vue'
import AvatarWrapper from '../../AvatarWrapper/AvatarWrapper.vue'
import VideoBackground from './VideoBackground.vue'
import { AVATAR } from '../../../constants.ts'
import { useActorStore } from '../../../stores/actor.js'
import { useCallViewStore } from '../../../stores/callView.ts'
import attachMediaStream from '../../../utils/attachmediastream.js'
import { ConnectionState } from '../../../utils/webrtc/models/CallParticipantModel.js'
@ -158,6 +159,7 @@ export default {
devMode,
screenshotMode,
callViewStore: useCallViewStore(),
actorStore: useActorStore(),
}
},
@ -208,15 +210,11 @@ export default {
},
userId() {
return this.$store.getters.getUserId()
},
actorType() {
return this.$store.getters.getActorType()
return this.actorStore.userId
},
displayName() {
return this.$store.getters.getDisplayName()
return this.actorStore.displayName
},
avatarSize() {

View file

@ -36,6 +36,7 @@ import usernameToColor from '@nextcloud/vue/functions/usernameToColor'
import Hex from 'crypto-js/enc-hex.js'
import SHA1 from 'crypto-js/sha1.js'
import TransitionWrapper from '../../UIShared/TransitionWrapper.vue'
import { useActorStore } from '../../../stores/actor.js'
import { useGuestNameStore } from '../../../stores/guestName.js'
const reactions = {
@ -86,7 +87,10 @@ export default {
setup() {
const guestNameStore = useGuestNameStore()
return { guestNameStore }
return {
guestNameStore,
actorStore: useActorStore(),
}
},
data() {
@ -159,7 +163,7 @@ export default {
reaction,
reactionURL: this.getReactionURL(reaction),
name: isLocalModel
? this.$store.getters.getDisplayName() || t('spreed', 'Guest')
? this.actorStore.displayName || t('spreed', 'Guest')
: this.getParticipantName(model),
seed: Math.random(),
})

View file

@ -101,6 +101,7 @@ import VideoIcon from 'vue-material-design-icons/Video.vue'
import VideoOff from 'vue-material-design-icons/VideoOff.vue'
import TransitionWrapper from '../../UIShared/TransitionWrapper.vue'
import { PARTICIPANT } from '../../../constants.ts'
import { useActorStore } from '../../../stores/actor.js'
import { useCallViewStore } from '../../../stores/callView.ts'
import { ConnectionState } from '../../../utils/webrtc/models/CallParticipantModel.js'
@ -186,6 +187,7 @@ export default {
setup() {
return {
callViewStore: useCallViewStore(),
actorStore: useActorStore(),
}
},
@ -265,7 +267,7 @@ export default {
// Moderator rights
participantType() {
return this.$store.getters.conversation(this.token)?.participantType
|| (this.$store.getters.getUserId() !== null
|| (this.actorStore.isLoggedIn
? PARTICIPANT.TYPE.USER
: PARTICIPANT.TYPE.GUEST)
},

View file

@ -71,6 +71,7 @@ import TransitionWrapper from './UIShared/TransitionWrapper.vue'
import { CONVERSATION, PARTICIPANT } from '../constants.ts'
import { getTalkConfig } from '../services/CapabilitiesManager.ts'
import { EventBus } from '../services/EventBus.ts'
import { useActorStore } from '../stores/actor.js'
import { useChatExtrasStore } from '../stores/chatExtras.js'
export default {
@ -108,6 +109,7 @@ export default {
provide('chatView:isSidebar', props.isSidebar)
return {
chatExtrasStore: useChatExtrasStore(),
actorStore: useActorStore(),
}
},
@ -120,16 +122,15 @@ export default {
computed: {
isGuest() {
return this.$store.getters.isActorGuest()
return this.actorStore.isActorGuest
},
isGuestWithoutDisplayName() {
const userName = this.$store.getters.getDisplayName()
return !userName && this.isGuest
return !this.actorStore.displayName && this.isGuest
},
canUploadFiles() {
return getTalkConfig(this.token, 'attachments', 'allowed') && this.$store.getters.getUserId()
return getTalkConfig(this.token, 'attachments', 'allowed') && this.actorStore.userId
&& this.$store.getters.getAttachmentFolderFreeSpace() !== 0
&& (this.conversation.permissions & PARTICIPANT.PERMISSIONS.CHAT)
&& !this.conversation.remoteServer // no attachments support in federated conversations

View file

@ -131,6 +131,7 @@ import RecordingConsentSettings from './RecordingConsentSettings.vue'
import SipSettings from './SipSettings.vue'
import { CALL, CONFIG, CONVERSATION, PARTICIPANT } from '../../constants.ts'
import { getTalkConfig, hasTalkFeature } from '../../services/CapabilitiesManager.ts'
import { useActorStore } from '../../stores/actor.js'
import { useSettingsStore } from '../../stores/settings.js'
const supportsArchive = hasTalkFeature('local', 'archived-conversations-v2')
@ -167,6 +168,7 @@ export default {
supportsArchive,
settingsStore,
meetingHeader,
actorStore: useActorStore(),
}
},
@ -195,7 +197,7 @@ export default {
},
isGuest() {
return this.$store.getters.isActorGuest()
return this.actorStore.isActorGuest
},
token() {

View file

@ -31,6 +31,7 @@ import { useStore } from '../../composables/useStore.js'
import { CONVERSATION } from '../../constants.ts'
import { getTalkConfig, hasTalkFeature } from '../../services/CapabilitiesManager.ts'
import { EventBus } from '../../services/EventBus.ts'
import { useActorStore } from '../../stores/actor.js'
import { useDashboardStore } from '../../stores/dashboard.ts'
import { hasUnreadMentions } from '../../utils/conversation.ts'
import { copyConversationLinkToClipboard } from '../../utils/handleUrl.ts'
@ -46,6 +47,7 @@ const isDirectionRTL = isRTL()
const store = useStore()
const router = useRouter()
const dashboardStore = useDashboardStore()
const actorStore = useActorStore()
const forwardScrollable = ref(false)
const backwardScrollable = ref(false)
const eventCardsWrapper = ref<HTMLDivElement | null>(null)
@ -166,7 +168,7 @@ function scrollEventCards({ direction }: { direction: 'backward' | 'forward' })
<template>
<div class="talk-dashboard-wrapper">
<h2 class="talk-dashboard__header">
{{ t('spreed', 'Hello, {displayName}', { displayName: store.getters.getDisplayName() }, { escape: false }) }}
{{ t('spreed', 'Hello, {displayName}', { displayName: actorStore.displayName }, { escape: false }) }}
</h2>
<div class="talk-dashboard__actions">
<NcPopover v-if="canStartConversations"

View file

@ -56,6 +56,7 @@ import { callSIPDialOut } from '../../../services/callsService.js'
import { hasTalkFeature } from '../../../services/CapabilitiesManager.ts'
import { createLegacyConversation } from '../../../services/conversationsService.ts'
import { addParticipant } from '../../../services/participantsService.js'
import { useActorStore } from '../../../stores/actor.js'
export default {
name: 'CallPhoneDialog',
@ -71,6 +72,12 @@ export default {
expose: ['showModal'],
setup() {
return {
actorStore: useActorStore(),
}
},
data() {
return {
modal: false,
@ -156,7 +163,7 @@ export default {
console.info('Joining call')
await this.$store.dispatch('joinCall', {
token,
participantIdentifier: this.$store.getters.getParticipantIdentifier(),
participantIdentifier: this.actorStore.getParticipantIdentifier,
flags,
silent: false,
recordingConsent: true,

View file

@ -302,6 +302,7 @@ import {
import { autocompleteQuery } from '../../services/coreService.ts'
import { EventBus } from '../../services/EventBus.ts'
import { talkBroadcastChannel } from '../../services/talkBroadcastChannel.js'
import { useActorStore } from '../../stores/actor.js'
import { useFederationStore } from '../../stores/federation.ts'
import { useSettingsStore } from '../../stores/settings.js'
import { useTalkHashStore } from '../../stores/talkHash.js'
@ -393,6 +394,7 @@ export default {
showArchived,
settingsStore,
FILTER_LABELS,
actorStore: useActorStore(),
}
},
@ -680,7 +682,7 @@ export default {
acc.push(result.name)
}
return acc
}, [this.$store.getters.getUserId()])
}, [this.actorStore.userId])
this.searchResults = response?.data?.ocs?.data.filter((match) => {
return !(match.source === ATTENDEE.ACTOR_TYPE.USERS && oneToOneMap.includes(match.id))

View file

@ -42,6 +42,7 @@ import NcRichText from '@nextcloud/vue/components/NcRichText'
import RoomService from 'vue-material-design-icons/RoomService.vue'
import GuestWelcomeWindow from './GuestWelcomeWindow.vue'
import SetGuestUsername from './SetGuestUsername.vue'
import { useActorStore } from '../stores/actor.js'
import { futureRelativeTime, ONE_DAY_IN_MS } from '../utils/formattedTime.ts'
export default {
@ -55,6 +56,12 @@ export default {
SetGuestUsername,
},
setup() {
return {
actorStore: useActorStore(),
}
},
computed: {
token() {
@ -94,12 +101,11 @@ export default {
// Determines whether the current user is a guest user
currentUserIsGuest() {
return !this.$store.getters.getUserId()
return !this.actorStore.userId
},
isGuestWithoutDisplayName() {
const userName = this.$store.getters.getDisplayName()
return !userName && this.currentUserIsGuest
return !this.actorStore.displayName && this.currentUserIsGuest
},
},

View file

@ -35,7 +35,7 @@
<AvatarWrapper :id="userId"
:token="token"
:name="displayName"
:source="actorType"
:source="actorStore.actorType"
:size="AVATAR.SIZE.EXTRA_LARGE"
disable-menu
disable-tooltip />
@ -230,6 +230,7 @@ import { useIsInCall } from '../../composables/useIsInCall.js'
import { AVATAR, CALL, CONFIG, PARTICIPANT, VIRTUAL_BACKGROUND } from '../../constants.ts'
import BrowserStorage from '../../services/BrowserStorage.js'
import { getTalkConfig } from '../../services/CapabilitiesManager.ts'
import { useActorStore } from '../../stores/actor.js'
import { useGuestNameStore } from '../../stores/guestName.js'
import { useSettingsStore } from '../../stores/settings.js'
import { localMediaModel } from '../../utils/webrtc/index.js'
@ -336,6 +337,7 @@ export default {
dialogHeaderId,
supportStartWithoutMedia,
supportDefaultBlurVirtualBackground,
actorStore: useActorStore(),
}
},
@ -360,22 +362,18 @@ export default {
computed: {
displayName() {
return this.$store.getters.getDisplayName()
return this.actorStore.displayName
},
guestName() {
return this.guestNameStore.getGuestName(
this.$store.getters.getToken(),
this.$store.getters.getActorId(),
this.actorStore.actorId,
)
},
userId() {
return this.$store.getters.getUserId()
},
actorType() {
return this.$store.getters.getActorType()
return this.actorStore.userId
},
token() {

View file

@ -85,6 +85,7 @@ import { VIRTUAL_BACKGROUND } from '../../constants.ts'
import BrowserStorage from '../../services/BrowserStorage.js'
import { getTalkConfig } from '../../services/CapabilitiesManager.ts'
import { getDavClient } from '../../services/DavClient.js'
import { useActorStore } from '../../stores/actor.js'
import { useSettingsStore } from '../../stores/settings.js'
import { findUniquePath } from '../../utils/fileUpload.js'
@ -131,6 +132,7 @@ export default {
predefinedBackgrounds: getTalkConfig('local', 'call', 'predefined-backgrounds'),
predefinedBackgroundsV2: getTalkConfig('local', 'call', 'predefined-backgrounds-v2'),
settingsStore: useSettingsStore(),
actorStore: useActorStore(),
}
},
@ -174,12 +176,12 @@ export default {
async mounted() {
this.loadBackground()
if (this.$store.getters.getUserId() === null) {
if (this.actorStore.userId === null) {
console.debug('Skip Talk backgrounds folder check and setup for participants that are not logged in')
return
}
const userRoot = '/files/' + this.$store.getters.getUserId()
const userRoot = '/files/' + this.actorStore.userId
const absoluteBackgroundsFolderPath = userRoot + this.relativeBackgroundsFolderPath
try {
@ -216,7 +218,7 @@ export default {
event.target.value = ''
// userRoot path
const userRoot = '/files/' + this.$store.getters.getUserId()
const userRoot = '/files/' + this.actorStore.userId
const filePath = this.$store.getters.getAttachmentFolder() + '/Backgrounds/' + file.name

View file

@ -122,6 +122,7 @@ import Reactions from './MessagePart/Reactions.vue'
import { CONVERSATION, MENTION, MESSAGE, PARTICIPANT } from '../../../../constants.ts'
import { getTalkConfig, hasTalkFeature } from '../../../../services/CapabilitiesManager.ts'
import { EventBus } from '../../../../services/EventBus.ts'
import { useActorStore } from '../../../../stores/actor.js'
import { useChatExtrasStore } from '../../../../stores/chatExtras.js'
import { getItemTypeFromMessage } from '../../../../utils/getItemTypeFromMessage.ts'
@ -204,6 +205,7 @@ export default {
return {
isTranslationAvailable,
chatExtrasStore: useChatExtrasStore(),
actorStore: useActorStore(),
}
},
@ -279,8 +281,8 @@ export default {
return !this.isSystemMessage
&& !this.isTemporary
&& !this.isDeleting
&& this.message.actorType === this.$store.getters.getActorType()
&& this.message.actorId === this.$store.getters.getActorId()
&& this.message.actorType === this.actorStore.actorType
&& this.message.actorId === this.actorStore.actorId
&& !this.isDeletedMessage
},

View file

@ -302,6 +302,7 @@ import { useMessageInfo } from '../../../../../composables/useMessageInfo.js'
import { ATTENDEE, CONVERSATION, MESSAGE, PARTICIPANT } from '../../../../../constants.ts'
import { hasTalkFeature } from '../../../../../services/CapabilitiesManager.ts'
import { getMessageReminder, removeMessageReminder, setMessageReminder } from '../../../../../services/remindersService.js'
import { useActorStore } from '../../../../../stores/actor.js'
import { useIntegrationsStore } from '../../../../../stores/integrations.js'
import { useReactionsStore } from '../../../../../stores/reactions.js'
import { generatePublicShareDownloadUrl, generateUserFileUrl } from '../../../../../utils/davUtils.ts'
@ -406,6 +407,7 @@ export default {
const { message } = toRefs(props)
const reactionsStore = useReactionsStore()
const { messageActions } = useIntegrationsStore()
const actorStore = useActorStore()
const {
isEditable,
isDeleteable,
@ -430,6 +432,7 @@ export default {
isDeleteable,
isConversationReadOnly,
isConversationModifiable,
actorStore,
}
},
@ -457,7 +460,7 @@ export default {
|| this.conversation.type === CONVERSATION.TYPE.GROUP)
&& !this.isCurrentUserOwnMessage
&& this.message.actorType === ATTENDEE.ACTOR_TYPE.USERS
&& this.$store.getters.isActorUser()
&& !this.isCurrentGuest
},
messageFile() {
@ -472,7 +475,7 @@ export default {
},
isCurrentGuest() {
return this.$store.getters.isActorGuest()
return this.actorStore.isActorGuest
},
isDeletedMessage() {

View file

@ -18,6 +18,7 @@ import { t } from '@nextcloud/l10n'
import { encodePath } from '@nextcloud/paths'
import { generateRemoteUrl } from '@nextcloud/router'
import { EventBus } from '../../../../../services/EventBus.ts'
import { useActorStore } from '../../../../../stores/actor.js'
export default {
name: 'AudioPlayer',
@ -67,6 +68,12 @@ export default {
},
},
setup() {
return {
actorStore: useActorStore(),
}
},
computed: {
internalAbsolutePath() {
if (this.path.startsWith('/')) {
@ -79,7 +86,7 @@ export default {
if (this.localUrl) {
return this.localUrl
}
const userId = this.$store.getters.getUserId()
const userId = this.actorStore.userId
if (userId === null) {
// guest mode, use public link download URL
return this.link + '/download/' + encodePath(this.name)

View file

@ -79,6 +79,7 @@ import AudioPlayer from './AudioPlayer.vue'
import { useViewer } from '../../../../../composables/useViewer.js'
import { SHARED_ITEM } from '../../../../../constants.ts'
import { getTalkConfig } from '../../../../../services/CapabilitiesManager.ts'
import { useActorStore } from '../../../../../stores/actor.js'
import { useSharedItemsStore } from '../../../../../stores/sharedItems.js'
const PREVIEW_TYPE = {
@ -176,6 +177,7 @@ export default {
return {
openViewer,
sharedItemsStore,
actorStore: useActorStore(),
}
},
@ -324,7 +326,7 @@ export default {
},
previewUrl() {
const userId = this.$store.getters.getUserId()
const userId = this.actorStore.userId
if (this.previewType === PREVIEW_TYPE.TEMPORARY) {
return this.file.localUrl

View file

@ -20,6 +20,7 @@ import { useIsDarkTheme } from '@nextcloud/vue/composables/useIsDarkTheme'
import NcUserBubble from '@nextcloud/vue/components/NcUserBubble'
import { MENTION } from '../../../../../constants.ts'
import { getConversationAvatarOcsUrl, getUserProxyAvatarOcsUrl } from '../../../../../services/avatarService.ts'
import { useActorStore } from '../../../../../stores/actor.js'
export default {
name: 'Mention',
@ -60,6 +61,7 @@ export default {
return {
isDarkTheme,
actorStore: useActorStore(),
}
},
@ -97,9 +99,9 @@ export default {
// So when comparing a guest we have to prefix "guest/"
// when comparing the id
// However we do not prefix email accounts, so simply compare id
return this.$store.getters.isActorGuest()
&& (this.id === ('guest/' + this.$store.getters.getActorId())
|| this.id === this.$store.getters.getActorId())
return this.actorStore.isActorGuest
&& (this.id === ('guest/' + this.actorStore.actorId)
|| this.id === this.actorStore.actorId)
},
isCurrentUser() {
@ -108,16 +110,16 @@ export default {
return false
}
return this.$store.getters.isActorUser()
&& this.id === this.$store.getters.getUserId()
return this.actorStore.isActorUser
&& this.id === this.actorStore.userId
},
isCurrentUserGroup() {
return this.isGroupMention && this.$store.getters.isActorMemberOfGroup(this.id)
return this.isGroupMention && this.actorStore.isActorMemberOfGroup(this.id)
},
isCurrentUserTeam() {
return this.isTeamMention && this.$store.getters.isActorMemberOfTeam(this.id)
return this.isTeamMention && this.actorStore.isActorMemberOfTeam(this.id)
},
primary() {

View file

@ -86,6 +86,7 @@ import EmoticonPlusOutline from 'vue-material-design-icons/EmoticonPlusOutline.v
import HeartOutlineIcon from 'vue-material-design-icons/HeartOutline.vue'
import ReactionsList from './ReactionsList.vue'
import { ATTENDEE } from '../../../../../constants.ts'
import { useActorStore } from '../../../../../stores/actor.js'
import { useGuestNameStore } from '../../../../../stores/guestName.js'
import { useReactionsStore } from '../../../../../stores/reactions.js'
import { getDisplayNameWithFallback } from '../../../../../utils/getDisplayName.ts'
@ -134,11 +135,10 @@ export default {
emits: ['emoji-picker-toggled'],
setup() {
const guestNameStore = useGuestNameStore()
const reactionsStore = useReactionsStore()
return {
guestNameStore,
reactionsStore,
guestNameStore: useGuestNameStore(),
reactionsStore: useReactionsStore(),
actorStore: useActorStore(),
}
},
@ -249,8 +249,8 @@ export default {
const summary = []
for (const item in list) {
if (list[item].actorType === this.$store.getters.getActorType()
&& list[item].actorId === this.$store.getters.getActorId()) {
if (list[item].actorType === this.actorStore.actorType
&& list[item].actorId === this.actorStore.actorId) {
summary.unshift(t('spreed', 'You'))
} else {
summary.push(this.getDisplayNameForReaction(list[item]))

View file

@ -34,6 +34,7 @@ import AvatarWrapper from '../../AvatarWrapper/AvatarWrapper.vue'
import Message from './Message/Message.vue'
import { useMessageInfo } from '../../../composables/useMessageInfo.js'
import { ATTENDEE, AVATAR } from '../../../constants.ts'
import { useActorStore } from '../../../stores/actor.js'
import { useGuestNameStore } from '../../../stores/guestName.js'
export default {
@ -92,6 +93,7 @@ export default {
return {
AVATAR,
guestNameStore: useGuestNameStore(),
actorStore: useActorStore(),
actorDisplayName,
actorInfo,
}
@ -109,7 +111,7 @@ export default {
disableMenu() {
// disable the menu if accessing the conversation as guest
// or the message sender is a bridged user
return this.$store.getters.isActorGuest() || this.actorType === ATTENDEE.ACTOR_TYPE.BRIDGED
return this.actorStore.isActorGuest || this.actorType === ATTENDEE.ACTOR_TYPE.BRIDGED
},
},

View file

@ -200,6 +200,7 @@ import BrowserStorage from '../../services/BrowserStorage.js'
import { getTalkConfig, hasTalkFeature } from '../../services/CapabilitiesManager.ts'
import { EventBus } from '../../services/EventBus.ts'
import { shareFile } from '../../services/filesSharingServices.ts'
import { useActorStore } from '../../stores/actor.js'
import { useChatExtrasStore } from '../../stores/chatExtras.js'
import { useGroupwareStore } from '../../stores/groupware.ts'
import { useSettingsStore } from '../../stores/settings.js'
@ -295,6 +296,7 @@ export default {
const { autoComplete, userData } = useChatMentions(token)
const { createTemporaryMessage } = useTemporaryMessage()
return {
actorStore: useActorStore(),
chatExtrasStore: useChatExtrasStore(),
groupwareStore: useGroupwareStore(),
settingsStore: useSettingsStore(),
@ -377,12 +379,8 @@ export default {
return messageToEditId && this.$store.getters.message(this.token, messageToEditId)
},
currentUserIsGuest() {
return this.$store.getters.getUserId() === null
},
canShareFiles() {
return !this.currentUserIsGuest
return !this.actorStore.isActorGuest
&& !this.conversation.remoteServer // no attachments support in federated conversations
},
@ -893,8 +891,8 @@ export default {
// last message within 24 hours
const lastMessageByCurrentUser = this.$store.getters.messagesList(this.token).findLast((message) => {
return message.actorId === this.$store.getters.getUserId()
&& message.actorType === this.$store.getters.getActorType()
return message.actorId === this.actorStore.userId
&& message.actorType === this.actorStore.userType
&& !message.isTemporary && !message.systemMessage
&& (Date.now() - message.timestamp * 1000 < ONE_DAY_IN_MS)
})

View file

@ -30,6 +30,7 @@ import { n, t } from '@nextcloud/l10n'
import escapeHtml from 'escape-html'
import AvatarWrapper from '../AvatarWrapper/AvatarWrapper.vue'
import { AVATAR } from '../../constants.ts'
import { useActorStore } from '../../stores/actor.js'
import { useGuestNameStore } from '../../stores/guestName.js'
export default {
@ -48,12 +49,16 @@ export default {
setup() {
const guestNameStore = useGuestNameStore()
return { AVATAR, guestNameStore }
return {
AVATAR,
guestNameStore,
actorStore: useActorStore(),
}
},
computed: {
isGuest() {
return this.$store.getters.isActorGuest()
return this.actorStore.isActorGuest
},
externalTypingSignals() {

View file

@ -137,6 +137,7 @@ import { useIsInCall } from '../../composables/useIsInCall.js'
import { POLL } from '../../constants.ts'
import { hasTalkFeature } from '../../services/CapabilitiesManager.ts'
import { EventBus } from '../../services/EventBus.ts'
import { useActorStore } from '../../stores/actor.js'
import { usePollsStore } from '../../stores/polls.ts'
import { calculateVotePercentage } from '../../utils/calculateVotePercentage.ts'
import { convertToJSONDataURI } from '../../utils/fileDownload.ts'
@ -187,6 +188,7 @@ export default {
return {
isInCall: useIsInCall(),
actorStore: useActorStore(),
pollsStore,
voteToSubmit,
modalPage,
@ -243,8 +245,8 @@ export default {
selfIsOwnerOrModerator() {
return this.isModerator
|| (this.poll?.actorType === this.$store.getters.getActorType()
&& this.poll?.actorId === this.$store.getters.getActorId())
|| (this.poll?.actorType === this.actorStore.actorType
&& this.poll?.actorId === this.actorStore.actorId)
},
pollSummaryText() {

View file

@ -67,6 +67,7 @@ import FilePreview from './MessagesList/MessagesGroup/Message/MessagePart/FilePr
import { useMessageInfo } from '../composables/useMessageInfo.js'
import { ATTENDEE, AVATAR } from '../constants.ts'
import { EventBus } from '../services/EventBus.ts'
import { useActorStore } from '../stores/actor.js'
import { useChatExtrasStore } from '../stores/chatExtras.js'
export default {
@ -125,6 +126,7 @@ export default {
isFileShareWithoutCaption,
actorDisplayName,
actorInfo,
actorStore: useActorStore(),
}
},
@ -136,8 +138,8 @@ export default {
},
isOwnMessageQuoted() {
return this.message.actorId === this.$store.getters.getActorId()
&& this.message.actorType === this.$store.getters.getActorType()
return this.message.actorId === this.actorStore.actorId
&& this.message.actorType === this.actorStore.actorType
},
richParameters() {

View file

@ -354,6 +354,7 @@ import {
callSIPUnmutePhone,
} from '../../../services/callsService.js'
import { hasTalkFeature } from '../../../services/CapabilitiesManager.ts'
import { useActorStore } from '../../../stores/actor.js'
import { formattedTime } from '../../../utils/formattedTime.ts'
import { getDisplayNameWithFallback } from '../../../utils/getDisplayName.ts'
import { readableNumber } from '../../../utils/readableNumber.ts'
@ -417,6 +418,7 @@ export default {
setup() {
return {
isInCall: useIsInCall(),
actorStore: useActorStore(),
}
},
@ -609,7 +611,7 @@ export default {
return this.$store.getters.conversation(this.token) || {
sessionId: '0',
participantFlags: 0,
participantType: this.$store.getters.getUserId() !== null ? PARTICIPANT.TYPE.USER : PARTICIPANT.TYPE.GUEST,
participantType: this.actorStore.isLoggedIn ? PARTICIPANT.TYPE.USER : PARTICIPANT.TYPE.GUEST,
}
},
@ -625,7 +627,7 @@ export default {
},
isSelf() {
return this.participant.actorType === this.$store.getters.getActorType() && this.participant.actorId === this.$store.getters.getActorId()
return this.participant.actorType === this.actorStore.actorType && this.participant.actorId === this.actorStore.actorId
},
selfIsModerator() {
@ -904,7 +906,7 @@ export default {
console.info('Joining call')
await this.$store.dispatch('joinCall', {
token: this.token,
participantIdentifier: this.$store.getters.getParticipantIdentifier(),
participantIdentifier: this.actorStore.getParticipantIdentifier,
flags,
silent: false,
recordingConsent: true,

View file

@ -94,6 +94,7 @@ import { getTalkConfig, hasTalkFeature } from '../../../services/CapabilitiesMan
import { autocompleteQuery } from '../../../services/coreService.ts'
import { EventBus } from '../../../services/EventBus.ts'
import { addParticipant } from '../../../services/participantsService.js'
import { useActorStore } from '../../../stores/actor.js'
import { useSidebarStore } from '../../../stores/sidebar.ts'
import CancelableRequest from '../../../utils/cancelableRequest.js'
@ -155,6 +156,7 @@ export default {
isInCall,
cancelableGetParticipants,
sidebarStore: useSidebarStore(),
actorStore: useActorStore(),
}
},
@ -220,7 +222,7 @@ export default {
},
userId() {
return this.$store.getters.getUserId()
return this.actorStore.userId
},
canAddPhones() {

View file

@ -142,6 +142,7 @@ import SharedItemsTab from './SharedItems/SharedItemsTab.vue'
import SipSettings from './SipSettings.vue'
import { CONVERSATION, PARTICIPANT, WEBINAR } from '../../constants.ts'
import { getTalkConfig, hasTalkFeature } from '../../services/CapabilitiesManager.ts'
import { useActorStore } from '../../stores/actor.js'
import { useSidebarStore } from '../../stores/sidebar.ts'
const canStartConversations = getTalkConfig('local', 'conversations', 'can-create')
@ -234,6 +235,7 @@ export default {
sidebar,
sidebarContent,
sidebarStore: useSidebarStore(),
actorStore: useActorStore(),
}
},
@ -279,7 +281,7 @@ export default {
},
getUserId() {
return this.$store.getters.getUserId()
return this.actorStore.userId
},
canAddParticipants() {

View file

@ -90,6 +90,7 @@ import SharedItemsBrowser from './SharedItemsBrowser.vue'
import { CONVERSATION } from '../../../constants.ts'
import { hasTalkFeature } from '../../../services/CapabilitiesManager.ts'
import { EventBus } from '../../../services/EventBus.ts'
import { useActorStore } from '../../../stores/actor.js'
import { useSharedItemsStore } from '../../../stores/sharedItems.js'
import { useSidebarStore } from '../../../stores/sidebar.ts'
import {
@ -126,6 +127,7 @@ export default {
setup() {
return {
actorStore: useActorStore(),
sharedItemsStore: useSharedItemsStore(),
sidebarStore: useSidebarStore(),
sharedItemButtonTitle,
@ -146,7 +148,7 @@ export default {
computed: {
getUserId() {
return this.$store.getters.getUserId()
return this.actorStore.userId
},
token() {

View file

@ -46,6 +46,7 @@ import escapeHtml from 'escape-html'
import NcButton from '@nextcloud/vue/components/NcButton'
import NcTextField from '@nextcloud/vue/components/NcTextField'
import Pencil from 'vue-material-design-icons/Pencil.vue'
import { useActorStore } from '../stores/actor.js'
import { useGuestNameStore } from '../stores/guestName.js'
export default {
@ -59,7 +60,10 @@ export default {
setup() {
const guestNameStore = useGuestNameStore()
return { guestNameStore }
return {
guestNameStore,
actorStore: useActorStore(),
}
},
data() {
@ -72,7 +76,7 @@ export default {
computed: {
actorDisplayName() {
return this.$store.getters.getDisplayName() || t('spreed', 'Guest')
return this.actorStore.displayName || t('spreed', 'Guest')
},
displayNameLabel() {
@ -82,7 +86,7 @@ export default {
},
actorId() {
return this.$store.getters.getActorId()
return this.actorStore.actorId
},
token() {

View file

@ -232,6 +232,7 @@ import BrowserStorage from '../../services/BrowserStorage.js'
import { getTalkConfig } from '../../services/CapabilitiesManager.ts'
import { useCustomSettings } from '../../services/SettingsAPI.ts'
import { setUserConfig } from '../../services/settingsService.ts'
import { useActorStore } from '../../stores/actor.js'
import { useSettingsStore } from '../../stores/settings.js'
import { useSoundsStore } from '../../stores/sounds.js'
import { isMac } from '../../utils/browserCheck.ts'
@ -276,6 +277,7 @@ export default {
customSettingsSections,
supportStartWithoutMedia,
supportConversationsListStyle,
actorStore: useActorStore(),
}
},
@ -305,7 +307,7 @@ export default {
},
isGuest() {
return !this.$store.getters.getUserId()
return !this.actorStore.userId
},
readStatusPrivacyIsPublic() {

View file

@ -106,6 +106,7 @@ import { ATTENDEE, CALL, CONVERSATION, PARTICIPANT } from '../../constants.ts'
import { callSIPDialOut } from '../../services/callsService.js'
import { hasTalkFeature } from '../../services/CapabilitiesManager.ts'
import { EventBus } from '../../services/EventBus.ts'
import { useActorStore } from '../../stores/actor.js'
import { useBreakoutRoomsStore } from '../../stores/breakoutRooms.ts'
import { useCallViewStore } from '../../stores/callView.ts'
import { useSettingsStore } from '../../stores/settings.js'
@ -189,6 +190,7 @@ export default {
setup() {
return {
actorStore: useActorStore(),
isInCall: useIsInCall(),
breakoutRoomsStore: useBreakoutRoomsStore(),
callViewStore: useCallViewStore(),
@ -395,7 +397,7 @@ export default {
})
await this.$store.dispatch('joinCall', {
token: this.token,
participantIdentifier: this.$store.getters.getParticipantIdentifier(),
participantIdentifier: this.actorStore.getParticipantIdentifier,
flags,
silent: this.hasCall ? true : this.silentCall,
recordingConsent: this.recordingConsentGiven,
@ -436,7 +438,7 @@ export default {
})
await this.$store.dispatch('leaveCall', {
token: this.token,
participantIdentifier: this.$store.getters.getParticipantIdentifier(),
participantIdentifier: this.actorStore.getParticipantIdentifier,
all: endMeetingForAll,
})
this.loading = false

View file

@ -132,6 +132,7 @@ import TopBarMenu from './TopBarMenu.vue'
import { useGetParticipants } from '../../composables/useGetParticipants.js'
import { AVATAR, CONVERSATION } from '../../constants.ts'
import { getTalkConfig, hasTalkFeature } from '../../services/CapabilitiesManager.ts'
import { useActorStore } from '../../stores/actor.js'
import { useGroupwareStore } from '../../stores/groupware.ts'
import { useSidebarStore } from '../../stores/sidebar.ts'
import { getStatusMessage } from '../../utils/userStatus.ts'
@ -187,6 +188,7 @@ export default {
localMediaModel,
groupwareStore: useGroupwareStore(),
sidebarStore: useSidebarStore(),
actorStore: useActorStore(),
CONVERSATION,
}
},
@ -229,13 +231,6 @@ export default {
return getStatusMessage(this.conversation)
},
/**
* Current actor id
*/
actorId() {
return this.$store.getters.getActorId()
},
/**
* Online status of the peer in one to one conversation.
*/
@ -249,7 +244,7 @@ export default {
let peer
const participants = this.$store.getters.participantsList(this.token)
for (const participant of participants) {
if (participant.actorId !== this.actorId) {
if (participant.actorId !== this.actorStore.actorId) {
peer = participant
}
}
@ -287,7 +282,7 @@ export default {
},
getUserId() {
return this.$store.getters.getUserId()
return this.actorStore.userId
},
},

View file

@ -184,6 +184,7 @@ import {
import { useIsInCall } from '../../composables/useIsInCall.js'
import { CALL, CONVERSATION, PARTICIPANT } from '../../constants.ts'
import { getTalkConfig, hasTalkFeature } from '../../services/CapabilitiesManager.ts'
import { useActorStore } from '../../stores/actor.js'
import { useBreakoutRoomsStore } from '../../stores/breakoutRooms.ts'
import { useCallViewStore } from '../../stores/callView.ts'
import { generateAbsoluteUrl } from '../../utils/handleUrl.ts'
@ -259,6 +260,7 @@ export default {
isFullscreen: useDocumentFullscreen(),
breakoutRoomsStore: useBreakoutRoomsStore(),
callViewStore: useCallViewStore(),
actorStore: useActorStore(),
}
},
@ -472,7 +474,7 @@ export default {
this.$store.dispatch(
'setParticipantHandRaised',
{
sessionId: this.$store.getters.getSessionId(),
sessionId: this.actorStore.sessionId,
raisedHand: this.model.attributes.raisedHand,
},
)
@ -480,7 +482,7 @@ export default {
// also send request for assistance to the moderators.
if (this.userIsInBreakoutRoomAndInCall && !this.canModerate) {
const hasRaisedHands = Object.keys(this.$store.getters.participantRaisedHandList)
.filter((sessionId) => sessionId !== this.$store.getters.getSessionId())
.filter((sessionId) => sessionId !== this.actorStore.sessionId)
.length !== 0
if (hasRaisedHands) {
return // Assistance is already requested by someone in the room

View file

@ -5,6 +5,7 @@
import { n, t } from '@nextcloud/l10n'
import cloneDeep from 'lodash/cloneDeep.js'
import { useActorStore } from '../stores/actor.js'
import { useStore } from './useStore.js'
/**
@ -20,8 +21,9 @@ export function useCombinedSystemMessage() {
* @return {boolean}
*/
function checkIfSelfIsActor(message) {
return message.actorId === store.getters.getActorId()
&& message.actorType === store.getters.getActorType()
const actorStore = useActorStore()
return message.actorId === actorStore.actorId
&& message.actorType === actorStore.actorType
}
/**
@ -30,8 +32,9 @@ export function useCombinedSystemMessage() {
* @return {boolean}
*/
function checkIfSelfIsOneOfActors(message) {
return message.messageParameters.actor.id === store.getters.getActorId()
&& message.messageParameters.actor.type + 's' === store.getters.getActorType()
const actorStore = useActorStore()
return message.messageParameters.actor.id === actorStore.actorId
&& message.messageParameters.actor.type + 's' === actorStore.actorType
}
/**
@ -40,8 +43,9 @@ export function useCombinedSystemMessage() {
* @return {boolean}
*/
function checkIfSelfIsOneOfUsers(message) {
return message.messageParameters.user.id === store.getters.getActorId()
&& message.messageParameters.user.type + 's' === store.getters.getActorType()
const actorStore = useActorStore()
return message.messageParameters.user.id === actorStore.actorId
&& message.messageParameters.user.type + 's' === actorStore.actorType
}
/**

View file

@ -10,6 +10,7 @@ import { t } from '@nextcloud/l10n'
import { computed, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router/composables'
import { EventBus } from '../services/EventBus.ts'
import { useActorStore } from '../stores/actor.js'
import { hasCall, hasUnreadMentions } from '../utils/conversation.ts'
import { useDocumentVisibility } from './useDocumentVisibility.ts'
import { useStore } from './useStore.js'
@ -35,8 +36,9 @@ export function useDocumentTitle() {
const savedLastMessageMap = ref<LastMessageMap>({})
const conversationList = computed(() => store.getters.conversationsList)
const actorId = computed(() => store.getters.getActorId())
const actorType = computed(() => store.getters.getActorType())
const actorStore = useActorStore()
const actorId = computed(() => actorStore.actorId)
const actorType = computed(() => actorStore.actorType)
watch(conversationList, (newValue) => {
if (isDocumentVisible.value || document.title.startsWith('* ')

View file

@ -7,6 +7,7 @@ import { t } from '@nextcloud/l10n'
import { computed, ref } from 'vue'
import { ATTENDEE, CONVERSATION, MESSAGE } from '../constants.ts'
import { hasTalkFeature } from '../services/CapabilitiesManager.ts'
import { useActorStore } from '../stores/actor.js'
import { useGuestNameStore } from '../stores/guestName.js'
import { ONE_DAY_IN_MS, ONE_HOUR_IN_MS } from '../utils/formattedTime.ts'
import { getDisplayNameWithFallback } from '../utils/getDisplayName.ts'
@ -22,9 +23,10 @@ import { useStore } from './useStore.js'
export function useMessageInfo(message = ref({})) {
// Get the conversation
const store = useStore()
const actorStore = useActorStore()
const conversation = computed(() => store.getters.conversation(message.value.token))
const currentActorId = store.getters.getActorId()
const currentActorType = store.getters.getActorType()
const currentActorId = actorStore.actorId
const currentActorType = actorStore.actorType
// If the conversation or message is not available, return false
if (!conversation.value || !message.value.id) {
return {

View file

@ -5,6 +5,7 @@
import type { PrepareTemporaryMessagePayload } from '../utils/prepareTemporaryMessage.ts'
import { useActorStore } from '../stores/actor.js'
import { useChatExtrasStore } from '../stores/chatExtras.js'
import { prepareTemporaryMessage } from '../utils/prepareTemporaryMessage.ts'
import { useStore } from './useStore.js'
@ -16,6 +17,7 @@ import { useStore } from './useStore.js'
export function useTemporaryMessage(context: unknown) {
const store = context ?? useStore()
const chatExtrasStore = useChatExtrasStore()
const actorStore = useActorStore()
/**
* @param payload payload for generating a temporary message
@ -25,9 +27,9 @@ export function useTemporaryMessage(context: unknown) {
return prepareTemporaryMessage({
...payload,
actorId: store.getters.getActorId(),
actorType: store.getters.getActorType(),
actorDisplayName: store.getters.getDisplayName(),
actorId: actorStore.actorId ?? '',
actorType: actorStore.actorType ?? '',
actorDisplayName: actorStore.displayName,
parent: parentId && store.getters.message(payload.token, parentId),
})
}

View file

@ -1,204 +0,0 @@
/**
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
/**
* This store helps to identify a the current actor in all cases.
* In Talk not every user is a local nextcloud user, so identifying
* solely by userId is not enough.
* If an as no userId, they are a guest and identified by actorType + sessionId.
*/
import { loadState } from '@nextcloud/initial-state'
import { ATTENDEE, PARTICIPANT } from '../constants.ts'
import { getTeams } from '../services/teamsService.ts'
const state = {
userId: null,
sessionId: null,
attendeeId: null,
actorId: null,
actorType: null,
displayName: '',
actorGroups: loadState('spreed', 'user_group_ids', []),
actorTeams: [],
}
const getters = {
getUserId: (state) => () => {
return state.userId
},
getSessionId: (state) => () => {
return state.sessionId
},
getAttendeeId: (state) => () => {
return state.attendeeId
},
getActorId: (state) => () => {
return state.actorId
},
getActorType: (state) => () => {
return state.actorType
},
isActorUser: (state) => () => {
return state.actorType === ATTENDEE.ACTOR_TYPE.USERS
},
isActorGuest: (state) => () => {
return state.actorType === ATTENDEE.ACTOR_TYPE.GUESTS
},
isActorMemberOfGroup: (state) => (groupId) => {
return state.actorGroups.includes(groupId)
},
isActorMemberOfTeam: (state) => (teamId) => {
return state.actorTeams.includes(teamId)
},
getDisplayName: (state) => () => {
return state.displayName
},
getParticipantIdentifier: (state) => () => {
return {
attendeeId: state.attendeeId,
actorType: state.actorType,
actorId: state.actorId,
sessionId: state.sessionId,
}
},
}
const mutations = {
/**
* Set the userId
*
* @param {object} state current store state;
* @param {string} userId The user id
*/
setUserId(state, userId) {
state.userId = userId
state.actorId = userId
},
/**
* Set the attendeeId
*
* @param {object} state current store state;
* @param {string} attendeeId The actors attendee id
*/
setAttendeeId(state, attendeeId) {
state.attendeeId = attendeeId
},
/**
* Set the sessionId
*
* @param {object} state current store state;
* @param {string} sessionId The actors session id
*/
setSessionId(state, sessionId) {
state.sessionId = sessionId
},
/**
* Set the actorId
*
* @param {object} state current store state;
* @param {string} actorId The actor id
*/
setActorId(state, actorId) {
state.actorId = actorId
},
/**
* Set the userId
*
* @param {object} state current store state;
* @param {string} displayName The name
*/
setDisplayName(state, displayName) {
state.displayName = displayName
},
/**
* Set the userId
*
* @param {object} state current store state;
* @param {actorType} actorType The actor type of the user
*/
setActorType(state, actorType) {
state.actorType = actorType
},
/**
* Set the user teams ids
*
* @param {object} state current store state;
* @param {Array} teams Teams ids of the current user
*/
setCurrentUserTeams(state, teams) {
state.actorTeams = teams
},
}
const actions = {
/**
* Set the actor from the current user
*
* @param {object} context default store context;
* @param {object} user A NextcloudUser object as returned by @nextcloud/auth
* @param {string} user.uid The user id of the user
* @param {string|null} user.displayName The display name of the user
*/
setCurrentUser(context, user) {
context.commit('setUserId', user.uid)
context.commit('setDisplayName', user.displayName || user.uid)
context.commit('setActorType', ATTENDEE.ACTOR_TYPE.USERS)
context.commit('setActorId', user.uid)
},
/**
* Set the actor from the current participant
*
* @param {object} context default store context;
* @param {object} participant The participant data
* @param {number} participant.attendeeId The attendee id of the participant
* @param {number} participant.participantType The type of the participant
* @param {string} participant.sessionId The session id of the participant
* @param {string} participant.actorId The actor id of the participant
*/
setCurrentParticipant(context, participant) {
context.commit('setSessionId', participant.sessionId)
context.commit('setAttendeeId', participant.attendeeId)
if (participant.participantType === PARTICIPANT.TYPE.GUEST
|| participant.participantType === PARTICIPANT.TYPE.GUEST_MODERATOR) {
context.commit('setUserId', null)
context.commit('setActorType', ATTENDEE.ACTOR_TYPE.GUESTS)
context.commit('setActorId', participant.actorId)
// FIXME context.commit('setDisplayName', '')
}
},
/**
* Sets displayName only, we currently use this for guests user names.
*
* @param {object} context default store context;
* @param {string} displayName the display name to be set;
*/
setDisplayName(context, displayName) {
context.commit('setDisplayName', displayName)
},
/**
* Sets current user teams, if circles app enabled
*
* @param {object} context default store context;
*/
async getCurrentUserTeams(context) {
if (!loadState('spreed', 'circles_enabled', false)) {
return
}
try {
const response = await getTeams()
const teams = response.data.ocs.data.map((team) => team.id)
context.commit('setCurrentUserTeams', teams)
} catch (error) {
console.error(error)
}
},
}
export default { state, mutations, getters, actions }

View file

@ -64,6 +64,7 @@ import {
stopCallRecording,
} from '../services/recordingService.js'
import { talkBroadcastChannel } from '../services/talkBroadcastChannel.js'
import { useActorStore } from '../stores/actor.js'
import { useBreakoutRoomsStore } from '../stores/breakoutRooms.ts'
import { useChatExtrasStore } from '../stores/chatExtras.js'
import { useFederationStore } from '../stores/federation.ts'
@ -299,10 +300,11 @@ const actions = {
return
}
const actorStore = useActorStore()
// Add current user to a new conversation participants
let currentUser = {
uid: context.getters.getUserId(),
displayName: context.getters.getDisplayName(),
uid: actorStore.userId,
displayName: actorStore.displayName,
}
// Fallback to getCurrentUser() only if it has not been set yet (as
@ -1059,8 +1061,9 @@ const actions = {
*/
async extendOneToOneConversation(context, { token, newParticipants }) {
const conversation = context.getters.conversation(token)
const actorStore = useActorStore()
const participants = [
{ id: conversation.actorId, source: conversation.actorType, label: context.rootGetters.getDisplayName() },
{ id: conversation.actorId, source: conversation.actorType, label: actorStore.displayName },
...newParticipants,
]
const roomName = getDisplayNamesList(participants.map((participant) => participant.label), CONVERSATION.MAX_NAME_LENGTH)

View file

@ -18,6 +18,7 @@ import {
shareFile,
} from '../services/filesSharingServices.ts'
import { setAttachmentFolder } from '../services/settingsService.ts'
import { useActorStore } from '../stores/actor.js'
import { useChatExtrasStore } from '../stores/chatExtras.js'
import {
findUniquePath,
@ -335,7 +336,8 @@ const actions = {
*/
async prepareUploadPaths(context, { token, uploadId }) {
const client = getDavClient()
const userRoot = '/files/' + context.getters.getUserId()
const actorStore = useActorStore()
const userRoot = '/files/' + actorStore.userId
// Store propfind attempts within one action to reduce amount of requests for duplicates
const knownPaths = {}
@ -584,7 +586,8 @@ const actions = {
return
}
if (getters.getUserId() === null) {
const actorStore = useActorStore()
if (actorStore.userId === null) {
console.debug('Skip file templates setup for participants that are not logged in')
commit('markFileTemplatesInitialised')
return

View file

@ -25,6 +25,7 @@ import {
postRichObjectToConversation,
updateLastReadMessage,
} from '../services/messagesService.ts'
import { useActorStore } from '../stores/actor.js'
import { useCallViewStore } from '../stores/callView.ts'
import { useGuestNameStore } from '../stores/guestName.js'
import { usePollsStore } from '../stores/polls.ts'
@ -44,6 +45,7 @@ import { convertToUnix } from '../utils/formattedTime.ts'
* false otherwise
*/
function hasMentionToSelf(context, message) {
const actorStore = useActorStore()
if (!message.messageParameters) {
return false
}
@ -55,14 +57,14 @@ function hasMentionToSelf(context, message) {
return true
}
if (param.type === 'guest'
&& context.getters.isActorGuest()
&& param.id === ('guest/' + context.getters.getActorId())
&& actorStore.isActorGuest
&& param.id === ('guest/' + actorStore.actorId)
) {
return true
}
if (param.type === 'user'
&& context.getters.isActorUser()
&& param.id === context.getters.getUserId()
&& actorStore.isActorUser
&& param.id === actorStore.userId
) {
return true
}
@ -542,6 +544,7 @@ const actions = {
*/
processMessage(context, { token, message }) {
const sharedItemsStore = useSharedItemsStore()
const actorStore = useActorStore()
if (message.systemMessage === 'message_deleted'
|| message.systemMessage === 'reaction'
@ -588,8 +591,7 @@ const actions = {
if (tempMessages.length > 0) {
// Replacing temporary placeholder message with server response (text message / file share)
const conversation = context.getters.conversation(token)
const isOwnMessage = message.actorId === context.getters.getActorId()
&& message.actorType === context.getters.getActorType()
const isOwnMessage = actorStore.checkIfSelfIsActor(message)
// update lastMessage and lastReadMessage (no await to make it async)
// do it conditionally because there could have been more messages appearing concurrently
@ -856,7 +858,8 @@ const actions = {
context.commit('setVisualLastReadMessageId', { token, id: visualIdToUpdate })
}
if (context.getters.getUserId()) {
const actorStore = useActorStore()
if (actorStore.userId) {
// only update on server side if there's an actual user, not guest
const response = await updateLastReadMessage(token, id)
context.dispatch('addConversation', response.data.ocs.data)
@ -1107,6 +1110,7 @@ const actions = {
* @param {number} data.lastKnownMessageId The id of the last message in the store.
*/
async pollNewMessages(context, { token, lastKnownMessageId, requestId, requestOptions }) {
const actorStore = useActorStore()
context.dispatch('cancelPollNewMessages', { requestId })
if (!lastKnownMessageId) {
@ -1137,8 +1141,8 @@ const actions = {
}
const conversation = context.getters.conversation(token)
const actorId = context.getters.getActorId()
const actorType = context.getters.getActorType()
const actorId = actorStore.actorId
const actorType = actorStore.actorType
let countNewMessages = 0
let hasNewMention = conversation.unreadMention
let lastMessage = null
@ -1179,14 +1183,13 @@ const actions = {
}
if (message.systemMessage === 'call_ended_everyone'
&& conversation.type !== CONVERSATION.TYPE.ONE_TO_ONE
&& !(message.actorId === context.getters.getActorId()
&& message.actorType === context.getters.getActorType())) {
&& !actorStore.checkIfSelfIsActor(message)) {
const callViewStore = useCallViewStore()
callViewStore.setCallHasJustEnded(message.timestamp)
context.dispatch('leaveCall', {
token,
participantIdentifier: context.getters.getParticipantIdentifier(),
participantIdentifier: actorStore.getParticipantIdentifier,
})
}
}

View file

@ -33,6 +33,7 @@ import {
} from '../services/participantsService.js'
import SessionStorage from '../services/SessionStorage.js'
import { talkBroadcastChannel } from '../services/talkBroadcastChannel.js'
import { useActorStore } from '../stores/actor.js'
import { useCallViewStore } from '../stores/callView.ts'
import { useGuestNameStore } from '../stores/guestName.js'
import { useSessionStore } from '../stores/session.ts'
@ -123,17 +124,14 @@ const getters = {
* Gets the array of external session ids.
*
* @param {object} state - the state object.
* @param {object} getters - the getters object.
* @param {object} rootState - the rootState object.
* @param {object} rootGetters - the rootGetters object.
* @return {Array} the typing session IDs array.
*/
externalTypingSignals: (state, getters, rootState, rootGetters) => (token) => {
externalTypingSignals: (state) => (token) => {
if (!state.typing[token]) {
return []
}
return Object.keys(state.typing[token]).filter((sessionId) => rootGetters.getSessionId() !== sessionId)
const actorStore = useActorStore()
return Object.keys(state.typing[token]).filter((sessionId) => actorStore.sessionId !== sessionId)
},
/**
@ -149,8 +147,8 @@ const getters = {
if (!state.typing[rootGetters.getToken()]) {
return false
}
return Object.keys(state.typing[rootGetters.getToken()]).some((sessionId) => rootGetters.getSessionId() === sessionId)
const actorStore = useActorStore()
return Object.keys(state.typing[rootGetters.getToken()]).some((sessionId) => actorStore.sessionId === sessionId)
},
/**
@ -159,20 +157,19 @@ const getters = {
*
* @param {object} state - the state object.
* @param {object} getters - the getters object.
* @param {object} rootState - the rootState object.
* @param {object} rootGetters - the rootGetters object.
* @return {Array} the participants array (for registered users only).
*/
participantsListTyping: (state, getters, rootState, rootGetters) => (token) => {
participantsListTyping: (state, getters) => (token) => {
if (!getters.externalTypingSignals(token).length) {
return []
}
const actorStore = useActorStore()
return getters.participantsList(token).filter((attendee) => {
// Check if participant's sessionId matches with any of sessionIds from signaling...
return getters.externalTypingSignals(token).some((sessionId) => attendee.sessionIds.includes(sessionId))
// ... and it's not the participant with same actorType and actorId as yourself
&& (attendee.actorType !== rootGetters.getActorType() || attendee.actorId !== rootGetters.getActorId())
&& !actorStore.checkIfSelfIsActor(attendee)
})
},
@ -1030,16 +1027,17 @@ const actions = {
*/
async joinConversation(context, { token }) {
const forceJoin = SessionStorage.getItem('joined_conversation') === token
const actorStore = useActorStore()
try {
const response = await joinConversation({ token, forceJoin })
// Update the participant and actor session after a force join
context.dispatch('setCurrentParticipant', response.data.ocs.data)
actorStore.setCurrentParticipant(response.data.ocs.data)
context.dispatch('addConversation', response.data.ocs.data)
context.dispatch('updateSessionId', {
token,
participantIdentifier: context.getters.getParticipantIdentifier(),
participantIdentifier: actorStore.getParticipantIdentifier,
sessionId: response.data.ocs.data.sessionId,
})
@ -1087,10 +1085,11 @@ const actions = {
* @param {string} data.token - conversation token.
*/
async leaveConversation(context, { token }) {
const actorStore = useActorStore()
if (context.getters.isInCall(token)) {
await context.dispatch('leaveCall', {
token,
participantIdentifier: context.getters.getParticipantIdentifier(),
participantIdentifier: actorStore.getParticipantIdentifier,
})
}

View file

@ -3,7 +3,6 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import actorStore from './actorStore.js'
import conversationsStore from './conversationsStore.js'
import fileUploadStore from './fileUploadStore.js'
import messagesStore from './messagesStore.js'
@ -12,7 +11,6 @@ import tokenStore from './tokenStore.js'
export default {
modules: {
actorStore,
conversationsStore,
fileUploadStore,
messagesStore,

139
src/stores/actor.js Normal file
View file

@ -0,0 +1,139 @@
/**
* SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
/**
* This store helps to identify a the current actor in all cases.
* In Talk not every user is a local nextcloud user, so identifying
* solely by userId is not enough.
* If an as no userId, they are a guest and identified by actorType + sessionId.
*/
import { loadState } from '@nextcloud/initial-state'
import { defineStore } from 'pinia'
import { ATTENDEE, PARTICIPANT } from '../constants.ts'
import { getTeams } from '../services/teamsService.ts'
import { ref, computed } from 'vue'
export const useActorStore = defineStore('actor', () => {
const userId = ref(null)
const sessionId = ref(null)
const attendeeId = ref(null)
const actorId = ref(null)
const actorType = ref(null)
const displayName = ref('')
const actorGroups = ref(loadState('spreed', 'user_group_ids', []))
const actorTeams = ref([])
const isActorUser = computed(() => actorType.value === ATTENDEE.ACTOR_TYPE.USERS)
const isActorGuest = computed(() => actorType.value === ATTENDEE.ACTOR_TYPE.GUESTS)
const getParticipantIdentifier = computed(() => ({
attendeeId: attendeeId.value,
actorType: actorType.value,
actorId: actorId.value,
sessionId: sessionId.value,
}))
/**
* Check if the actor is a member of a group
*
* @param {string} groupId The group id
*/
function isActorMemberOfGroup(groupId) {
return actorGroups.value.includes(groupId)
}
/**
* Check if the actor is a member of a team
*
* @param {string} teamId The team id
*/
function isActorMemberOfTeam(teamId) {
return actorTeams.value.includes(teamId)
}
/**
* Set the userId
*
* @param {string} displayName The name
*/
function setDisplayName(displayName) {
displayName.value = displayName
}
/**
* Set the actor from the current user
*
* @param {object} user A NextcloudUser object as returned by @nextcloud/auth
* @param {string} user.uid The user id of the user
* @param {string|null} user.displayName The display name of the user
*/
function setCurrentUser(user) {
userId.value = user.uid
displayName.value = user.displayName || user.uid
actorType.value = ATTENDEE.ACTOR_TYPE.USERS
actorId.value = user.uid
}
/**
* Set the actor from the current participant
*
* @param {object} participant The participant data
* @param {number} participant.attendeeId The attendee id of the participant
* @param {number} participant.participantType The type of the participant
* @param {string} participant.sessionId The session id of the participant
* @param {string} participant.actorId The actor id of the participant
*/
function setCurrentParticipant(participant) {
sessionId.value = participant.sessionId
attendeeId.value = participant.attendeeId
if (participant.participantType === PARTICIPANT.TYPE.GUEST
|| participant.participantType === PARTICIPANT.TYPE.GUEST_MODERATOR) {
// FIXME displayName.value = ''
userId.value = null
actorType.value = ATTENDEE.ACTOR_TYPE.GUESTS
actorId.value = participant.actorId
}
}
/**
* Sets current user teams, if circles app enabled
*
*/
async function getCurrentUserTeams() {
if (!loadState('spreed', 'circles_enabled', false)) {
return
}
try {
const response = await getTeams()
const teams = response.data.ocs.data.map((team) => team.id)
actorTeams.value = teams
} catch (error) {
console.error(error)
}
}
return {
userId,
sessionId,
attendeeId,
actorId,
actorType,
displayName,
actorGroups,
actorTeams,
isActorUser,
isActorGuest,
getParticipantIdentifier,
isActorMemberOfGroup,
isActorMemberOfTeam,
setDisplayName,
setCurrentUser,
setCurrentParticipant,
getCurrentUserTeams,
}
})

View file

@ -9,6 +9,7 @@ import { defineStore } from 'pinia'
import Vue from 'vue'
import { setGuestUserName } from '../services/participantsService.js'
import store from '../store/index.js'
import { useActorStore } from './actor.js'
export const useGuestNameStore = defineStore('guestName', {
state: () => ({
@ -77,11 +78,12 @@ export const useGuestNameStore = defineStore('guestName', {
* @param {string} name the new guest name
*/
async submitGuestUsername(token, name) {
const actorId = store.getters.getActorId()
const actorStore = useActorStore()
const actorId = actorStore.actorId
const previousName = this.getGuestName(token, actorId)
try {
store.dispatch('setDisplayName', name)
actorStore.setDisplayName(name)
this.addGuestName({
token,
actorId,
@ -93,7 +95,7 @@ export const useGuestNameStore = defineStore('guestName', {
setGuestNickname(name || t('spreed', 'Guest'))
emit('talk:guest-name:added')
} catch (error) {
store.dispatch('setDisplayName', previousName)
actorStore.setDisplayName(previousName)
this.addGuestName({
token,
actorId,

View file

@ -3,6 +3,8 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { useActorStore } from '../stores/actor.js'
import pinia from '../stores/pinia.ts'
import SignalingParticipantList from './SignalingParticipantList.js'
/**
@ -17,6 +19,7 @@ import SignalingParticipantList from './SignalingParticipantList.js'
*/
export default function SignalingTypingHandler(store) {
this._store = store
this._actorStore = useActorStore(pinia)
this._signaling = null
this._signalingParticipantList = new SignalingParticipantList()
@ -74,7 +77,7 @@ SignalingTypingHandler.prototype = {
return
}
const currentNextcloudSessionId = this._store.getters.getSessionId()
const currentNextcloudSessionId = this._actorStore.sessionId
for (const participant of this._signalingParticipantList.getParticipants()) {
if (participant.nextcloudSessionId === currentNextcloudSessionId) {
@ -89,7 +92,7 @@ SignalingTypingHandler.prototype = {
this._store.dispatch('setTyping', {
token: this._store.getters.getToken(),
sessionId: this._store.getters.getSessionId(),
sessionId: this._actorStore.sessionId,
typing,
})
},

View file

@ -19,11 +19,15 @@ import { EventBus } from '../services/EventBus.ts'
import { rejoinConversation } from '../services/participantsService.js'
import { pullSignalingMessages } from '../services/signalingService.js'
import store from '../store/index.js'
import { useActorStore } from '../stores/actor.js'
import pinia from '../stores/pinia.ts'
import CancelableRequest from './cancelableRequest.js'
import Encryption from './e2ee/encryption.js'
import { convertToUnix } from './formattedTime.ts'
import { messagePleaseTryToReload } from './talkDesktopUtils.ts'
const actorStore = useActorStore(pinia)
const Signaling = {
Base: {},
Internal: {},
@ -898,7 +902,7 @@ Signaling.Standalone.prototype.forceReconnect = function(newSession, flags) {
this.nextcloudSessionId = response.data.ocs.data.sessionId
store.dispatch('setCurrentParticipant', response.data.ocs.data)
actorStore.setCurrentParticipant(response.data.ocs.data)
store.commit('setInCall', {
token: this.currentRoomToken,
sessionId: this.nextcloudSessionId,

View file

@ -10,9 +10,13 @@
* It is expected that the speaking status of participant will be
* modified only when the current conversation is joined and call is started.
*/
import { useActorStore } from '../../stores/actor.js'
import pinia from '../../stores/pinia.ts'
export default class SpeakingStatusHandler {
// Constants, properties
#store
#actorStore
#localMediaModel
#localCallParticipantModel
#callParticipantCollection
@ -26,6 +30,7 @@ export default class SpeakingStatusHandler {
constructor(store, localMediaModel, localCallParticipantModel, callParticipantCollection) {
this.#store = store
this.#actorStore = useActorStore(pinia)
this.#localMediaModel = localMediaModel
this.#localCallParticipantModel = localCallParticipantModel
this.#callParticipantCollection = callParticipantCollection
@ -95,7 +100,7 @@ export default class SpeakingStatusHandler {
*/
#handleLocalSpeaking(localMediaModel, speaking) {
this.#store.dispatch('setSpeaking', {
attendeeId: this.#store.getters.getAttendeeId(),
attendeeId: this.#actorStore.attendeeId,
speaking,
})
}
@ -106,7 +111,7 @@ export default class SpeakingStatusHandler {
*/
#handleLocalPeerId() {
this.#store.dispatch('setSpeaking', {
attendeeId: this.#store.getters.getAttendeeId(),
attendeeId: this.#actorStore.attendeeId,
speaking: this.#localMediaModel.attributes.speaking,
})
}

View file

@ -3,11 +3,14 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { reactive } from 'vue'
import { reactive, watch } from 'vue'
import store from '../../../store/index.js'
import { useActorStore } from '../../../stores/actor.js'
import pinia from '../../../stores/pinia.ts'
import EmitterMixin from '../../EmitterMixin.js'
import { ConnectionState } from './CallParticipantModel.js'
const actorStore = useActorStore(pinia)
/**
*
*/
@ -55,7 +58,10 @@ LocalCallParticipantModel.prototype = {
this.set('guestName', null)
this._webRtc.on('forcedMute', this._handleForcedMuteBound)
this._unwatchDisplayNameChange = store.watch((state) => state.actorStore.displayName, this.setGuestName.bind(this))
this._unwatchDisplayNameChange = watch(
() => actorStore.displayName,
this.setGuestName.bind(this),
)
},
setPeerId(peerId) {

View file

@ -11,6 +11,8 @@ import {
import { t } from '@nextcloud/l10n'
import { PARTICIPANT } from '../../constants.ts'
import store from '../../store/index.js'
import { useActorStore } from '../../stores/actor.js'
import pinia from '../../stores/pinia.ts'
import { Sounds } from '../sounds.js'
import SimpleWebRTC from './simplewebrtc/simplewebrtc.js'
@ -31,6 +33,7 @@ let callParticipantCollection = null
let localCallParticipantModel = null
let showedTURNWarning = false
let sendCurrentStateWithRepetitionTimeout = null
const actorStore = useActorStore(pinia)
/**
* @param {Array} a Source object
@ -198,7 +201,7 @@ function sendCurrentMediaState() {
*
*/
function sendCurrentNick() {
webrtc.webrtc.emit('nickChanged', store.getters.getDisplayName())
webrtc.webrtc.emit('nickChanged', actorStore.displayName)
}
/**
@ -471,10 +474,9 @@ function usersInCallChanged(signaling, users) {
&& selfInCall === PARTICIPANT.CALL_FLAG.DISCONNECTED
&& localUserInCall) {
console.info('Force leaving the call for current participant')
store.dispatch('leaveCall', {
token: store.getters.getToken(),
participantIdentifier: store.getters.getParticipantIdentifier(),
participantIdentifier: actorStore.getParticipantIdentifier,
})
// Do not return to disconnect already from the other participants
@ -669,7 +671,6 @@ export default function initWebRtc(signaling, _callParticipantCollection, _local
message.broadcaster = message.from
}
})
webrtc = new SimpleWebRTC({
autoRequestMedia: true,
debug: false,
@ -678,7 +679,7 @@ export default function initWebRtc(signaling, _callParticipantCollection, _local
connection: signaling,
enableDataChannels: true,
enableSimulcast: signaling.hasFeature('simulcast'),
nick: store.getters.getDisplayName(),
nick: actorStore.displayName,
})
if (!window.OCA.Talk) {

View file

@ -14,6 +14,7 @@ import PollViewer from '../components/PollViewer/PollViewer.vue'
import TopBar from '../components/TopBar/TopBar.vue'
import { useIsInCall } from '../composables/useIsInCall.js'
import { useStore } from '../composables/useStore.js'
import { useActorStore } from '../stores/actor.js'
const props = defineProps<{
token: string
@ -23,6 +24,7 @@ const store = useStore()
const isInCall = useIsInCall()
const router = useRouter()
const route = useRoute()
const actorStore = useActorStore()
const isInLobby = computed(() => store.getters.isInLobby)
const connectionFailed = computed(() => store.getters.connectionFailed(props.token))
@ -32,7 +34,7 @@ watch(isInLobby, (isInLobby) => {
if (isInLobby && isInCall.value) {
store.dispatch('leaveCall', {
token: props.token,
participantIdentifier: store.getters.getParticipantIdentifier(),
participantIdentifier: actorStore.getParticipantIdentifier,
})
}
})