Server IP : 80.87.202.40 / Your IP : 216.73.216.169 Web Server : Apache System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64 User : bitrix ( 600) PHP Version : 8.2.27 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /home/bitrix/ext_www/rospirotorg.ru/bitrix/js/im/v2/component/sidebar/dist/ |
Upload File : |
/* eslint-disable */ this.BX = this.BX || {}; this.BX.Messenger = this.BX.Messenger || {}; this.BX.Messenger.v2 = this.BX.Messenger.v2 || {}; (function (exports,im_v2_lib_localStorage,im_v2_lib_sidebar,ui_vue3_directives_lazyload,ui_label,main_date,im_v2_lib_channel,im_v2_component_elements_toggle,im_v2_component_elements_autoDelete,im_v2_lib_autoDelete,ui_vue3_directives_hint,im_v2_component_elements_copilotRolesDialog,im_v2_lib_rest,ui_promoVideoPopup,ui_manual,im_v2_lib_promo,im_v2_lib_feature,ui_viewer,im_v2_provider_service_disk,im_v2_model,im_v2_component_elements_audioplayer,ui_icons,ui_notification,rest_client,ui_vue3_vuex,im_v2_lib_market,im_v2_lib_entityCreator,im_v2_lib_analytics,im_v2_lib_layout,im_v2_component_entitySelector,im_v2_lib_notifier,im_v2_lib_menu,im_v2_lib_call,im_v2_provider_service_chat,im_v2_lib_permission,im_v2_lib_confirm,im_v2_provider_service_message,im_v2_lib_logger,im_v2_lib_parser,im_v2_lib_textHighlighter,im_v2_component_elements_searchInput,main_core,im_v2_lib_utils,im_v2_component_elements_chatTitle,im_v2_component_elements_avatar,im_v2_lib_user,im_v2_application_core,main_core_events,im_public,im_v2_const,im_v2_component_elements_loader,im_v2_component_elements_button,im_v2_lib_dateFormatter) { 'use strict'; function getChatId(dialogId) { const dialog = im_v2_application_core.Core.getStore().getters['chats/get'](dialogId, true); return dialog.chatId; } function getLastElementId(collection, sort = 'ASC') { if (collection.length === 0) { return null; } collection.sort((a, b) => { if (sort === 'ASC') { return a.id - b.id; } return b.id - a.id; }); const [lastCollectionItem] = collection; if (main_core.Type.isNumber(lastCollectionItem.id)) { return lastCollectionItem.id; } return null; } const REQUEST_ITEMS_LIMIT = 50; class Favorite { constructor({ dialogId }) { this.store = im_v2_application_core.Core.getStore(); this.restClient = im_v2_application_core.Core.getRestClient(); this.dialogId = dialogId; this.chatId = getChatId(dialogId); this.userManager = new im_v2_lib_user.UserManager(); } getInitialQuery() { return { [im_v2_const.RestMethod.imChatFavoriteCounterGet]: { chat_id: this.chatId }, [im_v2_const.RestMethod.imChatFavoriteGet]: { chat_id: this.chatId, limit: REQUEST_ITEMS_LIMIT } }; } getResponseHandler() { return response => { if (!response[im_v2_const.RestMethod.imChatFavoriteCounterGet]) { return Promise.reject(new Error('SidebarInfo service error: no response')); } const favoriteCounterGetResponse = response[im_v2_const.RestMethod.imChatFavoriteCounterGet]; const setCounterResult = this.store.dispatch('sidebar/favorites/setCounter', { chatId: this.chatId, counter: favoriteCounterGetResponse.counter }); const setFavoriteResult = this.handleResponse(response[im_v2_const.RestMethod.imChatFavoriteGet]); return Promise.all([setCounterResult, setFavoriteResult]); }; } loadNextPage() { const queryParams = this.getQueryParams(); return this.requestPage(queryParams); } getQueryParams() { const queryParams = { CHAT_ID: this.chatId, LIMIT: REQUEST_ITEMS_LIMIT }; const lastId = this.store.getters['sidebar/favorites/getLastId'](this.chatId); if (lastId > 0) { queryParams.LAST_ID = lastId; } return queryParams; } requestPage(queryParams) { return this.restClient.callMethod(im_v2_const.RestMethod.imChatFavoriteGet, queryParams).then(response => { return this.handleResponse(response.data()); }).catch(error => { console.error('SidebarInfo: Im.imChatFavoriteGet: page request error', error); }); } handleResponse(response) { return this.updateModels(response); } updateModels(resultData) { const { list = [], users = [], files = [], tariffRestrictions = {} } = resultData; const addUsersPromise = this.userManager.setUsersToModel(users); const isHistoryLimitExceeded = Boolean(tariffRestrictions.isHistoryLimitExceeded); const rawMessages = list.map(favorite => favorite.message); const hasNextPage = list.length === REQUEST_ITEMS_LIMIT; const lastId = getLastElementId(list); const setFilesPromise = this.store.dispatch('files/set', files); const storeMessagesPromise = this.store.dispatch('messages/store', rawMessages); const setFavoritesPromise = this.store.dispatch('sidebar/favorites/set', { chatId: this.chatId, favorites: list, hasNextPage, lastId, isHistoryLimitExceeded }); return Promise.all([setFilesPromise, storeMessagesPromise, setFavoritesPromise, addUsersPromise]); } } const REQUEST_ITEMS_LIMIT$1 = 50; class Link { constructor({ dialogId }) { this.store = im_v2_application_core.Core.getStore(); this.restClient = im_v2_application_core.Core.getRestClient(); this.dialogId = dialogId; this.chatId = getChatId(dialogId); this.userManager = new im_v2_lib_user.UserManager(); } getInitialQuery() { return { [im_v2_const.RestMethod.imChatUrlCounterGet]: { chat_id: this.chatId }, [im_v2_const.RestMethod.imChatUrlGet]: { chat_id: this.chatId, limit: REQUEST_ITEMS_LIMIT$1 } }; } getResponseHandler() { return response => { if (!response[im_v2_const.RestMethod.imChatUrlCounterGet] || !response[im_v2_const.RestMethod.imChatUrlGet]) { return Promise.reject(new Error('SidebarInfo service error: no response')); } const urlGetResult = this.handleUrlGetResponse(response[im_v2_const.RestMethod.imChatUrlGet]); const counterGetResult = this.handleCounterGetResponse(response[im_v2_const.RestMethod.imChatUrlCounterGet]); return Promise.all([urlGetResult, counterGetResult]); }; } loadNextPage() { const linksCount = this.getLinksCountFromModel(); if (linksCount === 0) { return Promise.resolve(); } const queryParams = this.getQueryParams(linksCount); return this.requestPage(queryParams); } getQueryParams(offset = 0) { const queryParams = { CHAT_ID: this.chatId, LIMIT: REQUEST_ITEMS_LIMIT$1 }; if (main_core.Type.isNumber(offset) && offset > 0) { queryParams.OFFSET = offset; } return queryParams; } requestPage(queryParams) { return this.restClient.callMethod(im_v2_const.RestMethod.imChatUrlGet, queryParams).then(response => { return this.handleUrlGetResponse(response.data()); }).catch(error => { console.error('SidebarInfo: Im.chatUrlList: page request error', error); }); } handleUrlGetResponse(response) { const { list, users, tariffRestrictions = {} } = response; const isHistoryLimitExceeded = Boolean(tariffRestrictions.isHistoryLimitExceeded); const addUsersPromise = this.userManager.setUsersToModel(users); const setLinksPromise = this.store.dispatch('sidebar/links/set', { chatId: this.chatId, links: list, hasNextPage: list.length === REQUEST_ITEMS_LIMIT$1, isHistoryLimitExceeded }); return Promise.all([setLinksPromise, addUsersPromise]); } handleCounterGetResponse(response) { const counter = response.counter; return this.store.dispatch('sidebar/links/setCounter', { chatId: this.chatId, counter }); } getLinksCountFromModel() { return this.store.getters['sidebar/links/getSize'](this.chatId); } } const REQUEST_ITEMS_LIMIT$2 = 50; class File { constructor({ dialogId }) { this.store = im_v2_application_core.Core.getStore(); this.restClient = im_v2_application_core.Core.getRestClient(); this.dialogId = dialogId; this.chatId = getChatId(dialogId); this.userManager = new im_v2_lib_user.UserManager(); } getInitialQuery() { return { [im_v2_const.RestMethod.imChatFileCollectionGet]: { chat_id: this.chatId, limit: REQUEST_ITEMS_LIMIT$2 } }; } getResponseHandler() { return response => { if (!response[im_v2_const.RestMethod.imChatFileCollectionGet]) { return Promise.reject(new Error('SidebarInfo service error: no response')); } return this.updateModels(response[im_v2_const.RestMethod.imChatFileCollectionGet]); }; } updateModels(resultData, group = '') { const { list, users, files, tariffRestrictions = {} } = resultData; const isHistoryLimitExceeded = Boolean(tariffRestrictions.isHistoryLimitExceeded); const historyLimitPromise = this.store.dispatch('sidebar/files/setHistoryLimitExceeded', { chatId: this.chatId, isHistoryLimitExceeded }); if (group && !main_core.Type.isArrayFilled(list)) { return this.store.dispatch('sidebar/files/setHasNextPage', { chatId: this.chatId, group, hasNextPage: false }); } const addUsersPromise = this.userManager.setUsersToModel(users); const setFilesPromise = this.store.dispatch('files/set', files); const sortedGroups = {}; list.forEach(file => { var _file$group; const fileGroup = (_file$group = file.group) != null ? _file$group : im_v2_const.SidebarFileGroups.fileUnsorted; if (!sortedGroups[fileGroup]) { sortedGroups[fileGroup] = []; } sortedGroups[fileGroup].push(file); }); const setSidebarFilesPromises = []; Object.entries(sortedGroups).forEach(([groupName, listByGroup]) => { setSidebarFilesPromises.push(this.store.dispatch('sidebar/files/set', { chatId: this.chatId, files: listByGroup, group: groupName }), this.store.dispatch('sidebar/files/setHasNextPage', { chatId: this.chatId, group: groupName, hasNextPage: listByGroup.length === REQUEST_ITEMS_LIMIT$2 }), this.store.dispatch('sidebar/files/setLastId', { chatId: this.chatId, group: groupName, lastId: getLastElementId(listByGroup) })); }); return Promise.all([setFilesPromise, addUsersPromise, historyLimitPromise, ...setSidebarFilesPromises]); } loadFirstPage(group) { return this.loadFirstPageByGroup(group); } loadNextPage(group) { return this.loadNextPageByGroup(group); } loadFirstPageByGroup(group) { const filesCount = this.getFilesCountFromModel(group); if (filesCount > REQUEST_ITEMS_LIMIT$2) { return Promise.resolve(); } const queryParams = this.getQueryParams(group); return this.requestPage(queryParams); } loadNextPageByGroup(group) { const queryParams = this.getQueryParams(group); return this.requestPage(queryParams); } getQueryParams(group) { const queryParams = { CHAT_ID: this.chatId, GROUP: group, LIMIT: REQUEST_ITEMS_LIMIT$2 }; const lastId = this.store.getters['sidebar/files/getLastId'](this.chatId, group); if (lastId > 0) { queryParams.LAST_ID = lastId; } return queryParams; } requestPage(queryParams) { return this.restClient.callMethod(im_v2_const.RestMethod.imChatFileGet, queryParams).then(response => { return this.updateModels(response.data(), queryParams.GROUP); }).catch(error => { console.error('SidebarInfo: imChatFileGet: page request error', error); }); } getFilesCountFromModel(group) { return this.store.getters['sidebar/files/getSize'](this.chatId, group); } } const REQUEST_ITEMS_LIMIT$3 = 50; class Task { constructor({ dialogId }) { this.store = im_v2_application_core.Core.getStore(); this.restClient = im_v2_application_core.Core.getRestClient(); this.dialogId = dialogId; this.chatId = getChatId(dialogId); this.userManager = new im_v2_lib_user.UserManager(); } getInitialQuery() { return { [im_v2_const.RestMethod.imChatTaskGet]: { chat_id: this.chatId, limit: REQUEST_ITEMS_LIMIT$3 } }; } getResponseHandler() { return response => { if (!response[im_v2_const.RestMethod.imChatTaskGet]) { return Promise.reject(new Error('SidebarInfo service error: no response')); } return this.updateModels(response[im_v2_const.RestMethod.imChatTaskGet]); }; } loadFirstPage() { const tasksCount = this.getTasksCountFromModel(); if (tasksCount > REQUEST_ITEMS_LIMIT$3) { return Promise.resolve(); } const queryParams = this.getQueryParams(); return this.requestPage(queryParams); } loadNextPage() { const queryParams = this.getQueryParams(); return this.requestPage(queryParams); } getQueryParams() { const queryParams = { CHAT_ID: this.chatId, LIMIT: REQUEST_ITEMS_LIMIT$3 }; const lastId = this.store.getters['sidebar/tasks/getLastId'](this.chatId); if (lastId > 0) { queryParams.LAST_ID = lastId; } return queryParams; } requestPage(queryParams) { return this.restClient.callMethod(im_v2_const.RestMethod.imChatTaskGet, queryParams).then(response => { return this.updateModels(response.data()); }).catch(error => { console.error('SidebarInfo: Im.imChatFavoriteGet: page request error', error); }); } updateModels(resultData) { const { list, users, tariffRestrictions = {} } = resultData; const isHistoryLimitExceeded = Boolean(tariffRestrictions.isHistoryLimitExceeded); const hasNextPage = list.length === REQUEST_ITEMS_LIMIT$3; const lastId = getLastElementId(list); const addUsersPromise = this.userManager.setUsersToModel(users); const setTasksPromise = this.store.dispatch('sidebar/tasks/set', { chatId: this.chatId, tasks: list, hasNextPage, lastId, isHistoryLimitExceeded }); return Promise.all([setTasksPromise, addUsersPromise]); } getTasksCountFromModel() { return this.store.getters['sidebar/tasks/getSize'](this.chatId); } } const REQUEST_ITEMS_LIMIT$4 = 50; class Meeting { constructor({ dialogId }) { this.store = im_v2_application_core.Core.getStore(); this.restClient = im_v2_application_core.Core.getRestClient(); this.dialogId = dialogId; this.chatId = getChatId(dialogId); this.userManager = new im_v2_lib_user.UserManager(); } getInitialQuery() { return { [im_v2_const.RestMethod.imChatCalendarGet]: { chat_id: this.chatId, limit: REQUEST_ITEMS_LIMIT$4 } }; } getResponseHandler() { return response => { if (!response[im_v2_const.RestMethod.imChatCalendarGet]) { return Promise.reject(new Error('SidebarInfo service error: no response')); } return this.updateModels(response[im_v2_const.RestMethod.imChatCalendarGet]); }; } loadFirstPage() { const meetingsCount = this.getMeetingsCountFromState(); if (meetingsCount > REQUEST_ITEMS_LIMIT$4) { return Promise.resolve(); } const queryParams = this.getQueryParams(); return this.requestPage(queryParams); } loadNextPage() { const queryParams = this.getQueryParams(); return this.requestPage(queryParams); } getQueryParams() { const queryParams = { CHAT_ID: this.chatId, LIMIT: REQUEST_ITEMS_LIMIT$4 }; const lastId = this.store.getters['sidebar/meetings/getLastId'](this.chatId); if (lastId > 0) { queryParams.LAST_ID = lastId; } return queryParams; } requestPage(queryParams) { return this.restClient.callMethod(im_v2_const.RestMethod.imChatCalendarGet, queryParams).then(response => { return this.updateModels(response.data()); }).catch(error => { console.error('SidebarInfo: Im.imChatCalendarGet: page request error', error); }); } updateModels(resultData) { const { list, users, tariffRestrictions = {} } = resultData; const isHistoryLimitExceeded = Boolean(tariffRestrictions.isHistoryLimitExceeded); const hasNextPage = list.length === REQUEST_ITEMS_LIMIT$4; const lastId = getLastElementId(list); const addUsersPromise = this.userManager.setUsersToModel(users); const setMeetingsPromise = this.store.dispatch('sidebar/meetings/set', { chatId: this.chatId, meetings: list, hasNextPage, lastId, isHistoryLimitExceeded }); return Promise.all([setMeetingsPromise, addUsersPromise]); } getMeetingsCountFromState() { return this.store.getters['sidebar/meetings/getSize'](this.chatId); } } const REQUEST_ITEMS_LIMIT$5 = 50; class MembersService { constructor({ dialogId }) { this.store = im_v2_application_core.Core.getStore(); this.restClient = im_v2_application_core.Core.getRestClient(); this.dialogId = dialogId; this.chatId = getChatId(dialogId); this.userManager = new im_v2_lib_user.UserManager(); } getInitialQuery() { return { [im_v2_const.RestMethod.imV2ChatMemberTail]: { dialogId: this.dialogId, limit: REQUEST_ITEMS_LIMIT$5 } }; } loadFirstPage() { const membersCount = this.getMembersCountFromModel(); if (membersCount > REQUEST_ITEMS_LIMIT$5) { return Promise.resolve(); } const queryParams = this.getQueryParams(); return this.requestPage(queryParams); } loadNextPage() { const queryParams = this.getQueryParams(); return this.requestPage(queryParams); } getQueryParams() { const queryParams = { dialogId: this.dialogId, limit: REQUEST_ITEMS_LIMIT$5 }; const nextCursor = this.store.getters['sidebar/members/getNextCursor'](this.chatId); if (nextCursor) { queryParams.cursor = nextCursor; } return queryParams; } async requestPage(queryParams) { let restResult = {}; try { const response = await this.restClient.callMethod(im_v2_const.RestMethod.imV2ChatMemberTail, queryParams); restResult = response.data(); } catch (error) { console.error('SidebarMain: Im.DialogUsersList: page request error', error); } return this.updateModels(restResult); } getResponseHandler() { return response => { return this.updateModels(response[im_v2_const.RestMethod.imV2ChatMemberTail]); }; } updateModels(restResult) { const { users, nextCursor } = restResult; const userIds = []; const addUsersPromise = this.userManager.setUsersToModel(users); users.forEach(user => { userIds.push(user.id); }); const setMembersPromise = this.store.dispatch('sidebar/members/set', { chatId: this.chatId, users: userIds, hasNextPage: users.length === REQUEST_ITEMS_LIMIT$5 }); let cursorPromise = Promise.resolve(); if (nextCursor) { cursorPromise = this.store.dispatch('sidebar/members/setNextCursor', { chatId: this.chatId, nextCursor }); } return Promise.all([addUsersPromise, setMembersPromise, cursorPromise]); } getMembersCountFromModel() { return this.store.getters['sidebar/members/getSize'](this.chatId); } } const REQUEST_ITEMS_LIMIT$6 = 25; class Multidialog { constructor() { this.store = im_v2_application_core.Core.getStore(); this.userManager = new im_v2_lib_user.UserManager(); } getInitialQuery() { if (this.isInitedMultidialogBlock()) { return {}; } return { [im_v2_const.RestMethod.imBotNetworkChatCount]: {} }; } getResponseHandler() { return response => { if (this.isInitedMultidialogBlock()) { return Promise.resolve(); } if (!response[im_v2_const.RestMethod.imBotNetworkChatCount]) { return Promise.reject(new Error('SidebarInfo service error: no response')); } const setInitedPromise = this.store.dispatch('sidebar/multidialog/setInited', true); const updateModelsPromise = this.updateModels(response[im_v2_const.RestMethod.imBotNetworkChatCount]); return Promise.all([setInitedPromise, updateModelsPromise]); }; } loadNextPage() { const hasNextPage = this.store.getters['sidebar/multidialog/hasNextPage']; if (!hasNextPage) { return Promise.resolve(); } const offset = this.store.getters['sidebar/multidialog/getNumberMultidialogs']; const config = { data: this.getQueryParams({ offset }) }; return this.requestPage(config); } getQueryParams(params) { const queryParams = { offset: 0, limit: REQUEST_ITEMS_LIMIT$6, ...params }; Object.keys(queryParams).forEach(key => { const value = queryParams[key]; if (main_core.Type.isNumber(value) && value > 0) { queryParams[key] = value; } }); return queryParams; } requestPage(config) { return im_v2_lib_rest.runAction(im_v2_const.RestMethod.imBotNetworkChatList, config).then(response => { return this.updateModels(response); }).catch(error => { console.error('SidebarInfo: imBotNetworkChatList: page request error', error); }); } createSupportChat() { im_v2_lib_logger.Logger.warn('SidebarInfo: imBotNetworkChatAdd'); return im_v2_lib_rest.runAction(im_v2_const.RestMethod.imBotNetworkChatAdd).then(response => { void this.updateModels({ chats: response }); const { dialogId } = response; im_v2_lib_logger.Logger.warn('SidebarInfo: createSupportChat result', response); return dialogId; }).catch(error => { console.error('SidebarInfo: createSupportChat error:', error); }); } loadFirstPage() { const isInitedDetail = this.store.getters['sidebar/multidialog/isInitedDetail']; if (isInitedDetail) { return Promise.resolve(); } const numberMultidialogs = this.store.getters['sidebar/multidialog/getNumberMultidialogs']; const limit = REQUEST_ITEMS_LIMIT$6 < numberMultidialogs ? numberMultidialogs : REQUEST_ITEMS_LIMIT$6; const config = { data: this.getQueryParams({ limit }) }; return this.requestPage(config).then(() => { return this.store.dispatch('sidebar/multidialog/setInitedDetail', true); }); } updateModels(resultData) { const { count, chatIdsWithCounters, multidialogs, chats, users, openSessionsLimit } = resultData; const promises = []; if (chats) { const setChatsPromise = this.store.dispatch('chats/set', chats); promises.push(setChatsPromise); } if (users) { const setUsersPromise = this.userManager.setUsersToModel(users); promises.push(setUsersPromise); } const setSupportTicketPromise = this.store.dispatch('sidebar/multidialog/set', { chatsCount: count, unreadChats: chatIdsWithCounters, multidialogs, openSessionsLimit }); promises.push(setSupportTicketPromise); return Promise.all(promises); } isInitedMultidialogBlock() { return this.store.getters['sidebar/multidialog/isInited']; } } const REQUEST_ITEMS_LIMIT$7 = 50; class FileUnsorted { constructor({ dialogId }) { this.store = im_v2_application_core.Core.getStore(); this.restClient = im_v2_application_core.Core.getRestClient(); this.dialogId = dialogId; this.chatId = this.getChatId(); this.userManager = new im_v2_lib_user.UserManager(); } getInitialQuery() { return { [im_v2_const.RestMethod.imDiskFolderListGet]: { chat_id: this.chatId, limit: REQUEST_ITEMS_LIMIT$7 } }; } getResponseHandler() { return response => { if (!response[im_v2_const.RestMethod.imDiskFolderListGet]) { return Promise.reject(new Error('SidebarInfo service error: no response')); } return this.updateModels(response[im_v2_const.RestMethod.imDiskFolderListGet]); }; } loadFirstPage() { const filesCount = this.getFilesCountFromModel(im_v2_const.SidebarDetailBlock.fileUnsorted); if (filesCount > REQUEST_ITEMS_LIMIT$7) { return Promise.resolve(); } const queryParams = this.getQueryParams(); return this.requestPage(queryParams); } loadNextPage() { const queryParams = this.getQueryParams(); return this.requestPage(queryParams); } getQueryParams() { const queryParams = { CHAT_ID: this.chatId, LIMIT: REQUEST_ITEMS_LIMIT$7 }; const lastId = this.store.getters['sidebar/files/getLastId'](this.chatId, im_v2_const.SidebarDetailBlock.fileUnsorted); if (lastId > 0) { queryParams.LAST_ID = lastId; } return queryParams; } requestPage(queryParams) { return this.restClient.callMethod(im_v2_const.RestMethod.imDiskFolderListGet, queryParams).then(response => { return this.handleResponse(response.data()); }).catch(error => { console.error('SidebarInfo: Im.imDiskFolderListGet: page request error', error); }); } handleResponse(response) { const diskFolderListGetResult = response; if (diskFolderListGetResult.files.length < REQUEST_ITEMS_LIMIT$7) { this.hasMoreItemsToLoad = false; } const lastId = getLastElementId(diskFolderListGetResult.files); if (lastId) { this.lastId = lastId; } return this.updateModels(diskFolderListGetResult); } updateModels(resultData) { const { users, files, tariffRestrictions = {} } = resultData; const isHistoryLimitExceeded = Boolean(tariffRestrictions.isHistoryLimitExceeded); const historyLimitPromise = this.store.dispatch('sidebar/files/setHistoryLimitExceeded', { chatId: this.chatId, isHistoryLimitExceeded }); const preparedFiles = files.map(file => { return { ...file, group: im_v2_const.SidebarDetailBlock.fileUnsorted }; }); const addUsersPromise = this.userManager.setUsersToModel(users); const setFilesPromise = this.store.dispatch('files/set', preparedFiles); const setSidebarFilesPromise = this.store.dispatch('sidebar/files/set', { chatId: this.chatId, files: preparedFiles, group: im_v2_const.SidebarDetailBlock.fileUnsorted }); const hasNextPagePromise = this.store.dispatch('sidebar/files/setHasNextPage', { chatId: this.chatId, group: im_v2_const.SidebarDetailBlock.fileUnsorted, hasNextPage: preparedFiles.length === REQUEST_ITEMS_LIMIT$7 }); const setLastIdPromise = this.store.dispatch('sidebar/files/setLastId', { chatId: this.chatId, group: im_v2_const.SidebarDetailBlock.fileUnsorted, lastId: getLastElementId(preparedFiles) }); return Promise.all([setFilesPromise, setSidebarFilesPromise, addUsersPromise, hasNextPagePromise, setLastIdPromise, historyLimitPromise]); } getFilesCountFromModel(group) { return this.store.getters['sidebar/files/getSize'](this.chatId, group); } getChatId() { const dialog = this.store.getters['chats/get'](this.dialogId, true); return dialog.chatId; } } const MainPanelServiceClasses = { Members: MembersService, Favorite, Link, Task, File, Meeting, FileUnsorted, Multidialog }; const BlockToServices = Object.freeze({ [im_v2_const.SidebarMainPanelBlock.chat]: [im_v2_const.SidebarDetailBlock.members], [im_v2_const.SidebarMainPanelBlock.copilot]: [im_v2_const.SidebarDetailBlock.members], [im_v2_const.SidebarMainPanelBlock.task]: [im_v2_const.SidebarDetailBlock.members], [im_v2_const.SidebarMainPanelBlock.copilotInfo]: [im_v2_const.SidebarDetailBlock.favorite], [im_v2_const.SidebarMainPanelBlock.info]: [im_v2_const.SidebarDetailBlock.favorite, im_v2_const.SidebarDetailBlock.link], [im_v2_const.SidebarMainPanelBlock.fileList]: [im_v2_const.SidebarDetailBlock.file], [im_v2_const.SidebarMainPanelBlock.fileUnsortedList]: [im_v2_const.SidebarDetailBlock.fileUnsorted], [im_v2_const.SidebarMainPanelBlock.taskList]: [im_v2_const.SidebarDetailBlock.task], [im_v2_const.SidebarMainPanelBlock.meetingList]: [im_v2_const.SidebarDetailBlock.meeting], [im_v2_const.SidebarMainPanelBlock.multidialog]: [im_v2_const.SidebarDetailBlock.multidialog] }); class Main { constructor({ dialogId }) { this.blockServices = []; this.store = im_v2_application_core.Core.getStore(); this.restClient = im_v2_application_core.Core.getRestClient(); this.dialogId = dialogId; this.buildBlocks(); } // region public methods async requestInitialData() { const query = this.getInitialQuery(); const response = await im_v2_lib_rest.callBatch(query); return this.handleBatchRequestResult(response); } // endregion buildBlocks() { const classNames = this.getServiceClassesForBlocks(); this.blockServices = classNames.map(ClassName => { const blockService = new MainPanelServiceClasses[ClassName]({ dialogId: this.dialogId }); return { initialQuery: blockService.getInitialQuery(), responseHandler: blockService.getResponseHandler() }; }); } getServiceClassesForBlocks() { const services = []; const sidebarConfig = im_v2_lib_sidebar.SidebarManager.getInstance().getConfig(this.dialogId); const blockList = sidebarConfig.getBlocks(this.dialogId); blockList.forEach(block => { const blockServices = BlockToServices[block]; if (blockServices) { services.push(...blockServices); } }); return services.map(service => main_core.Text.capitalize(service)); } getInitialQuery() { let query = {}; this.blockServices.forEach(block => { query = Object.assign(query, block.initialQuery); }); return query; } handleBatchRequestResult(response) { const responseHandlersResult = []; this.blockServices.forEach(block => { responseHandlersResult.push(block.responseHandler(response)); }); return Promise.all(responseHandlersResult).then(() => { return this.setInited(); }).catch(error => { console.error(error); }); } setInited() { return this.store.dispatch('sidebar/setInited', getChatId(this.dialogId)); } } var _deleteChat = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("deleteChat"); var _deleteCollab = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("deleteCollab"); var _isDeletionCancelled = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("isDeletionCancelled"); var _isPersonalChat = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("isPersonalChat"); class MainMenu extends im_v2_lib_menu.RecentMenu { constructor() { super(); Object.defineProperty(this, _isPersonalChat, { value: _isPersonalChat2 }); Object.defineProperty(this, _isDeletionCancelled, { value: _isDeletionCancelled2 }); Object.defineProperty(this, _deleteCollab, { value: _deleteCollab2 }); Object.defineProperty(this, _deleteChat, { value: _deleteChat2 }); this.id = 'im-sidebar-context-menu'; this.permissionManager = im_v2_lib_permission.PermissionManager.getInstance(); } getMenuOptions() { return { ...super.getMenuOptions(), className: this.getMenuClassName(), angle: false }; } getMenuItems() { return [this.getPinMessageItem(), this.getEditItem(), this.getAddMembersToChatItem(), this.getOpenProfileItem(), this.getOpenUserCalendarItem(), this.getChatsWithUserItem(), this.getHideItem(), this.getLeaveItem(), this.getDeleteItem()]; } getEditItem() { if (!this.permissionManager.canPerformActionByRole(im_v2_const.ActionByRole.update, this.context.dialogId)) { return null; } return { text: main_core.Loc.getMessage('IM_SIDEBAR_MENU_UPDATE_CHAT'), onclick: () => { im_v2_lib_analytics.Analytics.getInstance().chatEdit.onOpenForm(this.context.dialogId); void im_v2_lib_layout.LayoutManager.getInstance().setLayout({ name: im_v2_const.Layout.updateChat.name, entityId: this.context.dialogId }); } }; } getDeleteItem() { if (!this.permissionManager.canPerformActionByRole(im_v2_const.ActionByRole.delete, this.context.dialogId)) { return null; } return { text: main_core.Loc.getMessage('IM_SIDEBAR_MENU_DELETE_CHAT'), className: 'menu-popup-no-icon bx-im-sidebar__context-menu_delete', onclick: async () => { im_v2_lib_analytics.Analytics.getInstance().chatDelete.onClick(this.context.dialogId); if (await babelHelpers.classPrivateFieldLooseBase(this, _isDeletionCancelled)[_isDeletionCancelled]()) { return; } im_v2_lib_analytics.Analytics.getInstance().chatDelete.onConfirm(this.context.dialogId); if (this.isCollabChat()) { babelHelpers.classPrivateFieldLooseBase(this, _deleteCollab)[_deleteCollab](); return; } babelHelpers.classPrivateFieldLooseBase(this, _deleteChat)[_deleteChat](); } }; } getOpenUserCalendarItem() { if (!this.isUser()) { return null; } if (this.isBot()) { return null; } const profileUri = im_v2_lib_utils.Utils.user.getCalendarLink(this.context.dialogId); return { text: main_core.Loc.getMessage('IM_LIB_MENU_OPEN_CALENDAR_V2'), onclick: () => { BX.SidePanel.Instance.open(profileUri); this.menuInstance.close(); } }; } getAddMembersToChatItem() { if (this.isBot() || this.isChatWithCurrentUser()) { return null; } const hasCreateChatAccess = this.permissionManager.canPerformActionByUserType(im_v2_const.ActionByUserType.createChat); if (babelHelpers.classPrivateFieldLooseBase(this, _isPersonalChat)[_isPersonalChat]() && !hasCreateChatAccess) { return null; } const hasAccessByRole = this.permissionManager.canPerformActionByRole(im_v2_const.ActionByRole.extend, this.context.dialogId); if (!hasAccessByRole) { return null; } const text = this.isChannel() ? main_core.Loc.getMessage('IM_SIDEBAR_MENU_INVITE_SUBSCRIBERS') : main_core.Loc.getMessage('IM_SIDEBAR_MENU_INVITE_MEMBERS_V2'); return { text, onclick: () => { im_v2_lib_analytics.Analytics.getInstance().userAdd.onChatSidebarClick(this.dialogId); this.emit(MainMenu.events.onAddToChatShow); this.menuInstance.close(); } }; } } async function _deleteChat2() { await new im_v2_provider_service_chat.ChatService().deleteChat(this.context.dialogId); void im_v2_lib_layout.LayoutManager.getInstance().clearCurrentLayoutEntityId(); } async function _deleteCollab2() { im_v2_lib_notifier.Notifier.collab.onBeforeDelete(); await new im_v2_provider_service_chat.ChatService().deleteCollab(this.context.dialogId); void im_v2_lib_layout.LayoutManager.getInstance().clearCurrentLayoutEntityId(); void im_v2_lib_layout.LayoutManager.getInstance().deleteLastOpenedElementById(this.context.dialogId); } async function _isDeletionCancelled2() { const { dialogId } = this.context; const confirmResult = await im_v2_lib_confirm.showDeleteChatConfirm(dialogId); if (!confirmResult) { im_v2_lib_analytics.Analytics.getInstance().chatDelete.onCancel(dialogId); return true; } return false; } function _isPersonalChat2() { const chat = this.getChat(this.context.dialogId); return chat.type === im_v2_const.ChatType.user; } MainMenu.events = { onAddToChatShow: 'onAddToChatShow' }; // @vue/component const MainHeader = { name: 'MainHeader', components: { AddToChat: im_v2_component_entitySelector.AddToChat, AddToCollab: im_v2_component_entitySelector.AddToCollab }, props: { dialogId: { type: String, required: true } }, data() { return { showAddToChatPopup: false }; }, computed: { recentItem() { return this.$store.getters['recent/get'](this.dialogId, true); }, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, sidebarConfig() { return im_v2_lib_sidebar.SidebarManager.getInstance().getConfig(this.dialogId); }, headerTitle() { return this.sidebarConfig.getHeaderTitle(); }, showMenuIcon() { return this.canOpenMenu && this.isMenuEnabled; }, canOpenMenu() { return im_v2_lib_permission.PermissionManager.getInstance().canPerformActionByRole(im_v2_const.ActionByRole.openSidebarMenu, this.dialogId); }, isMenuEnabled() { return this.sidebarConfig.isMenuEnabled(); }, addMembersPopupComponent() { return this.dialog.type === im_v2_const.ChatType.collab ? im_v2_component_entitySelector.AddToCollab : im_v2_component_entitySelector.AddToChat; } }, created() { this.contextMenu = new MainMenu(); this.contextMenu.subscribe(MainMenu.events.onAddToChatShow, this.onAddChatShow); }, beforeUnmount() { this.contextMenu.destroy(); this.contextMenu.unsubscribe(MainMenu.events.onAddToChatShow, this.onAddChatShow); }, methods: { onAddChatShow() { this.showAddToChatPopup = true; }, onContextMenuClick(event) { const item = { dialogId: this.dialogId, ...this.recentItem }; this.contextMenu.openMenu(item, event.target); }, onSidebarCloseClick() { main_core_events.EventEmitter.emit(im_v2_const.EventType.sidebar.close); }, loc(phraseCode) { return this.$Bitrix.Loc.getMessage(phraseCode); } }, template: ` <div class="bx-im-sidebar-header__container bx-im-sidebar-header__scope"> <div class="bx-im-sidebar-header__title-container"> <button class="bx-im-sidebar-header__cross-icon bx-im-messenger__cross-icon" @click="onSidebarCloseClick" ></button> <div class="bx-im-sidebar-header__title">{{ headerTitle }}</div> </div> <button v-if="showMenuIcon" class="bx-im-sidebar-header__context-menu-icon bx-im-messenger__context-menu-icon" @click="onContextMenuClick" ref="context-menu" ></button> <component v-if="showAddToChatPopup" :is="addMembersPopupComponent" :bindElement="$refs['context-menu'] || {}" :dialogId="dialogId" :popupConfig="{offsetTop: 0, offsetLeft: -420}" @close="showAddToChatPopup = false" /> </div> ` }; // @vue/component const ChatLinks = { name: 'ChatLinks', directives: { hint: ui_vue3_directives_hint.hint }, props: { dialogId: { type: String, required: true } }, data() { return { expanded: false }; }, computed: { dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, urlCounter() { const counter = this.$store.getters['sidebar/links/getCounter'](this.chatId); return this.getCounterString(counter); }, isLinksAvailable() { return this.$store.state.sidebar.isLinksMigrated; }, hintDirectiveContent() { return { text: this.$Bitrix.Loc.getMessage('IM_SIDEBAR_LINKS_NOT_AVAILABLE'), popupOptions: { angle: true, targetContainer: document.body, offsetLeft: 141, offsetTop: -10, bindOptions: { position: 'top' } } }; }, chatId() { return this.dialog.chatId; } }, methods: { getCounterString(counter) { const MAX_COUNTER = 100; if (counter >= MAX_COUNTER) { return '99+'; } return counter.toString(); }, onLinkClick() { if (!this.isLinksAvailable) { return; } main_core_events.EventEmitter.emit(im_v2_const.EventType.sidebar.open, { panel: im_v2_const.SidebarDetailBlock.link, dialogId: this.dialogId }); }, loc(phraseCode) { return this.$Bitrix.Loc.getMessage(phraseCode); } }, template: ` <div class="bx-im-sidebar-chat-links__container" :class="[isLinksAvailable ? '' : '--links-not-active']" @click="onLinkClick" > <div v-if="!isLinksAvailable" class="bx-im-sidebar-chat-links__hint-not-active" v-hint="hintDirectiveContent" ></div> <div class="bx-im-sidebar-chat-links__title-container"> <div class="bx-im-sidebar-chat-links__icon"></div> <div class="bx-im-sidebar-chat-links__title-text"> {{ loc('IM_SIDEBAR_LINK_DETAIL_TITLE') }} </div> </div> <div class="bx-im-sidebar-chat-links__counter-container"> <span class="bx-im-sidebar-chat-links__counter">{{urlCounter}}</span> </div> </div> ` }; // @vue/component const ChatFavourites = { name: 'ChatFavourites', props: { dialogId: { type: String, required: true } }, computed: { dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, favoriteCounter() { const counter = this.$store.getters['sidebar/favorites/getCounter'](this.chatId); return this.getCounterString(counter); }, chatId() { return this.dialog.chatId; }, isCopilotLayout() { const { name: currentLayoutName } = this.$store.getters['application/getLayout']; return currentLayoutName === im_v2_const.Layout.copilot.name; } }, methods: { getCounterString(counter) { const MAX_COUNTER = 100; if (counter >= MAX_COUNTER) { return '99+'; } return counter.toString(); }, onFavouriteClick() { main_core_events.EventEmitter.emit(im_v2_const.EventType.sidebar.open, { panel: im_v2_const.SidebarDetailBlock.favorite, dialogId: this.dialogId }); }, loc(phraseCode) { return this.$Bitrix.Loc.getMessage(phraseCode); } }, template: ` <div class="bx-im-sidebar-chat-favourites__container" :class="{'--copilot': isCopilotLayout}" @click="onFavouriteClick" > <div class="bx-im-sidebar-chat-favourites__title"> <div class="bx-im-sidebar-chat-favourites__icon"></div> <div class="bx-im-sidebar-chat-favourites__title-text"> {{ loc('IM_SIDEBAR_FAVORITE_DETAIL_TITLE') }} </div> </div> <div class="bx-im-sidebar-chat-favourites__counter-container"> <span class="bx-im-sidebar-chat-favourites__counter">{{favoriteCounter}}</span> </div> </div> ` }; const MAX_DESCRIPTION_SYMBOLS = 25; const NEW_LINE_SYMBOL = '\n'; const DescriptionByChatType = { [im_v2_const.ChatType.user]: main_core.Loc.getMessage('IM_SIDEBAR_CHAT_TYPE_USER'), [im_v2_const.ChatType.channel]: main_core.Loc.getMessage('IM_SIDEBAR_CHAT_TYPE_CHANNEL'), [im_v2_const.ChatType.openChannel]: main_core.Loc.getMessage('IM_SIDEBAR_CHAT_TYPE_CHANNEL'), [im_v2_const.ChatType.generalChannel]: main_core.Loc.getMessage('IM_SIDEBAR_CHAT_TYPE_CHANNEL'), [im_v2_const.ChatType.comment]: main_core.Loc.getMessage('IM_SIDEBAR_CHAT_TYPE_COMMENTS'), default: main_core.Loc.getMessage('IM_SIDEBAR_CHAT_TYPE_GROUP_V2') }; // @vue/component const ChatDescription = { name: 'ChatDescription', props: { dialogId: { type: String, required: true } }, data() { return { expanded: false }; }, computed: { dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, isUser() { return this.dialog.type === im_v2_const.ChatType.user; }, isBot() { const user = this.$store.getters['users/get'](this.dialogId, true); return user.type === im_v2_const.UserType.bot; }, isCollabChat() { return this.dialog.type === im_v2_const.ChatType.collab; }, isLongDescription() { const hasNewLine = this.dialog.description.includes(NEW_LINE_SYMBOL); return this.dialog.description.length > MAX_DESCRIPTION_SYMBOLS || hasNewLine; }, previewDescription() { if (this.dialog.description.length === 0) { return this.chatTypeText; } if (this.isLongDescription) { return `${this.dialog.description.slice(0, MAX_DESCRIPTION_SYMBOLS)}...`; } return this.dialog.description; }, descriptionToShow() { return this.expanded ? this.dialog.description : this.previewDescription; }, chatTypeText() { var _DescriptionByChatTyp; if (this.isCopilotLayout) { return this.$store.getters['copilot/getProvider']; } if (this.isBot) { return this.loc('IM_SIDEBAR_CHAT_TYPE_BOT'); } if (this.isCollabChat) { return this.loc('IM_SIDEBAR_CHAT_TYPE_COLLAB'); } return (_DescriptionByChatTyp = DescriptionByChatType[this.dialog.type]) != null ? _DescriptionByChatTyp : DescriptionByChatType.default; }, showExpandButton() { if (this.expanded) { return false; } return this.isLongDescription; }, isCopilotLayout() { const { name: currentLayoutName } = this.$store.getters['application/getLayout']; return currentLayoutName === im_v2_const.Layout.copilot.name; } }, methods: { loc(phraseCode) { return this.$Bitrix.Loc.getMessage(phraseCode); } }, template: ` <div class="bx-im-sidebar-chat-description__container"> <div class="bx-im-sidebar-chat-description__text-container" :class="[expanded ? '--expanded' : '']"> <div class="bx-im-sidebar-chat-description__icon"></div> <div class="bx-im-sidebar-chat-description__text"> {{ descriptionToShow }}</div> </div> <button v-if="showExpandButton" class="bx-im-sidebar-chat-description__show-more-button" @click="expanded = !expanded" > {{ loc('IM_SIDEBAR_CHAT_DESCRIPTION_SHOW') }} </button> </div> ` }; // @vue/component const ChatShared = { name: 'ChatShared', props: { dialogId: { type: String, required: true } }, methods: { async onLinkClick() { main_core_events.EventEmitter.emit(im_v2_const.EventType.sidebar.open, { panel: im_v2_const.SidebarDetailBlock.chatsWithUser, standalone: true, dialogId: this.dialogId }); }, loc(phraseCode) { return this.$Bitrix.Loc.getMessage(phraseCode); } }, template: ` <div class="bx-im-sidebar-chat-shared__container" @click="onLinkClick" > <div class="bx-im-sidebar-chat-shared__title-container"> <div class="bx-im-sidebar-chat-shared__icon"></div> <div class="bx-im-sidebar-chat-shared__title-text"> {{ loc('IM_SIDEBAR_SHARED_CHATS_TITLE') }} </div> </div> <div class="bx-im-sidebar-chat-shared__arrow"></div> </div> ` }; // @vue/component const InfoPreview = { name: 'InfoPreview', components: { ChatDescription, ChatLinks, ChatFavourites, ChatShared }, props: { dialogId: { type: String, required: true } }, computed: { user() { return this.$store.getters['users/get'](this.dialogId, true); }, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, isUser() { return this.dialog.type === im_v2_const.ChatType.user; }, isSelfChat() { return this.isUser && this.user.id === im_v2_application_core.Core.getUserId(); }, isUserOrBot() { return this.isUser && [im_v2_const.UserType.bot, im_v2_const.UserType.user].includes(this.user.type); }, showSharedChats() { return this.isUserOrBot && !this.isSelfChat; } }, template: ` <div class="bx-im-sidebar-info-preview__container"> <ChatDescription :dialogId="dialogId" /> <ChatFavourites :dialogId="dialogId" /> <ChatLinks :dialogId="dialogId" /> <ChatShared v-if="showSharedChats" :dialogId="dialogId" /> </div> ` }; // @vue/component const FilePreviewItem = { name: 'FilePreviewItem', directives: { lazyload: ui_vue3_directives_lazyload.lazyload }, props: { fileItem: { type: Object, required: true } }, computed: { sidebarFileItem() { return this.fileItem; }, file() { return this.$store.getters['files/get'](this.sidebarFileItem.fileId, true); }, previewImageStyles() { if (!this.hasPreview) { return {}; } return { backgroundImage: `url('${this.file.urlPreview}')` }; }, hasPreview() { return this.file.urlPreview !== ''; }, fileShortName() { const NAME_MAX_LENGTH = 22; return im_v2_lib_utils.Utils.file.getShortFileName(this.file.name, NAME_MAX_LENGTH); }, viewerAttributes() { return im_v2_lib_utils.Utils.file.getViewerDataAttributes({ viewerAttributes: this.file.viewerAttrs, previewImageSrc: this.imageSrc, context: im_v2_const.FileViewerContext.sidebarMain }); }, isImage() { return this.file.type === 'image'; }, isVideo() { return this.file.type === 'video'; }, isAudio() { return this.file.type === 'audio'; }, fileIconClass() { return `ui-icon ui-icon-file-${this.file.icon}`; }, isViewerAvailable() { return Object.keys(this.viewerAttributes).length > 0; }, imageSrc() { const isAnimation = ['gif', 'webp'].includes(this.file.extension); return isAnimation ? this.file.urlShow : this.file.urlPreview; } }, methods: { download() { if (this.isViewerAvailable) { return; } window.open(this.file.urlDownload, '_blank'); } }, template: ` <div class="bx-im-sidebar-file-preview-item__container bx-im-sidebar-file-preview-item__scope" @click="download" :title="file.name" > <img v-if="isImage" v-bind="viewerAttributes" v-lazyload data-lazyload-dont-hide :data-lazyload-src="imageSrc" :title="file.name" :alt="file.name" class="bx-im-sidebar-file-preview-item__preview-box" /> <div v-else-if="isVideo" class="bx-im-sidebar-file-preview-item__preview-box bx-im-sidebar-file-preview-item__preview-video-box" :style="previewImageStyles" v-bind="viewerAttributes" > <video v-if="!hasPreview" :src="file.urlDownload" preload="metadata" class="bx-im-sidebar-file-preview-item__preview-video" ></video> <div class="bx-im-sidebar-file-preview-item__preview-video-play-button"></div> <div class="bx-im-sidebar-file-preview-item__preview-video-play-icon"></div> </div> <div v-else-if="isAudio" v-bind="viewerAttributes" class="bx-im-sidebar-file-preview-item__preview-box"> <div class="bx-im-sidebar-file-preview-item__preview-audio-play-button"></div> </div> <div v-else v-bind="viewerAttributes" class="bx-im-sidebar-file-preview-item__preview-box"> <div :class="fileIconClass"><i></i></div> </div> <div class="bx-im-sidebar-file-preview-item__text">{{ fileShortName }}</div> </div> ` }; // @vue/component const DetailEmptyState = { name: 'DetailEmptyState', props: { title: { type: String, required: true }, iconType: { type: String, required: true } }, computed: { iconClass() { return `--${main_core.Text.toKebabCase(this.iconType)}`; } }, template: ` <div class="bx-im-sidebar-detail-empty-state__container bx-im-sidebar-detail-empty-state__scope"> <span class="bx-im-sidebar-detail-empty-state__icon" :class="[iconClass]"></span> <span class="bx-im-sidebar-detail-empty-state__text">{{ title }}</span> </div> ` }; // @vue/component const FileListPreview = { name: 'FileListPreview', components: { DetailEmptyState, FilePreviewItem }, props: { dialogId: { type: String, required: true } }, computed: { SidebarDetailBlock: () => im_v2_const.SidebarDetailBlock, files() { if (this.isMigrationFinished) { return this.$store.getters['sidebar/files/getLatest'](this.chatId); } return this.$store.getters['sidebar/files/getLatestUnsorted'](this.chatId); }, hasFiles() { return this.files.length > 0; }, isMigrationFinished() { return this.$store.state.sidebar.isFilesMigrated; }, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, chatId() { return this.dialog.chatId; } }, methods: { onOpenDetail() { if (!this.hasFiles) { return; } const panel = this.isMigrationFinished ? im_v2_const.SidebarDetailBlock.file : im_v2_const.SidebarDetailBlock.fileUnsorted; main_core_events.EventEmitter.emit(im_v2_const.EventType.sidebar.open, { panel, dialogId: this.dialogId }); } }, template: ` <div class="bx-im-sidebar-file-preview__scope"> <div class="bx-im-sidebar-file-preview__container"> <div class="bx-im-sidebar-file-preview__header_container" :class="[hasFiles ? '--active': '']" @click="onOpenDetail" > <span class="bx-im-sidebar-file-preview__title-text"> {{ $Bitrix.Loc.getMessage('IM_SIDEBAR_MEDIA_DETAIL_TITLE') }} </span> <div v-if="hasFiles" class="bx-im-sidebar__forward-icon"></div> </div> <div v-if="hasFiles" class="bx-im-sidebar-file-preview__files-container"> <FilePreviewItem v-for="file in files" :fileItem="file" /> </div> <DetailEmptyState v-else :title="$Bitrix.Loc.getMessage('IM_SIDEBAR_MEDIA_AND_FILES_EMPTY')" :iconType="SidebarDetailBlock.media" /> </div> </div> ` }; class SidebarMenu extends im_v2_lib_menu.BaseMenu { constructor() { super(); this.id = 'im-sidebar-context-menu'; } getMenuOptions() { return { ...super.getMenuOptions(), className: this.getMenuClassName() }; } getOpenContextMessageItem() { if (!this.context.messageId || this.context.messageId === 0) { return null; } return { text: main_core.Loc.getMessage('IM_SIDEBAR_MENU_GO_TO_CONTEXT_MESSAGE'), onclick: () => { main_core_events.EventEmitter.emit(im_v2_const.EventType.dialog.goToMessageContext, { messageId: this.context.messageId, dialogId: this.context.dialogId }); this.menuInstance.close(); } }; } getCopyLinkItem(title) { if (!BX.clipboard.isCopySupported()) { return null; } return { text: title, onclick: () => { if (BX.clipboard.copy(this.context.source)) { im_v2_lib_notifier.Notifier.onCopyLinkComplete(); } this.menuInstance.close(); } }; } } class TaskManager { constructor() { this.store = im_v2_application_core.Core.getStore(); this.restClient = im_v2_application_core.Core.getRestClient(); } delete({ id, chatId }) { this.store.dispatch('sidebar/tasks/delete', { chatId, id }); const queryParams = { LINK_ID: id }; this.restClient.callMethod(im_v2_const.RestMethod.imChatTaskDelete, queryParams).catch(error => { console.error('Im.Sidebar: error deleting task', error); }); } } class TaskMenu extends SidebarMenu { constructor() { super(); this.id = 'im-sidebar-context-menu'; this.taskManager = new TaskManager(); } getMenuItems() { return [this.getOpenContextMessageItem(), this.getCopyLinkItem(main_core.Loc.getMessage('IM_SIDEBAR_MENU_COPY_TASK_LINK')), this.getDeleteItem()]; } getDeleteItem() { return { text: main_core.Loc.getMessage('IM_SIDEBAR_MENU_DELETE_TASK_CONNECTION'), onclick: function () { this.taskManager.delete(this.context.task); this.menuInstance.close(); }.bind(this) }; } } // @vue/component const TaskItem = { name: 'TaskItem', components: { ChatAvatar: im_v2_component_elements_avatar.ChatAvatar, AvatarSize: im_v2_component_elements_avatar.AvatarSize }, props: { task: { type: Object, required: true }, contextDialogId: { type: String, required: true }, searchQuery: { type: String, default: '' } }, emits: ['contextMenuClick'], data() { return { showContextButton: false }; }, computed: { AvatarSize: () => im_v2_component_elements_avatar.AvatarSize, taskItem() { return this.task; }, taskTitle() { if (this.searchQuery.length === 0) { return main_core.Text.encode(this.taskItem.task.title); } return im_v2_lib_textHighlighter.highlightText(main_core.Text.encode(this.taskItem.task.title), this.searchQuery); }, taskAuthorDialogId() { return this.taskItem.task.creatorId.toString(); }, taskResponsibleDialogId() { return this.taskItem.task.responsibleId.toString(); }, taskDeadlineText() { const statusToShow = main_core.Type.isStringFilled(this.taskItem.task.state) ? this.taskItem.task.state : this.taskItem.task.statusTitle; return im_v2_lib_utils.Utils.text.convertHtmlEntities(statusToShow); }, taskBackgroundColorClass() { if (this.taskItem.task.status === 5) { return '--completed'; } return ''; }, statusColorClass() { if (!this.taskItem.task.color || !ui_label.LabelColor[this.taskItem.task.color.toUpperCase()]) { return ''; } return `ui-label-${this.taskItem.task.color.toLowerCase()}`; } }, methods: { onTaskClick() { BX.SidePanel.Instance.open(this.taskItem.task.source, { cacheable: false }); }, onContextMenuClick(event) { this.$emit('contextMenuClick', { task: this.taskItem, source: this.taskItem.task.source, messageId: this.taskItem.messageId }, event.currentTarget); } }, template: ` <div class="bx-im-sidebar-task-item__container bx-im-sidebar-task-item__scope" :class="taskBackgroundColorClass" @mouseover="showContextButton = true" @mouseleave="showContextButton = false" > <div class="bx-im-sidebar-task-item__content" @click="onTaskClick"> <div class="bx-im-sidebar-task-item__header-text" :title="taskTitle" v-html="taskTitle"></div> <div class="bx-im-sidebar-task-item__detail-container"> <ChatAvatar :size="AvatarSize.XS" :avatarDialogId="taskAuthorDialogId" :contextDialogId="contextDialogId" /> <div class="bx-im-sidebar-task-item__forward-small-icon bx-im-sidebar__forward-small-icon"></div> <ChatAvatar :avatarDialogId="taskResponsibleDialogId" :contextDialogId="contextDialogId" :size="AvatarSize.XS" /> <div class="bx-im-sidebar-task-item__status-text" :class="statusColorClass"> {{taskDeadlineText}} </div> </div> </div> <button v-if="showContextButton" class="bx-im-messenger__context-menu-icon" @click="onContextMenuClick" ></button> </div> ` }; // @vue/component const TaskListPreview = { name: 'TaskListPreview', components: { DetailEmptyState, TaskItem, ChatButton: im_v2_component_elements_button.ChatButton }, props: { dialogId: { type: String, required: true } }, computed: { SidebarDetailBlock: () => im_v2_const.SidebarDetailBlock, ButtonSize: () => im_v2_component_elements_button.ButtonSize, ButtonColor: () => im_v2_component_elements_button.ButtonColor, firstTask() { return this.$store.getters['sidebar/tasks/get'](this.chatId)[0]; }, showAddButton() { return im_v2_lib_permission.PermissionManager.getInstance().canPerformActionByRole(im_v2_const.ActionByRole.createTask, this.dialogId); }, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, chatId() { return this.dialog.chatId; }, addButtonColor() { return this.ButtonColor.PrimaryLight; } }, created() { this.contextMenu = new TaskMenu(); }, beforeUnmount() { this.contextMenu.destroy(); }, methods: { getEntityCreator() { return new im_v2_lib_entityCreator.EntityCreator(this.chatId); }, onAddClick() { im_v2_lib_analytics.Analytics.getInstance().chatEntities.onCreateTaskFromSidebarClick(this.dialogId); void this.getEntityCreator().createTaskForChat(); }, onOpenDetail() { if (!this.firstTask) { return; } main_core_events.EventEmitter.emit(im_v2_const.EventType.sidebar.open, { panel: im_v2_const.SidebarDetailBlock.task, dialogId: this.dialogId }); }, onContextMenuClick(event, target) { const item = { ...event, dialogId: this.dialogId }; this.contextMenu.openMenu(item, target); }, loc(phraseCode) { return this.$Bitrix.Loc.getMessage(phraseCode); } }, template: ` <div class="bx-im-sidebar-task-list-preview__scope"> <div class="bx-im-sidebar-task-list-preview__container"> <div class="bx-im-sidebar-task-list-preview__header_container" :class="[firstTask ? '--active': '']" @click="onOpenDetail" > <div class="bx-im-sidebar-task-list-preview__title"> <span class="bx-im-sidebar-task-list-preview__title-text"> {{ loc('IM_SIDEBAR_TASK_DETAIL_TITLE') }} </span> <div v-if="firstTask" class="bx-im-sidebar__forward-icon"></div> </div> <transition name="add-button"> <ChatButton v-if="showAddButton" :text="loc('IM_SIDEBAR_ADD_BUTTON_TEXT')" :size="ButtonSize.S" :color="addButtonColor" :isRounded="true" :isUppercase="false" icon="plus" @click="onAddClick" class="bx-im-sidebar-task-list-preview__title-button" /> </transition> </div> <TaskItem v-if="firstTask" :contextDialogId="dialogId" :task="firstTask" @contextMenuClick="onContextMenuClick" /> <DetailEmptyState v-else :title="loc('IM_SIDEBAR_TASKS_EMPTY')" :iconType="SidebarDetailBlock.task" /> </div> </div> ` }; // @vue/component const MarketItem = { name: 'MarketItem', props: { item: { type: Object, required: true } }, computed: { marketItem() { return this.item; }, iconClass() { return `fa ${this.marketItem.options.iconName}`; }, iconColor() { return this.marketItem.options.color; } }, template: ` <div class="bx-im-sidebar-market-preview-item__container bx-im-sidebar-market-preview-item__scope"> <div class="bx-im-sidebar-market-preview-item__icon-container" :style="{backgroundColor: iconColor}"> <i :class="iconClass" aria-hidden="true"></i> </div> <div class="bx-im-sidebar-market-preview-item__title-container" :title="marketItem.title"> {{ marketItem.title }} </div> </div> ` }; // @vue/component const MarketAppListPreview = { name: 'MarketAppListPreview', components: { MarketItem }, props: { dialogId: { type: String, required: true } }, emits: ['openDetail'], computed: { marketMenuItems() { return im_v2_lib_market.MarketManager.getInstance().getAvailablePlacementsByType(im_v2_const.PlacementType.sidebar, this.dialogId); } }, methods: { onMarketItemClick(entityId) { main_core_events.EventEmitter.emit(im_v2_const.EventType.sidebar.open, { panel: im_v2_const.SidebarDetailBlock.market, dialogId: this.dialogId, entityId }); }, loc(phraseCode) { return this.$Bitrix.Loc.getMessage(phraseCode); } }, template: ` <div class="bx-im-sidebar-market-preview__scope bx-im-sidebar-market-preview__container"> <div class="bx-im-sidebar-market-preview__header_container"> <div class="bx-im-sidebar-market-preview__title"> <span class="bx-im-sidebar-market-preview__title-text"> {{ loc('IM_SIDEBAR_MARKET_DETAIL_TITLE') }} </span> </div> </div> <MarketItem v-for="item in marketMenuItems" :key="item.id" :item="item" @click="onMarketItemClick(item.id)" /> </div> ` }; class MeetingManager { constructor() { this.store = im_v2_application_core.Core.getStore(); this.restClient = im_v2_application_core.Core.getRestClient(); } delete({ id, chatId }) { this.store.dispatch('sidebar/meetings/delete', { chatId, id }); const queryParams = { LINK_ID: id }; this.restClient.callMethod(im_v2_const.RestMethod.imChatCalendarDelete, queryParams).catch(error => { console.error('Im.Sidebar: error deleting meeting', error); }); } } class MeetingMenu extends SidebarMenu { constructor() { super(); this.id = 'im-sidebar-context-menu'; this.meetingManager = new MeetingManager(); } getMenuItems() { return [this.getOpenContextMessageItem(), this.getCopyLinkItem(main_core.Loc.getMessage('IM_SIDEBAR_MENU_COPY_MEETING_LINK')), this.getDeleteItem()]; } getDeleteItem() { return { text: main_core.Loc.getMessage('IM_SIDEBAR_MENU_DELETE_MEETING_CONNECTION'), onclick: function () { this.meetingManager.delete(this.context.meeting); this.menuInstance.close(); }.bind(this) }; } } // @vue/component const MeetingItem = { name: 'MeetingItem', props: { meeting: { type: Object, required: true }, searchQuery: { type: String, default: '' } }, emits: ['contextMenuClick'], data() { return { showContextButton: false }; }, computed: { meetingItem() { return this.meeting; }, title() { if (this.searchQuery.length === 0) { return main_core.Text.encode(this.meetingItem.meeting.title); } return im_v2_lib_textHighlighter.highlightText(main_core.Text.encode(this.meetingItem.meeting.title), this.searchQuery); }, date() { const meetingDate = this.meetingItem.meeting.dateFrom; return im_v2_lib_dateFormatter.DateFormatter.formatByTemplate(meetingDate, im_v2_lib_dateFormatter.DateTemplate.meeting); }, day() { return this.meetingItem.meeting.dateFrom.getDate().toString(); }, monthShort() { return main_date.DateTimeFormat.format('M', this.meetingItem.meeting.dateFrom); }, isActive() { return this.meetingItem.meeting.dateFrom.getTime() > Date.now(); } }, methods: { onMeetingClick() { // todo replace this call to something new (window.top.BX || window.BX).Calendar.SliderLoader(this.meetingItem.meeting.id).show(); }, onContextMenuClick(event) { this.$emit('contextMenuClick', { meeting: this.meetingItem, source: this.meetingItem.meeting.source, messageId: this.meetingItem.messageId }, event.currentTarget); } }, template: ` <div class="bx-im-sidebar-meeting-item__container bx-im-sidebar-meeting-item__scope" @mouseover="showContextButton = true" @mouseleave="showContextButton = false" > <div class="bx-im-sidebar-meeting-item__icon-container" :class="[isActive ? '--active' : '--inactive']" > <div class="bx-im-sidebar-meeting-item__day-text">{{ day }}</div> <div class="bx-im-sidebar-meeting-item__month-text">{{ monthShort }}</div> </div> <div class="bx-im-sidebar-meeting-item__content-container" @click="onMeetingClick"> <div class="bx-im-sidebar-meeting-item__content"> <div class="bx-im-sidebar-meeting-item__title" :title="title" v-html="title"></div> <div class="bx-im-sidebar-meeting-item__date">{{ date }}</div> </div> </div> <button v-if="showContextButton" class="bx-im-messenger__context-menu-icon" @click="onContextMenuClick" ></button> </div> ` }; // @vue/component const MeetingListPreview = { name: 'MeetingListPreview', components: { MeetingItem, DetailEmptyState, ChatButton: im_v2_component_elements_button.ChatButton }, props: { dialogId: { type: String, required: true } }, computed: { SidebarDetailBlock: () => im_v2_const.SidebarDetailBlock, ButtonSize: () => im_v2_component_elements_button.ButtonSize, ButtonColor: () => im_v2_component_elements_button.ButtonColor, firstMeeting() { return this.$store.getters['sidebar/meetings/get'](this.chatId)[0]; }, showAddButton() { return im_v2_lib_permission.PermissionManager.getInstance().canPerformActionByRole(im_v2_const.ActionByRole.createMeeting, this.dialogId); }, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, chatId() { return this.dialog.chatId; }, addButtonColor() { return this.ButtonColor.PrimaryLight; } }, created() { this.contextMenu = new MeetingMenu(); }, beforeUnmount() { this.contextMenu.destroy(); }, methods: { getEntityCreator() { return new im_v2_lib_entityCreator.EntityCreator(this.chatId); }, onAddClick() { im_v2_lib_analytics.Analytics.getInstance().chatEntities.onCreateEventFromSidebarClick(this.dialogId); void this.getEntityCreator().createMeetingForChat(); }, onOpenDetail() { if (!this.firstMeeting) { return; } main_core_events.EventEmitter.emit(im_v2_const.EventType.sidebar.open, { panel: im_v2_const.SidebarDetailBlock.meeting, dialogId: this.dialogId }); }, onContextMenuClick(event, target) { const item = { ...event, dialogId: this.dialogId }; this.contextMenu.openMenu(item, target); }, loc(phraseCode) { return this.$Bitrix.Loc.getMessage(phraseCode); } }, template: ` <div class="bx-im-sidebar-meeting-preview__scope"> <div class="bx-im-sidebar-meeting-preview__container"> <div class="bx-im-sidebar-meeting-preview__header_container" :class="[firstMeeting ? '--active': '']" @click="onOpenDetail" > <div class="bx-im-sidebar-meeting-preview__title"> <span class="bx-im-sidebar-meeting-preview__title-text"> {{ loc('IM_SIDEBAR_MEETING_DETAIL_TITLE') }} </span> <div v-if="firstMeeting" class="bx-im-sidebar__forward-icon"></div> </div> <transition name="add-button"> <ChatButton v-if="showAddButton" :text="loc('IM_SIDEBAR_ADD_BUTTON_TEXT')" :size="ButtonSize.S" :color="addButtonColor" :isRounded="true" :isUppercase="false" icon="plus" @click="onAddClick" class="bx-im-sidebar-meeting-preview__title-button" /> </transition> </div> <MeetingItem v-if="firstMeeting" :meeting="firstMeeting" @contextMenuClick="onContextMenuClick"/> <DetailEmptyState v-else :title="loc('IM_SIDEBAR_MEETINGS_EMPTY')" :iconType="SidebarDetailBlock.meeting" /> </div> </div> ` }; // @vue/component const CopilotInfoPreview = { name: 'CopilotInfoPreview', components: { ChatDescription, ChatLinks, ChatFavourites }, props: { dialogId: { type: String, required: true } }, template: ` <div class="bx-im-sidebar-info-preview__container"> <ChatDescription :dialogId="dialogId" /> <ChatFavourites :dialogId="dialogId" /> </div> ` }; // @vue/component const MuteChat = { name: 'MuteChat', directives: { hint: ui_vue3_directives_hint.hint }, components: { Toggle: im_v2_component_elements_toggle.Toggle }, props: { dialogId: { type: String, required: true } }, computed: { ToggleSize: () => im_v2_component_elements_toggle.ToggleSize, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, isGroupChat() { return this.dialogId.startsWith('chat'); }, canBeMuted() { return im_v2_lib_permission.PermissionManager.getInstance().canPerformActionByRole(im_v2_const.ActionByRole.mute, this.dialogId); }, isChatMuted() { const isMuted = this.dialog.muteList.find(element => { return element === im_v2_application_core.Core.getUserId(); }); return Boolean(isMuted); }, hintMuteNotAvailable() { if (this.canBeMuted) { return null; } return { text: this.$Bitrix.Loc.getMessage('IM_SIDEBAR_MUTE_NOT_AVAILABLE'), popupOptions: { angle: true, targetContainer: document.body, offsetLeft: 141, offsetTop: -10, bindOptions: { position: 'top' } } }; }, isCopilotLayout() { const { name: currentLayoutName } = this.$store.getters['application/getLayout']; return currentLayoutName === im_v2_const.Layout.copilot.name; } }, methods: { getChatService() { if (!this.chatService) { this.chatService = new im_v2_provider_service_chat.ChatService(); } return this.chatService; }, muteActionHandler() { if (!this.canBeMuted) { return; } if (this.isChatMuted) { this.getChatService().unmuteChat(this.dialogId); } else { this.getChatService().muteChat(this.dialogId); } }, loc(phraseCode) { return this.$Bitrix.Loc.getMessage(phraseCode); } }, template: ` <div v-if="isGroupChat" class="bx-im-sidebar-mute-chat__container" :class="{'--not-active': !canBeMuted, '--copilot': isCopilotLayout}" v-hint="hintMuteNotAvailable" > <div class="bx-im-sidebar-mute-chat__title"> <div class="bx-im-sidebar-mute-chat__title-text bx-im-sidebar-mute-chat__icon"> {{ loc('IM_SIDEBAR_ENABLE_NOTIFICATION_TITLE_2') }} </div> <Toggle :size="ToggleSize.M" :isEnabled="!isChatMuted" @click="muteActionHandler" /> </div> </div> ` }; // @vue/component const AutoDelete = { name: 'AutoDelete', directives: { hint: ui_vue3_directives_hint.hint }, components: { Toggle: im_v2_component_elements_toggle.Toggle, AutoDeleteHint: im_v2_component_elements_autoDelete.AutoDeleteHint, AutoDeleteDropdown: im_v2_component_elements_autoDelete.AutoDeleteDropdown, AutoDeletePopup: im_v2_component_elements_autoDelete.AutoDeletePopup }, props: { dialogId: { type: String, required: true } }, data() { return { showHint: false, showPopup: false }; }, computed: { ToggleSize: () => im_v2_component_elements_toggle.ToggleSize, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, chatId() { return this.dialog.chatId; }, autoDeleteDelayInHours() { return this.$store.getters['chats/autoDelete/getDelay'](this.chatId); }, isAutoDeleteFeatureAvailable() { return im_v2_lib_feature.FeatureManager.isFeatureAvailable(im_v2_lib_feature.Feature.messagesAutoDeleteAvailable); }, isAutoDeleteFeatureEnabled() { return im_v2_lib_feature.FeatureManager.isFeatureAvailable(im_v2_lib_feature.Feature.messagesAutoDeleteEnabled); }, isAutoDeleteAllowed() { return im_v2_lib_autoDelete.AutoDeleteManager.isAutoDeleteAllowed(this.dialogId); }, hintAutoDelete() { if (this.isAutoDeleteFeatureAvailable) { return null; } return { text: this.loc('IM_MESSENGER_NOT_AVAILABLE'), popupOptions: { bindOptions: { position: 'top' }, angle: true, targetContainer: document.body, offsetLeft: 125, offsetTop: -10 } }; }, isBot() { const user = this.$store.getters['users/get'](this.dialogId, true); return user.type === im_v2_const.UserType.bot; }, isAutoDeleteAvailableByChatType() { const NoAutoDeleteChatTypes = [im_v2_const.ChatType.copilot, im_v2_const.ChatType.lines, im_v2_const.ChatType.videoconf, ...im_v2_lib_channel.ChannelManager.getChannelTypes()]; if (NoAutoDeleteChatTypes.includes(this.dialog.type)) { return false; } return !this.isBot; }, isAutoDeleteActive() { return this.autoDeleteDelayInHours > 0; } }, methods: { getChatService() { if (!this.chatService) { this.chatService = new im_v2_provider_service_chat.ChatService(); } return this.chatService; }, changeAutoDeleteActionHandler() { if (!this.isAutoDeleteFeatureAvailable) { return; } if (!this.isAutoDeleteAllowed) { this.showHint = true; return; } if (this.isAutoDeleteActive) { this.updateAutoDeleteDelay(im_v2_const.AutoDeleteDelay.Off); return; } if (!this.isAutoDeleteFeatureEnabled) { im_v2_lib_feature.FeatureManager.messagesAutoDelete.openFeatureSlider(); return; } this.showPopup = true; }, updateAutoDeleteDelay(delay) { this.getChatService().setMessagesAutoDeleteDelay(this.dialogId, delay); }, loc(phraseCode) { return this.$Bitrix.Loc.getMessage(phraseCode); }, onAutoDeleteDelayChange(delay) { this.updateAutoDeleteDelay(delay); this.$emit('close'); }, onDropDownClick(event) { if (this.isAutoDeleteAllowed) { return; } event.stopPropagation(); this.showHint = true; } }, template: ` <div v-if="isAutoDeleteAvailableByChatType" class="bx-im-sidebar-auto-delete__container" :class="{'--enabled': isAutoDeleteFeatureAvailable}" v-hint="hintAutoDelete" ref="auto-delete" > <div class="bx-im-sidebar-auto-delete__title"> <div class="bx-im-sidebar-auto-delete__title-text bx-im-sidebar-auto-delete__icon"> {{ loc('IM_SIDEBAR_ENABLE_AUTODELETE_TITLE') }} </div> <Toggle :size="ToggleSize.M" :isEnabled="isAutoDeleteActive" :disabled="!isAutoDeleteAllowed" @click="changeAutoDeleteActionHandler" /> </div> <AutoDeleteDropdown :currentDelay="autoDeleteDelayInHours" @delayChange="updateAutoDeleteDelay" @click.capture="onDropDownClick" /> <AutoDeleteHint v-if="showHint" :bindElement="$refs['auto-delete']" @close="showHint = false" /> <AutoDeletePopup v-if="showPopup" :autoDeleteDelay="autoDeleteDelayInHours" @close="showPopup = false" @autoDeleteDelayChange="onAutoDeleteDelayChange" /> </div> ` }; // @vue/component const ChatMembersAvatars = { name: 'ChatMembersAvatars', components: { ChatAvatar: im_v2_component_elements_avatar.ChatAvatar, ChatButton: im_v2_component_elements_button.ChatButton, AddToChat: im_v2_component_entitySelector.AddToChat }, props: { dialogId: { type: String, required: true }, showMembers: { type: Boolean, default: true } }, data() { return { showAddToChatPopup: false }; }, computed: { AvatarSize: () => im_v2_component_elements_avatar.AvatarSize, ButtonSize: () => im_v2_component_elements_button.ButtonSize, ButtonColor: () => im_v2_component_elements_button.ButtonColor, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, chatId() { return this.dialog.chatId; }, dialogIds() { const PREVIEW_USERS_COUNT = 4; const userIds = this.$store.getters['sidebar/members/get'](this.chatId); return userIds.map(id => id.toString()).slice(0, PREVIEW_USERS_COUNT); }, canSeeMembers() { return im_v2_lib_permission.PermissionManager.getInstance().canPerformActionByRole(im_v2_const.ActionByRole.userList, this.dialogId); }, canInviteMembers() { return im_v2_lib_permission.PermissionManager.getInstance().canPerformActionByRole(im_v2_const.ActionByRole.extend, this.dialogId); }, usersInChatCount() { return this.dialog.userCounter; }, moreUsersCount() { return Math.max(this.usersInChatCount - this.dialogIds.length, 0); }, isCollab() { return this.dialog.type === im_v2_const.ChatType.collab; }, addUsersButtonColor() { if (this.isCollab) { return this.ButtonColor.Collab; } return this.ButtonColor.PrimaryLight; }, addMembersPopupComponent() { return this.dialog.type === im_v2_const.ChatType.collab ? im_v2_component_entitySelector.AddToCollab : im_v2_component_entitySelector.AddToChat; } }, methods: { onOpenUsers() { main_core_events.EventEmitter.emit(im_v2_const.EventType.sidebar.open, { panel: im_v2_const.SidebarDetailBlock.members, dialogId: this.dialogId }); }, onOpenInvitePopup() { im_v2_lib_analytics.Analytics.getInstance().userAdd.onChatSidebarClick(this.dialogId); this.showAddToChatPopup = true; }, loc(phraseCode) { return this.$Bitrix.Loc.getMessage(phraseCode); } }, template: ` <div class="bx-im-sidebar-chat-members-avatars__container"> <div v-if="canSeeMembers && showMembers" class="bx-im-sidebar-chat-members-avatars__members" @click="onOpenUsers"> <div class="bx-im-sidebar-chat-members-avatars__avatars" > <ChatAvatar v-for="id in dialogIds" :size="AvatarSize.S" :avatarDialogId="id" :contextDialogId="dialogId" class="bx-im-sidebar-chat-members-avatars__avatar" /> </div> <div v-if="moreUsersCount > 0" class="bx-im-sidebar-chat-members-avatars__text"> +{{ moreUsersCount }} </div> </div> <div ref="add-members"> <ChatButton v-if="canInviteMembers" :text="loc('IM_SIDEBAR_ADD_BUTTON_TEXT')" :size="ButtonSize.S" :color="addUsersButtonColor" :isRounded="true" :isUppercase="false" icon="plus" @click="onOpenInvitePopup" /> </div> <component v-if="showAddToChatPopup" :is="addMembersPopupComponent" :bindElement="$refs['add-members'] || {}" :dialogId="dialogId" :popupConfig="{offsetTop: -220, offsetLeft: -420}" @close="showAddToChatPopup = false" /> </div> ` }; // @vue/component const ChatPreview = { name: 'ChatPreview', components: { ChatAvatar: im_v2_component_elements_avatar.ChatAvatar, ChatTitle: im_v2_component_elements_chatTitle.ChatTitle, MuteChat, ChatMembersAvatars, AutoDelete }, props: { dialogId: { type: String, required: true } }, computed: { AvatarSize: () => im_v2_component_elements_avatar.AvatarSize }, template: ` <div class="bx-im-sidebar-main-preview__scope"> <div class="bx-im-sidebar-main-preview-group-chat__avatar-container"> <div class="bx-im-sidebar-main-preview-group-chat__avatar"> <ChatAvatar :avatarDialogId="dialogId" :contextDialogId="dialogId" :size="AvatarSize.XXXL" /> </div> <ChatTitle :dialogId="dialogId" :twoLine="true" class="bx-im-sidebar-main-preview-group-chat__title" /> </div> <div class="bx-im-sidebar-main-preview-group-chat__chat-members"> <ChatMembersAvatars :dialogId="dialogId" /> </div> <div class="bx-im-sidebar-main-preview-group-chat__settings"> <MuteChat :dialogId="dialogId" /> <AutoDelete :dialogId="dialogId" /> </div> </div> ` }; // @vue/component const PostPreview = { name: 'PostPreview', components: { ChatAvatar: im_v2_component_elements_avatar.ChatAvatar, ChatTitle: im_v2_component_elements_chatTitle.ChatTitle, MuteChat, ChatMembersAvatars, AutoDelete }, props: { dialogId: { type: String, required: true } }, computed: { AvatarSize: () => im_v2_component_elements_avatar.AvatarSize, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, postDialog() { return this.$store.getters['chats/getByChatId'](this.dialog.parentChatId); } }, methods: { loc(phraseCode) { return this.$Bitrix.Loc.getMessage(phraseCode); } }, template: ` <div class="bx-im-sidebar-main-preview-post__scope"> <div class="bx-im-sidebar-main-preview-post__avatar-container"> <div class="bx-im-sidebar-main-preview-post__avatar"> <ChatAvatar :avatarDialogId="postDialog.dialogId" :contextDialogId="postDialog.dialogId" :size="AvatarSize.XXXL" /> </div> <div class="bx-im-sidebar-main-preview-post__title">{{ loc('IM_SIDEBAR_COMMENTS_POST_PREVIEW_TITLE') }}</div> <div class="bx-im-sidebar-main-preview-post__subtitle">{{ postDialog.name }}</div> </div> <div class="bx-im-sidebar-main-preview-post__settings"> <!-- TODO: follow toggle --> </div> </div> ` }; // @vue/component const UserPreview = { name: 'UserPreview', directives: { hint: ui_vue3_directives_hint.hint }, components: { ChatAvatar: im_v2_component_elements_avatar.ChatAvatar, ChatTitle: im_v2_component_elements_chatTitle.ChatTitle, ChatButton: im_v2_component_elements_button.ChatButton, AddToChat: im_v2_component_entitySelector.AddToChat, AutoDelete }, props: { dialogId: { type: String, required: true } }, data() { return { showAddToChatPopup: false }; }, computed: { AvatarSize: () => im_v2_component_elements_avatar.AvatarSize, ButtonSize: () => im_v2_component_elements_button.ButtonSize, ButtonColor: () => im_v2_component_elements_button.ButtonColor, userPosition() { return this.$store.getters['users/getPosition'](this.dialogId); }, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, user() { return this.$store.getters['users/get'](this.dialogId, true); }, chatId() { return this.dialog.chatId; }, canInviteMembers() { const canCreateChat = im_v2_lib_permission.PermissionManager.getInstance().canPerformActionByUserType(im_v2_const.ActionByUserType.createChat); const canExtendChat = im_v2_lib_permission.PermissionManager.getInstance().canPerformActionByRole(im_v2_const.ActionByRole.extend, this.dialogId); return canCreateChat && canExtendChat; }, showInviteButton() { if (this.isBot) { return false; } return this.canInviteMembers; }, userLink() { return im_v2_lib_utils.Utils.user.getProfileLink(this.dialogId); }, isBot() { return this.user.type === im_v2_const.UserType.bot; } }, methods: { onAddClick() { im_v2_lib_analytics.Analytics.getInstance().userAdd.onChatSidebarClick(this.dialogId); this.showAddToChatPopup = true; } }, template: ` <div class="bx-im-sidebar-main-preview__scope"> <div class="bx-im-sidebar-main-preview-personal-chat__avatar-container"> <ChatAvatar :avatarDialogId="dialogId" :contextDialogId="dialogId" :size="AvatarSize.XXXL" class="bx-im-sidebar-main-preview-personal-chat__avatar" /> <a :href="userLink" target="_blank"> <ChatTitle :dialogId="dialogId" class="bx-im-sidebar-main-preview-personal-chat__user-name" /> </a> <div class="bx-im-sidebar-main-preview-personal-chat__user-position" :title="userPosition"> {{ userPosition }} </div> </div> <div v-if="showInviteButton" class="bx-im-sidebar-main-preview-personal-chat__invite-button-container" ref="add-members" > <ChatButton v-if="canInviteMembers" :text="$Bitrix.Loc.getMessage('IM_SIDEBAR_CREATE_GROUP_CHAT')" :size="ButtonSize.S" :color="ButtonColor.PrimaryLight" :isRounded="true" :isUppercase="false" icon="plus" @click="onAddClick" /> </div> <div class="bx-im-sidebar-main-preview-personal-chat__auto-delete-container"> <AutoDelete :dialogId="dialogId" /> </div> <AddToChat v-if="showAddToChatPopup" :bindElement="$refs['add-members'] || {}" :dialogId="dialogId" :popupConfig="{offsetTop: -220, offsetLeft: -320}" @close="showAddToChatPopup = false" /> </div> ` }; var _store = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("store"); var _sendRequest = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("sendRequest"); class CopilotService { constructor() { Object.defineProperty(this, _sendRequest, { value: _sendRequest2 }); Object.defineProperty(this, _store, { writable: true, value: void 0 }); babelHelpers.classPrivateFieldLooseBase(this, _store)[_store] = im_v2_application_core.Core.getStore(); } updateRole({ dialogId, role }) { im_v2_lib_logger.Logger.warn('CopilotService: update role', dialogId); void babelHelpers.classPrivateFieldLooseBase(this, _store)[_store].dispatch('copilot/chats/add', { dialogId, role: role.code }); void babelHelpers.classPrivateFieldLooseBase(this, _store)[_store].dispatch('copilot/roles/add', [role]); return babelHelpers.classPrivateFieldLooseBase(this, _sendRequest)[_sendRequest]({ dialogId, role: role.code }); } } function _sendRequest2({ dialogId, role }) { const requestParams = { data: { dialogId, role } }; return im_v2_lib_rest.runAction(im_v2_const.RestMethod.imV2ChatCopilotUpdateRole, requestParams); } // @vue/component const ChangeRolePromo = { name: 'ChangeRolePromo', props: { bindElement: { type: Object, required: true } }, emits: ['hide', 'accept'], computed: { text() { return main_core.Loc.getMessage('IM_SIDEBAR_COPILOT_CHANGE_ROLE_PROMO_TEXT', { '[copilot_color]': '<em class="bx-im-copilot-change-role-promo__copilot">', '[/copilot_color]': '</em>' }); }, videoSource() { const basePath = '/bitrix/js/im/v2/component/sidebar/src/components/elements/copilot-role/css/videos/'; const sources = { ru: 'copilot-roles-promo-ru.webm', en: 'copilot-roles-promo-en.webm' }; const language = main_core.Loc.getMessage('LANGUAGE_ID'); return language === 'ru' ? `${basePath}${sources.ru}` : `${basePath}${sources.en}`; } }, created() { this.promoPopup = new ui_promoVideoPopup.PromoVideoPopup({ videoSrc: this.videoSource, title: 'Copilot', text: this.text, targetOptions: this.bindElement, angleOptions: { position: BX.UI.AnglePosition.RIGHT, offset: 98 }, colors: { iconBackground: '#8e52ec', title: '#b095dc' }, icon: BX.UI.IconSet.Main.COPILOT_AI, offset: { top: -125, left: -510 } }); this.promoPopup.subscribe(ui_promoVideoPopup.PromoVideoPopupEvents.ACCEPT, this.onAccept); this.promoPopup.subscribe(ui_promoVideoPopup.PromoVideoPopupEvents.HIDE, this.onHide); }, mounted() { this.promoPopup.show(); }, beforeUnmount() { if (!this.promoPopup) { return; } this.promoPopup.hide(); this.promoPopup.unsubscribe(ui_promoVideoPopup.PromoVideoPopupEvents.ACCEPT, this.onAccept); this.promoPopup.unsubscribe(ui_promoVideoPopup.PromoVideoPopupEvents.HIDE, this.onHide); }, methods: { onHide() { this.$emit('hide'); this.promoPopup.hide(); }, onAccept() { this.$emit('accept'); this.promoPopup.hide(); }, loc(phraseCode, replacements = {}) { return this.$Bitrix.Loc.getMessage(phraseCode, replacements); } }, template: ` <template></template> ` }; // @vue/component const CopilotRole = { name: 'CopilotRole', components: { ChangeRolePromo, CopilotRolesDialog: im_v2_component_elements_copilotRolesDialog.CopilotRolesDialog }, props: { dialogId: { type: String, required: true } }, data() { return { shouldShowChangeRolePromo: false, showRolesDialog: false }; }, computed: { chatRole() { const chatRole = this.$store.getters['copilot/chats/getRole'](this.dialogId); if (!chatRole) { return this.$store.getters['copilot/roles/getDefault']; } return chatRole; }, roleName() { return this.chatRole.name; }, canShowChangeRolePromo() { const needCopilotInRecentTabHint = im_v2_lib_promo.PromoManager.getInstance().needToShow(im_v2_const.PromoId.copilotInRecentTab); const needShowAddUsersToChatHint = im_v2_lib_promo.PromoManager.getInstance().needToShow(im_v2_const.PromoId.addUsersToCopilotChat); const needToShowChangeRolePromo = im_v2_lib_promo.PromoManager.getInstance().needToShow(im_v2_const.PromoId.changeRoleCopilot); return !needCopilotInRecentTabHint && !needShowAddUsersToChatHint && needToShowChangeRolePromo; } }, mounted() { // Show promo after sidebar animation is over. setTimeout(() => { this.shouldShowChangeRolePromo = this.canShowChangeRolePromo; }, 300); }, beforeUnmount() { this.showRolesDialog = false; this.shouldShowChangeRolePromo = false; }, methods: { handleChangeRole() { this.showRolesDialog = true; }, loc(phraseCode) { return this.$Bitrix.Loc.getMessage(phraseCode); }, onChangeRolePromoAccept() { this.shouldShowChangeRolePromo = false; void im_v2_lib_promo.PromoManager.getInstance().markAsWatched(im_v2_const.PromoId.changeRoleCopilot); }, onCopilotDialogSelectRole(role) { void new CopilotService().updateRole({ dialogId: this.dialogId, role }); } }, template: ` <div class="bx-im-sidebar-copilot-role__container" @click="handleChangeRole" ref="change-role"> <div class="bx-im-sidebar-copilot-role__title"> <div class="bx-im-sidebar-copilot-role__title-icon"></div> <div class="bx-im-sidebar-copilot-role__title-text"> {{ roleName }} </div> </div> <div class="bx-im-sidebar-copilot-role__arrow-icon"></div> <ChangeRolePromo v-if="shouldShowChangeRolePromo" :bindElement="$refs['change-role']" @accept="onChangeRolePromoAccept" @hide="shouldShowChangeRolePromo = false" /> <CopilotRolesDialog v-if="showRolesDialog" :title="loc('IM_SIDEBAR_COPILOT_CHANGE_ROLE_DIALOG_TITLE')" @selectRole="onCopilotDialogSelectRole" @close="showRolesDialog = false" /> </div> ` }; // @vue/component const CopilotPreview = { name: 'CopilotPreview', components: { ChatAvatar: im_v2_component_elements_avatar.ChatAvatar, ChatTitle: im_v2_component_elements_chatTitle.ChatTitle, MuteChat, ChatMembersAvatars, CopilotRole }, props: { dialogId: { type: String, required: true } }, computed: { AvatarSize: () => im_v2_component_elements_avatar.AvatarSize, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, chatId() { return this.dialog.chatId; }, showMembers() { return this.dialog.userCounter > 2; } }, template: ` <div class="bx-im-sidebar-copilot-preview__scope"> <div class="bx-im-sidebar-copilot-preview-group-chat__avatar-container"> <ChatAvatar :avatarDialogId="dialogId" :contextDialogId="dialogId" :size="AvatarSize.XXXL" :withSpecialTypes="false" /> <ChatTitle :dialogId="dialogId" :twoLine="true" class="bx-im-sidebar-copilot-preview-group-chat__title" /> </div> <div class="bx-im-sidebar-copilot-preview-group-chat__chat-members"> <ChatMembersAvatars :showMembers="showMembers" :dialogId="dialogId" /> </div> <div class="bx-im-sidebar-copilot-preview-group-chat__settings"> <CopilotRole :dialogId="dialogId" /> <MuteChat :dialogId="dialogId" /> </div> </div> ` }; // @vue/component const SupportPreview = { name: 'SupportPreview', components: { ChatAvatar: im_v2_component_elements_avatar.ChatAvatar, ChatTitle: im_v2_component_elements_chatTitle.ChatTitle, AutoDelete }, props: { dialogId: { type: String, required: true } }, computed: { AvatarSize: () => im_v2_component_elements_avatar.AvatarSize }, template: ` <div class="bx-im-sidebar-main-preview__scope"> <div class="bx-im-sidebar-main-preview-group-chat__avatar-container"> <div class="bx-im-sidebar-main-preview-group-chat__avatar"> <ChatAvatar :size="AvatarSize.XXXL" :avatarDialogId="dialogId" :contextDialogId="dialogId" /> </div> <ChatTitle :dialogId="dialogId" :twoLine="true" class="bx-im-sidebar-main-preview-group-chat__title" /> </div> <div class="bx-im-sidebar-main-preview-group-chat__settings"> <AutoDelete :dialogId="dialogId" /> </div> </div> ` }; // @vue/component const MultidialogPreview = { name: 'MultidialogPreview', props: { dialogId: { type: String, required: true } }, computed: { chatId() { return this.$store.getters['chats/get'](this.dialogId, true).chatId; }, numberRequests() { const chatsCount = this.$store.getters['sidebar/multidialog/getChatsCount']; return chatsCount > 999 ? '999+' : chatsCount; }, totalChatCounter() { const counter = this.$store.getters['sidebar/multidialog/getTotalChatCounter']; return counter > 99 ? '99+' : counter; } }, methods: { loc(phraseCode) { return this.$Bitrix.Loc.getMessage(phraseCode); }, onOpenDetail() { main_core_events.EventEmitter.emit(im_v2_const.EventType.sidebar.open, { panel: im_v2_const.SidebarDetailBlock.multidialog, dialogId: this.dialogId, standalone: true }); } }, template: ` <div class="bx-im-sidebar-multidialog-preview__scope"> <div class="bx-im-sidebar-multidialog-preview__container" @click="onOpenDetail"> <div class="bx-im-sidebar-multidialog-preview__questions-container"> <div class="bx-im-sidebar-multidialog-preview__questions-text"> {{ loc('IM_SIDEBAR_SUPPORT_TICKET_TITLE') }} </div> <div class="bx-im-sidebar-multidialog-preview__questions-count"> {{ numberRequests }} </div> </div> <div class="bx-im-sidebar-multidialog-preview__new-message-container"> <div v-if="totalChatCounter" class="bx-im-sidebar-multidialog-preview__new-message-counter"> {{ totalChatCounter }} </div> <div class="bx-im-sidebar__forward-icon" /> </div> </div> </div> ` }; // @vue/component const TariffLimit = { name: 'TariffLimit', props: { dialogId: { type: String, required: true }, panel: { type: String, required: true } }, computed: { dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, title() { return im_v2_lib_feature.FeatureManager.chatHistory.getLimitTitle(); }, preparedDescription() { return im_v2_lib_feature.FeatureManager.chatHistory.getLimitSubtitle(true).replace('[action_emphasis]', '<em class="bx-im-sidebar-elements-tariff-limit__description-accent">').replace('[/action_emphasis]', '</em>'); }, tooltipText() { return im_v2_lib_feature.FeatureManager.chatHistory.getTooltipText(); } }, watch: { dialogId() { this.sendAnalyticsOnCreate(); }, panel() { this.sendAnalyticsOnCreate(); } }, created() { this.sendAnalyticsOnCreate(); }, methods: { onDetailClick() { this.sendAnalyticsOnClick(); im_v2_lib_feature.FeatureManager.chatHistory.openFeatureSlider(); }, loc(phraseCode) { return this.$Bitrix.Loc.getMessage(phraseCode); }, sendAnalyticsOnClick() { im_v2_lib_analytics.Analytics.getInstance().historyLimit.onSidebarBannerClick({ dialogId: this.dialogId, panel: this.panel }); }, sendAnalyticsOnCreate() { im_v2_lib_analytics.Analytics.getInstance().historyLimit.onSidebarLimitExceeded({ dialogId: this.dialogId, panel: this.panel }); } }, template: ` <div class="bx-im-sidebar-elements-tariff-limit__container" :title="tooltipText" @click="onDetailClick" > <div class="bx-im-sidebar-elements-tariff-limit__header"> <div class="bx-im-sidebar-elements-tariff-limit__title-container"> <div class="bx-im-sidebar-elements-tariff-limit__icon"></div> <div class="bx-im-sidebar-elements-tariff-limit__title --line-clamp-2">{{ title }}</div> </div> <div class="bx-im-sidebar-elements-tariff-limit__arrow bx-im-sidebar__forward-green-icon"></div> </div> <div class="bx-im-sidebar-elements-tariff-limit__delimiter"></div> <div class="bx-im-sidebar-elements-tariff-limit__content"> <div class="bx-im-sidebar-elements-tariff-limit__description" v-html="preparedDescription"></div> </div> </div> ` }; // @vue/component const TariffLimitPreview = { name: 'TariffLimitPreview', components: { TariffLimit }, props: { dialogId: { type: String, required: true } }, computed: { SidebarDetailBlock: () => im_v2_const.SidebarDetailBlock }, template: ` <TariffLimit :dialogId="dialogId" :panel="SidebarDetailBlock.main" /> ` }; const INTRANET_MANUAL_CODE = 'collab'; const COLLABER_MANUAL_CODE = 'collab_guest'; // @vue/component const CollabHelpdeskPreview = { name: 'CollabHelpdeskPreview', props: { dialogId: { type: String, required: true } }, data() { return { needToShow: im_v2_lib_promo.PromoManager.getInstance().needToShow(im_v2_const.PromoId.collabHelpdeskSidebar) }; }, computed: { isCurrentUserCollaber() { const currentUser = this.$store.getters['users/get'](im_v2_application_core.Core.getUserId(), true); return currentUser.type === im_v2_const.UserType.collaber; } }, methods: { close() { this.needToShow = false; void im_v2_lib_promo.PromoManager.getInstance().markAsWatched(im_v2_const.PromoId.collabHelpdeskSidebar); }, openHelpdesk() { const manualCode = this.isCurrentUserCollaber ? COLLABER_MANUAL_CODE : INTRANET_MANUAL_CODE; const urlParams = { utm_source: 'portal', utm_content: 'widget' }; ui_manual.Manual.show(manualCode, urlParams); }, loc(phraseCode, replacements = {}) { return this.$Bitrix.Loc.getMessage(phraseCode, replacements); } }, template: ` <div v-if="needToShow" class="bx-im-sidebar-collab-helpdesk__container" @click="openHelpdesk"> <div class="bx-im-sidebar-collab-helpdesk__icon"></div> <div class="bx-im-sidebar-collab-helpdesk__content"> <div class="bx-im-sidebar-collab-helpdesk__title"> {{ loc('IM_SIDEBAR_COLLAB_HELPDESK_TITLE') }} </div> <div class="bx-im-sidebar-collab-helpdesk__description --line-clamp-3"> {{ loc('IM_SIDEBAR_COLLAB_HELPDESK_DESCRIPTION') }} </div> </div> <div class="bx-im-sidebar-collab-helpdesk__close" @click.stop="close"></div> </div> ` }; // @vue/component const NotesPreview = { name: 'NotesPreview', components: { ChatAvatar: im_v2_component_elements_avatar.ChatAvatar, ChatTitle: im_v2_component_elements_chatTitle.ChatTitle }, props: { dialogId: { type: String, required: true } }, computed: { ChatAvatarType: () => im_v2_component_elements_avatar.ChatAvatarType, AvatarSize: () => im_v2_component_elements_avatar.AvatarSize, ChatTitleType: () => im_v2_component_elements_chatTitle.ChatTitleType }, methods: { loc(phraseCode) { return this.$Bitrix.Loc.getMessage(phraseCode); } }, template: ` <div class="bx-im-sidebar-notes-preview"> <div class="bx-im-sidebar-notes-preview__avatar"> <ChatAvatar :avatarDialogId="dialogId" :contextDialogId="dialogId" :size="AvatarSize.XXXL" :customType="ChatAvatarType.notes" /> </div> <div class="bx-im-sidebar-notes-preview__head"> <ChatTitle :dialogId="dialogId" :customType="ChatTitleType.notes" :showItsYou="false"/> <span class="bx-im-sidebar-notes-preview__description"> {{ loc('IM_SIDEBAR_NOTES_PREVIEW_DESCRIPTION') }} </span> </div> </div> ` }; // @vue/component const TaskPreview = { name: 'TaskPreview', components: { ChatTitle: im_v2_component_elements_chatTitle.ChatTitle, ChatMembersAvatars }, props: { dialogId: { type: String, required: true } }, template: ` <div class="bx-im-sidebar-task-preview__container"> <div class="bx-im-sidebar-task-preview__avatar-container"> <div class="bx-im-sidebar-task-preview__avatar"></div> <ChatTitle :dialogId="dialogId" :twoLine="true" class="bx-im-sidebar-task-preview__title" /> </div> <div class="bx-im-sidebar-task-preview__chat-members"> <ChatMembersAvatars :dialogId="dialogId" /> </div> </div> ` }; const ComponentMap = { [im_v2_const.SidebarMainPanelBlock.chat]: ChatPreview, [im_v2_const.SidebarMainPanelBlock.notes]: NotesPreview, [im_v2_const.SidebarMainPanelBlock.post]: PostPreview, [im_v2_const.SidebarMainPanelBlock.user]: UserPreview, [im_v2_const.SidebarMainPanelBlock.support]: SupportPreview, [im_v2_const.SidebarMainPanelBlock.info]: InfoPreview, [im_v2_const.SidebarMainPanelBlock.fileList]: FileListPreview, [im_v2_const.SidebarMainPanelBlock.task]: TaskPreview, [im_v2_const.SidebarMainPanelBlock.taskList]: TaskListPreview, [im_v2_const.SidebarMainPanelBlock.meetingList]: MeetingListPreview, [im_v2_const.SidebarMainPanelBlock.fileUnsortedList]: FileListPreview, [im_v2_const.SidebarMainPanelBlock.marketAppList]: MarketAppListPreview, [im_v2_const.SidebarMainPanelBlock.multidialog]: MultidialogPreview, [im_v2_const.SidebarMainPanelBlock.copilot]: CopilotPreview, [im_v2_const.SidebarMainPanelBlock.copilotInfo]: CopilotInfoPreview, [im_v2_const.SidebarMainPanelBlock.tariffLimit]: TariffLimitPreview, [im_v2_const.SidebarMainPanelBlock.collabHelpdesk]: CollabHelpdeskPreview }; // @vue/component const SidebarSkeleton = { name: 'SidebarSkeleton', template: ` <div class="bx-im-sidebar-skeleton__container"> <div class="bx-im-sidebar-skeleton__block"> <div class="bx-im-sidebar-skeleton__avatar"></div> <div class="bx-im-sidebar-skeleton__invite-button"></div> <div class="bx-im-sidebar-skeleton__settings"></div> </div> <div class="bx-im-sidebar-skeleton__block"> <div class="bx-im-sidebar-skeleton__info"></div> </div> <div class="bx-im-sidebar-skeleton__block"> <div class="bx-im-sidebar-skeleton__files"></div> </div> <div class="bx-im-sidebar-skeleton__block"> <div class="bx-im-sidebar-skeleton__tasks"></div> </div> </div> ` }; // @vue/component const MainPanel = { name: 'MainPanel', components: { MainHeader, SidebarSkeleton }, props: { dialogId: { type: String, required: true } }, data() { return { isLoading: true }; }, computed: { blocks() { const sidebarConfig = im_v2_lib_sidebar.SidebarManager.getInstance().getConfig(this.dialogId); const blocks = sidebarConfig.getBlocks(this.dialogId); return blocks.map(block => { return ComponentMap[block]; }); }, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, dialogInited() { return this.dialog.inited; }, chatId() { return this.dialog.chatId; }, hasInitialData() { return this.$store.getters['sidebar/isInited'](this.chatId); } }, watch: { dialogId() { this.initializeSidebar(); }, dialogInited() { this.initializeSidebar(); } }, created() { this.initializeSidebar(); }, methods: { initializeSidebar() { if (!this.dialogInited) { return; } if (this.hasInitialData) { this.isLoading = false; return; } this.sidebarService = new Main({ dialogId: this.dialogId }); this.isLoading = true; this.sidebarService.requestInitialData().then(() => { this.isLoading = false; }).catch(error => { im_v2_lib_logger.Logger.warn('Sidebar: request initial data error:', error); }); } }, template: ` <div class="bx-im-sidebar-main-panel__container"> <MainHeader :dialogId="dialogId" /> <SidebarSkeleton v-if="isLoading || !dialogInited" /> <div v-else class="bx-im-sidebar-main-panel__blocks"> <component v-for="block in blocks" :key="block.name" :is="block" :dialogId="dialogId" class="bx-im-sidebar-main-panel__block" /> </div> </div> ` }; function concatAndSortSearchResult(concatArrayFirst, concatArraySecond) { return [...concatArrayFirst, ...concatArraySecond].sort((a, z) => z - a); } const REQUEST_ITEMS_LIMIT$8 = 50; var _query = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("query"); var _processSearchResponse = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("processSearchResponse"); class TaskSearch { constructor({ dialogId }) { Object.defineProperty(this, _processSearchResponse, { value: _processSearchResponse2 }); this.hasMoreItemsToLoad = true; Object.defineProperty(this, _query, { writable: true, value: '' }); this.store = im_v2_application_core.Core.getStore(); this.restClient = im_v2_application_core.Core.getRestClient(); this.dialogId = dialogId; this.chatId = getChatId(dialogId); this.userManager = new im_v2_lib_user.UserManager(); } searchOnServer(query) { if (babelHelpers.classPrivateFieldLooseBase(this, _query)[_query] !== query) { babelHelpers.classPrivateFieldLooseBase(this, _query)[_query] = query; this.hasMoreItemsToLoad = true; } return this.request(); } resetSearchState() { babelHelpers.classPrivateFieldLooseBase(this, _query)[_query] = ''; this.hasMoreItemsToLoad = true; void this.store.dispatch('sidebar/tasks/clearSearch', {}); } async request() { const queryParams = this.getQueryParams(); let responseData = {}; try { const response = await this.restClient.callMethod(im_v2_const.RestMethod.imChatTaskGet, queryParams); responseData = response.data(); } catch (error) { console.error('SidebarSearch: Im.imChatTaskGet: page request error', error); } return babelHelpers.classPrivateFieldLooseBase(this, _processSearchResponse)[_processSearchResponse](responseData); } getQueryParams() { const queryParams = { CHAT_ID: this.chatId, LIMIT: REQUEST_ITEMS_LIMIT$8, SEARCH_TASK_NAME: babelHelpers.classPrivateFieldLooseBase(this, _query)[_query] }; const lastId = this.store.getters['sidebar/tasks/getSearchResultCollectionLastId'](this.chatId); if (lastId > 0) { queryParams.LAST_ID = lastId; } return queryParams; } updateModels(resultData) { const { list, users, tariffRestrictions = {} } = resultData; const isHistoryLimitExceeded = Boolean(tariffRestrictions.isHistoryLimitExceeded); const hasNextPage = list.length === REQUEST_ITEMS_LIMIT$8; const lastId = getLastElementId(list); const addUsersPromise = this.userManager.setUsersToModel(users); const setTasksPromise = this.store.dispatch('sidebar/tasks/setSearch', { chatId: this.chatId, tasks: list, hasNextPage, lastId, isHistoryLimitExceeded }); return Promise.all([setTasksPromise, addUsersPromise]); } } function _processSearchResponse2(response) { return this.updateModels(response).then(() => { return response.list.map(message => message.messageId); }); } // @vue/component const DateGroup = { name: 'DateGroup', props: { dateText: { type: String, required: true } }, template: ` <div class="bx-im-sidebar-date-group__container bx-im-sidebar-date-group__scope"> <div class="bx-im-sidebar-date-group__text"> {{ dateText }} </div> </div> ` }; // @vue/component const DetailHeader = { name: 'DetailHeader', components: { ChatButton: im_v2_component_elements_button.ChatButton, SearchInput: im_v2_component_elements_searchInput.SearchInput }, props: { dialogId: { type: String, required: true }, title: { type: String, required: true }, secondLevel: { type: Boolean, default: false }, withAddButton: { type: Boolean, default: false }, withSearch: { type: Boolean, default: false }, isSearchHeaderOpened: { type: Boolean, default: false }, delayForFocusOnStart: { type: Number || null, default: null } }, emits: ['back', 'addClick', 'changeQuery', 'toggleSearchPanelOpened'], computed: { ButtonSize: () => im_v2_component_elements_button.ButtonSize, ButtonColor: () => im_v2_component_elements_button.ButtonColor, isCopilotLayout() { const { name: currentLayoutName } = this.$store.getters['application/getLayout']; return currentLayoutName === im_v2_const.Layout.copilot.name; }, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, isCollab() { return this.dialog.type === im_v2_const.ChatType.collab; }, addButtonColor() { if (this.isCollab) { return this.ButtonColor.Collab; } return this.ButtonColor.PrimaryLight; } }, methods: { loc(phraseCode) { return this.$Bitrix.Loc.getMessage(phraseCode); } }, template: ` <div class="bx-im-sidebar-detail-header__container bx-im-sidebar-detail-header__scope"> <div class="bx-im-sidebar-detail-header__title-container"> <button :class="{'bx-im-messenger__cross-icon': !secondLevel, 'bx-im-sidebar__back-icon': secondLevel}" @click="$emit('back')" /> <div v-if="!isSearchHeaderOpened" class="bx-im-sidebar-detail-header__title-text">{{ title }}</div> <slot name="action"> <div v-if="withAddButton && !isSearchHeaderOpened" class="bx-im-sidebar-detail-header__add-button" ref="add-button"> <ChatButton :text="loc('IM_SIDEBAR_ADD_BUTTON_TEXT')" :size="ButtonSize.S" :color="addButtonColor" :isRounded="true" :isUppercase="false" icon="plus" @click="$emit('addClick', {target: $refs['add-button']})" /> </div> </slot> <div v-if="withSearch" class="bx-im-sidebar-detail-header__search"> <SearchInput v-if="isSearchHeaderOpened" :placeholder="loc('IM_SIDEBAR_SEARCH_MESSAGE_PLACEHOLDER')" :withIcon="false" :delayForFocusOnStart="delayForFocusOnStart" @queryChange="$emit('changeQuery', $event)" @close="$emit('toggleSearchPanelOpened', $event)" class="bx-im-sidebar-search-header__input" /> <div v-else @click="$emit('toggleSearchPanelOpened', $event)" class="bx-im-sidebar-detail-header__search__icon --search"></div> </div> </div> </div> ` }; // @vue/component const DetailEmptySearchState = { name: 'DetailEmptySearchState', props: { title: { type: String, required: true }, subTitle: { type: String, required: false, default: '' } }, template: ` <div class="bx-im-detail-empty-search-state__container"> <div class="bx-im-detail-empty-search-state__icon"></div> <div class="bx-im-detail-empty-search-state__title"> {{ title }} </div> <div class="bx-im-detail-empty-search-state__subtitle"> {{ subTitle }} </div> </div> ` }; class SidebarCollectionFormatter { constructor() { this.cachedDateGroups = {}; } format(collection) { const dateGroups = {}; collection.forEach(item => { const dateGroup = this.getDateGroup(item.date); if (!dateGroups[dateGroup.title]) { dateGroups[dateGroup.title] = { dateGroupTitle: dateGroup.title, items: [] }; } dateGroups[dateGroup.title].items.push(item); }); return Object.values(dateGroups); } getDateGroup(date) { const INDEX_BETWEEN_DATE_AND_TIME = 10; // 2022-10-25T14:58:44.000Z => 2022-10-25 const shortDate = date.toJSON().slice(0, INDEX_BETWEEN_DATE_AND_TIME); if (this.cachedDateGroups[shortDate]) { return this.cachedDateGroups[shortDate]; } this.cachedDateGroups[shortDate] = { id: shortDate, title: im_v2_lib_dateFormatter.DateFormatter.formatByTemplate(date, im_v2_lib_dateFormatter.DateTemplate.dateGroup) }; return this.cachedDateGroups[shortDate]; } destroy() { this.cachedDateGroups = {}; } } const DEFAULT_MIN_TOKEN_SIZE = 3; // @vue/component const TaskPanel = { name: 'TaskPanel', components: { TaskItem, DateGroup, DetailHeader, DetailEmptyState, StartState: DetailEmptyState, DetailEmptySearchState, Loader: im_v2_component_elements_loader.Loader, TariffLimit }, props: { dialogId: { type: String, required: true }, secondLevel: { type: Boolean, default: false } }, data() { return { isLoading: false, isSearchHeaderOpened: false, searchQuery: '', searchResult: [], currentServerQueries: 0, minTokenSize: DEFAULT_MIN_TOKEN_SIZE }; }, computed: { SidebarDetailBlock: () => im_v2_const.SidebarDetailBlock, tasks() { if (this.isSearchHeaderOpened) { return this.$store.getters['sidebar/tasks/getSearchResultCollection'](this.chatId); } return this.$store.getters['sidebar/tasks/get'](this.chatId); }, formattedCollection() { return this.collectionFormatter.format(this.tasks); }, isEmptyState() { return this.formattedCollection.length === 0; }, showAddButton() { return im_v2_lib_permission.PermissionManager.getInstance().canPerformActionByRole(im_v2_const.ActionByRole.createTask, this.dialogId); }, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, chatId() { return this.dialog.chatId; }, preparedQuery() { return this.searchQuery.trim().toLowerCase(); }, isSearchQueryMinimumSize() { return this.preparedQuery.length < this.minTokenSize; }, hasHistoryLimit() { return this.$store.getters['sidebar/tasks/isHistoryLimitExceeded'](this.chatId); } }, watch: { preparedQuery(newQuery, previousQuery) { if (newQuery === previousQuery) { return; } this.cleanSearchResult(); this.startSearch(); } }, created() { this.initSettings(); this.collectionFormatter = new SidebarCollectionFormatter(); this.contextMenu = new TaskMenu(); this.service = new Task({ dialogId: this.dialogId }); this.serviceSearch = new TaskSearch({ dialogId: this.dialogId }); this.searchOnServerDelayed = main_core.Runtime.debounce(this.searchOnServer, 500, this); }, beforeUnmount() { this.collectionFormatter.destroy(); this.contextMenu.destroy(); }, methods: { initSettings() { const settings = main_core.Extension.getSettings('im.v2.component.sidebar'); this.minTokenSize = settings.get('minSearchTokenSize', DEFAULT_MIN_TOKEN_SIZE); }, searchOnServer(query) { this.currentServerQueries++; this.serviceSearch.searchOnServer(query).then(messageIds => { if (query !== this.preparedQuery) { this.isLoading = false; return; } this.searchResult = concatAndSortSearchResult(this.searchResult, messageIds); }).catch(error => { console.error(error); }).finally(() => { this.currentServerQueries--; this.stopLoader(); if (this.isSearchQueryMinimumSize) { this.cleanSearchResult(); } }); }, stopLoader() { if (this.currentServerQueries > 0) { return; } this.isLoading = false; }, startSearch() { if (this.isSearchQueryMinimumSize) { this.cleanSearchResult(); } else { this.isLoading = true; this.searchOnServerDelayed(this.preparedQuery); } }, cleanSearchResult() { this.serviceSearch.resetSearchState(); this.searchResult = []; }, onChangeQuery(query) { this.searchQuery = query; }, toggleSearchPanelOpened() { this.isSearchHeaderOpened = !this.isSearchHeaderOpened; }, onContextMenuClick(event, target) { const item = { ...event, dialogId: this.dialogId }; this.contextMenu.openMenu(item, target); }, onBackClick() { main_core_events.EventEmitter.emit(im_v2_const.EventType.sidebar.close, { panel: im_v2_const.SidebarDetailBlock.task }); }, needToLoadNextPage(event) { const target = event.target; const isAtThreshold = target.scrollTop + target.clientHeight >= target.scrollHeight - target.clientHeight; const nameGetter = this.searchQuery.length > 0 ? 'sidebar/tasks/hasNextPageSearch' : 'sidebar/tasks/hasNextPage'; const hasNextPage = this.$store.getters[nameGetter](this.chatId); return isAtThreshold && hasNextPage; }, async onScroll(event) { this.contextMenu.destroy(); if (this.isLoading || !this.needToLoadNextPage(event)) { return; } this.isLoading = true; if (this.isSearchQueryMinimumSize) { await this.service.loadNextPage(); } else { await this.serviceSearch.request(); } this.isLoading = false; }, onAddClick() { new im_v2_lib_entityCreator.EntityCreator(this.chatId).createTaskForChat(); }, loc(phraseCode, replacements = {}) { return this.$Bitrix.Loc.getMessage(phraseCode, replacements); } }, template: ` <div class="bx-im-sidebar-task-detail__scope"> <DetailHeader :dialogId="dialogId" :title="loc('IM_SIDEBAR_TASK_DETAIL_TITLE')" :secondLevel="secondLevel" :withAddButton="showAddButton" :isSearchHeaderOpened="isSearchHeaderOpened" :delayForFocusOnStart="0" withSearch @changeQuery="onChangeQuery" @toggleSearchPanelOpened="toggleSearchPanelOpened" @addClick="onAddClick" @back="onBackClick" /> <div class="bx-im-sidebar-task-detail__container bx-im-sidebar-detail__container" @scroll="onScroll"> <div v-for="dateGroup in formattedCollection" class="bx-im-sidebar-task-detail__date-group_container"> <DateGroup :dateText="dateGroup.dateGroupTitle" /> <TaskItem v-for="task in dateGroup.items" :task="task" :searchQuery="searchQuery" :contextDialogId="dialogId" @contextMenuClick="onContextMenuClick" /> </div> <TariffLimit v-if="hasHistoryLimit" :dialogId="dialogId" :panel="SidebarDetailBlock.task" class="bx-im-sidebar-task-detail__tariff-limit-container" /> <template v-if="!isLoading"> <template v-if="isSearchHeaderOpened"> <StartState v-if="preparedQuery.length === 0" :title="loc('IM_SIDEBAR_SEARCH_MESSAGE_START_TITLE')" :iconType="SidebarDetailBlock.messageSearch" /> <DetailEmptySearchState v-else-if="isEmptyState" :title="loc('IM_SIDEBAR_MESSAGE_SEARCH_NOT_FOUND_EXTENDED')" :subTitle="loc('IM_SIDEBAR_MESSAGE_SEARCH_NOT_FOUND_DESCRIPTION_EXTENDED')" /> </template> <DetailEmptyState v-else-if="isEmptyState" :title="loc('IM_SIDEBAR_TASKS_EMPTY')" :iconType="SidebarDetailBlock.task" /> </template> <Loader v-if="isLoading" class="bx-im-sidebar-detail__loader-container" /> </div> </div> ` }; const ARROW_CONTROL_SIZE = 50; // @vue/component const DetailTabs = { name: 'DetailTabs', props: { tabs: { type: Array, default: () => [] } }, emits: ['tabSelect'], data() { return { hasLeftControl: false, hasRightControl: false, currentElementIndex: 0, highlightOffsetLeft: 0, highlightWidth: 0 }; }, computed: { highlightStyle() { return { left: `${this.highlightOffsetLeft}px`, width: `${this.highlightWidth}px` }; } }, watch: { currentElementIndex(newIndex) { this.updateHighlightPosition(newIndex); this.$emit('tabSelect', this.tabs[newIndex]); this.scrollToElement(newIndex); } }, mounted() { if (this.$refs.tabs.scrollWidth > this.$refs.tabs.offsetWidth) { this.hasRightControl = true; } this.updateHighlightPosition(this.currentElementIndex); }, methods: { getElementNodeByIndex(index) { return [...this.$refs.tabs.children].filter(node => { return !main_core.Dom.hasClass(node, 'bx-sidebar-tabs-highlight'); })[index]; }, updateHighlightPosition(index) { const element = this.getElementNodeByIndex(index); this.highlightOffsetLeft = element.offsetLeft; this.highlightWidth = element.offsetWidth; }, scrollToElement(elementIndex) { const element = this.getElementNodeByIndex(elementIndex); this.$refs.tabs.scroll({ left: element.offsetLeft - ARROW_CONTROL_SIZE, behavior: 'smooth' }); }, onTabClick(event) { this.currentElementIndex = event.index; }, getTabTitle(tab) { const langPhraseCode = `IM_SIDEBAR_FILES_${tab.toUpperCase()}_TAB`; return this.$Bitrix.Loc.getMessage(langPhraseCode); }, isSelectedTab(index) { return index === this.currentElementIndex; }, onLeftClick() { if (this.currentElementIndex <= 0) { return; } this.currentElementIndex--; }, onRightClick() { if (this.currentElementIndex >= this.tabs.length - 1) { return; } this.currentElementIndex++; }, updateControlsVisibility() { this.hasRightControl = this.$refs.tabs.scrollWidth > this.$refs.tabs.scrollLeft + this.$refs.tabs.clientWidth; this.hasLeftControl = this.$refs.tabs.scrollLeft > 0; } }, template: ` <div class="bx-im-sidebar-detail-tabs__container bx-im-sidebar-detail-tabs__scope"> <div v-if="hasLeftControl" @click.stop="onLeftClick" class="bx-im-sidebar-ears__control --left"> <div class="bx-im-sidebar__forward-icon"></div> </div> <div v-if="hasRightControl" @click.stop="onRightClick" class="bx-im-sidebar-ears__control --right"> <div class="bx-im-sidebar__forward-icon"></div> </div> <div class="bx-im-sidebar-ears__elements" ref="tabs" @scroll.passive="updateControlsVisibility"> <div class="bx-sidebar-tabs-highlight" :style="highlightStyle"></div> <div v-for="(tab, index) in tabs" :key="tab" class="bx-im-sidebar-detail-tabs__item" :class="[isSelectedTab(index) ? '--selected' : '']" @click="onTabClick({index: index})" > <div class="bx-im-sidebar-detail-tabs__item-title">{{ getTabTitle(tab) }}</div> </div> </div> </div> ` }; const REQUEST_ITEMS_LIMIT$9 = 50; var _query$1 = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("query"); var _processSearchResponse$1 = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("processSearchResponse"); class FileSearch { constructor({ dialogId }) { Object.defineProperty(this, _processSearchResponse$1, { value: _processSearchResponse2$1 }); this.hasMoreItemsToLoad = true; Object.defineProperty(this, _query$1, { writable: true, value: '' }); this.store = im_v2_application_core.Core.getStore(); this.restClient = im_v2_application_core.Core.getRestClient(); this.dialogId = dialogId; this.chatId = getChatId(dialogId); this.userManager = new im_v2_lib_user.UserManager(); } searchOnServer(query, group) { if (babelHelpers.classPrivateFieldLooseBase(this, _query$1)[_query$1] !== query) { babelHelpers.classPrivateFieldLooseBase(this, _query$1)[_query$1] = query; this.hasMoreItemsToLoad = true; } return this.request(group); } resetSearchState() { babelHelpers.classPrivateFieldLooseBase(this, _query$1)[_query$1] = ''; this.hasMoreItemsToLoad = true; void this.store.dispatch('sidebar/files/clearSearch', {}); } async request(group) { const queryParams = this.getQueryParams(group); let responseData = {}; try { const response = await this.restClient.callMethod(im_v2_const.RestMethod.imChatFileGet, queryParams); responseData = response.data(); } catch (error) { console.error('SidebarSearch: Im.imChatFileGet: page request error', error); } return babelHelpers.classPrivateFieldLooseBase(this, _processSearchResponse$1)[_processSearchResponse$1](responseData); } updateModels(resultData) { const { list, users, files, tariffRestrictions = {} } = resultData; const isHistoryLimitExceeded = Boolean(tariffRestrictions.isHistoryLimitExceeded); const historyLimitPromise = this.store.dispatch('sidebar/files/setHistoryLimitExceeded', { chatId: this.chatId, isHistoryLimitExceeded }); const addUsersPromise = this.userManager.setUsersToModel(users); const setFilesPromise = this.store.dispatch('files/set', files); const sortedGroups = {}; list.forEach(file => { if (!sortedGroups[file.group]) { sortedGroups[file.group] = []; } sortedGroups[file.group].push(file); }); const setSidebarFilesPromises = []; Object.keys(sortedGroups).forEach(group => { const listByType = sortedGroups[group]; setSidebarFilesPromises.push(this.store.dispatch('sidebar/files/setSearch', { chatId: this.chatId, files: listByType, group }), this.store.dispatch('sidebar/files/setHasNextPageSearch', { chatId: this.chatId, group, hasNextPage: listByType.length === REQUEST_ITEMS_LIMIT$9 }), this.store.dispatch('sidebar/files/setLastIdSearch', { chatId: this.chatId, group, lastId: getLastElementId(listByType) })); }); return Promise.all([setFilesPromise, addUsersPromise, historyLimitPromise, ...setSidebarFilesPromises]); } loadNextPage(group, searchQuery) { if (babelHelpers.classPrivateFieldLooseBase(this, _query$1)[_query$1] !== searchQuery) { babelHelpers.classPrivateFieldLooseBase(this, _query$1)[_query$1] = searchQuery; } return this.request(group); } getQueryParams(group) { const queryParams = { CHAT_ID: this.chatId, SEARCH_FILE_NAME: babelHelpers.classPrivateFieldLooseBase(this, _query$1)[_query$1], GROUP: group.toUpperCase(), LIMIT: REQUEST_ITEMS_LIMIT$9 }; const lastId = this.store.getters['sidebar/files/getSearchResultCollectionLastId'](this.chatId, group); if (lastId > 0) { queryParams.LAST_ID = lastId; } return queryParams; } } function _processSearchResponse2$1(response) { return this.updateModels(response).then(() => { return response.files.map(file => file.id); }); } // @vue/component const MediaDetailItem = { name: 'MediaDetailItem', components: { MessageAvatar: im_v2_component_elements_avatar.MessageAvatar }, props: { fileItem: { type: Object, required: true }, contextDialogId: { type: String, required: true } }, emits: ['contextMenuClick'], data() { return { showContextButton: false, videoDuration: 0 }; }, computed: { AvatarSize: () => im_v2_component_elements_avatar.AvatarSize, sidebarFileItem() { return this.fileItem; }, file() { return this.$store.getters['files/get'](this.sidebarFileItem.fileId, true); }, previewPicture() { if (!this.hasPreview) { return {}; } return { backgroundImage: `url('${this.imageSrc}')` }; }, hasPreview() { return main_core.Type.isStringFilled(this.file.urlPreview); }, isImage() { return this.file.type === 'image'; }, isVideo() { return this.file.type === 'video'; }, viewerAttributes() { return im_v2_lib_utils.Utils.file.getViewerDataAttributes({ viewerAttributes: this.file.viewerAttrs, previewImageSrc: this.imageSrc, context: im_v2_const.FileViewerContext.sidebarTabMedia }); }, videoDurationText() { if (this.videoDuration === 0) { return '--:--'; } return this.formatTime(this.videoDuration); }, canBeOpenedWithViewer() { var _BX$UI; return this.file.viewerAttrs && ((_BX$UI = BX.UI) == null ? void 0 : _BX$UI.Viewer); }, imageSrc() { const isAnimation = ['gif', 'webp'].includes(this.file.extension); return isAnimation ? this.file.urlShow : this.file.urlPreview; } }, methods: { formatTime(rawSeconds) { rawSeconds = Math.floor(rawSeconds); const durationHours = Math.floor(rawSeconds / 60 / 60); if (durationHours > 0) { rawSeconds -= durationHours * 60 * 60; } const durationMinutes = Math.floor(rawSeconds / 60); if (durationMinutes > 0) { rawSeconds -= durationMinutes * 60; } const hours = durationHours > 0 ? `${durationHours}:` : ''; const minutes = hours > 0 ? `${durationMinutes.toString().padStart(2, '0')}:` : `${durationMinutes}:`; const seconds = rawSeconds.toString().padStart(2, '0'); return hours + minutes + seconds; }, handleVideoEvent() { if (!this.$refs.video) { return; } this.videoDuration = this.$refs.video.duration; }, onContextMenuClick(event) { this.$emit('contextMenuClick', { sidebarFile: this.sidebarFileItem, file: this.file, messageId: this.sidebarFileItem.messageId }, event.currentTarget); }, download() { if (this.file.progress !== 100 || this.canBeOpenedWithViewer) { return; } window.open(this.file.urlDownload, '_blank'); } }, template: ` <div class="bx-im-sidebar-file-media-detail-item__container bx-im-sidebar-file-media-detail-item__scope" @mouseover="showContextButton = true" @mouseleave="showContextButton = false" > <div class="bx-im-sidebar-file-media-detail-item__header-container"> <div class="bx-im-sidebar-file-media-detail-item__avatar-container"> <MessageAvatar :messageId="sidebarFileItem.messageId" :authorId="sidebarFileItem.authorId" :size="AvatarSize.S" /> </div> <button v-if="showContextButton" class="bx-im-sidebar-file-media-detail-item__context-menu bx-im-messenger__context-menu-icon" @click="onContextMenuClick" ></button> </div> <div v-if="isImage" class="bx-im-sidebar-file-media-detail-item__content --image" :style="previewPicture" v-bind="viewerAttributes" :title="file.name" @click="download" > </div> <div v-if="isVideo" class="bx-im-sidebar-file-media-detail-item__content --video" :style="previewPicture" v-bind="viewerAttributes" :title="file.name" @click="download" > <video v-show="!hasPreview" :src="file.urlDownload" ref="video" class="bx-im-sidebar-file-media-detail-item__video" preload="metadata" @durationchange="handleVideoEvent" @loadeddata="handleVideoEvent" @loadedmetadata="handleVideoEvent" ></video> </div> <div v-if="isVideo" class="bx-im-sidebar-file-media-detail-item__video-controls"> <span class="bx-im-sidebar-file-media-detail-item__video-controls-icon"></span> <span class="bx-im-sidebar-file-media-detail-item__video-controls-time">{{ videoDurationText }}</span> </div> </div> ` }; class FileManager { constructor() { this.store = im_v2_application_core.Core.getStore(); this.diskService = new im_v2_provider_service_disk.DiskService(); } delete(sidebarFile) { void this.store.dispatch('sidebar/files/delete', { dialogId: sidebarFile.chatId, id: sidebarFile.id }); void this.diskService.delete({ chatId: sidebarFile.chatId, fileId: sidebarFile.fileId }); } saveOnDisk(fileIds) { return this.diskService.save(fileIds); } } class FileMenu extends SidebarMenu { constructor() { super(); this.id = 'im-sidebar-context-menu'; this.mediaManager = new FileManager(); } getMenuItems() { return [this.getOpenContextMessageItem(), this.getDownloadFileItem(), this.getSaveFileOnDiskItem(), this.getDeleteFileItem()]; } getDownloadFileItem() { if (!this.context.file.urlDownload) { return null; } return { html: this.getDownloadHtml(this.context.file.urlDownload, this.context.file.name), onclick: function () { this.menuInstance.close(); }.bind(this) }; } getSaveFileOnDiskItem() { if (!this.context.sidebarFile.fileId) { return null; } return { text: main_core.Loc.getMessage('IM_SIDEBAR_MENU_SAVE_FILE_ON_DISK_MSGVER_1'), onclick: async function () { this.menuInstance.close(); await this.mediaManager.saveOnDisk([this.context.sidebarFile.fileId]); im_v2_lib_notifier.Notifier.file.onDiskSaveComplete(); }.bind(this) }; } getDeleteFileItem() { if (this.getCurrentUserId() !== this.context.sidebarFile.authorId) { return null; } return { text: main_core.Loc.getMessage('IM_SIDEBAR_MENU_DELETE_FILE'), onclick: function () { this.mediaManager.delete(this.context.sidebarFile); this.menuInstance.close(); }.bind(this) }; } getDownloadHtml(urlDownload, fileName) { const a = main_core.Dom.create('a', { text: main_core.Loc.getMessage('IM_SIDEBAR_MENU_DOWNLOAD_FILE') }); main_core.Dom.style(a, 'display', 'block'); main_core.Dom.style(a, 'color', 'inherit'); main_core.Dom.style(a, 'text-decoration', 'inherit'); a.setAttribute('href', urlDownload); a.setAttribute('download', fileName); return a; } } const DEFAULT_MIN_TOKEN_SIZE$1 = 3; // @vue/component const MediaTab = { name: 'MediaTab', components: { DateGroup, MediaDetailItem, DetailEmptyState, StartState: DetailEmptyState, DetailEmptySearchState, Loader: im_v2_component_elements_loader.Loader }, props: { dialogId: { type: String, required: true }, searchResult: { type: Array, required: false, default: () => [] }, isSearch: { type: Boolean, required: false }, isLoadingSearch: { type: Boolean, required: false }, searchQuery: { type: String, default: '' } }, data() { return { isLoading: false, minTokenSize: DEFAULT_MIN_TOKEN_SIZE$1 }; }, computed: { SidebarDetailBlock: () => im_v2_const.SidebarDetailBlock, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, chatId() { return this.dialog.chatId; }, files() { if (this.isSearch) { return this.$store.getters['sidebar/files/getSearchResultCollection'](this.chatId, im_v2_const.SidebarFileGroups.media); } return this.$store.getters['sidebar/files/get'](this.chatId, im_v2_const.SidebarFileGroups.media); }, formattedCollection() { return this.collectionFormatter.format(this.files); }, isEmptyState() { return this.formattedCollection.length === 0; }, isSearchQueryMinimumSize() { return this.searchQuery.length < this.minTokenSize; } }, created() { this.initSettings(); this.service = new File({ dialogId: this.dialogId }); this.serviceSearch = new FileSearch({ dialogId: this.dialogId }); this.collectionFormatter = new SidebarCollectionFormatter(); this.contextMenu = new FileMenu(); }, beforeUnmount() { this.collectionFormatter.destroy(); this.contextMenu.destroy(); }, methods: { initSettings() { const settings = main_core.Extension.getSettings('im.v2.component.sidebar'); this.minTokenSize = settings.get('minSearchTokenSize', DEFAULT_MIN_TOKEN_SIZE$1); }, onContextMenuClick(event, target) { const item = { ...event, dialogId: this.dialogId }; this.contextMenu.openMenu(item, target); }, needToLoadNextPage(event) { const target = event.target; const isAtThreshold = target.scrollTop + target.clientHeight >= target.scrollHeight - target.clientHeight; const nameGetter = this.searchQuery.length > 0 ? 'sidebar/files/hasNextPageSearch' : 'sidebar/files/hasNextPage'; const hasNextPage = this.$store.getters[nameGetter](this.chatId, im_v2_const.SidebarFileGroups.media); return isAtThreshold && hasNextPage; }, async onScroll(event) { this.contextMenu.destroy(); if (this.isLoading || !this.needToLoadNextPage(event)) { return; } this.isLoading = true; if (this.isSearchQueryMinimumSize) { await this.service.loadNextPage(im_v2_const.SidebarFileGroups.media); } else { await this.serviceSearch.loadNextPage(im_v2_const.SidebarFileGroups.media, this.searchQuery); } this.isLoading = false; }, loc(phraseCode, replacements = {}) { return this.$Bitrix.Loc.getMessage(phraseCode, replacements); } }, template: ` <div class="bx-im-sidebar-file-media-detail__scope bx-im-sidebar-detail__container" @scroll="onScroll"> <div v-for="dateGroup in formattedCollection" class="bx-im-sidebar-file-media-detail__date-group_container"> <DateGroup :dateText="dateGroup.dateGroupTitle" /> <div class="bx-im-sidebar-file-media-detail__items-group"> <MediaDetailItem v-for="file in dateGroup.items" :fileItem="file" :contextDialogId="dialogId" @contextMenuClick="onContextMenuClick" /> </div> </div> <template v-if="!isLoading && !isLoadingSearch"> <template v-if="isSearch"> <StartState v-if="searchQuery.length === 0" :title="loc('IM_SIDEBAR_SEARCH_RESULT_START_TITLE')" :iconType="SidebarDetailBlock.messageSearch" /> <DetailEmptySearchState v-else-if="isEmptyState" :title="loc('IM_SIDEBAR_MESSAGE_SEARCH_NOT_FOUND_EXTENDED')" :subTitle="loc('IM_SIDEBAR_MESSAGE_SEARCH_NOT_FOUND_DESCRIPTION_EXTENDED')" /> </template> <DetailEmptyState v-else-if="isEmptyState" :title="loc('IM_SIDEBAR_MEDIA_EMPTY')" :iconType="SidebarDetailBlock.media" /> </template> <Loader v-if="isLoading || isLoadingSearch" class="bx-im-sidebar-detail__loader-container" /> </div> ` }; // @vue/component const AudioDetailItem = { name: 'AudioDetailItem', components: { AudioPlayer: im_v2_component_elements_audioplayer.AudioPlayer }, props: { id: { type: Number, required: true }, fileItem: { type: Object, required: true } }, emits: ['contextMenuClick'], data() { return { timelineType: 0 }; }, computed: { sidebarFileItem() { return this.fileItem; }, file() { return this.$store.getters['files/get'](this.sidebarFileItem.fileId, true); }, audioUrl() { return this.file.urlDownload; } }, created() { this.timelineType = Math.floor(Math.random() * 5); }, methods: { onContextMenuClick(event) { this.$emit('contextMenuClick', { sidebarFile: this.sidebarFileItem, file: this.file, messageId: this.sidebarFileItem.messageId }, event.currentTarget); } }, template: ` <div class="bx-im-sidebar-file-audio-detail-item__container bx-im-sidebar-file-audio-detail-item__scope"> <AudioPlayer :id="id" :src="audioUrl" :file="file" :messageId="sidebarFileItem.messageId" :timelineType="timelineType" :authorId="sidebarFileItem.authorId" :withPlaybackRateControl="true" @contextMenuClick="onContextMenuClick" /> </div> ` }; const DEFAULT_MIN_TOKEN_SIZE$2 = 3; // @vue/component const AudioTab = { name: 'AudioTab', components: { DetailEmptyState, AudioDetailItem, DateGroup, StartState: DetailEmptyState, DetailEmptySearchState, Loader: im_v2_component_elements_loader.Loader }, props: { dialogId: { type: String, required: true }, searchResult: { type: Array, required: false, default: () => [] }, isSearch: { type: Boolean, required: false }, isLoadingSearch: { type: Boolean, required: false }, searchQuery: { type: String, default: '' } }, data() { return { isLoading: false, minTokenSize: DEFAULT_MIN_TOKEN_SIZE$2 }; }, computed: { SidebarDetailBlock: () => im_v2_const.SidebarDetailBlock, files() { if (this.isSearch) { return this.$store.getters['sidebar/files/getSearchResultCollection'](this.chatId, im_v2_const.SidebarFileGroups.audio); } return this.$store.getters['sidebar/files/get'](this.chatId, im_v2_const.SidebarFileGroups.audio); }, formattedCollection() { return this.collectionFormatter.format(this.files); }, isEmptyState() { return this.formattedCollection.length === 0; }, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, chatId() { return this.dialog.chatId; }, isSearchQueryMinimumSize() { return this.searchQuery.length < this.minTokenSize; } }, created() { this.initSettings(); this.service = new File({ dialogId: this.dialogId }); this.serviceSearch = new FileSearch({ dialogId: this.dialogId }); this.collectionFormatter = new SidebarCollectionFormatter(); this.contextMenu = new FileMenu(); }, beforeUnmount() { this.collectionFormatter.destroy(); this.contextMenu.destroy(); }, methods: { initSettings() { const settings = main_core.Extension.getSettings('im.v2.component.sidebar'); this.minTokenSize = settings.get('minSearchTokenSize', DEFAULT_MIN_TOKEN_SIZE$2); }, onContextMenuClick(event, target) { const item = { ...event, dialogId: this.dialogId }; this.contextMenu.openMenu(item, target); }, needToLoadNextPage(event) { const target = event.target; const isAtThreshold = target.scrollTop + target.clientHeight >= target.scrollHeight - target.clientHeight; const nameGetter = this.searchQuery.length > 0 ? 'sidebar/files/hasNextPageSearch' : 'sidebar/files/hasNextPage'; const hasNextPage = this.$store.getters[nameGetter](this.chatId, im_v2_const.SidebarFileGroups.audio); return isAtThreshold && hasNextPage; }, async onScroll(event) { this.contextMenu.destroy(); if (this.isLoading || !this.needToLoadNextPage(event)) { return; } this.isLoading = true; if (this.isSearchQueryMinimumSize) { await this.service.loadNextPage(im_v2_const.SidebarFileGroups.audio); } else { await this.serviceSearch.loadNextPage(im_v2_const.SidebarFileGroups.audio, this.searchQuery); } this.isLoading = false; }, loc(phraseCode, replacements = {}) { return this.$Bitrix.Loc.getMessage(phraseCode, replacements); } }, template: ` <div class="bx-im-sidebar-file-audio-detail__scope bx-im-sidebar-detail__container" @scroll="onScroll"> <div v-for="dateGroup in formattedCollection" class="bx-im-sidebar-file-audio-detail__date-group_container"> <DateGroup :dateText="dateGroup.dateGroupTitle" /> <AudioDetailItem v-for="file in dateGroup.items" :id="file.id" :fileItem="file" @contextMenuClick="onContextMenuClick" /> </div> <template v-if="!isLoading && !isLoadingSearch"> <template v-if="isSearch"> <StartState v-if="searchQuery.length === 0" :title="loc('IM_SIDEBAR_SEARCH_RESULT_START_TITLE')" :iconType="SidebarDetailBlock.messageSearch" /> <DetailEmptySearchState v-else-if="isEmptyState" :title="loc('IM_SIDEBAR_MESSAGE_SEARCH_NOT_FOUND_EXTENDED')" :subTitle="loc('IM_SIDEBAR_MESSAGE_SEARCH_NOT_FOUND_DESCRIPTION_EXTENDED')" /> </template> <DetailEmptyState v-else-if="isEmptyState" :title="loc('IM_SIDEBAR_AUDIO_EMPTY')" :iconType="SidebarDetailBlock.audio" /> </template> <Loader v-if="isLoading || isLoadingSearch" class="bx-im-sidebar-detail__loader-container" /> </div> ` }; // @vue/component const BriefItem = { name: 'BriefItem', components: { MessageAvatar: im_v2_component_elements_avatar.MessageAvatar, ChatTitle: im_v2_component_elements_chatTitle.ChatTitle }, props: { brief: { type: Object, required: true }, contextDialogId: { type: String, required: true }, searchQuery: { type: String, default: '', required: false } }, emits: ['contextMenuClick'], data() { return { showContextButton: false }; }, computed: { AvatarSize: () => im_v2_component_elements_avatar.AvatarSize, sidebarFileItem() { return this.brief; }, file() { return this.$store.getters['files/get'](this.sidebarFileItem.fileId, true); }, fileShortName() { const NAME_MAX_LENGTH = 15; const shortName = im_v2_lib_utils.Utils.file.getShortFileName(this.file.name, NAME_MAX_LENGTH); if (this.searchQuery.length === 0) { return main_core.Text.encode(shortName); } return im_v2_lib_textHighlighter.highlightText(main_core.Text.encode(shortName), this.searchQuery); }, fileSize() { return im_v2_lib_utils.Utils.file.formatFileSize(this.file.size); }, viewerAttributes() { return im_v2_lib_utils.Utils.file.getViewerDataAttributes({ viewerAttributes: this.file.viewerAttrs, previewImageSrc: this.file.urlPreview, context: im_v2_const.FileViewerContext.sidebarTabBriefs }); }, isViewerAvailable() { return Object.keys(this.viewerAttributes).length > 0; } }, methods: { download() { if (this.isViewerAvailable) { return; } window.open(this.file.urlDownload, '_blank'); }, onContextMenuClick(event) { this.$emit('contextMenuClick', { sidebarFile: this.sidebarFileItem, file: this.file, messageId: this.sidebarFileItem.messageId }, event.currentTarget); } }, template: ` <div class="bx-im-sidebar-brief-item__container bx-im-sidebar-brief-item__scope" @mouseover="showContextButton = true" @mouseleave="showContextButton = false" > <div class="bx-im-sidebar-brief-item__icon-container"></div> <div class="bx-im-sidebar-brief-item__content-container"> <div class="bx-im-sidebar-brief-item__content"> <div class="bx-im-sidebar-brief-item__title" @click="download" v-bind="viewerAttributes"> <span class="bx-im-sidebar-brief-item__title-text" :title="file.name" v-html="fileShortName"></span> <span class="bx-im-sidebar-brief-item__size-text">{{fileSize}}</span> </div> <div class="bx-im-sidebar-brief-item__author-container"> <MessageAvatar :messageId="sidebarFileItem.messageId" :authorId="sidebarFileItem.authorId" :size="AvatarSize.XS" class="bx-im-sidebar-brief-item__author-avatar" /> <ChatTitle :dialogId="sidebarFileItem.authorId" :showItsYou="false" /> </div> </div> </div> <button v-if="showContextButton" class="bx-im-messenger__context-menu-icon bx-im-sidebar-brief-item__context-menu-button" @click="onContextMenuClick" ></button> </div> ` }; const DEFAULT_MIN_TOKEN_SIZE$3 = 3; // @vue/component const BriefTab = { name: 'BriefTab', components: { DateGroup, BriefItem, DetailEmptyState, StartState: DetailEmptyState, DetailEmptySearchState, Loader: im_v2_component_elements_loader.Loader }, props: { dialogId: { type: String, required: true }, searchResult: { type: Array, required: false, default: () => [] }, isSearch: { type: Boolean, required: false }, isLoadingSearch: { type: Boolean, required: false }, searchQuery: { type: String, default: '' } }, data() { return { isLoading: false, minTokenSize: DEFAULT_MIN_TOKEN_SIZE$3 }; }, computed: { SidebarDetailBlock: () => im_v2_const.SidebarDetailBlock, files() { if (this.isSearch) { return this.$store.getters['sidebar/files/getSearchResultCollection'](this.chatId, im_v2_const.SidebarFileGroups.brief); } return this.$store.getters['sidebar/files/get'](this.chatId, im_v2_const.SidebarFileGroups.brief); }, formattedCollection() { return this.collectionFormatter.format(this.files); }, isEmptyState() { return this.formattedCollection.length === 0; }, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, chatId() { return this.dialog.chatId; }, isSearchQueryMinimumSize() { return this.searchQuery.length < this.minTokenSize; } }, created() { this.initSettings(); this.service = new File({ dialogId: this.dialogId }); this.serviceSearch = new FileSearch({ dialogId: this.dialogId }); this.collectionFormatter = new SidebarCollectionFormatter(); this.contextMenu = new FileMenu(); }, beforeUnmount() { this.collectionFormatter.destroy(); this.contextMenu.destroy(); }, methods: { initSettings() { const settings = main_core.Extension.getSettings('im.v2.component.sidebar'); this.minTokenSize = settings.get('minSearchTokenSize', DEFAULT_MIN_TOKEN_SIZE$3); }, onContextMenuClick(event, target) { const item = { ...event, dialogId: this.dialogId }; this.contextMenu.openMenu(item, target); }, needToLoadNextPage(event) { const target = event.target; const isAtThreshold = target.scrollTop + target.clientHeight >= target.scrollHeight - target.clientHeight; const nameGetter = this.searchQuery.length > 0 ? 'sidebar/files/hasNextPageSearch' : 'sidebar/files/hasNextPage'; const hasNextPage = this.$store.getters[nameGetter](this.chatId, im_v2_const.SidebarFileGroups.brief); return isAtThreshold && hasNextPage; }, async onScroll(event) { this.contextMenu.destroy(); if (this.isLoading || !this.needToLoadNextPage(event)) { return; } this.isLoading = true; if (this.isSearchQueryMinimumSize) { await this.service.loadNextPage(im_v2_const.SidebarFileGroups.brief); } else { await this.serviceSearch.loadNextPage(im_v2_const.SidebarFileGroups.brief, this.searchQuery); } this.isLoading = false; }, loc(phraseCode, replacements = {}) { return this.$Bitrix.Loc.getMessage(phraseCode, replacements); } }, template: ` <div class="bx-im-sidebar-brief-detail__scope bx-im-sidebar-detail__container" @scroll="onScroll"> <div v-for="dateGroup in formattedCollection" class="bx-im-sidebar-brief-detail__date-group_container"> <DateGroup :dateText="dateGroup.dateGroupTitle"/> <BriefItem v-for="file in dateGroup.items" :brief="file" :contextDialogId="dialogId" :searchQuery="searchQuery" @contextMenuClick="onContextMenuClick" /> </div> <template v-if="!isLoading && !isLoadingSearch"> <template v-if="isSearch"> <StartState v-if="searchQuery.length === 0" :title="loc('IM_SIDEBAR_SEARCH_RESULT_START_TITLE')" :iconType="SidebarDetailBlock.messageSearch" /> <DetailEmptySearchState v-else-if="isEmptyState" :title="loc('IM_SIDEBAR_MESSAGE_SEARCH_NOT_FOUND_EXTENDED')" :subTitle="loc('IM_SIDEBAR_MESSAGE_SEARCH_NOT_FOUND_DESCRIPTION_EXTENDED')" /> </template> <DetailEmptyState v-else-if="isEmptyState" :title="loc('IM_SIDEBAR_BRIEFS_EMPTY')" :iconType="SidebarDetailBlock.document" /> </template> <Loader v-if="isLoading || isLoadingSearch" class="bx-im-sidebar-detail__loader-container" /> </div> ` }; // @vue/component const FileDetailItem = { name: 'FileDetailItem', components: { MessageAvatar: im_v2_component_elements_avatar.MessageAvatar, ChatTitle: im_v2_component_elements_chatTitle.ChatTitle }, props: { fileItem: { type: Object, required: true }, contextDialogId: { type: String, required: true }, searchQuery: { type: String, default: '', required: false }, viewerContext: { type: String, default: '' } }, emits: ['contextMenuClick'], data() { return { showContextButton: false }; }, computed: { AvatarSize: () => im_v2_component_elements_avatar.AvatarSize, sidebarFileItem() { return this.fileItem; }, file() { return this.$store.getters['files/get'](this.sidebarFileItem.fileId, true); }, fileIconClass() { return `ui-icon ui-icon-file-${this.file.icon}`; }, fileShortName() { const NAME_MAX_LENGTH = 15; const shortName = im_v2_lib_utils.Utils.file.getShortFileName(this.file.name, NAME_MAX_LENGTH); if (this.searchQuery.length === 0) { return main_core.Text.encode(shortName); } return im_v2_lib_textHighlighter.highlightText(main_core.Text.encode(shortName), this.searchQuery); }, fileSize() { return im_v2_lib_utils.Utils.file.formatFileSize(this.file.size); }, viewerAttributes() { return im_v2_lib_utils.Utils.file.getViewerDataAttributes({ viewerAttributes: this.file.viewerAttrs, previewImageSrc: this.file.urlPreview, context: this.viewerContext }); }, isViewerAvailable() { return Object.keys(this.viewerAttributes).length > 0; }, authorId() { return this.sidebarFileItem.authorId; } }, methods: { download() { if (this.isViewerAvailable) { return; } window.open(this.file.urlDownload, '_blank'); }, onContextMenuClick(event) { this.$emit('contextMenuClick', { sidebarFile: this.sidebarFileItem, file: this.file, messageId: this.sidebarFileItem.messageId }, event.currentTarget); } }, template: ` <div class="bx-im-sidebar-file-detail-item__container bx-im-sidebar-file-detail-item__scope" @mouseover="showContextButton = true" @mouseleave="showContextButton = false" > <div class="bx-im-sidebar-file-detail-item__icon-container"> <div :class="fileIconClass"><i></i></div> </div> <div class="bx-im-sidebar-file-detail-item__content-container" v-bind="viewerAttributes"> <div class="bx-im-sidebar-file-detail-item__content"> <div class="bx-im-sidebar-file-detail-item__file-title" @click="download" :title="file.name"> <span class="bx-im-sidebar-file-detail-item__file-title-text" v-html="fileShortName"></span> <span class="bx-im-sidebar-file-detail-item__file-size">{{fileSize}}</span> </div> <div class="bx-im-sidebar-file-detail-item__author-container"> <template v-if="authorId > 0"> <MessageAvatar :messageId="sidebarFileItem.messageId" :authorId="sidebarFileItem.authorId" :size="AvatarSize.XS" class="bx-im-sidebar-file-detail-item__author-avatar" /> <ChatTitle :dialogId="authorId" :showItsYou="false" /> </template> <span v-else class="bx-im-sidebar-file-detail-item__system-author-text"> {{ $Bitrix.Loc.getMessage('IM_SIDEBAR_SYSTEM_USER') }} </span> </div> </div> </div> <button v-if="showContextButton" class="bx-im-messenger__context-menu-icon" @click="onContextMenuClick" ></button> </div> ` }; const DEFAULT_MIN_TOKEN_SIZE$4 = 3; // @vue/component const FileTab = { name: 'FileTab', components: { DateGroup, FileDetailItem, DetailEmptyState, StartState: DetailEmptyState, DetailEmptySearchState, Loader: im_v2_component_elements_loader.Loader }, props: { dialogId: { type: String, required: true }, searchResult: { type: Array, required: false, default: () => [] }, isSearch: { type: Boolean, required: false }, isLoadingSearch: { type: Boolean, required: false }, searchQuery: { type: String, default: '' } }, data() { return { isLoading: false, minTokenSize: DEFAULT_MIN_TOKEN_SIZE$4 }; }, computed: { SidebarDetailBlock: () => im_v2_const.SidebarDetailBlock, FileViewerContext: () => im_v2_const.FileViewerContext, files() { if (this.isSearch) { return this.$store.getters['sidebar/files/getSearchResultCollection'](this.chatId, im_v2_const.SidebarFileGroups.file); } return this.$store.getters['sidebar/files/get'](this.chatId, im_v2_const.SidebarFileGroups.file); }, formattedCollection() { return this.collectionFormatter.format(this.files); }, isEmptyState() { return this.formattedCollection.length === 0; }, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, chatId() { return this.dialog.chatId; }, isSearchQueryMinimumSize() { return this.searchQuery.length < this.minTokenSize; } }, created() { this.initSettings(); this.service = new File({ dialogId: this.dialogId }); this.serviceSearch = new FileSearch({ dialogId: this.dialogId }); this.collectionFormatter = new SidebarCollectionFormatter(); this.contextMenu = new FileMenu(); }, beforeUnmount() { this.collectionFormatter.destroy(); this.contextMenu.destroy(); }, methods: { initSettings() { const settings = main_core.Extension.getSettings('im.v2.component.sidebar'); this.minTokenSize = settings.get('minSearchTokenSize', DEFAULT_MIN_TOKEN_SIZE$4); }, onContextMenuClick(event, target) { const item = { ...event, dialogId: this.dialogId }; this.contextMenu.openMenu(item, target); }, needToLoadNextPage(event) { const target = event.target; const isAtThreshold = target.scrollTop + target.clientHeight >= target.scrollHeight - target.clientHeight; const nameGetter = this.searchQuery.length > 0 ? 'sidebar/files/hasNextPageSearch' : 'sidebar/files/hasNextPage'; const hasNextPage = this.$store.getters[nameGetter](this.chatId, im_v2_const.SidebarFileGroups.file); return isAtThreshold && hasNextPage; }, async onScroll(event) { this.contextMenu.destroy(); if (this.isLoading || !this.needToLoadNextPage(event)) { return; } this.isLoading = true; if (this.isSearchQueryMinimumSize) { await this.service.loadNextPage(im_v2_const.SidebarFileGroups.file); } else { await this.serviceSearch.loadNextPage(im_v2_const.SidebarFileGroups.file, this.searchQuery); } this.isLoading = false; }, loc(phraseCode, replacements = {}) { return this.$Bitrix.Loc.getMessage(phraseCode, replacements); } }, template: ` <div class="bx-im-sidebar-file-detail__scope bx-im-sidebar-detail__container" @scroll="onScroll"> <div v-for="dateGroup in formattedCollection" class="bx-im-sidebar-file-detail__date-group_container"> <DateGroup :dateText="dateGroup.dateGroupTitle" /> <FileDetailItem v-for="file in dateGroup.items" :fileItem="file" :searchQuery="searchQuery" :contextDialogId="dialogId" :viewerContext="FileViewerContext.sidebarTabFiles" @contextMenuClick="onContextMenuClick" /> </div> <template v-if="!isLoading && !isLoadingSearch"> <template v-if="isSearch"> <StartState v-if="searchQuery.length === 0" :title="loc('IM_SIDEBAR_SEARCH_RESULT_START_TITLE')" :iconType="SidebarDetailBlock.messageSearch" /> <DetailEmptySearchState v-else-if="isEmptyState" :title="loc('IM_SIDEBAR_MESSAGE_SEARCH_NOT_FOUND_EXTENDED')" :subTitle="loc('IM_SIDEBAR_MESSAGE_SEARCH_NOT_FOUND_DESCRIPTION_EXTENDED')" /> </template> <DetailEmptyState v-else-if="isEmptyState" :title="loc('IM_SIDEBAR_FILES_EMPTY')" :iconType="SidebarDetailBlock.document" /> </template> <Loader v-if="isLoading || isLoadingSearch" class="bx-im-sidebar-detail__loader-container" /> </div> ` }; const DEFAULT_MIN_TOKEN_SIZE$5 = 3; // @vue/component const FilePanel = { name: 'FilePanel', components: { DetailHeader, DetailTabs, MediaTab, AudioTab, FileTab, BriefTab, Loader: im_v2_component_elements_loader.Loader, TariffLimit }, props: { dialogId: { type: String, required: true }, secondLevel: { type: Boolean, default: false } }, data() { return { tab: im_v2_const.SidebarFileTabGroups.media, isSearchHeaderOpened: false, searchQuery: '', searchResult: [], currentServerQueries: 0, isLoading: false, minTokenSize: DEFAULT_MIN_TOKEN_SIZE$5 }; }, computed: { SidebarDetailBlock: () => im_v2_const.SidebarDetailBlock, tabComponentName() { return `${main_core.Text.capitalize(this.tab)}Tab`; }, tabs() { const tabTypes = Object.values(im_v2_const.SidebarFileTabGroups); const canShowBriefs = im_v2_lib_feature.FeatureManager.isFeatureAvailable(im_v2_lib_feature.Feature.sidebarBriefs); if (!canShowBriefs) { return tabTypes.filter(tab => tab !== im_v2_const.SidebarDetailBlock.brief); } return tabTypes; }, preparedQuery() { return this.searchQuery.trim().toLowerCase(); }, isSearchQueryMinimumSize() { return this.preparedQuery.length < this.minTokenSize; }, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, chatId() { return this.dialog.chatId; }, hasHistoryLimit() { return this.$store.getters['sidebar/files/isHistoryLimitExceeded'](this.chatId); } }, watch: { preparedQuery(newQuery, previousQuery) { if (newQuery === previousQuery) { return; } this.cleanSearchResult(); this.startSearch(); } }, created() { this.initSettings(); this.service = new File({ dialogId: this.dialogId, tab: this.tab }); this.serviceSearch = new FileSearch({ dialogId: this.dialogId, tab: this.tab }); this.searchOnServerDelayed = main_core.Runtime.debounce(this.searchOnServer, 500, this); }, methods: { initSettings() { const settings = main_core.Extension.getSettings('im.v2.component.sidebar'); this.minTokenSize = settings.get('minSearchTokenSize', DEFAULT_MIN_TOKEN_SIZE$5); }, searchOnServer(query) { this.currentServerQueries++; this.serviceSearch.searchOnServer(query, this.tab).then(messageIds => { if (query !== this.preparedQuery) { this.isLoading = false; return; } this.searchResult = concatAndSortSearchResult(this.searchResult, messageIds); }).catch(error => { console.error(error); }).finally(() => { this.currentServerQueries--; this.stopLoader(); if (this.isSearchQueryMinimumSize) { this.cleanSearchResult(); } }); }, stopLoader() { if (this.currentServerQueries > 0) { return; } this.isLoading = false; }, startSearch() { if (this.isSearchQueryMinimumSize) { this.cleanSearchResult(); } else { this.isLoading = true; this.searchOnServerDelayed(this.preparedQuery); } }, cleanSearchResult() { this.serviceSearch.resetSearchState(); this.searchResult = []; }, onBackClick() { main_core_events.EventEmitter.emit(im_v2_const.EventType.sidebar.close, { panel: im_v2_const.SidebarDetailBlock.file }); }, onTabSelect(tabName) { this.tab = tabName; if (!this.isSearchQueryMinimumSize) { this.cleanSearchResult(); this.startSearch(); } }, onChangeQuery(query) { this.searchQuery = query; }, toggleSearchPanelOpened() { this.isSearchHeaderOpened = !this.isSearchHeaderOpened; }, loc(phraseCode, replacements = {}) { return this.$Bitrix.Loc.getMessage(phraseCode, replacements); } }, template: ` <div> <DetailHeader :dialogId="dialogId" :title="loc('IM_SIDEBAR_MEDIA_DETAIL_TITLE')" :secondLevel="secondLevel" :isSearchHeaderOpened="isSearchHeaderOpened" :delayForFocusOnStart="0" @changeQuery="onChangeQuery" @toggleSearchPanelOpened="toggleSearchPanelOpened" withSearch @back="onBackClick" /> <TariffLimit v-if="hasHistoryLimit" :dialogId="dialogId" :panel="SidebarDetailBlock.file" class="bx-im-sidebar-file__tariff-limit-container" /> <DetailTabs :tabs="tabs" @tabSelect="onTabSelect" /> <KeepAlive> <component :is="tabComponentName" :dialogId="dialogId" :searchResult="searchResult" :isSearch="isSearchHeaderOpened" :searchQuery="searchQuery" :isLoadingSearch="isLoading" /> </KeepAlive> </div> ` }; // @vue/component const FileUnsortedPanel = { name: 'FileUnsortedPanel', components: { DateGroup, FileDetailItem, DetailEmptyState, DetailHeader, Loader: im_v2_component_elements_loader.Loader, TariffLimit }, props: { dialogId: { type: String, required: true }, secondLevel: { type: Boolean, default: false } }, data() { return { isLoading: false }; }, computed: { SidebarDetailBlock: () => im_v2_const.SidebarDetailBlock, FileViewerContext: () => im_v2_const.FileViewerContext, files() { return this.$store.getters['sidebar/files/get'](this.chatId, im_v2_const.SidebarFileGroups.fileUnsorted); }, formattedCollection() { return this.collectionFormatter.format(this.files); }, isEmptyState() { return this.formattedCollection.length === 0; }, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, chatId() { return this.dialog.chatId; }, hasHistoryLimit() { return this.$store.getters['sidebar/files/isHistoryLimitExceeded'](this.chatId); } }, created() { this.service = new FileUnsorted({ dialogId: this.dialogId }); this.collectionFormatter = new SidebarCollectionFormatter(); this.contextMenu = new FileMenu(); }, beforeUnmount() { this.collectionFormatter.destroy(); this.contextMenu.destroy(); }, methods: { needToLoadNextPage(event) { const target = event.target; const isAtThreshold = target.scrollTop + target.clientHeight >= target.scrollHeight - target.clientHeight; const hasNextPage = this.$store.getters['sidebar/files/hasNextPage'](this.chatId, im_v2_const.SidebarFileGroups.fileUnsorted); return isAtThreshold && hasNextPage; }, async onScroll(event) { this.contextMenu.destroy(); if (this.isLoading || !this.needToLoadNextPage(event)) { return; } this.isLoading = true; await this.service.loadNextPage(); this.isLoading = false; }, onContextMenuClick(event, target) { const item = { ...event, dialogId: this.dialogId }; this.contextMenu.openMenu(item, target); }, onBackClick() { main_core_events.EventEmitter.emit(im_v2_const.EventType.sidebar.close, { panel: im_v2_const.SidebarDetailBlock.fileUnsorted }); } }, template: ` <div class="bx-im-sidebar-file-unsorted-detail__scope"> <DetailHeader :dialogId="dialogId" :title="$Bitrix.Loc.getMessage('IM_SIDEBAR_FILEUNSORTED_DETAIL_TITLE')" :secondLevel="secondLevel" @back="onBackClick" /> <div class="bx-im-sidebar-file-unsorted-detail__container bx-im-sidebar-detail__container" @scroll="onScroll"> <div v-for="dateGroup in formattedCollection" class="bx-im-sidebar-file-unsorted-detail__date-group_container"> <DateGroup :dateText="dateGroup.dateGroupTitle" /> <FileDetailItem v-for="file in dateGroup.items" :fileItem="file" :contextDialogId="dialogId" :viewerContext="FileViewerContext.sidebarTabFileUnsorted" @contextMenuClick="onContextMenuClick" /> </div> <TariffLimit v-if="hasHistoryLimit" :dialogId="dialogId" :panel="SidebarDetailBlock.fileUnsorted" class="bx-im-sidebar-file-unsorted-detail__tariff-limit-container" /> <DetailEmptyState v-if="!isLoading && isEmptyState" :title="$Bitrix.Loc.getMessage('IM_SIDEBAR_FILES_EMPTY')" :iconType="SidebarDetailBlock.document" /> <Loader v-if="isLoading" class="bx-im-sidebar-detail__loader-container" /> </div> </div> ` }; // @vue/component const LinkItem = { name: 'LinkItem', components: { MessageAvatar: im_v2_component_elements_avatar.MessageAvatar, ChatTitle: im_v2_component_elements_chatTitle.ChatTitle }, props: { link: { type: Object, required: true }, contextDialogId: { type: String, required: true }, searchQuery: { type: String, default: '' } }, emits: ['contextMenuClick'], data() { return { showContextButton: false }; }, computed: { AvatarSize: () => im_v2_component_elements_avatar.AvatarSize, linkItem() { return this.link; }, source() { return this.linkItem.source; }, shortDescription() { let hostName = ''; try { hostName = new URL(this.source).hostname; } catch (error) { hostName = this.source; console.error(error); } return hostName; }, description() { const { name, description } = this.linkItem.richData; const descriptionToShow = description || name || this.source; if (this.searchQuery.length === 0) { return im_v2_lib_utils.Utils.text.convertHtmlEntities(descriptionToShow); } return im_v2_lib_textHighlighter.highlightText(main_core.Text.encode(descriptionToShow), this.searchQuery); }, authorDialogId() { return this.linkItem.authorId.toString(); }, hasPreview() { var _this$linkItem$richDa; return Boolean((_this$linkItem$richDa = this.linkItem.richData) == null ? void 0 : _this$linkItem$richDa.previewUrl); }, previewStyles() { var _this$linkItem$richDa2; return { backgroundImage: `url('${(_this$linkItem$richDa2 = this.linkItem.richData) == null ? void 0 : _this$linkItem$richDa2.previewUrl}')`, backgroundSize: 'cover', backgroundRepeat: 'no-repeat' }; }, iconTypeClass() { var _this$linkItem$richDa3; switch ((_this$linkItem$richDa3 = this.linkItem.richData) == null ? void 0 : _this$linkItem$richDa3.type) { case 'TASKS': return '--task'; case 'LANDING': return '--landing'; case 'POST': return '--post'; case 'CALENDAR': return '--calendar'; default: return '--common'; } } }, methods: { onContextMenuClick(event) { this.$emit('contextMenuClick', { id: this.linkItem.id, authorId: this.linkItem.authorId, messageId: this.linkItem.messageId, source: this.source, target: event.currentTarget }); } }, template: ` <div class="bx-im-link-item__container bx-im-link-item__scope" @mouseover="showContextButton = true" @mouseleave="showContextButton = false" > <template v-if="hasPreview"> <div class="bx-im-link-item__icon-container" :style="previewStyles"></div> </template> <template v-else> <div class="bx-im-link-item__icon-container" :class="iconTypeClass"> <div class="bx-im-link-item__icon" :class="iconTypeClass" ></div> </div> </template> <div class="bx-im-link-item__content"> <div class="bx-im-link-item__short-description-text">{{ shortDescription }}</div> <a :href="source" :title="source" target="_blank" class="bx-im-link-item__description-text" v-html="description"></a> <div class="bx-im-link-item__author-container"> <MessageAvatar :messageId="linkItem.messageId" :authorId="linkItem.authorId" :size="AvatarSize.XS" class="bx-im-link-item__author-avatar" /> <ChatTitle :dialogId="authorDialogId" :showItsYou="false" class="bx-im-link-item__author-text" /> </div> </div> <div v-if="showContextButton" class="bx-im-link-item__context-menu"> <button class="bx-im-messenger__context-menu-icon" @click="onContextMenuClick"></button> </div> </div> ` }; const REQUEST_ITEMS_LIMIT$a = 50; var _query$2 = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("query"); var _processSearchResponse$2 = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("processSearchResponse"); var _updateModels = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("updateModels"); class LinkSearch { constructor({ dialogId }) { Object.defineProperty(this, _updateModels, { value: _updateModels2 }); Object.defineProperty(this, _processSearchResponse$2, { value: _processSearchResponse2$2 }); this.hasMoreItemsToLoad = true; Object.defineProperty(this, _query$2, { writable: true, value: '' }); this.store = im_v2_application_core.Core.getStore(); this.restClient = im_v2_application_core.Core.getRestClient(); this.dialogId = dialogId; this.chatId = getChatId(dialogId); this.userManager = new im_v2_lib_user.UserManager(); } searchOnServer(query) { if (babelHelpers.classPrivateFieldLooseBase(this, _query$2)[_query$2] !== query) { babelHelpers.classPrivateFieldLooseBase(this, _query$2)[_query$2] = query; this.hasMoreItemsToLoad = true; } return this.request(); } resetSearchState() { babelHelpers.classPrivateFieldLooseBase(this, _query$2)[_query$2] = ''; this.hasMoreItemsToLoad = true; void this.store.dispatch('sidebar/links/clearSearch', {}); } async request() { const queryParams = this.getQueryParams(); let responseData = {}; try { const response = await this.restClient.callMethod(im_v2_const.RestMethod.imChatUrlGet, queryParams); responseData = response.data(); } catch (error) { console.error('SidebarSearch: Im.imChatUrlGet: page request error', error); } return babelHelpers.classPrivateFieldLooseBase(this, _processSearchResponse$2)[_processSearchResponse$2](responseData); } getQueryParams() { const queryParams = { CHAT_ID: this.chatId, LIMIT: REQUEST_ITEMS_LIMIT$a, SEARCH_URL: babelHelpers.classPrivateFieldLooseBase(this, _query$2)[_query$2] }; const linksCount = this.getLinksCountFromModel(); if (main_core.Type.isNumber(linksCount) && linksCount > 0) { queryParams.OFFSET = linksCount; } return queryParams; } getLinksCountFromModel() { return this.store.getters['sidebar/links/getSearchResultCollectionSize'](this.chatId); } } function _processSearchResponse2$2(response) { return babelHelpers.classPrivateFieldLooseBase(this, _updateModels)[_updateModels](response).then(() => { return response.list.map(message => message.messageId); }); } function _updateModels2(resultData) { const { list, users, tariffRestrictions = {} } = resultData; const isHistoryLimitExceeded = Boolean(tariffRestrictions.isHistoryLimitExceeded); const addUsersPromise = this.userManager.setUsersToModel(users); const setLinksPromise = this.store.dispatch('sidebar/links/setSearch', { chatId: this.chatId, links: list, hasNextPage: list.length === REQUEST_ITEMS_LIMIT$a, isHistoryLimitExceeded }); return Promise.all([setLinksPromise, addUsersPromise]); } class LinkManager { constructor() { this.store = im_v2_application_core.Core.getStore(); this.restClient = im_v2_application_core.Core.getRestClient(); } delete(link) { this.store.dispatch('sidebar/links/delete', { chatId: link.chatId, id: link.id }); const queryParams = { LINK_ID: link.id }; this.restClient.callMethod(im_v2_const.RestMethod.imChatUrlDelete, queryParams).catch(error => { console.error('Im.Sidebar: error deleting link', error); }); } } class LinkMenu extends SidebarMenu { constructor() { super(); this.linkManager = new LinkManager(); } getMenuItems() { return [this.getOpenContextMessageItem(), this.getCopyLinkItem(main_core.Loc.getMessage('IM_SIDEBAR_MENU_COPY_LINK')), this.getDeleteLinkItem()]; } getDeleteLinkItem() { if (this.context.authorId !== this.getCurrentUserId()) { return null; } return { text: main_core.Loc.getMessage('IM_SIDEBAR_MENU_DELETE_FROM_LINKS'), onclick: function () { this.linkManager.delete(this.context); this.menuInstance.close(); }.bind(this) }; } } const DEFAULT_MIN_TOKEN_SIZE$6 = 3; // @vue/component const LinkPanel = { name: 'LinkPanel', components: { DetailHeader, LinkItem, DateGroup, DetailEmptyState, StartState: DetailEmptyState, DetailEmptySearchState, Loader: im_v2_component_elements_loader.Loader, TariffLimit }, props: { dialogId: { type: String, required: true }, secondLevel: { type: Boolean, default: false } }, data() { return { isLoading: false, isSearchHeaderOpened: false, searchQuery: '', searchResult: [], currentServerQueries: 0, minTokenSize: DEFAULT_MIN_TOKEN_SIZE$6 }; }, computed: { SidebarDetailBlock: () => im_v2_const.SidebarDetailBlock, links() { if (this.isSearchHeaderOpened) { return this.$store.getters['sidebar/links/getSearchResultCollection'](this.chatId); } return this.$store.getters['sidebar/links/get'](this.chatId); }, formattedCollection() { return this.collectionFormatter.format(this.links); }, isEmptyState() { return this.formattedCollection.length === 0; }, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, chatId() { return this.dialog.chatId; }, preparedQuery() { return this.searchQuery.trim().toLowerCase(); }, isSearchQueryMinimumSize() { return this.preparedQuery.length < this.minTokenSize; }, hasHistoryLimit() { return this.$store.getters['sidebar/links/isHistoryLimitExceeded'](this.chatId); } }, watch: { preparedQuery(newQuery, previousQuery) { if (newQuery === previousQuery) { return; } this.cleanSearchResult(); this.startSearch(); } }, created() { this.initSettings(); this.collectionFormatter = new SidebarCollectionFormatter(); this.contextMenu = new LinkMenu(); this.service = new Link({ dialogId: this.dialogId }); this.serviceSearch = new LinkSearch({ dialogId: this.dialogId }); this.searchOnServerDelayed = main_core.Runtime.debounce(this.searchOnServer, 500, this); }, beforeUnmount() { this.contextMenu.destroy(); this.collectionFormatter.destroy(); }, methods: { initSettings() { const settings = main_core.Extension.getSettings('im.v2.component.sidebar'); this.minTokenSize = settings.get('minSearchTokenSize', DEFAULT_MIN_TOKEN_SIZE$6); }, searchOnServer(query) { this.currentServerQueries++; this.serviceSearch.searchOnServer(query).then(messageIds => { if (query !== this.preparedQuery) { this.isLoading = false; return; } this.searchResult = concatAndSortSearchResult(this.searchResult, messageIds); }).catch(error => { console.error(error); }).finally(() => { this.currentServerQueries--; this.stopLoader(); if (this.isSearchQueryMinimumSize) { this.cleanSearchResult(); } }); }, stopLoader() { if (this.currentServerQueries > 0) { return; } this.isLoading = false; }, startSearch() { if (this.isSearchQueryMinimumSize) { this.cleanSearchResult(); } else { this.isLoading = true; this.searchOnServerDelayed(this.preparedQuery); } }, cleanSearchResult() { this.searchResult = []; this.serviceSearch.resetSearchState(); }, onChangeQuery(query) { this.searchQuery = query; }, toggleSearchPanelOpened() { this.isSearchHeaderOpened = !this.isSearchHeaderOpened; }, onContextMenuClick(event) { const item = { id: event.id, messageId: event.messageId, dialogId: this.dialogId, chatId: this.chatId, source: event.source, authorId: event.authorId }; this.contextMenu.openMenu(item, event.target); }, onBackClick() { main_core_events.EventEmitter.emit(im_v2_const.EventType.sidebar.close, { panel: im_v2_const.SidebarDetailBlock.link }); }, needToLoadNextPage(event) { const target = event.target; const isAtThreshold = target.scrollTop + target.clientHeight >= target.scrollHeight - target.clientHeight; const nameGetter = this.searchQuery.length > 0 ? 'sidebar/links/hasNextPageSearch' : 'sidebar/links/hasNextPage'; const hasNextPage = this.$store.getters[nameGetter](this.chatId); return isAtThreshold && hasNextPage; }, async onScroll(event) { this.contextMenu.destroy(); if (this.isLoading || !this.needToLoadNextPage(event)) { return; } this.isLoading = true; if (this.isSearchQueryMinimumSize) { await this.service.loadNextPage(); } else { await this.serviceSearch.request(); } this.isLoading = false; }, loc(phraseCode, replacements = {}) { return this.$Bitrix.Loc.getMessage(phraseCode, replacements); } }, template: ` <div class="bx-im-sidebar-link-detail__scope"> <DetailHeader :dialogId="dialogId" :title="loc('IM_SIDEBAR_LINK_DETAIL_TITLE')" :secondLevel="secondLevel" :isSearchHeaderOpened="isSearchHeaderOpened" :delayForFocusOnStart="0" @changeQuery="onChangeQuery" @toggleSearchPanelOpened="toggleSearchPanelOpened" withSearch @back="onBackClick" /> <div class="bx-im-sidebar-detail__container" @scroll="onScroll"> <div v-for="dateGroup in formattedCollection" class="bx-im-sidebar-link-detail__date-group_container"> <DateGroup :dateText="dateGroup.dateGroupTitle" /> <template v-for="link in dateGroup.items"> <LinkItem :contextDialogId="dialogId" :searchQuery="searchQuery" :link="link" @contextMenuClick="onContextMenuClick" /> </template> </div> <TariffLimit v-if="hasHistoryLimit" :dialogId="dialogId" :panel="SidebarDetailBlock.link" class="bx-im-sidebar-link-detail__tariff-limit-container" /> <template v-if="!isLoading"> <template v-if="isSearchHeaderOpened"> <StartState v-if="preparedQuery.length === 0" :title="loc('IM_SIDEBAR_SEARCH_MESSAGE_START_TITLE')" :iconType="SidebarDetailBlock.messageSearch" /> <DetailEmptySearchState v-else-if="isEmptyState" :title="loc('IM_SIDEBAR_MESSAGE_SEARCH_NOT_FOUND_EXTENDED')" :subTitle="loc('IM_SIDEBAR_MESSAGE_SEARCH_NOT_FOUND_DESCRIPTION_EXTENDED')" /> </template> <DetailEmptyState v-else-if="isEmptyState" :title="loc('IM_SIDEBAR_LINKS_EMPTY')" :iconType="SidebarDetailBlock.link" /> </template> <Loader v-if="isLoading" class="bx-im-sidebar-detail__loader-container" /> </div> </div> ` }; // @vue/component const MarketPanel = { name: 'MarketPanel', components: { Spinner: im_v2_component_elements_loader.Spinner, DetailHeader }, props: { dialogId: { type: String, required: true }, entityId: { type: String, required: true }, secondLevel: { type: Boolean, default: false } }, data() { return { isLoading: true }; }, computed: { SpinnerSize: () => im_v2_component_elements_loader.SpinnerSize, SidebarDetailBlock: () => im_v2_const.SidebarDetailBlock, placement() { const placementId = Number.parseInt(this.entityId, 10); return this.$store.getters['market/getById'](placementId); }, title() { if (this.placement && main_core.Type.isStringFilled(this.placement.title)) { return this.placement.title; } return this.$Bitrix.Loc.getMessage('IM_SIDEBAR_MARKET_DETAIL_TITLE'); } }, created() { this.marketManager = im_v2_lib_market.MarketManager.getInstance(); }, async mounted() { const context = { dialogId: this.dialogId }; const response = await this.marketManager.loadPlacement(this.entityId, context); this.isLoading = false; main_core.Runtime.html(this.$refs['im-messenger-sidebar-placement'], response); }, methods: { onBackClick() { main_core_events.EventEmitter.emit(im_v2_const.EventType.sidebar.close, { panel: im_v2_const.SidebarDetailBlock.market }); } }, template: ` <div class="bx-im-sidebar-favorite-detail__scope"> <DetailHeader :dialogId="dialogId" :title="title" :secondLevel="secondLevel" @back="onBackClick" /> <div class="bx-im-sidebar-market-detail__container"> <div v-if="isLoading" class="bx-im-sidebar-market-detail__loader-container"> <Spinner :size="SpinnerSize.S" /> </div> <div class="bx-im-sidebar-market-detail__placement-container" ref="im-messenger-sidebar-placement" ></div> </div> </div> ` }; const REQUEST_ITEMS_LIMIT$b = 50; var _query$3 = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("query"); var _processSearchResponse$3 = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("processSearchResponse"); class MeetingSearch { constructor({ dialogId }) { Object.defineProperty(this, _processSearchResponse$3, { value: _processSearchResponse2$3 }); this.hasMoreItemsToLoad = true; Object.defineProperty(this, _query$3, { writable: true, value: '' }); this.store = im_v2_application_core.Core.getStore(); this.restClient = im_v2_application_core.Core.getRestClient(); this.dialogId = dialogId; this.chatId = getChatId(dialogId); this.userManager = new im_v2_lib_user.UserManager(); } searchOnServer(query) { if (babelHelpers.classPrivateFieldLooseBase(this, _query$3)[_query$3] !== query) { babelHelpers.classPrivateFieldLooseBase(this, _query$3)[_query$3] = query; this.hasMoreItemsToLoad = true; } return this.request(); } resetSearchState() { babelHelpers.classPrivateFieldLooseBase(this, _query$3)[_query$3] = ''; this.hasMoreItemsToLoad = true; void this.store.dispatch('sidebar/meetings/clearSearch', {}); } async request() { const queryParams = this.getQueryParams(); let responseData = {}; try { const response = await this.restClient.callMethod(im_v2_const.RestMethod.imChatCalendarGet, queryParams); responseData = response.data(); } catch (error) { console.error('SidebarSearch: Im.imChatCalendarGet: page request error', error); } return babelHelpers.classPrivateFieldLooseBase(this, _processSearchResponse$3)[_processSearchResponse$3](responseData); } getQueryParams() { const queryParams = { CHAT_ID: this.chatId, LIMIT: REQUEST_ITEMS_LIMIT$b, SEARCH_TITLE: babelHelpers.classPrivateFieldLooseBase(this, _query$3)[_query$3] }; const lastId = this.store.getters['sidebar/meetings/getSearchResultCollectionLastId'](this.chatId); if (lastId > 0) { queryParams.LAST_ID = lastId; } return queryParams; } updateModels(resultData) { const { list, users, tariffRestrictions = {} } = resultData; const isHistoryLimitExceeded = Boolean(tariffRestrictions.isHistoryLimitExceeded); const hasNextPage = list.length === REQUEST_ITEMS_LIMIT$b; const lastId = getLastElementId(list); const addUsersPromise = this.userManager.setUsersToModel(users); const setMeetingsPromise = this.store.dispatch('sidebar/meetings/setSearch', { chatId: this.chatId, meetings: list, hasNextPage, lastId, isHistoryLimitExceeded }); return Promise.all([setMeetingsPromise, addUsersPromise]); } } function _processSearchResponse2$3(response) { return this.updateModels(response).then(() => { return response.list.map(message => message.messageId); }); } const DEFAULT_MIN_TOKEN_SIZE$7 = 3; // @vue/component const MeetingPanel = { name: 'MeetingPanel', components: { MeetingItem, DateGroup, DetailEmptyState, StartState: DetailEmptyState, DetailHeader, DetailEmptySearchState, Loader: im_v2_component_elements_loader.Loader, TariffLimit }, props: { dialogId: { type: String, required: true }, secondLevel: { type: Boolean, default: false } }, data() { return { isLoading: false, isSearchHeaderOpened: false, searchQuery: '', searchResult: [], currentServerQueries: 0, minTokenSize: DEFAULT_MIN_TOKEN_SIZE$7 }; }, computed: { SidebarDetailBlock: () => im_v2_const.SidebarDetailBlock, meetings() { if (this.isSearchHeaderOpened) { return this.$store.getters['sidebar/meetings/getSearchResultCollection'](this.chatId); } return this.$store.getters['sidebar/meetings/get'](this.chatId); }, formattedCollection() { return this.collectionFormatter.format(this.meetings); }, isEmptyState() { return this.formattedCollection.length === 0; }, showAddButton() { return im_v2_lib_permission.PermissionManager.getInstance().canPerformActionByRole(im_v2_const.ActionByRole.createMeeting, this.dialogId); }, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, chatId() { return this.dialog.chatId; }, preparedQuery() { return this.searchQuery.trim().toLowerCase(); }, isSearchQueryMinimumSize() { return this.preparedQuery.length < this.minTokenSize; }, hasHistoryLimit() { return this.$store.getters['sidebar/meetings/isHistoryLimitExceeded'](this.chatId); } }, watch: { preparedQuery(newQuery, previousQuery) { if (newQuery === previousQuery) { return; } this.cleanSearchResult(); this.startSearch(); } }, created() { this.initSettings(); this.collectionFormatter = new SidebarCollectionFormatter(); this.contextMenu = new MeetingMenu(); this.service = new Meeting({ dialogId: this.dialogId }); this.serviceSearch = new MeetingSearch({ dialogId: this.dialogId }); this.searchOnServerDelayed = main_core.Runtime.debounce(this.searchOnServer, 500, this); }, beforeUnmount() { this.collectionFormatter.destroy(); this.contextMenu.destroy(); }, methods: { initSettings() { const settings = main_core.Extension.getSettings('im.v2.component.sidebar'); this.minTokenSize = settings.get('minSearchTokenSize', DEFAULT_MIN_TOKEN_SIZE$7); }, searchOnServer(query) { this.currentServerQueries++; this.serviceSearch.searchOnServer(query).then(messageIds => { if (query !== this.preparedQuery) { this.isLoading = false; return; } this.searchResult = concatAndSortSearchResult(this.searchResult, messageIds); }).catch(error => { console.error(error); }).finally(() => { this.currentServerQueries--; this.stopLoader(); if (this.isSearchQueryMinimumSize) { this.cleanSearchResult(); } }); }, stopLoader() { if (this.currentServerQueries > 0) { return; } this.isLoading = false; }, startSearch() { if (this.isSearchQueryMinimumSize) { this.cleanSearchResult(); } else { this.isLoading = true; this.searchOnServerDelayed(this.preparedQuery); } }, cleanSearchResult() { this.serviceSearch.resetSearchState(); this.searchResult = []; }, onChangeQuery(query) { this.searchQuery = query; }, toggleSearchPanelOpened() { this.isSearchHeaderOpened = !this.isSearchHeaderOpened; }, onContextMenuClick(event, target) { const item = { ...event, dialogId: this.dialogId }; this.contextMenu.openMenu(item, target); }, onBackClick() { main_core_events.EventEmitter.emit(im_v2_const.EventType.sidebar.close, { panel: im_v2_const.SidebarDetailBlock.meeting }); }, needToLoadNextPage(event) { const target = event.target; const isAtThreshold = target.scrollTop + target.clientHeight >= target.scrollHeight - target.clientHeight; const nameGetter = this.searchQuery.length > 0 ? 'sidebar/meetings/hasNextPageSearch' : 'sidebar/meetings/hasNextPage'; const hasNextPage = this.$store.getters[nameGetter](this.chatId); return isAtThreshold && hasNextPage; }, async onScroll(event) { this.contextMenu.destroy(); if (this.isLoading || !this.needToLoadNextPage(event)) { return; } this.isLoading = true; if (this.isSearchQueryMinimumSize) { await this.service.loadNextPage(); } else { await this.serviceSearch.request(); } this.isLoading = false; }, onAddClick() { new im_v2_lib_entityCreator.EntityCreator(this.chatId).createMeetingForChat(); }, loc(phraseCode, replacements = {}) { return this.$Bitrix.Loc.getMessage(phraseCode, replacements); } }, template: ` <div class="bx-im-sidebar-meeting-detail__scope"> <DetailHeader :dialogId="dialogId" :title="loc('IM_SIDEBAR_MEETING_DETAIL_TITLE')" :secondLevel="secondLevel" :withAddButton="showAddButton" :isSearchHeaderOpened="isSearchHeaderOpened" :delayForFocusOnStart="0" withSearch @changeQuery="onChangeQuery" @toggleSearchPanelOpened="toggleSearchPanelOpened" @addClick="onAddClick" @back="onBackClick" /> <div class="bx-im-sidebar-meeting-detail__container bx-im-sidebar-detail__container" @scroll="onScroll"> <div v-for="dateGroup in formattedCollection" class="bx-im-sidebar-meeting-detail__date-group_container"> <DateGroup :dateText="dateGroup.dateGroupTitle" /> <MeetingItem v-for="meeting in dateGroup.items" :meeting="meeting" :searchQuery="searchQuery" @contextMenuClick="onContextMenuClick" /> </div> <TariffLimit v-if="hasHistoryLimit" :dialogId="dialogId" :panel="SidebarDetailBlock.meeting" class="bx-im-sidebar-meeting-detail__tariff-limit-container" /> <template v-if="!isLoading"> <template v-if="isSearchHeaderOpened"> <StartState v-if="preparedQuery.length === 0" :title="loc('IM_SIDEBAR_SEARCH_MESSAGE_START_TITLE')" :iconType="SidebarDetailBlock.messageSearch" /> <DetailEmptySearchState v-else-if="isEmptyState" :title="loc('IM_SIDEBAR_MESSAGE_SEARCH_NOT_FOUND_EXTENDED')" :subTitle="loc('IM_SIDEBAR_MESSAGE_SEARCH_NOT_FOUND_DESCRIPTION_EXTENDED')" /> </template> <DetailEmptyState v-else-if="isEmptyState" :title="loc('IM_SIDEBAR_MEETINGS_EMPTY')" :iconType="SidebarDetailBlock.meeting" /> </template> <Loader v-if="isLoading" class="bx-im-sidebar-detail__loader-container" /> </div> </div> ` }; // @vue/component const DetailUser = { name: 'DetailUser', components: { ChatAvatar: im_v2_component_elements_avatar.ChatAvatar, ChatTitle: im_v2_component_elements_chatTitle.ChatTitle }, props: { dialogId: { type: String, required: true }, contextDialogId: { type: String, required: true }, isOwner: { type: Boolean, default: false }, isManager: { type: Boolean, default: false } }, data() { return { showContextButton: false }; }, computed: { AvatarSize: () => im_v2_component_elements_avatar.AvatarSize, position() { if (this.isCopilot) { return this.$store.getters['copilot/getProvider']; } return this.$store.getters['users/getPosition'](this.dialogId); }, user() { return this.$store.getters['users/get'](this.dialogId, true); }, userLink() { return im_v2_lib_utils.Utils.user.getProfileLink(this.dialogId); }, needContextMenu() { const bot = this.$store.getters['users/bots/getByUserId'](this.dialogId); if (!bot) { return true; } return bot.code !== 'copilot'; }, isCopilot() { const userId = Number.parseInt(this.dialogId, 10); return this.$store.getters['users/bots/isCopilot'](userId); }, hasLink() { return !this.isCopilot; } }, methods: { onClickContextMenu(event) { this.$emit('contextMenuClick', { userDialogId: this.dialogId, target: event.currentTarget }); } }, template: ` <div class="bx-im-sidebar-main-detail__user" @mouseover="showContextButton = true" @mouseleave="showContextButton = false" > <div class="bx-im-sidebar-main-detail__avatar-container"> <ChatAvatar :size="AvatarSize.L" :avatarDialogId="dialogId" :contextDialogId="contextDialogId" /> <span v-if="isOwner" class="bx-im-sidebar-main-detail__avatar-owner-icon"></span> <span v-else-if="isManager" class="bx-im-sidebar-main-detail__avatar-manager-icon"></span> </div> <div class="bx-im-sidebar-main-detail__user-info-container"> <div class="bx-im-sidebar-main-detail__user-title-container"> <a v-if="hasLink" :href="userLink" target="_blank" class="bx-im-sidebar-main-detail__user-title-link"> <ChatTitle :dialogId="dialogId" :withLeftIcon="!isCopilot" /> </a> <div v-else class="bx-im-sidebar-main-detail__user-title-link"> <ChatTitle :dialogId="dialogId" :withLeftIcon="!isCopilot" /> </div> <div v-if="needContextMenu && showContextButton" class="bx-im-sidebar-main-detail__context-menu-icon bx-im-messenger__context-menu-icon" @click="onClickContextMenu" ></div> </div> <div class="bx-im-sidebar-main-detail__position-text" :title="position"> {{ position }} </div> </div> </div> ` }; class MembersMenu extends im_v2_lib_menu.UserMenu { constructor() { super(); this.chatService = new im_v2_provider_service_chat.ChatService(); this.callManager = im_v2_lib_call.CallManager.getInstance(); this.permissionManager = im_v2_lib_permission.PermissionManager.getInstance(); } getMenuItems() { if (this.context.user.id === im_v2_application_core.Core.getUserId()) { return [this.getProfileItem(), this.getOpenUserCalendarItem(), this.getLeaveItem()]; } return [this.getMentionItem(), this.getSendItem(), this.getManagerItem(), this.getCallItem(), this.getProfileItem(), this.getOpenUserCalendarItem(), this.getKickItem()]; } getManagerItem() { const isOwner = this.context.user.id === this.context.dialog.ownerId; const canChangeManagers = im_v2_lib_permission.PermissionManager.getInstance().canPerformActionByRole(im_v2_const.ActionByRole.changeManagers, this.context.dialog.dialogId); const isCollabType = this.context.dialog.type === im_v2_const.ChatType.collab; if (isOwner || !canChangeManagers || isCollabType) { return null; } const isManager = this.context.dialog.managerList.includes(this.context.user.id); return { text: isManager ? main_core.Loc.getMessage('IM_SIDEBAR_MENU_MANAGER_REMOVE') : main_core.Loc.getMessage('IM_SIDEBAR_MENU_MANAGER_ADD'), onclick: () => { if (isManager) { this.chatService.removeManager(this.context.dialog.dialogId, this.context.user.id); } else { this.chatService.addManager(this.context.dialog.dialogId, this.context.user.id); } this.menuInstance.close(); } }; } getCallItem() { const userDialogId = this.context.user.id.toString(); const chatCanBeCalled = this.callManager.chatCanBeCalled(userDialogId); const chatIsAllowedToCall = this.permissionManager.canPerformActionByRole(im_v2_const.ActionByRole.call, userDialogId); if (!chatCanBeCalled || !chatIsAllowedToCall) { return null; } return { text: main_core.Loc.getMessage('IM_LIB_MENU_CALL_2'), onclick: () => { this.callManager.startCall(userDialogId); this.menuInstance.close(); } }; } getOpenUserCalendarItem() { if (this.isBot()) { return null; } const profileUri = im_v2_lib_utils.Utils.user.getCalendarLink(this.context.user.id); const isCurrentUser = this.context.user.id === im_v2_application_core.Core.getUserId(); const phraseCode = isCurrentUser ? 'IM_LIB_MENU_OPEN_OWN_CALENDAR' : 'IM_LIB_MENU_OPEN_CALENDAR_V2'; return { text: main_core.Loc.getMessage(phraseCode), onclick: () => { BX.SidePanel.Instance.open(profileUri); this.menuInstance.close(); } }; } getLeaveItem() { if (this.isCollabChat() && !this.canLeaveCollab()) { return null; } const canLeaveChat = this.permissionManager.canPerformActionByRole(im_v2_const.ActionByRole.leave, this.context.dialog.dialogId); if (!canLeaveChat) { return null; } return { text: main_core.Loc.getMessage('IM_LIB_MENU_LEAVE_MSGVER_1'), onclick: async () => { this.menuInstance.close(); const userChoice = await im_v2_lib_confirm.showLeaveChatConfirm(this.context.dialog.dialogId); if (!userChoice) { return; } if (this.isCollabChat()) { this.chatService.leaveCollab(this.context.dialog.dialogId); } else { this.chatService.leaveChat(this.context.dialog.dialogId); } } }; } isBot() { return this.context.user.type === im_v2_const.UserType.bot; } canLeaveCollab() { return this.permissionManager.canPerformActionByUserType(im_v2_const.ActionByUserType.leaveCollab); } } const MemberTitleByChatType = { [im_v2_const.ChatType.channel]: 'IM_SIDEBAR_MEMBERS_CHANNEL_DETAIL_TITLE', [im_v2_const.ChatType.openChannel]: 'IM_SIDEBAR_MEMBERS_CHANNEL_DETAIL_TITLE', [im_v2_const.ChatType.generalChannel]: 'IM_SIDEBAR_MEMBERS_CHANNEL_DETAIL_TITLE', default: 'IM_SIDEBAR_MEMBERS_DETAIL_TITLE' }; // @vue/component const MembersPanel = { name: 'MembersPanel', components: { DetailUser, ChatButton: im_v2_component_elements_button.ChatButton, DetailHeader, Loader: im_v2_component_elements_loader.Loader, AddToChat: im_v2_component_entitySelector.AddToChat }, props: { dialogId: { type: String, required: true }, secondLevel: { type: Boolean, default: false } }, data() { return { isLoading: false, showAddToChatPopup: false, showAddToChatTarget: null }; }, computed: { SidebarDetailBlock: () => im_v2_const.SidebarDetailBlock, ButtonSize: () => im_v2_component_elements_button.ButtonSize, ButtonColor: () => im_v2_component_elements_button.ButtonColor, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, userDialogIds() { const users = this.$store.getters['sidebar/members/get'](this.chatId); return users.map(userId => userId.toString()); }, chatLink() { const layoutName = im_v2_lib_layout.LayoutManager.getInstance().getLayout().name; const isCopilot = layoutName === im_v2_const.Layout.copilot.name; const chatGetParameter = isCopilot ? im_v2_const.GetParameter.openCopilotChat : im_v2_const.GetParameter.openChat; const getParams = new URLSearchParams({ [chatGetParameter]: this.dialogId }); return `${im_v2_application_core.Core.getHost()}${im_v2_const.Path.online}?${getParams.toString()}`; }, hasNextPage() { return this.$store.getters['sidebar/members/hasNextPage'](this.chatId); }, panelInited() { return this.$store.getters['sidebar/members/getInited'](this.chatId); }, chatId() { return this.dialog.chatId; }, title() { var _MemberTitleByChatTyp; let usersInChatCount = this.dialog.userCounter; if (usersInChatCount >= 1000) { usersInChatCount = `${Math.floor(usersInChatCount / 1000)}k`; } const phrase = (_MemberTitleByChatTyp = MemberTitleByChatType[this.dialog.type]) != null ? _MemberTitleByChatTyp : MemberTitleByChatType.default; return this.loc(phrase, { '#NUMBER#': usersInChatCount }); }, needAddButton() { return im_v2_lib_permission.PermissionManager.getInstance().canPerformActionByRole(im_v2_const.ActionByRole.extend, this.dialogId); }, needCopyLinkButton() { return this.dialog.type !== im_v2_const.ChatType.collab; }, addMembersPopupComponent() { return this.dialog.type === im_v2_const.ChatType.collab ? im_v2_component_entitySelector.AddToCollab : im_v2_component_entitySelector.AddToChat; } }, watch: { dialogId(dialogId) { this.service = new MembersService({ dialogId }); void this.loadFirstPage(); } }, created() { this.contextMenu = new MembersMenu(); this.service = new MembersService({ dialogId: this.dialogId }); void this.loadFirstPage(); }, beforeUnmount() { this.contextMenu.destroy(); }, methods: { async loadFirstPage() { if (this.panelInited || this.isLoading) { return; } this.isLoading = true; this.chats = await this.service.loadFirstPage(); this.isLoading = false; }, isOwner(userDialogId) { const userId = Number.parseInt(userDialogId, 10); return this.dialog.ownerId === userId; }, isManager(userDialogId) { const userId = Number.parseInt(userDialogId, 10); return this.dialog.managerList.includes(userId); }, onContextMenuClick(event) { const user = this.$store.getters['users/get'](event.userDialogId, true); const item = { user, dialog: this.dialog }; this.contextMenu.openMenu(item, event.target); }, onCopyInviteClick() { if (BX.clipboard.copy(this.chatLink)) { im_v2_lib_notifier.Notifier.onCopyLinkComplete(); } }, onBackClick() { main_core_events.EventEmitter.emit(im_v2_const.EventType.sidebar.close, { panel: im_v2_const.SidebarDetailBlock.members }); }, needToLoadNextPage(event) { const target = event.target; const isAtThreshold = target.scrollTop + target.clientHeight >= target.scrollHeight - target.clientHeight; return isAtThreshold && this.hasNextPage; }, async onScroll(event) { this.contextMenu.destroy(); if (this.isLoading || !this.needToLoadNextPage(event)) { return; } this.isLoading = true; await this.service.loadNextPage(); this.isLoading = false; }, onAddClick(event) { im_v2_lib_analytics.Analytics.getInstance().userAdd.onChatSidebarClick(this.dialogId); this.showAddToChatPopup = true; this.showAddToChatTarget = event.target; }, loc(phraseCode, replacements = {}) { return this.$Bitrix.Loc.getMessage(phraseCode, replacements); } }, template: ` <div class="bx-im-sidebar-main-detail__scope"> <DetailHeader :dialogId="dialogId" :title="title" :secondLevel="secondLevel" :withAddButton="needAddButton" @addClick="onAddClick" @back="onBackClick" /> <div class="bx-im-sidebar-detail__container bx-im-sidebar-main-detail__container" @scroll="onScroll"> <div v-if="needCopyLinkButton" class="bx-im-sidebar-main-detail__invitation-button-container"> <ChatButton :text="loc('IM_SIDEBAR_COPY_INVITE_LINK')" :size="ButtonSize.M" :color="ButtonColor.PrimaryBorder" :isRounded="true" :isUppercase="false" icon="link" @click="onCopyInviteClick" /> </div> <DetailUser v-for="userDialogId in userDialogIds" :dialogId="userDialogId" :contextDialogId="dialogId" :isOwner="isOwner(userDialogId)" :isManager="isManager(userDialogId)" @contextMenuClick="onContextMenuClick" /> <Loader v-if="isLoading" class="bx-im-sidebar-detail__loader-container" /> </div> <component v-if="showAddToChatPopup" :is="addMembersPopupComponent" :bindElement="showAddToChatTarget || {}" :dialogId="dialogId" :popupConfig="{offsetTop: 0, offsetLeft: 0}" @close="showAddToChatPopup = false" /> </div> ` }; class FavoriteMenu extends SidebarMenu { constructor() { super(); this.id = 'im-sidebar-context-menu'; } getMenuItems() { return [this.getOpenContextMessageItem(), this.getDeleteFromFavoriteItem()]; } getDeleteFromFavoriteItem() { return { text: main_core.Loc.getMessage('IM_SIDEBAR_MENU_REMOVE_FROM_SAVED_V2'), onclick: function () { const messageService = new im_v2_provider_service_message.MessageService({ chatId: this.context.chatId }); messageService.removeMessageFromFavorite(this.context.messageId); this.menuInstance.close(); }.bind(this) }; } } const REQUEST_ITEMS_LIMIT$c = 50; var _query$4 = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("query"); var _processSearchResponse$4 = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("processSearchResponse"); class FavoriteSearch { constructor({ dialogId }) { Object.defineProperty(this, _processSearchResponse$4, { value: _processSearchResponse2$4 }); this.hasMoreItemsToLoad = true; Object.defineProperty(this, _query$4, { writable: true, value: '' }); this.store = im_v2_application_core.Core.getStore(); this.restClient = im_v2_application_core.Core.getRestClient(); this.dialogId = dialogId; this.chatId = getChatId(dialogId); this.userManager = new im_v2_lib_user.UserManager(); } searchOnServer(query) { if (babelHelpers.classPrivateFieldLooseBase(this, _query$4)[_query$4] !== query) { babelHelpers.classPrivateFieldLooseBase(this, _query$4)[_query$4] = query; this.hasMoreItemsToLoad = true; } return this.request(); } resetSearchState() { babelHelpers.classPrivateFieldLooseBase(this, _query$4)[_query$4] = ''; this.hasMoreItemsToLoad = true; void this.store.dispatch('sidebar/favorites/clearSearch', {}); } async request() { const queryParams = this.getQueryParams(); let responseData = {}; try { const response = await this.restClient.callMethod(im_v2_const.RestMethod.imChatFavoriteGet, queryParams); responseData = response.data(); } catch (error) { console.error('SidebarSearch: Im.imChatFavoriteGet: page request error', error); } return babelHelpers.classPrivateFieldLooseBase(this, _processSearchResponse$4)[_processSearchResponse$4](responseData); } getQueryParams() { const queryParams = { CHAT_ID: this.chatId, LIMIT: REQUEST_ITEMS_LIMIT$c, SEARCH_MESSAGE: babelHelpers.classPrivateFieldLooseBase(this, _query$4)[_query$4] }; const lastId = this.store.getters['sidebar/favorites/getSearchResultCollectionLastId'](this.chatId); if (lastId > 0) { queryParams.LAST_ID = lastId; } return queryParams; } updateModels(resultData) { const { list = [], users = [], files = [], tariffRestrictions = {} } = resultData; const addUsersPromise = this.userManager.setUsersToModel(users); const isHistoryLimitExceeded = Boolean(tariffRestrictions.isHistoryLimitExceeded); const rawMessages = list.map(favorite => favorite.message); const hasNextPage = list.length === REQUEST_ITEMS_LIMIT$c; const lastId = getLastElementId(list); const setFilesPromise = this.store.dispatch('files/set', files); const storeMessagesPromise = this.store.dispatch('messages/store', rawMessages); const setFavoritesPromise = this.store.dispatch('sidebar/favorites/setSearch', { chatId: this.chatId, favorites: list, hasNextPage, lastId, isHistoryLimitExceeded }); return Promise.all([setFilesPromise, storeMessagesPromise, setFavoritesPromise, addUsersPromise]); } } function _processSearchResponse2$4(response) { return this.updateModels(response).then(() => { return response.list.map(message => message.messageId); }); } // @vue/component const FavoriteItem = { name: 'FavoriteItem', components: { MessageAvatar: im_v2_component_elements_avatar.MessageAvatar, MessageAuthorTitle: im_v2_component_elements_chatTitle.MessageAuthorTitle }, props: { favorite: { type: Object, required: true }, chatId: { type: Number, required: true }, dialogId: { type: String, required: true }, searchQuery: { type: String, default: '' } }, emits: ['contextMenuClick'], data() { return { showContextButton: false }; }, computed: { AvatarSize: () => im_v2_component_elements_avatar.AvatarSize, favoriteItem() { return this.favorite; }, favoriteMessage() { return this.$store.getters['messages/getById'](this.favoriteItem.messageId); }, authorDialogId() { return this.favoriteMessage.authorId.toString(); }, messageText() { const purifiedMessage = im_v2_lib_parser.Parser.purifyMessage(this.favoriteMessage); const textToShow = main_core.Text.encode(purifiedMessage); if (this.searchQuery.length === 0) { return textToShow; } return im_v2_lib_textHighlighter.highlightText(textToShow, this.searchQuery); }, isCopilot() { return this.$store.getters['users/bots/isCopilot'](this.favoriteMessage.authorId); } }, methods: { onContextMenuClick(event) { this.$emit('contextMenuClick', { id: this.favoriteItem.id, messageId: this.favorite.messageId, target: event.currentTarget }); }, onItemClick() { main_core_events.EventEmitter.emit(im_v2_const.EventType.dialog.goToMessageContext, { messageId: this.favorite.messageId, dialogId: this.dialogId }); } }, template: ` <div class="bx-im-favorite-item__container bx-im-favorite-item__scope" @click.stop="onItemClick" @mouseover="showContextButton = true" @mouseleave="showContextButton = false" > <div class="bx-im-favorite-item__header-container"> <div class="bx-im-favorite-item__author-container"> <MessageAvatar :messageId="favoriteItem.messageId" :authorId="authorDialogId" :size="AvatarSize.XS" class="bx-im-favorite-item__author-avatar" /> <MessageAuthorTitle :dialogId="authorDialogId" :messageId="favoriteItem.messageId" :withLeftIcon="!isCopilot" :showItsYou="false" class="bx-im-favorite-item__author-text" /> </div> <button v-if="showContextButton" class="bx-im-messenger__context-menu-icon" @click.stop="onContextMenuClick" ></button> </div> <div class="bx-im-favorite-item__message-text" v-html="messageText"></div> </div> ` }; const DEFAULT_MIN_TOKEN_SIZE$8 = 3; // @vue/component const FavoritePanel = { name: 'FavoritePanel', components: { FavoriteItem, DateGroup, StartState: DetailEmptyState, DetailEmptyState, DetailHeader, DetailEmptySearchState, Loader: im_v2_component_elements_loader.Loader, TariffLimit }, props: { dialogId: { type: String, required: true }, secondLevel: { type: Boolean, default: false } }, data() { return { isLoading: false, isSearchHeaderOpened: false, searchQuery: '', searchResult: [], currentServerQueries: 0, minTokenSize: DEFAULT_MIN_TOKEN_SIZE$8 }; }, computed: { SidebarDetailBlock: () => im_v2_const.SidebarDetailBlock, favorites() { if (this.isSearchHeaderOpened) { return this.$store.getters['sidebar/favorites/getSearchResultCollection'](this.chatId); } return this.$store.getters['sidebar/favorites/get'](this.chatId); }, formattedCollection() { return this.collectionFormatter.format(this.favorites); }, isEmptyState() { return this.formattedCollection.length === 0; }, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, chatId() { return this.dialog.chatId; }, preparedQuery() { return this.searchQuery.trim().toLowerCase(); }, isSearchQueryMinimumSize() { return this.preparedQuery.length < this.minTokenSize; }, hasHistoryLimit() { return this.$store.getters['sidebar/favorites/isHistoryLimitExceeded'](this.chatId); } }, watch: { preparedQuery(newQuery, previousQuery) { if (newQuery === previousQuery) { return; } this.cleanSearchResult(); this.startSearch(); } }, created() { this.initSettings(); this.collectionFormatter = new SidebarCollectionFormatter(); this.contextMenu = new FavoriteMenu(); this.service = new Favorite({ dialogId: this.dialogId }); this.serviceSearch = new FavoriteSearch({ dialogId: this.dialogId }); this.searchOnServerDelayed = main_core.Runtime.debounce(this.searchOnServer, 500, this); }, beforeUnmount() { this.contextMenu.destroy(); this.collectionFormatter.destroy(); }, methods: { initSettings() { const settings = main_core.Extension.getSettings('im.v2.component.sidebar'); this.minTokenSize = settings.get('minSearchTokenSize', DEFAULT_MIN_TOKEN_SIZE$8); }, searchOnServer(query) { this.currentServerQueries++; this.serviceSearch.searchOnServer(query).then(() => { if (query !== this.preparedQuery) { this.isLoading = false; } }).catch(error => { console.error(error); }).finally(() => { this.currentServerQueries--; this.stopLoader(); if (this.isSearchQueryMinimumSize) { this.cleanSearchResult(); } }); }, stopLoader() { if (this.currentServerQueries > 0) { return; } this.isLoading = false; }, startSearch() { if (this.isSearchQueryMinimumSize) { this.cleanSearchResult(); } else { this.isLoading = true; this.searchOnServerDelayed(this.preparedQuery); } }, cleanSearchResult() { this.searchResult = []; this.serviceSearch.resetSearchState(); }, onChangeQuery(query) { this.searchQuery = query; }, toggleSearchPanelOpened() { this.isSearchHeaderOpened = !this.isSearchHeaderOpened; }, onContextMenuClick(event) { const item = { id: event.id, messageId: event.messageId, dialogId: this.dialogId, chatId: this.chatId }; this.contextMenu.openMenu(item, event.target); }, onBackClick() { main_core_events.EventEmitter.emit(im_v2_const.EventType.sidebar.close, { panel: im_v2_const.SidebarDetailBlock.favorite }); }, needToLoadNextPage(event) { const target = event.target; const isAtThreshold = target.scrollTop + target.clientHeight >= target.scrollHeight - target.clientHeight; const nameGetter = this.searchQuery.length > 0 ? 'sidebar/favorites/hasNextPageSearch' : 'sidebar/favorites/hasNextPage'; const hasNextPage = this.$store.getters[nameGetter](this.chatId); return isAtThreshold && hasNextPage; }, async onScroll(event) { this.contextMenu.destroy(); if (this.isLoading || !this.needToLoadNextPage(event)) { return; } this.isLoading = true; if (this.isSearchQueryMinimumSize) { await this.service.loadNextPage(); } else { await this.serviceSearch.request(); } this.isLoading = false; }, loc(phraseCode, replacements = {}) { return this.$Bitrix.Loc.getMessage(phraseCode, replacements); } }, template: ` <div class="bx-im-sidebar-favorite-detail__scope"> <DetailHeader :dialogId="dialogId" :title="loc('IM_SIDEBAR_FAVORITE_DETAIL_TITLE')" :secondLevel="secondLevel" :isSearchHeaderOpened="isSearchHeaderOpened" :delayForFocusOnStart="0" @changeQuery="onChangeQuery" @toggleSearchPanelOpened="toggleSearchPanelOpened" withSearch @back="onBackClick" /> <div class="bx-im-sidebar-favorite-detail__container bx-im-sidebar-detail__container" @scroll="onScroll"> <div v-for="dateGroup in formattedCollection" class="bx-im-sidebar-favorite-detail__date-group_container" > <DateGroup :dateText="dateGroup.dateGroupTitle" /> <FavoriteItem v-for="favorite in dateGroup.items" :favorite="favorite" :chatId="chatId" :dialogId="dialogId" :searchQuery="searchQuery" @contextMenuClick="onContextMenuClick" /> </div> <TariffLimit v-if="hasHistoryLimit" :dialogId="dialogId" :panel="SidebarDetailBlock.favorite" class="bx-im-sidebar-favorite-detail__tariff-limit-container" /> <template v-if="!isLoading"> <template v-if="isSearchHeaderOpened"> <StartState v-if="preparedQuery.length === 0" :title="loc('IM_SIDEBAR_SEARCH_MESSAGE_START_TITLE')" :iconType="SidebarDetailBlock.messageSearch" /> <DetailEmptySearchState v-else-if="isEmptyState" :title="loc('IM_SIDEBAR_MESSAGE_SEARCH_NOT_FOUND_EXTENDED')" :subTitle="loc('IM_SIDEBAR_MESSAGE_SEARCH_NOT_FOUND_DESCRIPTION_EXTENDED')" /> </template> <DetailEmptyState v-else-if="isEmptyState" :title="loc('IM_SIDEBAR_FAVORITES_EMPTY')" :iconType="SidebarDetailBlock.favorite" /> </template> <Loader v-if="isLoading" class="bx-im-sidebar-detail__loader-container" /> </div> </div> ` }; const REQUEST_ITEMS_LIMIT$d = 50; var _lastMessageId = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("lastMessageId"); var _query$5 = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("query"); var _request = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("request"); var _processSearchResponse$5 = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("processSearchResponse"); var _updateModels$1 = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("updateModels"); class MessageSearch { // eslint-disable-next-line no-unused-private-class-members constructor({ dialogId }) { Object.defineProperty(this, _updateModels$1, { value: _updateModels2$1 }); Object.defineProperty(this, _processSearchResponse$5, { value: _processSearchResponse2$5 }); Object.defineProperty(this, _request, { value: _request2 }); this.hasMoreItemsToLoad = true; Object.defineProperty(this, _lastMessageId, { writable: true, value: 0 }); Object.defineProperty(this, _query$5, { writable: true, value: '' }); this.store = im_v2_application_core.Core.getStore(); this.restClient = im_v2_application_core.Core.getRestClient(); this.dialogId = dialogId; this.chatId = getChatId(dialogId); this.userManager = new im_v2_lib_user.UserManager(); } searchOnServer(query) { if (babelHelpers.classPrivateFieldLooseBase(this, _query$5)[_query$5] !== query) { babelHelpers.classPrivateFieldLooseBase(this, _query$5)[_query$5] = query; this.hasMoreItemsToLoad = true; babelHelpers.classPrivateFieldLooseBase(this, _lastMessageId)[_lastMessageId] = 0; } return babelHelpers.classPrivateFieldLooseBase(this, _request)[_request](); } loadNextPage() { return babelHelpers.classPrivateFieldLooseBase(this, _request)[_request](); } loadFirstPage() { return Promise.resolve(); } resetSearchState() { babelHelpers.classPrivateFieldLooseBase(this, _lastMessageId)[_lastMessageId] = 0; babelHelpers.classPrivateFieldLooseBase(this, _query$5)[_query$5] = ''; this.hasMoreItemsToLoad = true; } } function _request2() { const config = { SEARCH_MESSAGE: babelHelpers.classPrivateFieldLooseBase(this, _query$5)[_query$5], CHAT_ID: this.chatId }; if (babelHelpers.classPrivateFieldLooseBase(this, _lastMessageId)[_lastMessageId] > 0) { config.LAST_ID = babelHelpers.classPrivateFieldLooseBase(this, _lastMessageId)[_lastMessageId]; } return new Promise((resolve, reject) => { this.restClient.callMethod(im_v2_const.RestMethod.imDialogMessagesSearch, config).then(response => { const responseData = response.data(); resolve(babelHelpers.classPrivateFieldLooseBase(this, _processSearchResponse$5)[_processSearchResponse$5](responseData)); }).catch(error => reject(error)); }); } function _processSearchResponse2$5(response) { babelHelpers.classPrivateFieldLooseBase(this, _lastMessageId)[_lastMessageId] = getLastElementId(response.messages); if (response.messages.length < REQUEST_ITEMS_LIMIT$d) { this.hasMoreItemsToLoad = false; } return babelHelpers.classPrivateFieldLooseBase(this, _updateModels$1)[_updateModels$1](response).then(() => { return response.messages.map(message => message.id); }); } function _updateModels2$1(rawData) { const { files, users, usersShort, reactions, additionalMessages, messages, tariffRestrictions = {} } = rawData; const isHistoryLimitExceeded = Boolean(tariffRestrictions.isHistoryLimitExceeded); const historyLimitPromise = this.store.dispatch('sidebar/messageSearch/setHistoryLimitExceeded', { chatId: this.chatId, isHistoryLimitExceeded }); const usersPromise = Promise.all([this.userManager.setUsersToModel(users), this.userManager.addUsersToModel(usersShort)]); const filesPromise = this.store.dispatch('files/set', files); const reactionsPromise = this.store.dispatch('messages/reactions/set', reactions); const additionalMessagesPromise = this.store.dispatch('messages/store', additionalMessages); const messagesPromise = this.store.dispatch('messages/store', messages); return Promise.all([filesPromise, usersPromise, reactionsPromise, additionalMessagesPromise, messagesPromise, historyLimitPromise]); } // @vue/component const SearchItem = { name: 'SearchItem', components: { ChatAvatar: im_v2_component_elements_avatar.ChatAvatar, ChatTitle: im_v2_component_elements_chatTitle.ChatTitle }, props: { messageId: { type: [String, Number], required: true }, dialogId: { type: String, required: true }, query: { type: String, default: '' } }, computed: { AvatarSize: () => im_v2_component_elements_avatar.AvatarSize, message() { return this.$store.getters['messages/getById'](this.messageId); }, authorDialogId() { return this.message.authorId.toString(); }, isSystem() { return this.message.authorId === 0; }, messageText() { const purifiedMessage = im_v2_lib_parser.Parser.purifyMessage(this.message); return im_v2_lib_textHighlighter.highlightText(main_core.Text.encode(purifiedMessage), this.query); } }, methods: { onItemClick() { main_core_events.EventEmitter.emit(im_v2_const.EventType.dialog.goToMessageContext, { messageId: this.messageId, dialogId: this.dialogId }); }, onMessageBodyClick(event) { if (event.target.tagName === 'A') { event.stopPropagation(); } } }, template: ` <div class="bx-im-message-search-item__container bx-im-message-search-item__scope" @click.stop="onItemClick" > <div class="bx-im-message-search-item__header-container"> <div class="bx-im-message-search-item__author-container"> <template v-if="!isSystem"> <ChatAvatar :size="AvatarSize.XS" :avatarDialogId="authorDialogId" :contextDialogId="dialogId" class="bx-im-message-search-item__author-avatar" /> <ChatTitle :dialogId="authorDialogId" :showItsYou="false" class="bx-im-message-search-item__author-text" /> </template> <template v-else> <span class="bx-im-message-search-item__system-author"> {{ $Bitrix.Loc.getMessage('IM_SIDEBAR_SYSTEM_MESSAGE') }} </span> </template> </div> </div> <div class="bx-im-message-search-item__message-text" v-html="messageText" @click="onMessageBodyClick"></div> </div> ` }; // @vue/component const SearchHeader = { name: 'SearchHeader', components: { SearchInput: im_v2_component_elements_searchInput.SearchInput }, props: { secondLevel: { type: Boolean, default: false } }, emits: ['back', 'changeQuery'], template: ` <div class="bx-im-sidebar-search-header__container bx-im-sidebar-search-header__scope"> <div class="bx-im-sidebar-search-header__title-container"> <button :class="{'bx-im-messenger__cross-icon': !secondLevel, 'bx-im-sidebar__back-icon': secondLevel}" @click="$emit('back')" ></button> <SearchInput :placeholder="$Bitrix.Loc.getMessage('IM_SIDEBAR_SEARCH_MESSAGE_PLACEHOLDER')" :withIcon="false" :delayForFocusOnStart="300" @queryChange="$emit('changeQuery', $event)" class="bx-im-sidebar-search-header__input" /> </div> </div> ` }; // @vue/component const MessageSearchPanel = { name: 'MessageSearchPanel', components: { DateGroup, SearchItem, Loader: im_v2_component_elements_loader.Loader, StartState: DetailEmptyState, SearchHeader, DetailEmptySearchState, TariffLimit }, props: { dialogId: { type: String, required: true }, secondLevel: { type: Boolean, default: false } }, data() { return { searchQuery: '', isLoading: false, searchResult: [], currentServerQueries: 0 }; }, computed: { SidebarDetailBlock: () => im_v2_const.SidebarDetailBlock, formattedCollection() { const messages = this.searchResult.map(messageId => { return this.$store.getters['messages/getById'](messageId); }).filter(item => Boolean(item)); return this.collectionFormatter.format(messages); }, isEmptyState() { return this.preparedQuery.length > 0 && this.formattedCollection.length === 0; }, preparedQuery() { return this.searchQuery.trim().toLowerCase(); }, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, chatId() { return this.dialog.chatId; }, hasHistoryLimit() { return this.$store.getters['sidebar/messageSearch/isHistoryLimitExceeded'](this.chatId); } }, watch: { preparedQuery(newQuery, previousQuery) { if (newQuery === previousQuery) { return; } this.service.resetSearchState(); this.searchResult = []; this.startSearch(newQuery); } }, created() { this.service = new MessageSearch({ dialogId: this.dialogId }); this.collectionFormatter = new SidebarCollectionFormatter(); this.searchOnServerDelayed = main_core.Runtime.debounce(this.searchOnServer, 500, this); }, beforeUnmount() { this.collectionFormatter.destroy(); }, methods: { searchOnServer(query) { this.currentServerQueries++; this.service.searchOnServer(query).then(messageIds => { if (query !== this.preparedQuery) { this.isLoading = false; return; } this.searchResult = this.mergeResult(messageIds); }).catch(error => { console.error(error); }).finally(() => { this.currentServerQueries--; this.stopLoader(); }); }, startSearch(query) { if (query.length < 3) { return; } if (query.length >= 3) { this.isLoading = true; this.searchOnServerDelayed(query); } if (query.length === 0) { this.cleanSearchResult(); } }, stopLoader() { if (this.currentServerQueries > 0) { return; } this.isLoading = false; }, cleanSearchResult() { this.searchResult = []; }, needToLoadNextPage(event) { const target = event.target; return target.scrollTop + target.clientHeight >= target.scrollHeight - target.clientHeight; }, onScroll(event) { if (this.isLoading || this.preparedQuery.length === 0) { return; } if (!this.needToLoadNextPage(event) || !this.service.hasMoreItemsToLoad) { return; } this.isLoading = true; this.service.loadNextPage().then(messageIds => { this.searchResult = this.mergeResult(messageIds); this.isLoading = false; }).catch(error => { im_v2_lib_logger.Logger.warn('Message Search: loadNextPage error', error); }); }, mergeResult(messageIds) { return [...this.searchResult, ...messageIds].sort((a, z) => z - a); }, onChangeQuery(query) { this.searchQuery = query; }, onClickBack() { main_core_events.EventEmitter.emit(im_v2_const.EventType.sidebar.close, { panel: im_v2_const.SidebarDetailBlock.messageSearch }); }, loc(phraseCode, replacements = {}) { return this.$Bitrix.Loc.getMessage(phraseCode, replacements); } }, template: ` <div class="bx-im-message-search-detail__scope"> <SearchHeader :secondLevel="secondLevel" @changeQuery="onChangeQuery" @back="onClickBack" /> <div class="bx-im-message-search-detail__container bx-im-sidebar-detail__container" @scroll="onScroll"> <StartState v-if="!isLoading && preparedQuery.length === 0" :title="loc('IM_SIDEBAR_SEARCH_MESSAGE_START_TITLE')" :iconType="SidebarDetailBlock.messageSearch" /> <DetailEmptySearchState v-if="!isLoading && isEmptyState" :title="loc('IM_SIDEBAR_MESSAGE_SEARCH_NOT_FOUND')" :subTitle="loc('IM_SIDEBAR_MESSAGE_SEARCH_NOT_FOUND_DESCRIPTION')" /> <Loader v-if="isLoading && isEmptyState" class="bx-im-message-search-detail__loader" /> <div v-for="dateGroup in formattedCollection" class="bx-im-message-search-detail__date-group_container"> <DateGroup :dateText="dateGroup.dateGroupTitle" /> <SearchItem v-for="item in dateGroup.items" :messageId="item.id" :dialogId="dialogId" :query="preparedQuery" /> </div> <TariffLimit v-if="hasHistoryLimit" :dialogId="dialogId" :panel="SidebarDetailBlock.messageSearch" class="bx-im-message-search-detail__tariff-limit-container" /> </div> </div> ` }; const ItemTextByChatType = { [im_v2_const.ChatType.channel]: main_core.Loc.getMessage('IM_SIDEBAR_CHAT_TYPE_CHANNEL'), [im_v2_const.ChatType.openChannel]: main_core.Loc.getMessage('IM_SIDEBAR_CHAT_TYPE_CHANNEL'), [im_v2_const.ChatType.generalChannel]: main_core.Loc.getMessage('IM_SIDEBAR_CHAT_TYPE_CHANNEL'), [im_v2_const.ChatType.collab]: main_core.Loc.getMessage('IM_SIDEBAR_CHAT_TYPE_COLLAB'), default: main_core.Loc.getMessage('IM_SIDEBAR_CHAT_TYPE_GROUP_V2') }; // @vue/component const ChatItem = { name: 'ChatItem', components: { ChatAvatar: im_v2_component_elements_avatar.ChatAvatar, ChatTitle: im_v2_component_elements_chatTitle.ChatTitle }, props: { dialogId: { type: String, required: true }, dateMessage: { type: String, default: '' } }, emits: ['clickItem'], computed: { AvatarSize: () => im_v2_component_elements_avatar.AvatarSize, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, chatItemText() { var _ItemTextByChatType$t; return (_ItemTextByChatType$t = ItemTextByChatType[this.dialog.type]) != null ? _ItemTextByChatType$t : ItemTextByChatType.default; }, formattedDate() { if (!this.dateMessage) { return ''; } const date = im_v2_lib_utils.Utils.date.cast(this.dateMessage); return this.formatDate(date); } }, methods: { onClick(event) { this.$emit('clickItem', { dialogId: this.dialogId, nativeEvent: event }); }, formatDate(date) { return im_v2_lib_dateFormatter.DateFormatter.formatByTemplate(date, im_v2_lib_dateFormatter.DateTemplate.recent); } }, template: ` <div @click="onClick" class="bx-im-chat-with-user-item__container bx-im-chat-with-user-item__scope" > <div class="bx-im-chat-with-user-item__avatar-container"> <ChatAvatar :avatarDialogId="dialogId" :contextDialogId="dialogId" :size="AvatarSize.XL" /> </div> <div class="bx-im-chat-with-user-item__content-container"> <div class="bx-im-chat-with-user-item__content_header"> <ChatTitle :dialogId="dialogId" /> <div v-if="formattedDate.length > 0" class="bx-im-chat-with-user-item__date"> <span>{{ formattedDate }}</span> </div> </div> <div class="bx-im-chat-with-user-item__item-text" :title="chatItemText"> {{ chatItemText }} </div> </div> </div> ` }; const REQUEST_ITEMS_LIMIT$e = 50; var _chatsCount = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("chatsCount"); var _getRequestParams = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("getRequestParams"); var _requestPage = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("requestPage"); var _handleResponse = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("handleResponse"); var _updateModels$2 = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("updateModels"); var _setDialoguesPromise = /*#__PURE__*/babelHelpers.classPrivateFieldLooseKey("setDialoguesPromise"); class ChatsWithUser { constructor({ dialogId }) { Object.defineProperty(this, _setDialoguesPromise, { value: _setDialoguesPromise2 }); Object.defineProperty(this, _updateModels$2, { value: _updateModels2$2 }); Object.defineProperty(this, _handleResponse, { value: _handleResponse2 }); Object.defineProperty(this, _requestPage, { value: _requestPage2 }); Object.defineProperty(this, _getRequestParams, { value: _getRequestParams2 }); this.hasMoreItemsToLoad = true; Object.defineProperty(this, _chatsCount, { writable: true, value: 0 }); this.store = im_v2_application_core.Core.getStore(); this.restClient = im_v2_application_core.Core.getRestClient(); this.dialogId = dialogId; this.userManager = new im_v2_lib_user.UserManager(); } loadFirstPage() { return babelHelpers.classPrivateFieldLooseBase(this, _requestPage)[_requestPage](); } loadNextPage() { return babelHelpers.classPrivateFieldLooseBase(this, _requestPage)[_requestPage](); } } function _getRequestParams2() { const userId = Number.parseInt(this.dialogId, 10); const requestParams = { filter: { userId }, limit: REQUEST_ITEMS_LIMIT$e }; if (babelHelpers.classPrivateFieldLooseBase(this, _chatsCount)[_chatsCount] > 0) { requestParams.offset = babelHelpers.classPrivateFieldLooseBase(this, _chatsCount)[_chatsCount]; } return requestParams; } async function _requestPage2() { const requestParams = babelHelpers.classPrivateFieldLooseBase(this, _getRequestParams)[_getRequestParams](); const response = await this.restClient.callMethod(im_v2_const.RestMethod.imV2ChatListShared, requestParams); return babelHelpers.classPrivateFieldLooseBase(this, _handleResponse)[_handleResponse](response.data()); } async function _handleResponse2(response) { const { chats } = response; babelHelpers.classPrivateFieldLooseBase(this, _chatsCount)[_chatsCount] += chats.length; if (chats.length < REQUEST_ITEMS_LIMIT$e) { this.hasMoreItemsToLoad = false; } await babelHelpers.classPrivateFieldLooseBase(this, _updateModels$2)[_updateModels$2](chats); return chats.map(chat => { return { dialogId: chat.dialogId, dateMessage: chat.dateMessage }; }); } function _updateModels2$2(chats) { return babelHelpers.classPrivateFieldLooseBase(this, _setDialoguesPromise)[_setDialoguesPromise](chats); } function _setDialoguesPromise2(chats) { return this.store.dispatch('chats/set', chats); } // @vue/component const ChatsWithUserPanel = { name: 'ChatsWithUserPanel', components: { DetailHeader, ChatItem, DetailEmptyState, Loader: im_v2_component_elements_loader.Loader }, props: { dialogId: { type: String, required: true }, secondLevel: { type: Boolean, default: false } }, data() { return { isLoading: false, chats: [] }; }, computed: { SidebarDetailBlock: () => im_v2_const.SidebarDetailBlock, isEmptyState() { return !this.isLoading && this.chats.length === 0; }, dialog() { return this.$store.getters['chats/get'](this.dialogId, true); }, chatId() { return this.dialog.chatId; } }, watch: { dialogId() { this.chats = []; this.service = new ChatsWithUser({ dialogId: this.dialogId }); void this.loadFirstPage(); } }, created() { this.service = new ChatsWithUser({ dialogId: this.dialogId }); void this.loadFirstPage(); }, methods: { onClick(event) { const { dialogId } = event; void im_public.Messenger.openChat(dialogId); }, async loadFirstPage() { this.isLoading = true; this.chats = await this.service.loadFirstPage(); this.isLoading = false; }, needToLoadNextPage(event) { const target = event.target; return target.scrollTop + target.clientHeight >= target.scrollHeight - target.clientHeight; }, async onScroll(event) { if (this.isLoading) { return; } if (!this.needToLoadNextPage(event) || !this.service.hasMoreItemsToLoad) { return; } this.isLoading = true; const nextPageChats = await this.service.loadNextPage(); this.chats = [...this.chats, ...nextPageChats]; this.isLoading = false; }, onBackClick() { main_core_events.EventEmitter.emit(im_v2_const.EventType.sidebar.close, { panel: im_v2_const.SidebarDetailBlock.chatsWithUser }); }, loc(phrase) { return this.$Bitrix.Loc.getMessage(phrase); } }, template: ` <div class="bx-im-sidebar-chats-with-user-detail__scope"> <DetailHeader :dialogId="dialogId" :title="loc('IM_SIDEBAR_SHARED_CHAT_DETAIL_TITLE')" :secondLevel="secondLevel" @back="onBackClick" /> <div class="bx-im-sidebar-chats-with-user-detail__container" @scroll="onScroll" > <ChatItem v-for="chat in chats" :dialogId="chat.dialogId" :dateMessage="chat.dateMessage" @clickItem="onClick" /> <DetailEmptyState v-if="!isLoading && isEmptyState" :title="loc('IM_SIDEBAR_CHATS_WITH_USER_EMPTY')" :iconType="SidebarDetailBlock.messageSearch" /> <Loader v-if="isLoading" class="bx-im-sidebar-chats-with-user-detail__loader-container" /> </div> </div> ` }; // @vue/component const MultidialogItem = { name: 'MultidialogItem', props: { item: { type: Object, required: true } }, computed: { multidialogItem() { return this.item; }, dialogId() { return this.multidialogItem.dialogId; }, chatId() { return this.multidialogItem.chatId; }, title() { const chat = this.$store.getters['chats/get'](this.dialogId); return chat.name; }, status() { return this.multidialogItem.status; }, transferredStatus() { const code = `IM_SIDEBAR_SUPPORT_TICKET_STATUS_${this.status.toUpperCase()}`; return this.loc(code); }, containerClasses() { const status = `--${this.status}`; const chatIsOpened = this.$store.getters['application/isChatOpen'](this.dialogId); return [status, { '--selected': chatIsOpened }]; }, counter() { var _this$$store$getters$; const counter = (_this$$store$getters$ = this.$store.getters['counters/getChatCounterByChatId'](this.chatId)) != null ? _this$$store$getters$ : 0; return counter > 99 ? '99+' : counter; }, formatDate() { const date = this.multidialogItem.date; return im_v2_lib_dateFormatter.DateFormatter.formatByTemplate(date, im_v2_lib_dateFormatter.DateTemplate.recent); } }, methods: { loc(phraseCode) { return this.$Bitrix.Loc.getMessage(phraseCode); } }, template: ` <div class="bx-im-multidialog-item__container bx-im-sidebar-multidialog-preview__scope" :class="containerClasses" :title="title" > <span class="bx-im-multidialog-item__title">{{ title }}</span> <span class="bx-im-multidialog-item__date"> {{ formatDate }} </span> <div class="bx-im-multidialog-item__status"> {{ transferredStatus }} </div> <div v-show="counter" class="bx-im-multidialog-item__count bx-im-sidebar-multidialog-preview__new-message-counter"> {{ counter }} </div> </div> ` }; // @vue/component const MultidialogPanel = { name: 'MultidialogPanel', components: { DetailHeader, MultidialogItem, ChatButton: im_v2_component_elements_button.ChatButton, Loader: im_v2_component_elements_loader.Loader }, props: { dialogId: { type: String, required: true }, secondLevel: { type: Boolean, default: false } }, data() { return { isLoading: false, isCreating: false }; }, computed: { ButtonSize: () => im_v2_component_elements_button.ButtonSize, ButtonColor: () => im_v2_component_elements_button.ButtonColor, SidebarDetailBlock: () => im_v2_const.SidebarDetailBlock, activeMultidialogs() { const multidialogs = this.$store.getters['sidebar/multidialog/getMultidialogsByStatus']([im_v2_const.MultidialogStatus.new, im_v2_const.MultidialogStatus.open]); return multidialogs.sort((a, b) => b.date - a.date); }, closedMultidialogs() { const multidialogs = this.$store.getters['sidebar/multidialog/getMultidialogsByStatus']([im_v2_const.MultidialogStatus.close]); return multidialogs.sort((a, b) => b.date - a.date); }, limitReached() { const openMultidialogs = this.$store.getters['sidebar/multidialog/getMultidialogsByStatus']([im_v2_const.MultidialogStatus.open]); const openSessionsLimit = this.$store.getters['sidebar/multidialog/getOpenSessionsLimit']; return openSessionsLimit <= openMultidialogs.length; }, isInitedDetail() { return this.$store.getters['sidebar/multidialog/isInitedDetail']; }, isDisabledButtonCreate() { return this.limitReached || !this.isInitedDetail; }, buttonCreateTitle() { if (!this.limitReached || !this.isInitedDetail) { return ''; } return this.loc('IM_SIDEBAR_SUPPORT_TICKET_LIMIT'); } }, created() { this.service = new Multidialog(); }, mounted() { void this.loadFirstPage(); }, methods: { loc(phraseCode) { return this.$Bitrix.Loc.getMessage(phraseCode); }, onBackClick() { main_core_events.EventEmitter.emit(im_v2_const.EventType.sidebar.close, { panel: im_v2_const.SidebarDetailBlock.multidialog }); }, needToLoadNextPage(event) { const target = event.target; const isAtThreshold = target.scrollTop + target.clientHeight >= target.scrollHeight - target.clientHeight; const hasNextPage = this.$store.getters['sidebar/multidialog/hasNextPage']; return isAtThreshold && hasNextPage; }, async loadFirstPage() { if (this.isLoading) { return; } this.isLoading = true; await this.service.loadFirstPage(); this.isLoading = false; }, async onScroll(event) { if (this.isLoading || !this.needToLoadNextPage(event)) { return; } this.isLoading = true; await this.service.loadNextPage(); this.isLoading = false; }, async onAddSupport() { if (this.isCreating) { return; } this.isCreating = true; const newDialogId = await this.service.createSupportChat(); if (newDialogId) { this.openChat(newDialogId); } this.isCreating = false; }, openChat(dialogId) { void im_public.Messenger.openChat(dialogId); } }, template: ` <div class="bx-im-sidebar-multidialog-detail__scope"> <DetailHeader :dialogId="dialogId" :title="loc('IM_SIDEBAR_SUPPORT_TICKET_DETAIL_TITLE')" :secondLevel="true" @back="onBackClick" > <template #action> <div :title="buttonCreateTitle" class="bx-im-sidebar-detail-header__add-button"> <ChatButton :text="loc('IM_SIDEBAR_SUPPORT_TICKET_ADD_BUTTON_TEXT')" :size="ButtonSize.S" :color="ButtonColor.PrimaryLight" :isLoading="isCreating" :isDisabled="isDisabledButtonCreate" :isRounded="true" :isUppercase="false" icon="plus" @click="onAddSupport" /> </div> </template> </DetailHeader> <div class="bx-im-sidebar-multidialog-detail__container bx-im-sidebar-detail__container" @scroll="onScroll"> <MultidialogItem v-for="multidialog in activeMultidialogs" :key="multidialog.chatId" :item="multidialog" @click="openChat(multidialog.dialogId)" /> <MultidialogItem v-for="multidialog in closedMultidialogs" :key="multidialog.chatId" :item="multidialog" @click="openChat(multidialog.dialogId)" /> <Loader v-if="isLoading" class="bx-im-sidebar-detail__loader-container" /> </div> </div> ` }; // @vue/component const SidebarPanel = { name: 'SidebarPanel', components: { MainPanel, ChatsWithUserPanel, MembersPanel, FavoritePanel, LinkPanel, FilePanel, TaskPanel, MeetingPanel, MarketPanel, MessageSearchPanel, FileUnsortedPanel, MultidialogPanel }, props: { dialogId: { type: String, required: true }, panel: { type: String, required: true }, secondLevel: { type: Boolean, default: false }, entityId: { type: String, default: '' } }, computed: { panelComponentName() { return `${main_core.Text.capitalize(this.panel)}Panel`; } }, template: ` <div class="bx-im-sidebar-panel__container" :class="{'--second-level': secondLevel}"> <KeepAlive> <component :is="panelComponentName" :dialogId="dialogId" :entityId="entityId" :secondLevel="secondLevel" class="bx-im-sidebar-panel__component" /> </KeepAlive> </div> ` }; // @vue/component const ChatSidebar = { name: 'ChatSidebar', components: { SidebarPanel }, props: { originDialogId: { type: String, required: true }, isActive: { type: Boolean, default: true } }, emits: ['changePanel'], data() { return { needTopLevelTransition: true, needSecondLevelTransition: true, topLevelPanelType: '', topLevelPanelDialogId: '', topLevelPanelStandalone: false, secondLevelPanelType: '', secondLevelPanelDialogId: '', secondLevelPanelEntityId: '', secondLevelPanelStandalone: false }; }, computed: { SidebarDetailBlock: () => im_v2_const.SidebarDetailBlock, topLevelTransitionName() { return this.needTopLevelTransition ? 'top-level-panel' : ''; }, secondLevelTransitionName() { return this.needSecondLevelTransition ? 'second-level-panel' : ''; }, canShowTopPanel() { const membersPanel = this.topLevelPanelType === im_v2_const.SidebarDetailBlock.members; const personalChat = !this.originDialogId.startsWith('chat'); if (membersPanel && personalChat) { return false; } const messageSearchPanel = this.topLevelPanelType === im_v2_const.SidebarDetailBlock.messageSearch; return !messageSearchPanel; }, sidebarOpened() { return this.topLevelPanelType || this.secondLevelPanelType; } }, watch: { originDialogId(newValue, oldValue) { const chatSwitched = Boolean(newValue && oldValue); if (chatSwitched) { this.needTopLevelTransition = false; } if (!this.topLevelPanelStandalone) { this.updateTopPanelOriginDialogId(newValue); } const isSecondLevelPanelOpened = this.secondLevelPanelType.length > 0; if (isSecondLevelPanelOpened && !this.secondLevelPanelStandalone) { this.closeSecondLevelPanel(); } if (!this.canShowTopPanel) { this.closeTopPanel(); } }, topLevelPanelType(newValue, oldValue) { this.needTopLevelTransition = oldValue.length === 0 || newValue.length === 0; const isMainPanelOpened = newValue === im_v2_const.SidebarDetailBlock.main; this.saveSidebarOpenedState(isMainPanelOpened); }, secondLevelPanelType(newValue, oldValue) { this.needSecondLevelTransition = !(newValue && oldValue); } }, created() { im_v2_lib_logger.Logger.warn('ChatSidebar: created'); this.restoreOpenState(); }, mounted() { main_core_events.EventEmitter.subscribe(im_v2_const.EventType.sidebar.open, this.onSidebarOpen); main_core_events.EventEmitter.subscribe(im_v2_const.EventType.sidebar.close, this.onSidebarClose); }, beforeUnmount() { main_core_events.EventEmitter.unsubscribe(im_v2_const.EventType.sidebar.open, this.onSidebarOpen); main_core_events.EventEmitter.unsubscribe(im_v2_const.EventType.sidebar.close, this.onSidebarClose); }, methods: { onSidebarOpen(event) { if (!this.isActive) { return; } const { panel = '', standalone = false, dialogId, entityId = '' } = event.getData(); const needToCloseSecondLevelPanel = !standalone && panel && this.secondLevelPanelType === panel; if (needToCloseSecondLevelPanel) { this.closeSecondLevelPanel(); return; } const needToOpenSecondLevelPanel = this.topLevelPanelType && this.topLevelPanelType !== panel; if (needToOpenSecondLevelPanel) { this.openSecondLevelPanel(panel, dialogId, standalone, entityId); } else { this.openTopPanel(panel, dialogId, standalone); } }, onSidebarClose(event) { if (!this.isActive) { return; } this.needTopLevelTransition = true; const { panel = '' } = event.getData(); const needToCloseSecondLevelPanel = panel && this.secondLevelPanelType === panel; if (needToCloseSecondLevelPanel) { this.closeSecondLevelPanel(); } else { this.closeSecondLevelPanel(); this.closeTopPanel(); } }, restoreOpenState() { const sidebarOpenState = im_v2_lib_localStorage.LocalStorageManager.getInstance().get(im_v2_const.LocalStorageKey.sidebarOpened); if (!sidebarOpenState) { return; } this.openTopPanel(im_v2_const.SidebarDetailBlock.main, this.originDialogId, false); }, saveSidebarOpenedState(sidebarOpened) { const WRITE_TO_STORAGE_TIMEOUT = 200; clearTimeout(this.saveSidebarStateTimeout); this.saveSidebarStateTimeout = setTimeout(() => { im_v2_lib_localStorage.LocalStorageManager.getInstance().set(im_v2_const.LocalStorageKey.sidebarOpened, sidebarOpened); }, WRITE_TO_STORAGE_TIMEOUT); }, openTopPanel(type, dialogId, standalone = false) { this.topLevelPanelType = type; this.topLevelPanelDialogId = dialogId; this.topLevelPanelStandalone = standalone; this.$emit('changePanel', { panel: this.topLevelPanelType }); }, updateTopPanelOriginDialogId(dialogId) { this.topLevelPanelDialogId = dialogId; }, openSecondLevelPanel(type, dialogId, standalone = false, entityId = '') { this.secondLevelPanelType = type; this.secondLevelPanelDialogId = dialogId; this.secondLevelPanelStandalone = standalone; this.secondLevelPanelEntityId = entityId; this.$emit('changePanel', { panel: this.secondLevelPanelType }); }, closeTopPanel() { this.topLevelPanelType = ''; this.topLevelPanelDialogId = ''; this.topLevelPanelStandalone = false; this.$emit('changePanel', { panel: '' }); }, closeSecondLevelPanel() { this.secondLevelPanelType = ''; this.secondLevelPanelDialogId = ''; this.secondLevelPanelStandalone = false; this.$emit('changePanel', { panel: this.topLevelPanelType }); } }, template: ` <div class="bx-im-sidebar__container" :class="{'--opened': sidebarOpened}"> <Transition :name="topLevelTransitionName"> <SidebarPanel v-if="topLevelPanelType" :dialogId="topLevelPanelDialogId" :panel="topLevelPanelType" /> </Transition> <Transition :name="secondLevelTransitionName"> <SidebarPanel v-if="secondLevelPanelType" :dialogId="secondLevelPanelDialogId" :panel="secondLevelPanelType" :entityId="secondLevelPanelEntityId" :secondLevel="true" /> </Transition> </div> ` }; exports.ChatSidebar = ChatSidebar; }((this.BX.Messenger.v2.Component = this.BX.Messenger.v2.Component || {}),BX.Messenger.v2.Lib,BX.Messenger.v2.Lib,BX.Vue3.Directives,BX.UI,BX.Main,BX.Messenger.v2.Lib,BX.Messenger.v2.Component.Elements,BX.Messenger.v2.Component.Elements,BX.Messenger.v2.Lib,BX.Vue3.Directives,BX.Messenger.v2.Component.Elements,BX.Messenger.v2.Lib,BX.UI,BX.UI.Manual,BX.Messenger.v2.Lib,BX.Messenger.v2.Lib,BX.UI.Viewer,BX.Messenger.v2.Service,BX.Messenger.v2.Model,BX.Messenger.v2.Component.Elements,BX,BX,BX,BX.Vue3.Vuex,BX.Messenger.v2.Lib,BX.Messenger.v2.Lib,BX.Messenger.v2.Lib,BX.Messenger.v2.Lib,BX.Messenger.v2.Component.EntitySelector,BX.Messenger.v2.Lib,BX.Messenger.v2.Lib,BX.Messenger.v2.Lib,BX.Messenger.v2.Service,BX.Messenger.v2.Lib,BX.Messenger.v2.Lib,BX.Messenger.v2.Service,BX.Messenger.v2.Lib,BX.Messenger.v2.Lib,BX.Messenger.v2.Lib,BX.Messenger.v2.Component.Elements,BX,BX.Messenger.v2.Lib,BX.Messenger.v2.Component.Elements,BX.Messenger.v2.Component.Elements,BX.Messenger.v2.Lib,BX.Messenger.v2.Application,BX.Event,BX.Messenger.v2.Lib,BX.Messenger.v2.Const,BX.Messenger.v2.Component.Elements,BX.Messenger.v2.Component.Elements,BX.Messenger.v2.Lib)); //# sourceMappingURL=sidebar.bundle.js.map