403Webshell
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/old-chat-embedding/model/src/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/rospirotorg.ru/bitrix/js/im/old-chat-embedding/model/src/recent.js
import {Type} from 'main.core';
import {BuilderModel} from 'ui.vue3.vuex';

import {Core} from 'im.old-chat-embedding.application.core';
import {DialogType, MessageStatus, RecentCallStatus, RecentSettings} from 'im.old-chat-embedding.const';
import {Utils} from 'im.old-chat-embedding.lib.utils';

import type {RecentItem as ImModelRecentItem} from './type/recent-item';
import type {Dialog as ImModelDialog} from './type/dialog';

export class RecentModel extends BuilderModel
{
	getName()
	{
		return 'recent';
	}

	getState()
	{
		return {
			collection: {},
			recentCollection: new Set(),
			unreadCollection: new Set(),
			unloadedChatCounters: {},
			activeCalls: [],
			options: {
				showBirthday: true,
				showInvited: true,
				showLastMessage: true
			}
		};
	}

	getElementState()
	{
		return {
			dialogId: '0',
			message: {
				id: 0,
				senderId: 0,
				date: new Date(),
				status: MessageStatus.received,
				sending: false,
				text: '',
				params: {
					withFile: false,
					withAttach: false,
				}
			},
			draft: {
				text: '',
				date: null
			},
			unread: false,
			pinned: false,
			liked: false,
			invitation: {
				isActive: false,
				originator: 0,
				canResend: false
			},
			options: {}
		};
	}

	getActiveCallDefaultState()
	{
		return {
			dialogId: 0,
			name: '',
			call: {},
			state: RecentCallStatus.waiting
		};
	}

	getGetters()
	{
		return {
			getRecentCollection: (state: RecentState): ImModelRecentItem[] =>
			{
				return [...state.recentCollection].map(id => {
					return state.collection[id];
				});
			},
			getUnreadCollection: (state: RecentState): ImModelRecentItem[] =>
			{
				return [...state.unreadCollection].map(id => {
					return state.collection[id];
				});
			},
			getSortedCollection: (state: RecentState): ImModelRecentItem[] =>
			{
				const collectionAsArray = Object.values(state.collection).filter(item => {
					const isBirthdayPlaceholder = item.options.birthdayPlaceholder;
					const isInvitedUser = item.options.defaultUserRecord;

					return !isBirthdayPlaceholder && !isInvitedUser && item.message.id;
				});

				return [...collectionAsArray].sort((a, b) => {
					return b.message.date - a.message.date;
				});
			},
			get: (state: RecentState) => (dialogId: string): ImModelRecentItem | null =>
			{
				if (Type.isNumber(dialogId))
				{
					dialogId = dialogId.toString();
				}

				if (state.collection[dialogId])
				{
					return state.collection[dialogId];
				}

				return null;
			},

			needsBirthdayPlaceholder: (state: RecentState) => (dialogId): boolean =>
			{
				const currentItem = state.collection[dialogId];
				if (!currentItem)
				{
					return false;
				}

				const dialog = this.store.getters['dialogues/get'](dialogId);
				if (!dialog || dialog.type !== DialogType.user)
				{
					return false;
				}
				const hasBirthday = this.store.getters['users/hasBirthday'](dialogId);
				if (!hasBirthday)
				{
					return false;
				}

				const hasMessage = Utils.text.isTempMessage(currentItem.message.id) || currentItem.message.id > 0;
				const hasTodayMessage = hasMessage && Utils.date.isToday(currentItem.message.date);

				return state.options.showBirthday && !hasTodayMessage && dialog.counter === 0;
			},

			needsVacationPlaceholder: (state: RecentState) => (dialogId): boolean =>
			{
				const currentItem = state.collection[dialogId];
				if (!currentItem)
				{
					return false;
				}

				const dialog = this.store.getters['dialogues/get'](dialogId);
				if (!dialog || dialog.type !== DialogType.user)
				{
					return false;
				}
				const hasVacation = this.store.getters['users/hasVacation'](dialogId);
				if (!hasVacation)
				{
					return false;
				}

				const hasMessage = Utils.text.isTempMessage(currentItem.message.id) || currentItem.message.id > 0;
				const hasTodayMessage = hasMessage && Utils.date.isToday(currentItem.message.date);

				return !hasTodayMessage && dialog.counter === 0;
			},

			getMessageDate: (state: RecentState) => (dialogId): Date | null =>
			{
				const currentItem = state.collection[dialogId];
				if (!currentItem)
				{
					return null;
				}

				if (Type.isDate(currentItem.draft.date) && currentItem.draft.date > currentItem.message.date)
				{
					return currentItem.draft.date;
				}

				const needsBirthdayPlaceholder = this.store.getters['recent/needsBirthdayPlaceholder'](currentItem.dialogId);
				if (needsBirthdayPlaceholder)
				{
					return Utils.date.getStartOfTheDay();
				}

				return currentItem.message.date;
			},

			hasActiveCall: (state: RecentState): boolean =>
			{
				return state.activeCalls.some(item => item.state === RecentCallStatus.joined);
			},

			getOption: (state: RecentState) => (optionName: string): boolean =>
			{
				if (!RecentSettings[optionName])
				{
					return false;
				}

				return state.options[optionName];
			},

			getTotalCounter: (state: RecentState): number =>
			{
				let loadedChatsCounter = 0;
				[...state.recentCollection].forEach(dialogId => {
					const dialog: ImModelDialog = this.store.getters['dialogues/get'](dialogId, true);
					const recentItem: ImModelRecentItem = state.collection[dialogId];

					const isMuted = dialog.muteList.includes(Core.getUserId());
					if (isMuted)
					{
						return;
					}
					const isMarked = recentItem.unread;
					if (dialog.counter === 0 && isMarked)
					{
						loadedChatsCounter++;
						return;
					}
					loadedChatsCounter += dialog.counter;
				});

				let unloadedChatsCounter = 0;
				Object.values(state.unloadedChatCounters).forEach(counter => {
					unloadedChatsCounter += counter;
				});

				return loadedChatsCounter + unloadedChatsCounter;
			}
		};
	}

