2021-10-25 10:04:51 +00:00
|
|
|
import { v4 as uuidv4 } from 'uuid';
|
2021-07-20 11:31:49 +00:00
|
|
|
|
2022-09-05 11:24:13 +00:00
|
|
|
import { IState } from '../app/types';
|
2022-10-11 10:47:54 +00:00
|
|
|
import { REACTIONS_ENABLED } from '../base/flags/constants';
|
|
|
|
import { getFeatureFlag } from '../base/flags/functions';
|
2022-08-08 08:12:22 +00:00
|
|
|
import { getLocalParticipant } from '../base/participants/functions';
|
2022-05-23 15:02:14 +00:00
|
|
|
import { extractFqnFromPath } from '../dynamic-branding/functions.any';
|
2021-07-15 12:23:48 +00:00
|
|
|
|
2022-09-27 07:10:28 +00:00
|
|
|
import { REACTIONS, ReactionEmojiProps, ReactionThreshold, SOUNDS_THRESHOLDS } from './constants';
|
2021-07-15 12:23:48 +00:00
|
|
|
import logger from './logger';
|
|
|
|
|
2021-07-13 06:50:08 +00:00
|
|
|
/**
|
|
|
|
* Returns the queue of reactions.
|
|
|
|
*
|
|
|
|
* @param {Object} state - The state of the application.
|
2022-07-11 12:30:37 +00:00
|
|
|
* @returns {Array}
|
2021-07-13 06:50:08 +00:00
|
|
|
*/
|
2022-09-05 11:24:13 +00:00
|
|
|
export function getReactionsQueue(state: IState): Array<ReactionEmojiProps> {
|
2021-07-13 06:50:08 +00:00
|
|
|
return state['features/reactions'].queue;
|
|
|
|
}
|
2021-07-15 12:23:48 +00:00
|
|
|
|
|
|
|
/**
|
2021-07-20 11:31:49 +00:00
|
|
|
* Returns chat message from reactions buffer.
|
2021-07-15 12:23:48 +00:00
|
|
|
*
|
2021-07-20 11:31:49 +00:00
|
|
|
* @param {Array} buffer - The reactions buffer.
|
2022-07-11 12:30:37 +00:00
|
|
|
* @returns {string}
|
2021-07-15 12:23:48 +00:00
|
|
|
*/
|
2022-06-08 07:44:47 +00:00
|
|
|
export function getReactionMessageFromBuffer(buffer: Array<string>): string {
|
|
|
|
return buffer.map<string>(reaction => REACTIONS[reaction].message).reduce((acc, val) => `${acc}${val}`);
|
2021-07-15 12:23:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-07-20 11:31:49 +00:00
|
|
|
* Returns reactions array with uid.
|
2021-07-15 12:23:48 +00:00
|
|
|
*
|
2021-07-20 11:31:49 +00:00
|
|
|
* @param {Array} buffer - The reactions buffer.
|
2022-07-11 12:30:37 +00:00
|
|
|
* @returns {Array}
|
2021-07-15 12:23:48 +00:00
|
|
|
*/
|
2022-06-08 07:44:47 +00:00
|
|
|
export function getReactionsWithId(buffer: Array<string>): Array<ReactionEmojiProps> {
|
|
|
|
return buffer.map<ReactionEmojiProps>(reaction => {
|
2021-07-20 11:31:49 +00:00
|
|
|
return {
|
|
|
|
reaction,
|
2021-10-25 10:04:51 +00:00
|
|
|
uid: uuidv4()
|
2021-07-20 11:31:49 +00:00
|
|
|
};
|
|
|
|
});
|
2021-07-15 12:23:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sends reactions to the backend.
|
|
|
|
*
|
|
|
|
* @param {Object} state - The redux state object.
|
|
|
|
* @param {Array} reactions - Reactions array to be sent.
|
2022-07-11 12:30:37 +00:00
|
|
|
* @returns {void}
|
2021-07-15 12:23:48 +00:00
|
|
|
*/
|
2022-09-05 11:24:13 +00:00
|
|
|
export async function sendReactionsWebhook(state: IState, reactions: Array<string>) {
|
2021-07-15 12:23:48 +00:00
|
|
|
const { webhookProxyUrl: url } = state['features/base/config'];
|
|
|
|
const { conference } = state['features/base/conference'];
|
|
|
|
const { jwt } = state['features/base/jwt'];
|
2021-10-27 12:03:41 +00:00
|
|
|
const { connection } = state['features/base/connection'];
|
2022-09-05 11:24:13 +00:00
|
|
|
const jid = connection?.getJid();
|
2021-07-15 12:23:48 +00:00
|
|
|
const localParticipant = getLocalParticipant(state);
|
|
|
|
|
|
|
|
const headers = {
|
2021-11-03 15:43:47 +00:00
|
|
|
...jwt ? { 'Authorization': `Bearer ${jwt}` } : {},
|
2021-07-15 12:23:48 +00:00
|
|
|
'Content-Type': 'application/json'
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const reqBody = {
|
2021-09-10 07:00:54 +00:00
|
|
|
meetingFqn: extractFqnFromPath(),
|
2022-09-19 07:40:03 +00:00
|
|
|
sessionId: conference?.sessionId,
|
2021-07-15 12:23:48 +00:00
|
|
|
submitted: Date.now(),
|
|
|
|
reactions,
|
2022-09-14 07:54:56 +00:00
|
|
|
participantId: localParticipant?.jwtId,
|
|
|
|
participantName: localParticipant?.name,
|
2021-10-27 12:03:41 +00:00
|
|
|
participantJid: jid
|
2021-07-15 12:23:48 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
if (url) {
|
|
|
|
try {
|
|
|
|
const res = await fetch(`${url}/reactions`, {
|
|
|
|
method: 'POST',
|
|
|
|
headers,
|
|
|
|
body: JSON.stringify(reqBody)
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!res.ok) {
|
|
|
|
logger.error('Status error:', res.status);
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
logger.error('Could not send request', err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-08-23 09:57:56 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns unique reactions from the reactions buffer.
|
|
|
|
*
|
|
|
|
* @param {Array} reactions - The reactions buffer.
|
2022-07-11 12:30:37 +00:00
|
|
|
* @returns {Array}
|
2021-08-23 09:57:56 +00:00
|
|
|
*/
|
2022-06-08 07:44:47 +00:00
|
|
|
function getUniqueReactions(reactions: Array<string>): Array<string> {
|
2021-08-23 09:57:56 +00:00
|
|
|
return [ ...new Set(reactions) ];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns frequency of given reaction in array.
|
|
|
|
*
|
|
|
|
* @param {Array} reactions - Array of reactions.
|
|
|
|
* @param {string} reaction - Reaction to get frequency for.
|
2022-07-11 12:30:37 +00:00
|
|
|
* @returns {number}
|
2021-08-23 09:57:56 +00:00
|
|
|
*/
|
2022-06-08 07:44:47 +00:00
|
|
|
function getReactionFrequency(reactions: Array<string>, reaction: string): number {
|
2021-08-23 09:57:56 +00:00
|
|
|
return reactions.filter(r => r === reaction).length;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the threshold number for a given frequency.
|
|
|
|
*
|
|
|
|
* @param {number} frequency - Frequency of reaction.
|
2022-07-11 12:30:37 +00:00
|
|
|
* @returns {number}
|
2021-08-23 09:57:56 +00:00
|
|
|
*/
|
2022-06-08 07:44:47 +00:00
|
|
|
function getSoundThresholdByFrequency(frequency: number): number {
|
2021-08-23 09:57:56 +00:00
|
|
|
for (const i of SOUNDS_THRESHOLDS) {
|
|
|
|
if (frequency <= i) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return SOUNDS_THRESHOLDS[SOUNDS_THRESHOLDS.length - 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns unique reactions with threshold.
|
|
|
|
*
|
|
|
|
* @param {Array} reactions - The reactions buffer.
|
2022-07-11 12:30:37 +00:00
|
|
|
* @returns {Array}
|
2021-08-23 09:57:56 +00:00
|
|
|
*/
|
2022-06-08 07:44:47 +00:00
|
|
|
export function getReactionsSoundsThresholds(reactions: Array<string>): Array<ReactionThreshold> {
|
2021-08-23 09:57:56 +00:00
|
|
|
const unique = getUniqueReactions(reactions);
|
|
|
|
|
2022-06-08 07:44:47 +00:00
|
|
|
return unique.map<ReactionThreshold>(reaction => {
|
2021-08-23 09:57:56 +00:00
|
|
|
return {
|
|
|
|
reaction,
|
|
|
|
threshold: getSoundThresholdByFrequency(getReactionFrequency(reactions, reaction))
|
|
|
|
};
|
|
|
|
});
|
|
|
|
}
|
2021-08-31 11:00:27 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether or not the reactions are enabled.
|
|
|
|
*
|
|
|
|
* @param {Object} state - The Redux state object.
|
2022-07-11 12:30:37 +00:00
|
|
|
* @returns {boolean}
|
2021-08-31 11:00:27 +00:00
|
|
|
*/
|
2022-09-05 11:24:13 +00:00
|
|
|
export function isReactionsEnabled(state: IState): boolean {
|
2021-09-21 17:30:24 +00:00
|
|
|
const { disableReactions } = state['features/base/config'];
|
2021-08-31 11:00:27 +00:00
|
|
|
|
|
|
|
if (navigator.product === 'ReactNative') {
|
2021-09-21 17:30:24 +00:00
|
|
|
return !disableReactions && getFeatureFlag(state, REACTIONS_ENABLED, true);
|
2021-08-31 11:00:27 +00:00
|
|
|
}
|
|
|
|
|
2021-09-21 17:30:24 +00:00
|
|
|
return !disableReactions;
|
2021-08-31 11:00:27 +00:00
|
|
|
}
|