Proyectos de Subversion Moodle

Rev

Autoría | Ultima modificación | Ver Log |

{"version":3,"file":"message_drawer_view_conversation_patcher.min.js","sources":["../src/message_drawer_view_conversation_patcher.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * This module will take 2 view states from the message_drawer_view_conversation\n * module and generate a patch that can be given to the\n * message_drawer_view_conversation_renderer module to update the UI.\n *\n * This module should never modify either state. It's purely a read only\n * module.\n *\n * @module     core_message/message_drawer_view_conversation_patcher\n * @copyright  2018 Ryan Wyllie <ryan@moodle.com>\n * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(\n[\n    'jquery',\n    'core/user_date',\n    'core_message/message_drawer_view_conversation_constants'\n],\nfunction(\n    $,\n    UserDate,\n    Constants\n) {\n    /**\n     * Sort messages by day.\n     *\n     * @param  {Array} messages The list of messages to sort.\n     * @param  {Number} midnight User's midnight timestamp.\n     * @return {Array} messages sorted by day.\n     */\n    var sortMessagesByDay = function(messages, midnight) {\n        var messagesByDay = messages.reduce(function(carry, message) {\n            var timeCreated = message.timeCreated ? message.timeCreated : midnight;\n            var dayTimestamp = UserDate.getUserMidnightForTimestamp(timeCreated, midnight);\n\n            if (carry.hasOwnProperty(dayTimestamp)) {\n                carry[dayTimestamp].push(message);\n            } else {\n                carry[dayTimestamp] = [message];\n            }\n\n            return carry;\n        }, {});\n\n        return Object.keys(messagesByDay).map(function(dayTimestamp) {\n            return {\n                timestamp: dayTimestamp,\n                messages: messagesByDay[dayTimestamp]\n            };\n        });\n    };\n\n    /**\n     * Diff 2 arrays using a match function\n     *\n     * @param  {Array} a The first array.\n     * @param  {Array} b The second array.\n     * @param  {Function} matchFunction Function used for matching array items.\n     * @return {Object} Object containing array items missing from a, array items missing from b\n     * and matches\n     */\n    var diffArrays = function(a, b, matchFunction) {\n        // Make copy of it.\n        b = b.slice();\n        var missingFromA = [];\n        var missingFromB = [];\n        var matches = [];\n\n        a.forEach(function(current) {\n            var found = false;\n            var index = 0;\n\n            for (; index < b.length; index++) {\n                var next = b[index];\n\n                if (matchFunction(current, next)) {\n                    found = true;\n                    matches.push({\n                        a: current,\n                        b: next\n                    });\n                    break;\n                }\n            }\n\n            if (found) {\n                // This day has been processed so removed it from the list.\n                b.splice(index, 1);\n            } else {\n                // If we couldn't find it in the next messages then it means\n                // it needs to be added.\n                missingFromB.push(current);\n            }\n        });\n\n        missingFromA = b;\n\n        return {\n            missingFromA: missingFromA,\n            missingFromB: missingFromB,\n            matches: matches\n        };\n    };\n\n    /**\n     * Find an element in a array based on a matching function.\n     *\n     * @param  {array} array Array to search.\n     * @param  {Function} breakFunction Function to run on array item.\n     * @return {*} The array item.\n     */\n    var findPositionInArray = function(array, breakFunction) {\n        var before = null;\n\n        for (var i = 0; i < array.length; i++) {\n            var candidate = array[i];\n\n            if (breakFunction(candidate)) {\n                return candidate;\n            }\n        }\n\n        return before;\n    };\n\n    /**\n     * Check if 2 arrays are equal.\n     *\n     * @param  {Array} a The first array.\n     * @param  {Array} b The second array.\n     * @return {Boolean} Are arrays equal.\n     */\n    var isArrayEqual = function(a, b) {\n        // Make shallow copies so that we don't mess with the array sorting.\n        a = a.slice();\n        b = b.slice();\n        a.sort();\n        b.sort();\n        var aLength = a.length;\n        var bLength = b.length;\n\n        if (aLength < 1 && bLength < 1) {\n            return true;\n        }\n\n        if (aLength != bLength) {\n            return false;\n        }\n\n        return a.every(function(item, index) {\n            return item == b[index];\n        });\n    };\n\n    /**\n     * Do a shallow check to see if two objects appear to be equal. This should\n     * only be used for pretty basic objects.\n     *\n     * @param {Object} a First object to compare.\n     * @param {Object} b Second object to compare\n     * @return {Bool}\n     */\n    var isObjectEqual = function(a, b) {\n        var aKeys = Object.keys(a);\n        var bKeys = Object.keys(b);\n\n        if (aKeys.length != bKeys.length) {\n            return false;\n        }\n\n        return aKeys.every(function(key) {\n            var aVal = a[key];\n            var bVal = b[key];\n            var aType = typeof aVal;\n            var bType = typeof bVal;\n            aType = (aVal === null) ? 'null' : aType;\n            bType = (aVal === null) ? 'null' : bType;\n            aType = (aType === 'object' && Array.isArray(aType)) ? 'array' : aType;\n            bType = (bType === 'object' && Array.isArray(bType)) ? 'array' : bType;\n\n            if (aType !== bType) {\n                return false;\n            }\n\n            switch (aType) {\n                case 'object':\n                    return isObjectEqual(aVal, bVal);\n                case 'array':\n                    return isArrayEqual(aVal, bVal);\n                default:\n                    return a[key] == b[key];\n            }\n        });\n    };\n\n    /**\n     * Compare two messages to check if they are equal. This function only checks a subset\n     * of the message properties which we know will change rather than all properties.\n     *\n     * @param {Object} a The first message\n     * @param {Object} b The second message\n     * @return {Bool}\n     */\n    var isMessageEqual = function(a, b) {\n        return isObjectEqual(\n            {\n                id: a.id,\n                state: a.sendState,\n                text: a.text,\n                timeCreated: a.timeCreated\n            },\n            {\n                id: b.id,\n                state: b.sendState,\n                text: b.text,\n                timeCreated: b.timeCreated\n            }\n        );\n    };\n\n    /**\n     * Build a patch based on days.\n     *\n     * @param  {Object} current Current list current items.\n     * @param  {Array} remove List of days to remove.\n     * @param  {Array} add List of days to add.\n     * @return {Object} Patch with elements to add and remove.\n     */\n    var buildDaysPatch = function(current, remove, add) {\n        return {\n            remove: remove,\n            add: add.map(function(day) {\n                // Any days left over in the \"next\" list weren't in the \"current\" list\n                // so they will need to be added.\n                var before = findPositionInArray(current, function(candidate) {\n                    return day.timestamp < candidate.timestamp;\n                });\n\n                return {\n                    before: before,\n                    value: day\n                };\n            })\n        };\n    };\n\n    /**\n     * Build the messages patch for each day.\n     *\n     * @param {Array} matchingDays Array of old and new messages sorted by day.\n     * @return {Object} patch.\n     */\n    var buildMessagesPatch = function(matchingDays) {\n        var remove = [];\n        var add = [];\n        var update = [];\n\n        // Iterate over the list of days and determine which messages in those days\n        // have been changed.\n        matchingDays.forEach(function(days) {\n            var dayCurrent = days.a;\n            var dayNext = days.b;\n            // Find out which messages have changed in this day. This will return a list of messages\n            // from the current state that couldn't be found in the next state and a list of messages in\n            // the next state which couldn't be count in the current state.\n            var messagesDiff = diffArrays(dayCurrent.messages, dayNext.messages, isMessageEqual);\n            // Take the two arrays (list of messages changed from dayNext and list of messages changed\n            // from dayCurrent) any work out which messages have been added/removed from the list and\n            // which messages were just updated.\n            var patch = diffArrays(\n                // The messages from dayCurrent.message that weren't in dayNext.messages.\n                messagesDiff.missingFromB,\n                // The messages from dayNext.message that weren't in dayCurrent.messages.\n                messagesDiff.missingFromA,\n                function(a, b) {\n                    // This function is going to determine if the messages were\n                    // added/removed from either list or if they were simply an updated.\n                    //\n                    // If the IDs match or it was a state change (i.e. message with a temp\n                    // ID goes from pending to sent and receives an actual id) then they are\n                    // the same message which should be an update not an add/remove.\n                    return a.id == b.id || (a.sendState != b.sendState && a.timeAdded == b.timeAdded);\n                }\n            );\n\n            // Any messages from the current state for this day which aren't in the next state\n            // for this day (i.e. the user deleted the message) means we need to remove them from\n            // the UI.\n            remove = remove.concat(patch.missingFromB);\n\n            // Any messages not in the current state for this day which are in the next state\n            // for this day (i.e. it's a new message) means we need to add it to the UI so work\n            // out where in the list of messages it should appear (it could be a new message the\n            // user has sent or older messages loaded as part of the conversation scroll back).\n            patch.missingFromA.forEach(function(message) {\n                // By default a null value for before will render the message at the bottom of\n                // the message UI (i.e. it's the newest message).\n                var before = null;\n\n                if (message.timeCreated) {\n                    // If this message has a time created then find where it sits in the list of\n                    // message to insert it into the correct position.\n                    before = findPositionInArray(dayCurrent.messages, function(candidate) {\n                        if (message.timeCreated == candidate.timeCreated) {\n                            return message.id < candidate.id;\n                        } else {\n                            return message.timeCreated < candidate.timeCreated;\n                        }\n                    });\n                }\n\n                add.push({\n                    before: before,\n                    value: message,\n                    day: dayCurrent\n                });\n            });\n\n            // Any message that appears in both the current state for this day and the next state\n            // for this day means something in the message was updated.\n            update = update.concat(patch.matches.map(function(message) {\n                return {\n                    before: message.a,\n                    after: message.b\n                };\n            }));\n        });\n\n        return {\n            add: add,\n            remove: remove,\n            update: update\n        };\n    };\n\n    /**\n     * Build a patch for this conversation.\n     *\n     * @param  {Object} state The current state of this conversation.\n     * @param  {Object} newState The new state of this conversation.\n     * @returns {Object} Patch with days and messsages for each day.\n     */\n    var buildConversationPatch = function(state, newState) {\n        var diff = diffArrays(state.messages, newState.messages, isMessageEqual);\n\n        if (diff.missingFromA.length || diff.missingFromB.length) {\n            // Some messages have changed so let's work out which ones by sorting\n            // them into their respective days.\n            var current = sortMessagesByDay(state.messages, state.midnight);\n            var next = sortMessagesByDay(newState.messages, newState.midnight);\n            // This diffs the arrays to work out if there are any missing days that need\n            // to be added (i.e. we've got some new messages on a new day) or if there\n            // are any days that need to be deleted (i.e. the user has deleted some old messages).\n            var daysDiff = diffArrays(current, next, function(dayCurrent, dayNext) {\n                return dayCurrent.timestamp == dayNext.timestamp;\n            });\n\n            return {\n                // Handle adding or removing whole days.\n                days: buildDaysPatch(current, daysDiff.missingFromB, daysDiff.missingFromA),\n                // Handle updating messages that don't require adding/removing a whole day.\n                messages: buildMessagesPatch(daysDiff.matches)\n            };\n        } else {\n            return null;\n        }\n    };\n\n    /**\n     * Build a patch for the header of this conversation. Check if this conversation\n     * is a group conversation.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Object} patch\n     */\n    var buildHeaderPatchTypePrivate = function(state, newState) {\n        var requireAddContact = buildRequireAddContact(state, newState);\n        var confirmContactRequest = buildConfirmContactRequest(state, newState);\n        var oldOtherUser = getOtherUserFromState(state);\n        var newOtherUser = getOtherUserFromState(newState);\n        var requiresAddContact = requireAddContact && requireAddContact.show && !requireAddContact.hasMessages;\n        var requiredAddContact = requireAddContact && !requireAddContact.show;\n        // Render the header once we've got a user.\n        var shouldRenderHeader = !oldOtherUser && newOtherUser;\n        // We should also re-render the header if the other user requires\n        // being added as a contact or if they did but no longer do.\n        shouldRenderHeader = shouldRenderHeader || requiresAddContact || requiredAddContact;\n        // Finally, we should re-render if the other user has sent this user\n        // a contact request that is waiting for approval or if it's been approved/declined.\n        shouldRenderHeader = shouldRenderHeader || confirmContactRequest !== null;\n\n        if (shouldRenderHeader) {\n            return {\n                type: Constants.CONVERSATION_TYPES.PRIVATE,\n                // We can show controls if the other user doesn't require add contact\n                // and we aren't waiting for this user to respond to a contact request.\n                showControls: !requiresAddContact && !confirmContactRequest,\n                context: {\n                    id: newState.id,\n                    name: newState.name,\n                    subname: newState.subname,\n                    totalmembercount: newState.totalMemberCount,\n                    imageurl: newState.imageUrl,\n                    isfavourite: newState.isFavourite,\n                    ismuted: newState.isMuted,\n                    // Don't show favouriting if we don't have a conversation.\n                    showfavourite: newState.id !== null,\n                    userid: newOtherUser.id,\n                    showonlinestatus: newOtherUser.showonlinestatus,\n                    isonline: newOtherUser.isonline,\n                    isblocked: newOtherUser.isblocked,\n                    iscontact: newOtherUser.iscontact\n                }\n            };\n        }\n\n        return null;\n    };\n\n    /**\n     * Build a patch for the header of this conversation. Check if this conversation\n     * is a group conversation.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Object} patch\n     */\n    var buildHeaderPatchTypeSelf = function(state, newState) {\n        var shouldRenderHeader = (state.name === null && newState.name !== null);\n\n        if (shouldRenderHeader) {\n            return {\n                type: Constants.CONVERSATION_TYPES.SELF,\n                // Don't display the controls for the self-conversations.\n                showControls: false,\n                context: {\n                    id: newState.id,\n                    name: newState.name,\n                    subname: newState.subname,\n                    imageurl: newState.imageUrl,\n                    isfavourite: newState.isFavourite,\n                    // Don't show favouriting if we don't have a conversation.\n                    showfavourite: newState.id !== null,\n                    showonlinestatus: true,\n                }\n            };\n        }\n\n        return null;\n    };\n\n    /**\n     * Build a patch for the header of this conversation. Check if this conversation\n     * is a group conversation.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Object} patch\n     */\n    var buildHeaderPatchTypePublic = function(state, newState) {\n        var oldMemberCount = state.totalMemberCount;\n        var newMemberCount = newState.totalMemberCount;\n\n        if (oldMemberCount != newMemberCount) {\n            return {\n                type: Constants.CONVERSATION_TYPES.PUBLIC,\n                showControls: true,\n                context: {\n                    id: newState.id,\n                    name: newState.name,\n                    subname: newState.subname,\n                    totalmembercount: newState.totalMemberCount,\n                    imageurl: newState.imageUrl,\n                    isfavourite: newState.isFavourite,\n                    ismuted: newState.isMuted,\n                    // Don't show favouriting if we don't have a conversation.\n                    showfavourite: newState.id !== null\n                }\n            };\n        } else {\n            return null;\n        }\n    };\n\n    /**\n     * Find the newest or oldest message.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Number} Oldest or newest message id.\n     */\n    var buildScrollToMessagePatch = function(state, newState) {\n        var oldMessages = state.messages;\n        var newMessages = newState.messages;\n\n        if (newMessages.length < 1) {\n            return null;\n        }\n\n        if (oldMessages.length < 1) {\n            return newMessages[newMessages.length - 1].id;\n        }\n\n        var previousNewest = oldMessages[state.messages.length - 1];\n        var currentNewest = newMessages[newMessages.length - 1];\n        var previousOldest = oldMessages[0];\n        var currentOldest = newMessages[0];\n\n        if (previousNewest.id != currentNewest.id) {\n            return currentNewest.id;\n        } else if (previousOldest.id != currentOldest.id) {\n            return previousOldest.id;\n        }\n\n        return null;\n    };\n\n    /**\n     * Check if members should be loaded.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Bool|Null}\n     */\n    var buildLoadingMembersPatch = function(state, newState) {\n        if (!state.loadingMembers && newState.loadingMembers) {\n            return true;\n        } else if (state.loadingMembers && !newState.loadingMembers) {\n            return false;\n        } else {\n            return null;\n        }\n    };\n\n    /**\n     * Check if the messages are being loaded for the first time.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Bool|Null}\n     */\n    var buildLoadingFirstMessages = function(state, newState) {\n        if (state.hasTriedToLoadMessages === newState.hasTriedToLoadMessages) {\n            return null;\n        } else if (!newState.hasTriedToLoadMessages && newState.loadingMessages) {\n            return true;\n        } else if (newState.hasTriedToLoadMessages && !newState.loadingMessages) {\n            return false;\n        } else {\n            return null;\n        }\n    };\n\n    /**\n     * Check if the messages are still being loaded\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Bool|Null}\n     */\n    var buildLoadingMessages = function(state, newState) {\n        if (!state.loadingMessages && newState.loadingMessages) {\n            return true;\n        } else if (state.loadingMessages && !newState.loadingMessages) {\n            return false;\n        } else {\n            return null;\n        }\n    };\n\n    /**\n     * Determine if we should show the emoji picker.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Bool|Null}\n     */\n    var buildShowEmojiPicker = function(state, newState) {\n        if (!state.showEmojiPicker && newState.showEmojiPicker) {\n            return true;\n        } else if (state.showEmojiPicker && !newState.showEmojiPicker) {\n            return false;\n        } else {\n            return null;\n        }\n    };\n\n    /**\n     * Determine if we should show the emoji auto complete.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Bool|Null}\n     */\n    var buildShowEmojiAutoComplete = function(state, newState) {\n        if (!state.showEmojiAutoComplete && newState.showEmojiAutoComplete) {\n            return true;\n        } else if (state.showEmojiAutoComplete && !newState.showEmojiAutoComplete) {\n            return false;\n        } else {\n            return null;\n        }\n    };\n\n    /**\n     * Get the user Object of user to be blocked if pending.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Object|Bool|Null} User Object if Object.\n     */\n    var buildConfirmBlockUser = function(state, newState) {\n        if (newState.pendingBlockUserIds.length) {\n            // We currently only support a single user;\n            var userId = newState.pendingBlockUserIds[0];\n            return newState.members[userId];\n        } else if (state.pendingBlockUserIds.length) {\n            return false;\n        }\n\n        return null;\n    };\n\n    /**\n     * Get the user Object of user to be unblocked if pending.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Object|Bool|Null} User Object if Object.\n     */\n    var buildConfirmUnblockUser = function(state, newState) {\n        if (newState.pendingUnblockUserIds.length) {\n            // We currently only support a single user;\n            var userId = newState.pendingUnblockUserIds[0];\n            return newState.members[userId];\n        } else if (state.pendingUnblockUserIds.length) {\n            return false;\n        }\n\n        return null;\n    };\n\n    /**\n     * Get the user Object of user to be added as contact if pending.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Object|Bool|Null} User Object if Object.\n     */\n    var buildConfirmAddContact = function(state, newState) {\n        if (newState.pendingAddContactIds.length) {\n            // We currently only support a single user;\n            var userId = newState.pendingAddContactIds[0];\n            return newState.members[userId];\n        } else if (state.pendingAddContactIds.length) {\n            return false;\n        }\n\n        return null;\n    };\n\n    /**\n     * Get the user Object of user to be removed as contact if pending.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Object|Bool|Null} User Object if Object.\n     */\n    var buildConfirmRemoveContact = function(state, newState) {\n        if (newState.pendingRemoveContactIds.length) {\n            // We currently only support a single user;\n            var userId = newState.pendingRemoveContactIds[0];\n            return newState.members[userId];\n        } else if (state.pendingRemoveContactIds.length) {\n            return false;\n        }\n\n        return null;\n    };\n\n    /**\n     * Check if there are any messages to be deleted.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Object|Null} The conversation type and if the user can delete  the messages for all users.\n     */\n    var buildConfirmDeleteSelectedMessages = function(state, newState) {\n        var oldPendingCount = state.pendingDeleteMessageIds.length;\n        var newPendingCount = newState.pendingDeleteMessageIds.length;\n\n        if (newPendingCount && !oldPendingCount) {\n            return {\n                show: true,\n                type: newState.type,\n                canDeleteMessagesForAllUsers: newState.canDeleteMessagesForAllUsers\n            };\n        } else if (oldPendingCount && !newPendingCount) {\n            return {\n                show: false\n            };\n        }\n\n        return null;\n    };\n\n    /**\n     * Check if there is a conversation to be deleted.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {int|Null} The conversation type to be deleted.\n     */\n    var buildConfirmDeleteConversation = function(state, newState) {\n        if (!state.pendingDeleteConversation && newState.pendingDeleteConversation) {\n            return newState.type;\n        } else if (state.pendingDeleteConversation && !newState.pendingDeleteConversation) {\n            return false;\n        }\n\n        return null;\n    };\n\n    /**\n     * Check if there is a pending contact request to accept or decline.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Bool|Null}\n     */\n    var buildConfirmContactRequest = function(state, newState) {\n        var loggedInUserId = state.loggedInUserId;\n        var oldOtherUser = getOtherUserFromState(state);\n        var newOtherUser = getOtherUserFromState(newState);\n        var oldReceivedRequests = !oldOtherUser ? [] : oldOtherUser.contactrequests.filter(function(request) {\n            return request.requesteduserid == loggedInUserId && request.userid == oldOtherUser.id;\n        });\n        var newReceivedRequests = !newOtherUser ? [] : newOtherUser.contactrequests.filter(function(request) {\n            return request.requesteduserid == loggedInUserId && request.userid == newOtherUser.id;\n        });\n        var oldRequest = oldReceivedRequests.length ? oldReceivedRequests[0] : null;\n        var newRequest = newReceivedRequests.length ? newReceivedRequests[0] : null;\n\n        if (!oldRequest && newRequest) {\n            return newOtherUser;\n        } else if (oldRequest && !newRequest) {\n            return false;\n        } else {\n            return null;\n        }\n    };\n\n    /**\n     * Check if there are any changes in blocked users.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Bool|Null}\n     */\n    var buildIsBlocked = function(state, newState) {\n        var oldOtherUser = getOtherUserFromState(state);\n        var newOtherUser = getOtherUserFromState(newState);\n\n        if (!oldOtherUser && !newOtherUser) {\n            return null;\n        } else if (!oldOtherUser && newOtherUser) {\n            return newOtherUser.isblocked ? true : null;\n        } else if (!newOtherUser && oldOtherUser) {\n            return oldOtherUser.isblocked ? false : null;\n        } else if (oldOtherUser.isblocked && !newOtherUser.isblocked) {\n            return false;\n        } else if (!oldOtherUser.isblocked && newOtherUser.isblocked) {\n            return true;\n        } else {\n            return null;\n        }\n    };\n\n    /**\n     * Check if there are any changes the conversation favourite state.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Bool|Null}\n     */\n    var buildIsFavourite = function(state, newState) {\n        var oldIsFavourite = state.isFavourite;\n        var newIsFavourite = newState.isFavourite;\n\n        if (state.id === null && newState.id === null) {\n            // The conversation isn't yet created so don't change anything.\n            return null;\n        } else if (state.id === null && newState.id !== null) {\n            // The conversation was created so we can show the add favourite button.\n            return 'show-add';\n        } else if (state.id !== null && newState.id === null) {\n            // We're changing from a created conversation to a new conversation so hide\n            // the favouriting functionality for now.\n            return 'hide';\n        } else if (oldIsFavourite == newIsFavourite) {\n            // No change.\n            return null;\n        } else if (!oldIsFavourite && newIsFavourite) {\n            return 'show-remove';\n        } else if (oldIsFavourite && !newIsFavourite) {\n            return 'show-add';\n        } else {\n            return null;\n        }\n    };\n\n    /**\n     * Check if there are any changes the conversation muted state.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {string|null}\n     */\n    var buildIsMuted = function(state, newState) {\n        var oldIsMuted = state.isMuted;\n        var newIsMuted = newState.isMuted;\n\n        if (state.id === null && newState.id === null) {\n            // The conversation isn't yet created so don't change anything.\n            return null;\n        } else if (state.id === null && newState.id !== null) {\n            // The conversation was created so we can show the mute button.\n            return 'show-mute';\n        } else if (state.id !== null && newState.id === null) {\n            // We're changing from a created conversation to a new conversation so hide\n            // the muting functionality for now.\n            return 'hide';\n        } else if (oldIsMuted == newIsMuted) {\n            // No change.\n            return null;\n        } else if (!oldIsMuted && newIsMuted) {\n            return 'show-unmute';\n        } else if (oldIsMuted && !newIsMuted) {\n            return 'show-mute';\n        } else {\n            return null;\n        }\n    };\n\n    /**\n     * Check if there are any changes in the contact status of the current user\n     * and other user.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Bool|Null}\n     */\n    var buildIsContact = function(state, newState) {\n        var loggedInUserId = state.loggedInUserId;\n        var oldOtherUser = getOtherUserFromState(state);\n        var newOtherUser = getOtherUserFromState(newState);\n        var oldContactRequests = !oldOtherUser ? [] : oldOtherUser.contactrequests.filter(function(request) {\n            return (request.userid == loggedInUserId && request.requesteduserid == oldOtherUser.id) ||\n                (request.userid == oldOtherUser.id && request.requesteduserid == loggedInUserId);\n        });\n        var newContactRequests = !newOtherUser ? [] : newOtherUser.contactrequests.filter(function(request) {\n            return (request.userid == loggedInUserId && request.requesteduserid == newOtherUser.id) ||\n                (request.userid == newOtherUser.id && request.requesteduserid == loggedInUserId);\n        });\n        var oldHasContactRequests = oldContactRequests.length > 0;\n        var newHasContactRequests = newContactRequests.length > 0;\n\n        if (!oldOtherUser && !newOtherUser) {\n            return null;\n        } else if (oldHasContactRequests && newHasContactRequests) {\n            return null;\n        } else if (!oldHasContactRequests && newHasContactRequests && !newOtherUser.iscontact) {\n            return 'pending-contact';\n        } else if (!oldOtherUser && newOtherUser) {\n            return newOtherUser.iscontact ? 'contact' : null;\n        } else if (!newOtherUser && oldOtherUser) {\n            return oldOtherUser.iscontact ? 'non-contact' : null;\n        } else if (oldOtherUser.iscontact && !newOtherUser.iscontact) {\n            return newHasContactRequests ? 'pending-contact' : 'non-contact';\n        } else if (!oldOtherUser.iscontact && newOtherUser.iscontact) {\n            return 'contact';\n        } else {\n            return null;\n        }\n    };\n\n    /**\n     * Check if a confirm action is active.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Bool|Null}\n     */\n    var buildLoadingConfirmationAction = function(state, newState) {\n        if (!state.loadingConfirmAction && newState.loadingConfirmAction) {\n            return true;\n        } else if (state.loadingConfirmAction && !newState.loadingConfirmAction) {\n            return false;\n        } else {\n            return null;\n        }\n    };\n\n    /**\n     * Check if a edit mode is active.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Bool|Null}\n     */\n    var buildInEditMode = function(state, newState) {\n        var oldHasSelectedMessages = state.selectedMessageIds.length > 0;\n        var newHasSelectedMessages = newState.selectedMessageIds.length > 0;\n        var numberOfMessagesHasChanged = state.messages.length != newState.messages.length;\n\n        if (!oldHasSelectedMessages && newHasSelectedMessages) {\n            return true;\n        } else if (oldHasSelectedMessages && !newHasSelectedMessages) {\n            return false;\n        } else if (oldHasSelectedMessages && numberOfMessagesHasChanged) {\n            return true;\n        } else {\n            return null;\n        }\n    };\n\n    /**\n     * Build a patch for the messages selected.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Object} patch\n     */\n    var buildSelectedMessages = function(state, newState) {\n        var oldSelectedMessages = state.selectedMessageIds;\n        var newSelectedMessages = newState.selectedMessageIds;\n\n        if (isArrayEqual(oldSelectedMessages, newSelectedMessages)) {\n            return null;\n        }\n\n        var diff = diffArrays(oldSelectedMessages, newSelectedMessages, function(a, b) {\n            return a == b;\n        });\n\n        return {\n            count: newSelectedMessages.length,\n            add: diff.missingFromA,\n            remove: diff.missingFromB\n        };\n    };\n\n    /**\n     * Get a list of users from the state that are not the logged in user. Use to find group\n     * message members or the other user in a conversation.\n     *\n     * @param  {Object} state State\n     * @return {Array} List of users.\n     */\n    var getOtherUserFromState = function(state) {\n        return Object.keys(state.members).reduce(function(carry, userId) {\n            if (userId != state.loggedInUserId && !carry) {\n                carry = state.members[userId];\n            }\n\n            return carry;\n        }, null);\n    };\n\n    /**\n     * Check if the given user requires a contact request from the logged in user.\n     *\n     * @param  {Integer} loggedInUserId The logged in user id\n     * @param  {Object} user User record\n     * @return {Bool}\n     */\n    var requiresContactRequest = function(loggedInUserId, user) {\n        // If a user can message then no contact request is required.\n        if (user.canmessage) {\n            return false;\n        }\n\n        var contactRequests = user.contactrequests.filter(function(request) {\n            return request.userid == loggedInUserId || request.requesteduserid;\n        });\n        var hasSentContactRequest = contactRequests.length > 0;\n        return user.requirescontact && !user.iscontact && !hasSentContactRequest;\n    };\n\n    /**\n     * Check if other users are required to be added as contact.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Object} Object controlling the required to add contact dialog variables.\n     */\n    var buildRequireAddContact = function(state, newState) {\n        var oldOtherUser = getOtherUserFromState(state);\n        var newOtherUser = getOtherUserFromState(newState);\n        var hadMessages = state.messages.length > 0;\n        var hasMessages = newState.messages.length > 0;\n        var loggedInUserId = newState.loggedInUserId;\n        var prevRequiresContactRequest = oldOtherUser && requiresContactRequest(loggedInUserId, oldOtherUser);\n        var nextRequiresContactRequest = newOtherUser && requiresContactRequest(loggedInUserId, newOtherUser);\n        var confirmAddContact = buildConfirmAddContact(state, newState);\n        var finishedAddContact = confirmAddContact === false;\n\n        // Still doing first load.\n        if (!state.hasTriedToLoadMessages && !newState.hasTriedToLoadMessages) {\n            return null;\n        }\n\n        // No users yet.\n        if (!oldOtherUser && !newOtherUser) {\n            return null;\n        }\n\n        // We've loaded a new user and they require a contact request.\n        if (!oldOtherUser && nextRequiresContactRequest) {\n            return {\n                show: true,\n                hasMessages: hasMessages,\n                user: newOtherUser\n            };\n        }\n\n        // The logged in user has completed the confirm contact request dialogue\n        // but the other user still requires a contact request which means the logged\n        // in user either declined the confirmation or it failed.\n        if (finishedAddContact && nextRequiresContactRequest) {\n            return {\n                show: true,\n                hasMessages: hasMessages,\n                user: newOtherUser\n            };\n        }\n\n        // Everything is loaded.\n        if (state.hasTriedToLoadMessages && newState.hasTriedToLoadMessages) {\n            if (!prevRequiresContactRequest && nextRequiresContactRequest) {\n                return {\n                    show: true,\n                    hasMessages: hasMessages,\n                    user: newOtherUser\n                };\n            }\n\n            if (prevRequiresContactRequest && !nextRequiresContactRequest) {\n                return {\n                    show: false,\n                    hasMessages: hasMessages\n                };\n            }\n        }\n\n        // First load just completed.\n        if (!state.hasTriedToLoadMessages && newState.hasTriedToLoadMessages) {\n            if (nextRequiresContactRequest) {\n                return {\n                    show: true,\n                    hasMessages: hasMessages,\n                    user: newOtherUser\n                };\n            }\n        }\n\n        // Being reset.\n        if (state.hasTriedToLoadMessages && !newState.hasTriedToLoadMessages) {\n            if (prevRequiresContactRequest) {\n                return {\n                    show: false,\n                    hasMessages: hadMessages\n                };\n            }\n        }\n\n        return null;\n    };\n\n    /**\n     * Check if other users are required to be unblocked.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Bool|Null}\n     */\n    var buildRequireUnblock = function(state, newState) {\n        var oldOtherUser = getOtherUserFromState(state);\n        var newOtherUser = getOtherUserFromState(newState);\n\n        if (!oldOtherUser && !newOtherUser) {\n            return null;\n        } else if (oldOtherUser && !newOtherUser) {\n            return oldOtherUser.isblocked ? false : null;\n        } else if (!oldOtherUser && newOtherUser) {\n            return newOtherUser.isblocked ? true : null;\n        } else if (!oldOtherUser.isblocked && newOtherUser.isblocked) {\n            return true;\n        } else if (oldOtherUser.isblocked && !newOtherUser.isblocked) {\n            return false;\n        }\n\n        return null;\n    };\n\n    /**\n     * Check if other users can be messaged.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Bool|Null}\n     */\n    var buildUnableToMessage = function(state, newState) {\n        var oldOtherUser = getOtherUserFromState(state);\n        var newOtherUser = getOtherUserFromState(newState);\n\n        if (newState.type == Constants.CONVERSATION_TYPES.SELF) {\n            // Users always can send message themselves on self-conversations.\n            return null;\n        }\n\n        if (!oldOtherUser && !newOtherUser) {\n            return null;\n        } else if (oldOtherUser && !newOtherUser) {\n            return oldOtherUser.canmessage ? null : true;\n        } else if (!oldOtherUser && newOtherUser) {\n            return newOtherUser.canmessage ? null : true;\n        } else if (!oldOtherUser.canmessage && newOtherUser.canmessage) {\n            return false;\n        } else if (oldOtherUser.canmessage && !newOtherUser.canmessage) {\n            return true;\n        }\n\n        return null;\n    };\n\n    /**\n     * Build patch for footer information for a private conversation.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Object} containing footer state type.\n     */\n    var buildFooterPatchTypePrivate = function(state, newState) {\n        var loadingFirstMessages = buildLoadingFirstMessages(state, newState);\n        var inEditMode = buildInEditMode(state, newState);\n        var requireAddContact = buildRequireAddContact(state, newState);\n        var requireUnblock = buildRequireUnblock(state, newState);\n        var unableToMessage = buildUnableToMessage(state, newState);\n        var showRequireAddContact = requireAddContact !== null ? requireAddContact.show && requireAddContact.hasMessages : null;\n        var otherUser = getOtherUserFromState(newState);\n        var generateReturnValue = function(checkValue, successReturn) {\n            if (checkValue) {\n                return successReturn;\n            } else if (checkValue !== null && !checkValue) {\n                if (!otherUser) {\n                    return {type: 'content'};\n                } else if (otherUser.isblocked) {\n                    return {type: 'unblock'};\n                } else if (newState.messages.length && requiresContactRequest(newState.loggedInUserId, otherUser)) {\n                    return {\n                        type: 'add-contact',\n                        user: otherUser\n                    };\n                } else if (!otherUser.canmessage && (otherUser.requirescontact && !otherUser.iscontact)) {\n                    return {type: 'unable-to-message'};\n                }\n            }\n\n            return null;\n        };\n\n        if (\n            loadingFirstMessages === null &&\n            inEditMode === null &&\n            requireAddContact === null &&\n            requireUnblock === null\n        ) {\n            return null;\n        }\n\n        var checks = [\n            [loadingFirstMessages, {type: 'placeholder'}],\n            [inEditMode, {type: 'edit-mode'}],\n            [unableToMessage, {type: 'unable-to-message'}],\n            [requireUnblock, {type: 'unblock'}],\n            [showRequireAddContact, {type: 'add-contact', user: otherUser}]\n        ];\n\n        for (var i = 0; i < checks.length; i++) {\n            var checkValue = checks[i][0];\n            var successReturn = checks[i][1];\n            var result = generateReturnValue(checkValue, successReturn);\n\n            if (result !== null) {\n                return result;\n            }\n        }\n\n        return {\n            type: 'content'\n        };\n    };\n\n    /**\n     * Build patch for footer information for a public conversation.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Object} containing footer state type.\n     */\n    var buildFooterPatchTypePublic = function(state, newState) {\n        var loadingFirstMessages = buildLoadingFirstMessages(state, newState);\n        var inEditMode = buildInEditMode(state, newState);\n\n        if (loadingFirstMessages === null && inEditMode === null) {\n            return null;\n        }\n\n        if (loadingFirstMessages) {\n            return {type: 'placeholder'};\n        }\n\n        if (inEditMode) {\n            return {type: 'edit-mode'};\n        }\n\n        return {\n            type: 'content'\n        };\n    };\n\n    /**\n     * Check if we're viewing a different conversation. If so then we need to\n     * reset the UI.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {bool|null} If a reset needs to occur\n     */\n    var buildReset = function(state, newState) {\n        var oldType = state.type;\n        var newType = newState.type;\n        var oldConversationId = state.id;\n        var newConversationId = newState.id;\n        var oldMemberIds = Object.keys(state.members);\n        var newMemberIds = Object.keys(newState.members);\n\n        oldMemberIds.sort();\n        newMemberIds.sort();\n\n        var membersUnchanged = oldMemberIds.every(function(id, index) {\n            return id == newMemberIds[index];\n        });\n\n        if (oldType != newType) {\n            // If we've changed conversation type then we need to reset.\n            return true;\n        } else if (oldConversationId && !newConversationId) {\n            // We previously had a conversation id but no longer do. This likely means\n            // the user is viewing the conversation with someone they've never spoken to\n            // before.\n            return true;\n        } else if (oldConversationId && newConversationId && oldConversationId != newConversationId) {\n            // If we had a conversation id and it's changed then we need to reset.\n            return true;\n        } else if (!oldConversationId && !newConversationId && !membersUnchanged) {\n            // If we never had a conversation id but the members of the conversation have\n            // changed then we need to reset. This can happen if the user goes from viewing\n            // a user they've never had a conversation with to viewing a different user that\n            // they've never had a conversation with.\n            return true;\n        }\n\n        return null;\n    };\n\n    /**\n     * We should show this message always, for all the self-conversations.\n     *\n     * The message should be hidden when it's not a self-conversation.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {bool}\n     */\n    var buildSelfConversationMessage = function(state, newState) {\n        if (state.type != newState.type) {\n            return (newState.type == Constants.CONVERSATION_TYPES.SELF);\n        }\n\n        return null;\n    };\n\n    /**\n     * We should show the contact request sent message if the user just sent\n     * a contact request to the other user\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {string|false|null}\n     */\n    var buildContactRequestSent = function(state, newState) {\n        var loggedInUserId = newState.loggedInUserId;\n        var oldOtherUser = getOtherUserFromState(state);\n        var newOtherUser = getOtherUserFromState(newState);\n        var oldSentRequests = !oldOtherUser ? [] : oldOtherUser.contactrequests.filter(function(request) {\n            return request.userid == loggedInUserId;\n        });\n        var newSentRequests = !newOtherUser ? [] : newOtherUser.contactrequests.filter(function(request) {\n            return request.userid == loggedInUserId;\n        });\n        var oldRequest = oldSentRequests.length > 0;\n        var newRequest = newSentRequests.length > 0;\n\n        if (!oldRequest && newRequest && !newOtherUser.iscontact) {\n            return newOtherUser.fullname;\n        } else if (oldOtherUser && !oldOtherUser.iscontact && newRequest && newOtherUser.iscontact) {\n            // Contact request accepted.\n            return false;\n        } else if (oldRequest && !newRequest) {\n            return false;\n        } else {\n            return null;\n        }\n    };\n\n    /**\n     * Build the full patch comparing the current state and the new state. This patch is used by\n     * the conversation renderer to render the UI on any update.\n     *\n     * @param  {Object} state The current state.\n     * @param  {Object} newState The new state.\n     * @return {Object} Patch containing all information changed.\n     */\n    var buildPatch = function(state, newState) {\n        var config = {\n            all: {\n                reset: buildReset,\n                conversation: buildConversationPatch,\n                scrollToMessage: buildScrollToMessagePatch,\n                loadingMembers: buildLoadingMembersPatch,\n                loadingFirstMessages: buildLoadingFirstMessages,\n                loadingMessages: buildLoadingMessages,\n                confirmDeleteSelectedMessages: buildConfirmDeleteSelectedMessages,\n                inEditMode: buildInEditMode,\n                selectedMessages: buildSelectedMessages,\n                isFavourite: buildIsFavourite,\n                isMuted: buildIsMuted,\n                showEmojiPicker: buildShowEmojiPicker,\n                showEmojiAutoComplete: buildShowEmojiAutoComplete\n            }\n        };\n        // These build functions are only applicable to private conversations.\n        config[Constants.CONVERSATION_TYPES.PRIVATE] = {\n            header: buildHeaderPatchTypePrivate,\n            footer: buildFooterPatchTypePrivate,\n            confirmBlockUser: buildConfirmBlockUser,\n            confirmUnblockUser: buildConfirmUnblockUser,\n            confirmAddContact: buildConfirmAddContact,\n            confirmRemoveContact: buildConfirmRemoveContact,\n            confirmContactRequest: buildConfirmContactRequest,\n            confirmDeleteConversation: buildConfirmDeleteConversation,\n            isBlocked: buildIsBlocked,\n            isContact: buildIsContact,\n            loadingConfirmAction: buildLoadingConfirmationAction,\n            requireAddContact: buildRequireAddContact,\n            contactRequestSent: buildContactRequestSent\n        };\n        // These build functions are only applicable to public (group) conversations.\n        config[Constants.CONVERSATION_TYPES.PUBLIC] = {\n            header: buildHeaderPatchTypePublic,\n            footer: buildFooterPatchTypePublic,\n        };\n        // These build functions are only applicable to self-conversations.\n        config[Constants.CONVERSATION_TYPES.SELF] = {\n            header: buildHeaderPatchTypeSelf,\n            footer: buildFooterPatchTypePublic,\n            confirmDeleteConversation: buildConfirmDeleteConversation,\n            selfConversationMessage: buildSelfConversationMessage\n        };\n\n        var patchConfig = $.extend({}, config.all);\n        if (newState.type && newState.type in config) {\n            // Add the type specific builders to the patch config.\n            patchConfig = $.extend(patchConfig, config[newState.type]);\n        }\n\n        return Object.keys(patchConfig).reduce(function(patch, key) {\n            var buildFunc = patchConfig[key];\n            var value = buildFunc(state, newState);\n\n            if (value !== null) {\n                patch[key] = value;\n            }\n\n            return patch;\n        }, {});\n    };\n\n    return {\n        buildPatch: buildPatch\n    };\n});\n"],"names":["define","$","UserDate","Constants","sortMessagesByDay","messages","midnight","messagesByDay","reduce","carry","message","timeCreated","dayTimestamp","getUserMidnightForTimestamp","hasOwnProperty","push","Object","keys","map","timestamp","diffArrays","a","b","matchFunction","slice","missingFromB","matches","forEach","current","found","index","length","next","splice","missingFromA","findPositionInArray","array","breakFunction","i","candidate","isArrayEqual","sort","aLength","bLength","every","item","isObjectEqual","aKeys","bKeys","key","aVal","bVal","aType","bType","Array","isArray","isMessageEqual","id","state","sendState","text","buildDaysPatch","remove","add","day","before","value","buildConversationPatch","newState","matchingDays","update","diff","daysDiff","dayCurrent","dayNext","days","messagesDiff","patch","timeAdded","concat","after","buildHeaderPatchTypePrivate","requireAddContact","buildRequireAddContact","confirmContactRequest","buildConfirmContactRequest","oldOtherUser","getOtherUserFromState","newOtherUser","requiresAddContact","show","hasMessages","requiredAddContact","shouldRenderHeader","type","CONVERSATION_TYPES","PRIVATE","showControls","context","name","subname","totalmembercount","totalMemberCount","imageurl","imageUrl","isfavourite","isFavourite","ismuted","isMuted","showfavourite","userid","showonlinestatus","isonline","isblocked","iscontact","buildHeaderPatchTypeSelf","SELF","buildHeaderPatchTypePublic","PUBLIC","buildScrollToMessagePatch","oldMessages","newMessages","previousNewest","currentNewest","previousOldest","currentOldest","buildLoadingMembersPatch","loadingMembers","buildLoadingFirstMessages","hasTriedToLoadMessages","loadingMessages","buildLoadingMessages","buildShowEmojiPicker","showEmojiPicker","buildShowEmojiAutoComplete","showEmojiAutoComplete","buildConfirmBlockUser","pendingBlockUserIds","userId","members","buildConfirmUnblockUser","pendingUnblockUserIds","buildConfirmAddContact","pendingAddContactIds","buildConfirmRemoveContact","pendingRemoveContactIds","buildConfirmDeleteSelectedMessages","oldPendingCount","pendingDeleteMessageIds","newPendingCount","canDeleteMessagesForAllUsers","buildConfirmDeleteConversation","pendingDeleteConversation","loggedInUserId","oldReceivedRequests","contactrequests","filter","request","requesteduserid","newReceivedRequests","oldRequest","newRequest","buildIsBlocked","buildIsFavourite","oldIsFavourite","newIsFavourite","buildIsMuted","oldIsMuted","newIsMuted","buildIsContact","oldContactRequests","newContactRequests","oldHasContactRequests","newHasContactRequests","buildLoadingConfirmationAction","loadingConfirmAction","buildInEditMode","oldHasSelectedMessages","selectedMessageIds","newHasSelectedMessages","numberOfMessagesHasChanged","buildSelectedMessages","oldSelectedMessages","newSelectedMessages","count","requiresContactRequest","user","canmessage","hasSentContactRequest","requirescontact","hadMessages","prevRequiresContactRequest","nextRequiresContactRequest","finishedAddContact","buildFooterPatchTypePrivate","loadingFirstMessages","inEditMode","requireUnblock","buildRequireUnblock","unableToMessage","buildUnableToMessage","showRequireAddContact","otherUser","generateReturnValue","checkValue","successReturn","checks","result","buildFooterPatchTypePublic","buildReset","oldType","newType","oldConversationId","newConversationId","oldMemberIds","newMemberIds","membersUnchanged","buildSelfConversationMessage","buildContactRequestSent","oldSentRequests","newSentRequests","fullname","buildPatch","config","all","reset","conversation","scrollToMessage","confirmDeleteSelectedMessages","selectedMessages","header","footer","confirmBlockUser","confirmUnblockUser","confirmAddContact","confirmRemoveContact","confirmDeleteConversation","isBlocked","isContact","contactRequestSent","selfConversationMessage","patchConfig","extend","buildFunc"],"mappings":"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"}