	getActions()
	{
		return {
			setRecent: (store, payload: Array | Object) =>
			{
				this.store.dispatch('recent/set', payload).then(itemIds => {
					store.commit('setRecentCollection', itemIds);
				});

				if (!Array.isArray(payload) && Type.isPlainObject(payload))
				{
					payload = [payload];
				}
				const zeroedCountersForNewItems = {};
				payload.forEach(item => {
					zeroedCountersForNewItems[item.chat_id] = 0;
				});
				this.store.dispatch('recent/setUnloadedChatCounters', zeroedCountersForNewItems);
			},
			setUnread: (store, payload: Array | Object) =>
			{
				this.store.dispatch('recent/set', payload).then(itemIds => {
					store.commit('setUnreadCollection', itemIds);
				});
			},
			set: (store, payload: Array | Object) =>
			{
				if (!Array.isArray(payload) && Type.isPlainObject(payload))
				{
					payload = [payload];
				}

				const itemsToUpdate = [];
				const itemsToAdd = [];
				payload.map(element => {
					return this.validate(element);
				}).forEach(element => {
					const existingItem = store.state.collection[element.dialogId];
					if (existingItem)
					{
						itemsToUpdate.push({dialogId: existingItem.dialogId, fields: {...element}});
					}
					else
					{
						itemsToAdd.push({...this.getElementState(), ...element});
					}
				});

				if (itemsToAdd.length > 0)
				{
					store.commit('add', itemsToAdd);
				}
				if (itemsToUpdate.length > 0)
				{
					store.commit('update', itemsToUpdate);
				}

				return [...itemsToAdd, ...itemsToUpdate].map(item => item.dialogId);
			},

			update: (store, payload: {id: string | number, fields: Object}) =>
			{
				const {id, fields} = payload;
				const existingItem: ImModelRecentItem = store.state.collection[id];
				if (!existingItem)
				{
					return false;
				}

				if (fields.message)
				{
					fields.message = {...existingItem.message, ...fields.message};
				}
				store.commit('update', {
					dialogId: existingItem.dialogId,
					fields: this.validate(fields)
				});
			},

			unread: (store, payload: {id: string | number, action: boolean}) =>
			{
				const existingItem = store.state.collection[payload.id];
				if (!existingItem)
				{
					return false;
				}

				store.commit('update', {
					dialogId: existingItem.dialogId,
					fields: {unread: payload.action}
				});
			},

			pin: (store, payload: {id: string | number, action: boolean}) =>
			{
				const existingItem = store.state.collection[payload.id];
				if (!existingItem)
				{
					return false;
				}

				store.commit('update', {
					dialogId: existingItem.dialogId,
					fields: {pinned: payload.action}
				});
			},

			like: (store, payload: {id: string | number, messageId: number, liked: boolean}) =>
			{
				const existingItem = store.state.collection[payload.id];
				if (!existingItem)
				{
					return false;
				}

				const isLastMessage = existingItem.message.id === Number.parseInt(payload.messageId, 10);
				const isExactMessageLiked = !Type.isUndefined(payload.messageId) && payload.liked === true;
				if (isExactMessageLiked && !isLastMessage)
				{
					return false;
				}

				store.commit('update', {
					dialogId: existingItem.dialogId,
					fields: {liked: payload.liked === true}
				});
			},

			draft: (store, payload: {id: string | number, text: string}) =>
			{
				const dialog = this.store.getters['dialogues/get'](payload.id);
				if (!dialog)
				{
					return false;
				}

				let existingItem = store.state.collection[payload.id];
				if (!existingItem)
				{
					if (payload.text === '')
					{
						return false;
					}
					const newItem = {
						dialogId: payload.id.toString(),
					};
					store.commit('add', {...this.getElementState(), ...newItem});
					store.commit('setRecentCollection', [newItem.dialogId]);
					existingItem = store.state.collection[payload.id];
				}

				const fields = this.validate({draft: {text: payload.text.toString()}});
				if (fields.draft.text === existingItem.draft.text)
				{
					return false;
				}

				store.commit('update', {
					dialogId: existingItem.dialogId,
					fields
				});
			},

			delete: (store, payload: {id: string | number}) =>
			{
				const existingItem = store.state.collection[payload.id];
				if (!existingItem)
				{
					return false;
				}

				store.commit('delete', {
					id: existingItem.dialogId
				});
				store.commit('deleteFromRecentCollection', existingItem.dialogId);
			},

			addActiveCall: (store, payload) =>
			{
				const existingIndex = store.state.activeCalls.findIndex(item => {
					return item.dialogId === payload.dialogId || item.call.id === payload.call.id;
				});

				if (existingIndex > -1)
				{
					store.commit('updateActiveCall', {
						index: existingIndex,
						fields: this.validateActiveCall(payload)
					});

					return true;
				}

				store.commit('addActiveCall', this.prepareActiveCall(payload));
			},

			updateActiveCall: (store, payload) =>
			{
				const existingIndex = store.state.activeCalls.findIndex(item => {
					return item.dialogId === payload.dialogId;
				});

				store.commit('updateActiveCall', {
					index: existingIndex,
					fields: this.validateActiveCall(payload.fields)
				});
			},

			deleteActiveCall: (store, payload) =>
			{
				const existingIndex = store.state.activeCalls.findIndex(item => {
					return item.dialogId === payload.dialogId;
				});

				if (existingIndex === -1)
				{
					return false;
				}

				store.commit('deleteActiveCall', {
					index: existingIndex
				});
			},

			setOptions: (store, payload) =>
			{
				if (!Type.isPlainObject(payload))
				{
					return false;
				}

				payload = this.validateOptions(payload);
				Object.entries(payload).forEach(([option, value]) => {
					store.commit('setOptions', {
						option,
						value
					});
				});
			},

			clearUnread: (store) =>
			{
				store.commit('clearUnread');
			},

			setUnloadedChatCounters: (store, payload: {[chatId: string]: number}) =>
			{
				if (!Type.isPlainObject(payload))
				{
					return;
				}

				store.commit('setUnloadedChatCounters', payload);
			}
		};
	}

