diff --git a/src/components/CallView/shared/ReactionToaster.vue b/src/components/CallView/shared/ReactionToaster.vue index 8d219e193ed..65876c0a3f4 100644 --- a/src/components/CallView/shared/ReactionToaster.vue +++ b/src/components/CallView/shared/ReactionToaster.vue @@ -40,7 +40,7 @@ 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.ts' -import { useGuestNameStore } from '../../../stores/guestName.js' +import { useGuestNameStore } from '../../../stores/guestName.ts' const reactions = { '❤️': 'Heart.gif', diff --git a/src/components/CallView/shared/ScreenShare.vue b/src/components/CallView/shared/ScreenShare.vue index 06c640d3e71..cc817140be1 100644 --- a/src/components/CallView/shared/ScreenShare.vue +++ b/src/components/CallView/shared/ScreenShare.vue @@ -32,7 +32,7 @@ import SHA1 from 'crypto-js/sha1.js' import panzoom from 'panzoom' import { computed, onBeforeUnmount, onMounted, ref } from 'vue' import VideoBottomBar from './VideoBottomBar.vue' -import { useGuestNameStore } from '../../../stores/guestName.js' +import { useGuestNameStore } from '../../../stores/guestName.ts' import attachMediaStream from '../../../utils/attachmediastream.js' const ZOOM_MIN = 1 diff --git a/src/components/CallView/shared/VideoVue.vue b/src/components/CallView/shared/VideoVue.vue index c4a3b865986..0cf94a8b333 100644 --- a/src/components/CallView/shared/VideoVue.vue +++ b/src/components/CallView/shared/VideoVue.vue @@ -107,7 +107,7 @@ import VideoBottomBar from './VideoBottomBar.vue' import { ATTENDEE, AVATAR } from '../../../constants.ts' import { EventBus } from '../../../services/EventBus.ts' import { useCallViewStore } from '../../../stores/callView.ts' -import { useGuestNameStore } from '../../../stores/guestName.js' +import { useGuestNameStore } from '../../../stores/guestName.ts' import attachMediaStream from '../../../utils/attachmediastream.js' import { getDisplayNameWithFallback } from '../../../utils/getDisplayName.ts' import { ConnectionState } from '../../../utils/webrtc/models/CallParticipantModel.js' diff --git a/src/components/GuestWelcomeWindow.vue b/src/components/GuestWelcomeWindow.vue index 028e145e8e3..2bc5ff4557a 100644 --- a/src/components/GuestWelcomeWindow.vue +++ b/src/components/GuestWelcomeWindow.vue @@ -64,7 +64,7 @@ import NcModal from '@nextcloud/vue/components/NcModal' import NcTextField from '@nextcloud/vue/components/NcTextField' import Check from 'vue-material-design-icons/CheckBold.vue' import ConversationIcon from './ConversationIcon.vue' -import { useGuestNameStore } from '../stores/guestName.js' +import { useGuestNameStore } from '../stores/guestName.ts' export default { name: 'GuestWelcomeWindow', diff --git a/src/components/MediaSettings/MediaSettings.vue b/src/components/MediaSettings/MediaSettings.vue index d0213f3c579..465a12fa999 100644 --- a/src/components/MediaSettings/MediaSettings.vue +++ b/src/components/MediaSettings/MediaSettings.vue @@ -264,7 +264,7 @@ import { ATTENDEE, AVATAR, CALL, CONFIG, PARTICIPANT, VIRTUAL_BACKGROUND } from import BrowserStorage from '../../services/BrowserStorage.js' import { getTalkConfig } from '../../services/CapabilitiesManager.ts' import { useActorStore } from '../../stores/actor.ts' -import { useGuestNameStore } from '../../stores/guestName.js' +import { useGuestNameStore } from '../../stores/guestName.ts' import { useSettingsStore } from '../../stores/settings.ts' import { localMediaModel } from '../../utils/webrtc/index.js' diff --git a/src/components/MessagesList/MessagesGroup/Message/MessagePart/ReactionsList.vue b/src/components/MessagesList/MessagesGroup/Message/MessagePart/ReactionsList.vue index 3496a4ea91b..083e4cca9bd 100644 --- a/src/components/MessagesList/MessagesGroup/Message/MessagePart/ReactionsList.vue +++ b/src/components/MessagesList/MessagesGroup/Message/MessagePart/ReactionsList.vue @@ -56,7 +56,7 @@ import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon' import IconHeartOutline from 'vue-material-design-icons/HeartOutline.vue' import AvatarWrapper from '../../../../AvatarWrapper/AvatarWrapper.vue' import { ATTENDEE, AVATAR } from '../../../../../constants.ts' -import { useGuestNameStore } from '../../../../../stores/guestName.js' +import { useGuestNameStore } from '../../../../../stores/guestName.ts' import { getDisplayNameWithFallback } from '../../../../../utils/getDisplayName.ts' export default { diff --git a/src/components/MessagesList/MessagesGroup/Message/MessagePart/ReactionsWrapper.vue b/src/components/MessagesList/MessagesGroup/Message/MessagePart/ReactionsWrapper.vue index 865db431fcc..e511aee7044 100644 --- a/src/components/MessagesList/MessagesGroup/Message/MessagePart/ReactionsWrapper.vue +++ b/src/components/MessagesList/MessagesGroup/Message/MessagePart/ReactionsWrapper.vue @@ -93,7 +93,7 @@ import IconHeartOutline from 'vue-material-design-icons/HeartOutline.vue' import ReactionsList from './ReactionsList.vue' import { ATTENDEE } from '../../../../../constants.ts' import { useActorStore } from '../../../../../stores/actor.ts' -import { useGuestNameStore } from '../../../../../stores/guestName.js' +import { useGuestNameStore } from '../../../../../stores/guestName.ts' import { useReactionsStore } from '../../../../../stores/reactions.js' import { getDisplayNameWithFallback } from '../../../../../utils/getDisplayName.ts' diff --git a/src/components/MessagesList/MessagesGroup/MessagesGroup.spec.js b/src/components/MessagesList/MessagesGroup/MessagesGroup.spec.js index a74eac89f5b..f2fbfd7fa9b 100644 --- a/src/components/MessagesList/MessagesGroup/MessagesGroup.spec.js +++ b/src/components/MessagesList/MessagesGroup/MessagesGroup.spec.js @@ -13,7 +13,7 @@ import MessagesGroup from './MessagesGroup.vue' import { ATTENDEE, MESSAGE } from '../../../constants.ts' import storeConfig from '../../../store/storeConfig.js' import { useActorStore } from '../../../stores/actor.ts' -import { useGuestNameStore } from '../../../stores/guestName.js' +import { useGuestNameStore } from '../../../stores/guestName.ts' describe('MessagesGroup.vue', () => { const TOKEN = 'XXTOKENXX' diff --git a/src/components/MessagesList/MessagesGroup/MessagesGroup.vue b/src/components/MessagesList/MessagesGroup/MessagesGroup.vue index 0c8a75d7a55..cd522bd74fc 100644 --- a/src/components/MessagesList/MessagesGroup/MessagesGroup.vue +++ b/src/components/MessagesList/MessagesGroup/MessagesGroup.vue @@ -38,7 +38,7 @@ import MessageItem from './Message/MessageItem.vue' import { useMessageInfo } from '../../../composables/useMessageInfo.ts' import { ATTENDEE, AVATAR } from '../../../constants.ts' import { useActorStore } from '../../../stores/actor.ts' -import { useGuestNameStore } from '../../../stores/guestName.js' +import { useGuestNameStore } from '../../../stores/guestName.ts' export default { name: 'MessagesGroup', diff --git a/src/components/NewMessage/NewMessageTypingIndicator.vue b/src/components/NewMessage/NewMessageTypingIndicator.vue index 563abac8427..0c987f42e88 100644 --- a/src/components/NewMessage/NewMessageTypingIndicator.vue +++ b/src/components/NewMessage/NewMessageTypingIndicator.vue @@ -32,7 +32,7 @@ import escapeHtml from 'escape-html' import AvatarWrapper from '../AvatarWrapper/AvatarWrapper.vue' import { AVATAR } from '../../constants.ts' import { useActorStore } from '../../stores/actor.ts' -import { useGuestNameStore } from '../../stores/guestName.js' +import { useGuestNameStore } from '../../stores/guestName.ts' export default { name: 'NewMessageTypingIndicator', diff --git a/src/components/SetGuestUsername.vue b/src/components/SetGuestUsername.vue index 775211ab3f7..f3013843e6c 100644 --- a/src/components/SetGuestUsername.vue +++ b/src/components/SetGuestUsername.vue @@ -61,7 +61,7 @@ import IconPencilOutline from 'vue-material-design-icons/PencilOutline.vue' import { useGetToken } from '../composables/useGetToken.ts' import { EventBus } from '../services/EventBus.ts' import { useActorStore } from '../stores/actor.ts' -import { useGuestNameStore } from '../stores/guestName.js' +import { useGuestNameStore } from '../stores/guestName.ts' const { compact = false } = defineProps<{ compact?: boolean diff --git a/src/composables/__tests__/useMessageInfo.spec.js b/src/composables/__tests__/useMessageInfo.spec.js index d203d101a1f..9d1c6d89a2d 100644 --- a/src/composables/__tests__/useMessageInfo.spec.js +++ b/src/composables/__tests__/useMessageInfo.spec.js @@ -9,7 +9,7 @@ import { computed, ref } from 'vue' import { useStore } from 'vuex' import { ATTENDEE, CONVERSATION, MESSAGE } from '../../constants.ts' import { useActorStore } from '../../stores/actor.ts' -import { useGuestNameStore } from '../../stores/guestName.js' +import { useGuestNameStore } from '../../stores/guestName.ts' import { useConversationInfo } from '../useConversationInfo.ts' import { useMessageInfo } from '../useMessageInfo.ts' diff --git a/src/composables/useMessageInfo.ts b/src/composables/useMessageInfo.ts index 6a9f6987f86..f318f3db9e6 100644 --- a/src/composables/useMessageInfo.ts +++ b/src/composables/useMessageInfo.ts @@ -12,7 +12,7 @@ import { useStore } from 'vuex' import { ATTENDEE, CONVERSATION, MESSAGE } from '../constants.ts' import { hasTalkFeature } from '../services/CapabilitiesManager.ts' import { useActorStore } from '../stores/actor.ts' -import { useGuestNameStore } from '../stores/guestName.js' +import { useGuestNameStore } from '../stores/guestName.ts' import { ONE_DAY_IN_MS, ONE_HOUR_IN_MS } from '../utils/formattedTime.ts' import { getDisplayNameWithFallback } from '../utils/getDisplayName.ts' import { useConversationInfo } from './useConversationInfo.ts' diff --git a/src/store/messagesStore.js b/src/store/messagesStore.js index d4fbd587b09..f2c2a9c264a 100644 --- a/src/store/messagesStore.js +++ b/src/store/messagesStore.js @@ -29,7 +29,7 @@ import { useActorStore } from '../stores/actor.ts' import { useCallViewStore } from '../stores/callView.ts' import { useChatStore } from '../stores/chat.ts' import { useChatExtrasStore } from '../stores/chatExtras.ts' -import { useGuestNameStore } from '../stores/guestName.js' +import { useGuestNameStore } from '../stores/guestName.ts' import { usePollsStore } from '../stores/polls.ts' import { useReactionsStore } from '../stores/reactions.js' import { useSharedItemsStore } from '../stores/sharedItems.ts' diff --git a/src/store/messagesStore.spec.js b/src/store/messagesStore.spec.js index c7833c716ba..07c4df511fa 100644 --- a/src/store/messagesStore.spec.js +++ b/src/store/messagesStore.spec.js @@ -30,7 +30,7 @@ import { } from '../services/messagesService.ts' import { useActorStore } from '../stores/actor.ts' import { useChatStore } from '../stores/chat.ts' -import { useGuestNameStore } from '../stores/guestName.js' +import { useGuestNameStore } from '../stores/guestName.ts' import { useReactionsStore } from '../stores/reactions.js' import { generateOCSErrorResponse, generateOCSResponse } from '../test-helpers.js' import CancelableRequest from '../utils/cancelableRequest.js' diff --git a/src/store/participantsStore.js b/src/store/participantsStore.js index 403861f5da9..36a47d70906 100644 --- a/src/store/participantsStore.js +++ b/src/store/participantsStore.js @@ -34,7 +34,7 @@ import SessionStorage from '../services/SessionStorage.js' import { talkBroadcastChannel } from '../services/talkBroadcastChannel.js' import { useActorStore } from '../stores/actor.ts' import { useCallViewStore } from '../stores/callView.ts' -import { useGuestNameStore } from '../stores/guestName.js' +import { useGuestNameStore } from '../stores/guestName.ts' import pinia from '../stores/pinia.ts' import { useSessionStore } from '../stores/session.ts' import { useTokenStore } from '../stores/token.ts' diff --git a/src/store/participantsStore.spec.js b/src/store/participantsStore.spec.js index c11e61870fe..702ff5e54c8 100644 --- a/src/store/participantsStore.spec.js +++ b/src/store/participantsStore.spec.js @@ -31,7 +31,7 @@ import { } from '../services/participantsService.js' import SessionStorage from '../services/SessionStorage.js' import { useActorStore } from '../stores/actor.ts' -import { useGuestNameStore } from '../stores/guestName.js' +import { useGuestNameStore } from '../stores/guestName.ts' import { useSessionStore } from '../stores/session.ts' import { useTokenStore } from '../stores/token.ts' import { generateOCSErrorResponse, generateOCSResponse } from '../test-helpers.js' diff --git a/src/stores/__tests__/guestName.spec.js b/src/stores/__tests__/guestName.spec.js index d0a8e82a922..380bba03739 100644 --- a/src/stores/__tests__/guestName.spec.js +++ b/src/stores/__tests__/guestName.spec.js @@ -10,7 +10,7 @@ import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest' import { setGuestUserName } from '../../services/participantsService.js' import { generateOCSErrorResponse } from '../../test-helpers.js' import { useActorStore } from '../actor.ts' -import { useGuestNameStore } from '../guestName.js' +import { useGuestNameStore } from '../guestName.ts' vi.mock('../../services/participantsService', () => ({ setGuestUserName: vi.fn(), diff --git a/src/stores/__tests__/session.spec.js b/src/stores/__tests__/session.spec.js index 996e8cff9e2..cea667babf1 100644 --- a/src/stores/__tests__/session.spec.js +++ b/src/stores/__tests__/session.spec.js @@ -7,7 +7,7 @@ import { createPinia, setActivePinia } from 'pinia' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { ATTENDEE, PARTICIPANT } from '../../constants.ts' import vuexStore from '../../store/index.js' -import { useGuestNameStore } from '../guestName.js' +import { useGuestNameStore } from '../guestName.ts' import { useSessionStore } from '../session.ts' describe('sessionStore', () => { diff --git a/src/stores/guestName.js b/src/stores/guestName.js deleted file mode 100644 index c82101a2fcf..00000000000 --- a/src/stores/guestName.js +++ /dev/null @@ -1,109 +0,0 @@ -/** - * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -import { getGuestNickname, setGuestNickname } from '@nextcloud/auth' -import { t } from '@nextcloud/l10n' -import { defineStore } from 'pinia' -import { setGuestUserName } from '../services/participantsService.js' -import { useActorStore } from './actor.ts' - -export const useGuestNameStore = defineStore('guestName', { - state: () => ({ - guestNames: {}, - guestUserName: getGuestNickname() || '', - }), - - actions: { - /** - * Gets the participant display name - * - * @param {string} token the conversation's token - * @param {string} actorId the participant actorId - * @return {string} the participant name - */ - getGuestName(token, actorId) { - return this.guestNames[token]?.[actorId] ?? t('spreed', 'Guest') - }, - - /** - * Gets the participant display name with suffix - * if the display name is not default translatable Guest - * - * @param {string} token the conversation's token - * @param {string} actorId the participant actorId - * @return {string} the participant name with/without suffix - */ - getGuestNameWithGuestSuffix(token, actorId) { - const displayName = this.getGuestName(token, actorId) - if (displayName === t('spreed', 'Guest')) { - return displayName - } - return t('spreed', '{guest} (guest)', { - guest: displayName, - }) - }, - - /** - * Adds a guest name to the store - * - * @param {object} data the wrapping object - * @param {string} data.token the token of the conversation - * @param {string} data.actorId the guest - * @param {string} data.actorDisplayName the display name to set - * @param {object} options options - * @param {boolean} options.noUpdate Override the display name or set it if it is empty - */ - addGuestName({ token, actorId, actorDisplayName }, { noUpdate }) { - if (!this.guestNames[token]) { - this.guestNames[token] = {} - } - if (!this.guestNames[token][actorId] || actorDisplayName === '') { - this.guestNames[token][actorId] = t('spreed', 'Guest') - } else if (noUpdate) { - return - } - - if (actorDisplayName) { - this.guestNames[token][actorId] = actorDisplayName - } - }, - - /** - * Add the submitted guest name to the store - * - * @param {string} token the token of the conversation - * @param {string} name the new guest name - */ - async submitGuestUsername(token, name) { - if (!name) { - return - } - const actorStore = useActorStore() - const actorId = actorStore.actorId - const previousName = this.getGuestName(token, actorId) - - try { - actorStore.setDisplayName(name) - this.addGuestName({ - token, - actorId, - actorDisplayName: name, - }, { noUpdate: false }) - - await setGuestUserName(token, name) - - setGuestNickname(name) - } catch (error) { - actorStore.setDisplayName(previousName) - this.addGuestName({ - token, - actorId, - actorDisplayName: previousName, - }, { noUpdate: false }) - console.error(error) - } - }, - }, -}) diff --git a/src/stores/guestName.ts b/src/stores/guestName.ts new file mode 100644 index 00000000000..97ce15fcc1f --- /dev/null +++ b/src/stores/guestName.ts @@ -0,0 +1,118 @@ +/** + * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import { getGuestNickname, setGuestNickname } from '@nextcloud/auth' +import { t } from '@nextcloud/l10n' +import { defineStore } from 'pinia' +import { ref } from 'vue' +import { setGuestUserName } from '../services/participantsService.js' +import { useActorStore } from './actor.ts' + +type AddGuestNamePayload = { token: string, actorId: string, actorDisplayName: string } + +export const useGuestNameStore = defineStore('guestName', () => { + const LOCALIZED_GUEST = t('spreed', 'Guest') + + /** A map of guest names per conversation token and actorId */ + const guestNames = ref>>({}) + + /** An own display name of a current guest-user */ + const guestUserName = ref(getGuestNickname() || '') + + /** + * Gets the participant display name + * + * @param token the conversation's token + * @param actorId the participant actorId + */ + function getGuestName(token: string, actorId: string): string { + return guestNames.value[token]?.[actorId] ?? LOCALIZED_GUEST + } + + /** + * Gets the participant display name with suffix + * if the display name is not default, gets localized 'Guest' + * + * @param token the conversation's token + * @param actorId the participant actorId + */ + function getGuestNameWithGuestSuffix(token: string, actorId: string): string { + const guest = getGuestName(token, actorId) + if (guest === LOCALIZED_GUEST) { + return guest + } + return t('spreed', '{guest} (guest)', { guest }) + } + + /** + * Adds a guest name to the store + * + * @param payload the wrapping object + * @param payload.token the token of the conversation + * @param payload.actorId the guest id + * @param payload.actorDisplayName the display name to set + * @param options options + * @param options.noUpdate Override the display name or set it, if it is empty + */ + function addGuestName({ token, actorId, actorDisplayName }: AddGuestNamePayload, { noUpdate }: { noUpdate: boolean }) { + if (!guestNames.value[token]) { + guestNames.value[token] = {} + } + if (!guestNames.value[token][actorId] || actorDisplayName === '') { + guestNames.value[token][actorId] = LOCALIZED_GUEST + } else if (noUpdate) { + return + } + + if (actorDisplayName) { + guestNames.value[token][actorId] = actorDisplayName + } + } + + /** + * Add the submitted guest name to the store + * + * @param token the token of the conversation + * @param name the new guest name + */ + async function submitGuestUsername(token: string, name: string) { + if (!name) { + return + } + const actorStore = useActorStore() + const actorId = actorStore.actorId! + const previousName = getGuestName(token, actorId) + + try { + actorStore.setDisplayName(name) + addGuestName({ + token, + actorId, + actorDisplayName: name, + }, { noUpdate: false }) + + await setGuestUserName(token, name) + + setGuestNickname(name) + } catch (error) { + actorStore.setDisplayName(previousName) + addGuestName({ + token, + actorId, + actorDisplayName: previousName, + }, { noUpdate: false }) + console.error(error) + } + } + + return { + guestUserName, + + getGuestName, + getGuestNameWithGuestSuffix, + addGuestName, + submitGuestUsername, + } +}) diff --git a/src/stores/session.ts b/src/stores/session.ts index 4e4247f4007..201819759d4 100644 --- a/src/stores/session.ts +++ b/src/stores/session.ts @@ -17,7 +17,7 @@ import SHA1 from 'crypto-js/sha1.js' import { defineStore } from 'pinia' import { ATTENDEE, PARTICIPANT } from '../constants.ts' import store from '../store/index.js' -import { useGuestNameStore } from './guestName.js' +import { useGuestNameStore } from './guestName.ts' type Session = { attendeeId: number | undefined