	getMutations()
	{
		return {
			setRecentCollection: (state: RecentState, payload: string[]) => {
				payload.forEach(dialogId => {
					state.recentCollection.add(dialogId);
				});
			},
			deleteFromRecentCollection: (state: RecentState, payload: string) => {
				state.recentCollection.delete(payload);
			},
			setUnreadCollection: (state: RecentState, payload: string[]) => {
				payload.forEach(dialogId => {
					state.unreadCollection.add(dialogId);
				});
			},
			add: (state: RecentState, payload: Object[] | Object) => {
				if (!Array.isArray(payload) && Type.isPlainObject(payload))
				{
					payload = [payload];
				}
				payload.forEach(item => {
					state.collection[item.dialogId] = item;
				});
			},

			update: (state: RecentState, payload: Object[] | Object) => {
				if (!Array.isArray(payload) && Type.isPlainObject(payload))
				{
					payload = [payload];
				}
				payload.forEach(({dialogId, fields}) => {
					// if we already got chat - we should not update it with default user chat (unless it's an accepted invitation)
					const defaultUserElement = fields.options && fields.options.defaultUserRecord && !fields.invitation;
					if (defaultUserElement)
					{
						return false;
					}

					const currentElement = state.collection[dialogId];
					fields.message = {...currentElement.message, ...fields.message};
					fields.options = {...currentElement.options, ...fields.options};
					state.collection[dialogId] = {
						...currentElement,
						...fields
					};
				});
			},

			delete: (state: RecentState, payload: {id: string}) => {
				delete state.collection[payload.id];
			},

			addActiveCall: (state: RecentState, payload) => {
				state.activeCalls.push(payload);
			},

			updateActiveCall: (state: RecentState, payload) => {
				state.activeCalls[payload.index] = {
					...state.activeCalls[payload.index],
					...payload.fields
				};
			},

			deleteActiveCall: (state: RecentState, payload) => {
				state.activeCalls.splice(payload.index, 1);
			},

			setOptions: (state: RecentState, payload) => {
				state.options[payload.option] = payload.value;
			},

			clearUnread: (state: RecentState) => {
				Object.keys(state.collection).forEach(key => {
					state.collection[key].unread = false;
				});
			},

			setUnloadedChatCounters: (state: RecentState, payload: {[chatId: string]: number}) => {
				Object.entries(payload).forEach(([chatId, counter]) => {
					if (counter === 0)
					{
						delete state.unloadedChatCounters[chatId];
						return;
					}
					state.unloadedChatCounters[chatId] = counter;
				});
			}
		};
	}

	validate(fields: Object)
	{
		const result = {
			options: {}
		};

		if (Type.isNumber(fields.id))
		{
			result.dialogId = fields.id.toString();
		}
		if (Type.isStringFilled(fields.id))
		{
			result.dialogId = fields.id;
		}

		if (Type.isNumber(fields.dialogId))
		{
			result.dialogId = fields.dialogId.toString();
		}
		if (Type.isStringFilled(fields.dialogId))
		{
			result.dialogId = fields.dialogId;
		}

		if (Type.isPlainObject(fields.message))
		{
			result.message = this.prepareMessage(fields);
		}

		if (Type.isPlainObject(fields.draft))
		{
			result.draft = this.prepareDraft(fields);
		}

		if (Type.isBoolean(fields.unread))
		{
			result.unread = fields.unread;
		}

		if (Type.isBoolean(fields.pinned))
		{
			result.pinned = fields.pinned;
		}

		if (Type.isBoolean(fields.liked))
		{
			result.liked = fields.liked;
		}

		if (Type.isPlainObject(fields.invited))
		{
			result.invitation = {
				isActive: true,
				originator: fields.invited.originator_id,
				canResend: fields.invited.can_resend
			};
			result.options.defaultUserRecord = true;
		}
		else if (fields.invited === false)
		{
			result.invitation = {
				isActive: false,
				originator: 0,
				canResend: false
			};
			result.options.defaultUserRecord = true;
		}

		if (Type.isPlainObject(fields.options))
		{
			if (!result.options)
			{
				result.options = {};
			}

			if (Type.isBoolean(fields.options.default_user_record))
			{
				fields.options.defaultUserRecord = fields.options.default_user_record;
			}

			if (Type.isBoolean(fields.options.defaultUserRecord))
			{
				result.options.defaultUserRecord = fields.options.defaultUserRecord;
			}

			if (Type.isBoolean(fields.options.birthdayPlaceholder))
			{
				result.options.birthdayPlaceholder = fields.options.birthdayPlaceholder;
			}
		}

		return result;
	}

	prepareMessage(fields: Object): Object
	{
		const {message} = this.getElementState();
		if (Type.isNumber(fields.message.id) || Utils.text.isUuidV4(fields.message.id) || Type.isStringFilled(fields.message.id))
		{
			message.id = fields.message.id;
		}
		if (Type.isString(fields.message.text))
		{
			message.text = fields.message.text;
		}

		if (
			Type.isStringFilled(fields.message.attach)
			|| Type.isBoolean(fields.message.attach)
			|| Type.isArray(fields.message.attach)
		)
		{
			message.params.withAttach = fields.message.attach;
		}
		else if (
			Type.isStringFilled(fields.message.params?.withAttach)
			|| Type.isBoolean(fields.message.params?.withAttach)
			|| Type.isArray(fields.message.params?.withAttach)
		)
		{
			message.params.withAttach = fields.message.params.withAttach;
		}

		if (Type.isBoolean(fields.message.file) || Type.isPlainObject(fields.message.file))
		{
			message.params.withFile = fields.message.file;
		}
		else if (Type.isBoolean(fields.message.params?.withFile) || Type.isPlainObject(fields.message.params?.withFile))
		{
			message.params.withFile = fields.message.params.withFile;
		}

		if (Type.isDate(fields.message.date) || Type.isString(fields.message.date))
		{
			message.date = Utils.date.cast(fields.message.date);
		}

		if (Type.isNumber(fields.message.author_id))
		{
			message.senderId = fields.message.author_id;
		}
		else if (Type.isNumber(fields.message.authorId))
		{
			message.senderId = fields.message.authorId;
		}
		else if (Type.isNumber(fields.message.senderId))
		{
			message.senderId = fields.message.senderId;
		}

		if (Type.isStringFilled(fields.message.status))
		{
			message.status = fields.message.status;
		}
		if (Type.isBoolean(fields.message.sending))
		{
			message.sending = fields.message.sending;
		}

		return message;
	}

	prepareDraft(fields: Object): Object
	{
		const {draft} = this.getElementState();

		if (Type.isString(fields.draft.text))
		{
			draft.text = fields.draft.text;
		}

		if (Type.isStringFilled(draft.text))
		{
			draft.date = new Date();
		}
		else
		{
			draft.date = null;
		}

		return draft;
	}

	prepareActiveCall(call)
	{
		return {...this.getActiveCallDefaultState(), ...this.validateActiveCall(call)};
	}

	validateActiveCall(fields)
	{
		const result = {};

		if (Type.isStringFilled(fields.dialogId) || Type.isNumber(fields.dialogId))
		{
			result.dialogId = fields.dialogId;
		}

		if (Type.isStringFilled(fields.name))
		{
			result.name = fields.name;
		}

		if (Type.isObjectLike(fields.call))
		{
			result.call = fields.call;

			if (fields.call?.associatedEntity?.avatar === '/bitrix/js/im/images/blank.gif')
			{
				result.call.associatedEntity.avatar = '';
			}
		}

		if (RecentCallStatus[fields.state])
		{
			result.state = fields.state;
		}

		return result;
	}

	validateOptions(fields)
	{
		const result = {};

		if (Type.isBoolean(fields.showBirthday))
		{
			result.showBirthday = fields.showBirthday;
		}

		if (Type.isBoolean(fields.showInvited))
		{
			result.showInvited = fields.showInvited;
		}

		if (Type.isBoolean(fields.showLastMessage))
		{
			result.showLastMessage = fields.showLastMessage;
		}

		return result;
	}
}

type RecentState = {
	collection: {[dialogId: string]: ImModelRecentItem},
	recentCollection: Set<string>,
	unreadCollection: Set<string>,
	markedCollection: Set<number>,
	unloadedChatCounters: {[chatId: string]: number},
	activeCalls: ActiveCall[],
	options: {
		showBirthday: boolean,
		showInvited: boolean,
		showLastMessage: boolean
	}
};

type ActiveCall = {
	dialogId: string,
	name: string,
	call: Object,
	state: $Values<typeof RecentCallStatus>
};

Youez - 2016 - github.com/yon3zu
LinuXploit