Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
// This file is part of Moodle - http://moodle.org/
2
//
3
// Moodle is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, either version 3 of the License, or
6
// (at your option) any later version.
7
//
8
// Moodle is distributed in the hope that it will be useful,
9
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
// GNU General Public License for more details.
12
//
13
// You should have received a copy of the GNU General Public License
14
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
15
 
16
/**
17
 * This module operates on the view states from the message_drawer_view_conversation module.
18
 * It exposes functions that can be used to generate new version of the state.
19
 *
20
 * Important notes for this module:
21
 * 1.) The existing state is always immutable. It should never be modified.
22
 * 2.) All functions that operate on the state should always clone the state and
23
 *     modify the cloned state before returning it.
24
 *
25
 * It's important that the states remain immutable because they are diff'd in
26
 * the message_drawer_view_conversation_patcher module in order to work out what
27
 * has changed.
28
 *
29
 * @module     core_message/message_drawer_view_conversation_state_manager
30
 * @copyright  2018 Ryan Wyllie <ryan@moodle.com>
31
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
32
 */
33
define(['jquery'], function($) {
34
 
35
    /**
36
     * Clone a state, a state is a collection of information about the variables required to build
37
     * the conversation user interface.
38
     *
39
     * @param  {Object} state State to clone
40
     * @return {Object} newstate A copy of the state to clone.
41
     */
42
    var cloneState = function(state) {
43
        // Do a deep extend to make sure we recursively copy objects and
44
        // arrays so that the new state doesn't contain any references to
45
        // the old state, e.g. adding a value to an array in the new state
46
        // shouldn't also add it to the old state.
47
        return $.extend(true, {}, state);
48
    };
49
 
50
    /**
51
     * Format messages to be used in a state.
52
     *
53
     * @param  {Array} messages The messages to format.
54
     * @param  {Number} loggedInUserId The logged in user id.
55
     * @param  {Array} members The converstation members.
56
     * @return {Array} Formatted messages.
57
     */
58
    var formatMessages = function(messages, loggedInUserId, members) {
59
        return messages.map(function(message) {
60
            var fromLoggedInUser = message.useridfrom == loggedInUserId;
61
            return {
62
                // Stringify the id.
63
                id: "" + message.id,
64
                fromLoggedInUser: fromLoggedInUser,
65
                userFrom: members[message.useridfrom],
66
                text: message.text,
67
                timeCreated: message.timecreated ? parseInt(message.timecreated, 10) : null
68
            };
69
        });
70
    };
71
 
72
    /**
73
     * Format members to be used in a state.
74
     *
75
     * @param  {Array} members The messages to format.
76
     * @return {Array} Formatted members.
77
     */
78
    var formatMembers = function(members) {
79
        return members.map(function(member) {
80
            return {
81
                id: member.id,
82
                fullname: member.fullname,
83
                profileurl: member.profileurl,
84
                profileimageurl: member.profileimageurl,
85
                profileimageurlsmall: member.profileimageurlsmall,
86
                isonline:  member.isonline,
87
                showonlinestatus: member.showonlinestatus,
88
                isblocked: member.isblocked,
89
                iscontact: member.iscontact,
90
                isdeleted: member.isdeleted,
91
                canmessage: member.canmessage,
92
                canmessageevenifblocked: member.canmessageevenifblocked,
93
                requirescontact: member.requirescontact,
94
                contactrequests: member.contactrequests || []
95
            };
96
        });
97
    };
98
 
99
    /**
100
     * Create an initial (blank) state.
101
     *
102
     * @param  {Number} midnight Midnight time.
103
     * @param  {Number} loggedInUserId The logged in user id.
104
     * @param  {Number} id The conversation id.
105
     * @param  {Number} messagePollMin The message poll start timeout in seconds.
106
     * @param  {Number} messagePollMax The message poll max timeout limit in seconds.
107
     * @param  {Number} messagePollAfterMax The message poll frequency in seconds to reset to after max limit is reached.
108
     * @return {Object} Initial state.
109
     */
110
    var buildInitialState = function(
111
        midnight,
112
        loggedInUserId,
113
        id,
114
        messagePollMin,
115
        messagePollMax,
116
        messagePollAfterMax
117
    ) {
118
        return {
119
            midnight: midnight,
120
            loggedInUserId: loggedInUserId,
121
            id: id,
122
            messagePollMin: messagePollMin,
123
            messagePollMax: messagePollMax,
124
            messagePollAfterMax: messagePollAfterMax,
125
            name: null,
126
            subname: null,
127
            type: null,
128
            totalMemberCount: null,
129
            imageUrl: null,
130
            isFavourite: null,
131
            isMuted: null,
132
            canDeleteMessagesForAllUsers: false,
133
            deleteMessagesForAllUsers: false,
134
            members: {},
135
            messages: [],
136
            hasTriedToLoadMessages: false,
137
            loadingMessages: true,
138
            loadingMembers: true,
139
            loadingConfirmAction: false,
140
            pendingBlockUserIds: [],
141
            pendingUnblockUserIds: [],
142
            pendingRemoveContactIds: [],
143
            pendingAddContactIds: [],
144
            pendingDeleteMessageIds: [],
145
            pendingSendMessageIds: [],
146
            pendingDeleteConversation: false,
147
            selectedMessageIds: [],
148
            showEmojiAutoComplete: false,
149
            showEmojiPicker: false
150
        };
151
    };
152
 
153
    /**
154
     * Add messages to a state and sort them by timecreated.
155
     *
156
     * @param  {Object} state Current state.
157
     * @param  {Array} messages Messages to add to state.
158
     * @return {Object} state New state with added messages.
159
     */
160
    var addMessages = function(state, messages) {
161
        var newState = cloneState(state);
162
        var formattedMessages = formatMessages(messages, state.loggedInUserId, state.members);
163
        formattedMessages = formattedMessages.map(function(message) {
164
            message.sendState = null;
165
            message.timeAdded = Date.now();
166
            message.errorMessage = null;
167
            return message;
168
        });
169
        var allMessages = state.messages.concat(formattedMessages);
170
        // Sort the messages. Oldest to newest.
171
        allMessages.sort(function(a, b) {
172
            if (a.timeCreated === null && b.timeCreated === null) {
173
                if (a.timeAdded < b.timeAdded) {
174
                    return -1;
175
                } else if (a.timeAdded > b.timeAdded) {
176
                    return 1;
177
                }
178
            }
179
 
180
            if (a.timeCreated === null && b.timeCreated !== null) {
181
                // A comes after b.
182
                return 1;
183
            } else if (a.timeCreated !== null && b.timeCreated === null) {
184
                // A comes before b.
185
                return -1;
186
            } else if (a.timeCreated < b.timeCreated) {
187
                // A comes before b.
188
                return -1;
189
            } else if (a.timeCreated > b.timeCreated) {
190
                // A comes after b.
191
                return 1;
192
            } else if (a.id < b.id) {
193
                return -1;
194
            } else if (a.id > b.id) {
195
                return 1;
196
            } else {
197
                return 0;
198
            }
199
        });
200
 
201
        // Filter out any duplicate messages.
202
        newState.messages = allMessages.filter(function(message, index, sortedMessages) {
203
            return !index || message.id != sortedMessages[index - 1].id;
204
        });
205
 
206
        return newState;
207
    };
208
 
209
    /**
210
     * Update existing messages.
211
     *
212
     * @param  {Object} state Current state.
213
     * @param  {Array} data 2D array of old and new messages
214
     * @return {Object} state.
215
     */
216
    var updateMessages = function(state, data) {
217
        var newState = cloneState(state);
218
        var updatesById = data.reduce(function(carry, messageData) {
219
            var oldMessage = messageData[0];
220
            var newMessage = messageData[1];
221
            var formattedMessages = formatMessages([newMessage], state.loggedInUserId, state.members);
222
            var formattedMessage = formattedMessages[0];
223
 
224
            carry[oldMessage.id] = formattedMessage;
225
            return carry;
226
        }, {});
227
 
228
        newState.messages = newState.messages.map(function(message) {
229
            if (message.id in updatesById) {
230
                return $.extend(message, updatesById[message.id]);
231
            } else {
232
                return message;
233
            }
234
        });
235
 
236
        return newState;
237
    };
238
 
239
    /**
240
     * Remove messages from state.
241
     *
242
     * @param  {Object} state Current state.
243
     * @param  {Array} messages Messages to remove from state.
244
     * @return {Object} state New state with removed messages.
245
     */
246
    var removeMessages = function(state, messages) {
247
        var newState = cloneState(state);
248
        var removeMessageIds = messages.map(function(message) {
249
            return "" + message.id;
250
        });
251
        newState.messages = newState.messages.filter(function(message) {
252
            return removeMessageIds.indexOf(message.id) < 0;
253
        });
254
 
255
        return newState;
256
    };
257
 
258
    /**
259
     * Remove messages from state by message id.
260
     *
261
     * @param  {Object} state Current state.
262
     * @param  {Array} messageIds Message ids to remove from state.
263
     * @return {Object} state New state with removed messages.
264
     */
265
    var removeMessagesById = function(state, messageIds) {
266
        var newState = cloneState(state);
267
        messageIds = messageIds.map(function(id) {
268
            return "" + id;
269
        });
270
        newState.messages = newState.messages.filter(function(message) {
271
            return messageIds.indexOf(message.id) < 0;
272
        });
273
 
274
        return newState;
275
    };
276
 
277
    /**
278
     * Add conversation member to state.
279
     *
280
     * @param  {Object} state Current state.
281
     * @param  {Array} members Conversation members to be added to state.
282
     * @return {Object} New state with added members.
283
     */
284
    var addMembers = function(state, members) {
285
        var newState = cloneState(state);
286
        var formattedMembers = formatMembers(members);
287
        formattedMembers.forEach(function(member) {
288
            newState.members[member.id] = member;
289
        });
290
        return newState;
291
    };
292
 
293
    /**
294
     * Remove members from state.
295
     *
296
     * @param  {Object} state Current state.
297
     * @param  {Array} members Members to be removed from state.
298
     * @return {Object} New state with removed members.
299
     */
300
    var removeMembers = function(state, members) {
301
        var newState = cloneState(state);
302
        members.forEach(function(member) {
303
            delete newState.members[member.id];
304
        });
305
        return newState;
306
    };
307
 
308
    /**
309
     * Set the state loading messages attribute.
310
     *
311
     * @param  {Object} state Current state.
312
     * @param  {Bool} value New loading messages value.
313
     * @return {Object} New state with loading messages attribute.
314
     */
315
    var setLoadingMessages = function(state, value) {
316
        var newState = cloneState(state);
317
        newState.loadingMessages = value;
318
        if (state.loadingMessages && !value) {
319
            // If we're going from loading to not loading then
320
            // it means we've tried to load.
321
            newState.hasTriedToLoadMessages = true;
322
        }
323
        return newState;
324
    };
325
 
326
    /**
327
     * Set the state loading members attribute.
328
     *
329
     * @param  {Object} state Current state.
330
     * @param  {Bool} value New loading members value.
331
     * @return {Object} New state with loading members attribute.
332
     */
333
    var setLoadingMembers = function(state, value) {
334
        var newState = cloneState(state);
335
        newState.loadingMembers = value;
336
        return newState;
337
    };
338
 
339
    /**
340
     * Set the conversation id.
341
     *
342
     * @param  {Object} state Current state.
343
     * @param  {String} value The ID.
344
     * @return {Object} New state.
345
     */
346
    var setId = function(state, value) {
347
        var newState = cloneState(state);
348
        newState.id = value;
349
        return newState;
350
    };
351
 
352
    /**
353
     * Set the state name attribute.
354
     *
355
     * @param  {Object} state Current state.
356
     * @param  {String} value New name value.
357
     * @return {Object} New state with name attribute.
358
     */
359
    var setName = function(state, value) {
360
        var newState = cloneState(state);
361
        newState.name = value;
362
        return newState;
363
    };
364
 
365
    /**
366
     * Set the state subname attribute.
367
     *
368
     * @param  {Object} state Current state.
369
     * @param  {String} value New subname value.
370
     * @return {Object} New state.
371
     */
372
    var setSubname = function(state, value) {
373
        var newState = cloneState(state);
374
        newState.subname = value;
375
        return newState;
376
    };
377
 
378
    /**
379
     * Set the conversation type.
380
     *
381
     * @param  {Object} state Current state.
382
     * @param  {Int} type Conversation type.
383
     * @return {Object} New state.
384
     */
385
    var setType = function(state, type) {
386
        var newState = cloneState(state);
387
        newState.type = type;
388
        return newState;
389
    };
390
 
391
    /**
392
     * Set whether the conversation is a favourite conversation.
393
     *
394
     * @param  {Object} state Current state.
395
     * @param  {Bool} isFavourite If it's a favourite.
396
     * @return {Object} New state.
397
     */
398
    var setIsFavourite = function(state, isFavourite) {
399
        var newState = cloneState(state);
400
        newState.isFavourite = isFavourite;
401
        return newState;
402
    };
403
 
404
    /**
405
     * Set whether the conversation is a muted conversation.
406
     *
407
     * @param  {Object} state Current state.
408
     * @param  {bool} isMuted If it's muted.
409
     * @return {Object} New state.
410
     */
411
    var setIsMuted = function(state, isMuted) {
412
        var newState = cloneState(state);
413
        newState.isMuted = isMuted;
414
        return newState;
415
    };
416
 
417
    /**
418
     * Set the total member count.
419
     *
420
     * @param  {Object} state Current state.
421
     * @param  {String} count The count.
422
     * @return {Object} New state.
423
     */
424
    var setTotalMemberCount = function(state, count) {
425
        var newState = cloneState(state);
426
        newState.totalMemberCount = count;
427
        return newState;
428
    };
429
 
430
    /**
431
     * Set the conversation image url.
432
     *
433
     * @param  {Object} state Current state.
434
     * @param  {String} url The url to the image.
435
     * @return {Object} New state.
436
     */
437
    var setImageUrl = function(state, url) {
438
        var newState = cloneState(state);
439
        newState.imageUrl = url;
440
        return newState;
441
    };
442
 
443
    /**
444
     * Set the state loading confirm action attribute.
445
     *
446
     * @param  {Object} state Current state.
447
     * @param  {Bool} value New loading confirm action value.
448
     * @return {Object} New state with loading confirm action attribute.
449
     */
450
    var setLoadingConfirmAction = function(state, value) {
451
        var newState = cloneState(state);
452
        newState.loadingConfirmAction = value;
453
        return newState;
454
    };
455
 
456
    /**
457
     * Set the state pending delete conversation attribute.
458
     *
459
     * @param  {Object} state Current state.
460
     * @param  {Bool} value New pending delete conversation value.
461
     * @return {Object} New state with pending delete conversation attribute.
462
     */
463
    var setPendingDeleteConversation = function(state, value) {
464
        var newState = cloneState(state);
465
        newState.pendingDeleteConversation = value;
466
        return newState;
467
    };
468
 
469
    /**
470
     * Set the state of message to pending.
471
     *
472
     * @param  {Object} state Current state.
473
     * @param  {Array} messageIds Messages to delete.
474
     * @return {Object} New state with array of pending delete message ids.
475
     */
476
    var setMessagesSendPendingById = function(state, messageIds) {
477
        var newState = cloneState(state);
478
        messageIds = messageIds.map(function(id) {
479
            return "" + id;
480
        });
481
        newState.messages.forEach(function(message) {
482
            if (messageIds.indexOf(message.id) >= 0) {
483
                message.sendState = 'pending';
484
                message.errorMessage = null;
485
            }
486
        });
487
        return newState;
488
    };
489
 
490
    /**
491
     * Set the state of message to sent.
492
     *
493
     * @param  {Object} state Current state.
494
     * @param  {Array} messageIds Messages to delete.
495
     * @return {Object} New state with array of pending delete message ids.
496
     */
497
    var setMessagesSendSuccessById = function(state, messageIds) {
498
        var newState = cloneState(state);
499
        messageIds = messageIds.map(function(id) {
500
            return "" + id;
501
        });
502
        newState.messages.forEach(function(message) {
503
            if (messageIds.indexOf(message.id) >= 0) {
504
                message.sendState = 'sent';
505
                message.errorMessage = null;
506
            }
507
        });
508
        return newState;
509
    };
510
 
511
    /**
512
     * Set the state of messages to error.
513
     *
514
     * @param  {Object} state Current state.
515
     * @param  {Array} messageIds Messages to delete.
516
     * @param  {string} errorMessage
517
     * @return {Object} New state with array of pending delete message ids.
518
     */
519
    var setMessagesSendFailById = function(state, messageIds, errorMessage) {
520
        var newState = cloneState(state);
521
        messageIds = messageIds.map(function(id) {
522
            return "" + id;
523
        });
524
        newState.messages.forEach(function(message) {
525
            if (messageIds.indexOf(message.id) >= 0) {
526
                message.sendState = 'error';
527
                message.errorMessage = errorMessage;
528
            }
529
        });
530
        return newState;
531
    };
532
 
533
    /**
534
     * Set the visibility of the emoji picker.
535
     *
536
     * @param  {Object} state Current state.
537
     * @param  {Bool} show Should the emoji picker be shown.
538
     * @return {Object} New state with array of pending delete message ids.
539
     */
540
    var setShowEmojiPicker = function(state, show) {
541
        var newState = cloneState(state);
542
        newState.showEmojiPicker = show;
543
        return newState;
544
    };
545
 
546
    /**
547
     * Set whether emojis auto complete suggestions should be shown.
548
     *
549
     * @param  {Object} state Current state.
550
     * @param  {Bool} show Show the autocomplete
551
     * @return {Object} New state with array of pending delete message ids.
552
     */
553
    var setShowEmojiAutoComplete = function(state, show) {
554
        var newState = cloneState(state);
555
        newState.showEmojiAutoComplete = show;
556
        return newState;
557
    };
558
 
559
    /**
560
     * Set the state pending block userids.
561
     *
562
     * @param  {Object} state Current state.
563
     * @param  {Array} userIds User ids to block.
564
     * @return {Object} New state with array of pending block userids.
565
     */
566
    var addPendingBlockUsersById = function(state, userIds) {
567
        var newState = cloneState(state);
568
        userIds.forEach(function(id) {
569
            newState.pendingBlockUserIds.push(id);
570
        });
571
        return newState;
572
    };
573
 
574
    /**
575
     * Set the state pending remove userids.
576
     *
577
     * @param  {Object} state Current state.
578
     * @param  {Array} userIds User ids to remove.
579
     * @return {Object} New state with array of pending remove userids.
580
     */
581
    var addPendingRemoveContactsById = function(state, userIds) {
582
        var newState = cloneState(state);
583
        userIds.forEach(function(id) {
584
            newState.pendingRemoveContactIds.push(id);
585
        });
586
        return newState;
587
    };
588
 
589
    /**
590
     * Set the state pending unblock userids.
591
     *
592
     * @param  {Object} state Current state.
593
     * @param  {Array} userIds User ids to unblock.
594
     * @return {Object} New state with array of pending unblock userids.
595
     */
596
    var addPendingUnblockUsersById = function(state, userIds) {
597
        var newState = cloneState(state);
598
        userIds.forEach(function(id) {
599
            newState.pendingUnblockUserIds.push(id);
600
        });
601
        return newState;
602
    };
603
 
604
    /**
605
     * Set the state pending add users to contacts userids.
606
     *
607
     * @param  {Object} state Current state.
608
     * @param  {Array} userIds User ids to add users to contacts.
609
     * @return {Object} New state with array of pending add users to contacts userids.
610
     */
611
    var addPendingAddContactsById = function(state, userIds) {
612
        var newState = cloneState(state);
613
        userIds.forEach(function(id) {
614
            newState.pendingAddContactIds.push(id);
615
        });
616
        return newState;
617
    };
618
 
619
    /**
620
     * Set the state pending delete messages.
621
     *
622
     * @param  {Object} state Current state.
623
     * @param  {Array} messageIds Messages to delete.
624
     * @return {Object} New state with array of pending delete message ids.
625
     */
626
    var addPendingDeleteMessagesById = function(state, messageIds) {
627
        var newState = cloneState(state);
628
        messageIds.forEach(function(id) {
629
            newState.pendingDeleteMessageIds.push(id);
630
        });
631
        return newState;
632
    };
633
 
634
    /**
635
     * Update the state pending block userids.
636
     *
637
     * @param  {Object} state Current state.
638
     * @param  {Array} userIds User ids to remove from the list of user ids to block.
639
     * @return {Object} New state with array of pending block userids.
640
     */
641
    var removePendingBlockUsersById = function(state, userIds) {
642
        var newState = cloneState(state);
643
        newState.pendingBlockUserIds = newState.pendingBlockUserIds.filter(function(id) {
644
            return userIds.indexOf(id) < 0;
645
        });
646
        return newState;
647
    };
648
 
649
    /**
650
     * Update the state pending remove userids.
651
     *
652
     * @param  {Object} state Current state.
653
     * @param  {Array} userIds User ids to remove from the list of user ids to remove.
654
     * @return {Object} New state with array of pending remove userids.
655
     */
656
    var removePendingRemoveContactsById = function(state, userIds) {
657
        var newState = cloneState(state);
658
        newState.pendingRemoveContactIds = newState.pendingRemoveContactIds.filter(function(id) {
659
            return userIds.indexOf(id) < 0;
660
        });
661
        return newState;
662
    };
663
 
664
    /**
665
     * Update the state pending unblock userids.
666
     *
667
     * @param  {Object} state Current state.
668
     * @param  {Array} userIds User ids to remove from the list of user ids to unblock.
669
     * @return {Object} New state with array of pending unblock userids.
670
     */
671
    var removePendingUnblockUsersById = function(state, userIds) {
672
        var newState = cloneState(state);
673
        newState.pendingUnblockUserIds = newState.pendingUnblockUserIds.filter(function(id) {
674
            return userIds.indexOf(id) < 0;
675
        });
676
        return newState;
677
    };
678
 
679
    /**
680
     * Update the state pending add to contacts userids.
681
     *
682
     * @param  {Object} state Current state.
683
     * @param  {Array} userIds User ids to remove from the list of user ids to add to contacts.
684
     * @return {Object} New state with array of pending add to contacts userids.
685
     */
686
    var removePendingAddContactsById = function(state, userIds) {
687
        var newState = cloneState(state);
688
        newState.pendingAddContactIds = newState.pendingAddContactIds.filter(function(id) {
689
            return userIds.indexOf(id) < 0;
690
        });
691
        return newState;
692
    };
693
 
694
    /**
695
     * Update the state pending delete messages userids.
696
     *
697
     * @param  {Object} state Current state.
698
     * @param  {Array} messageIds Message ids to remove from the list of messages to delete.
699
     * @return {Object} New state with array of messages to delete.
700
     */
701
    var removePendingDeleteMessagesById = function(state, messageIds) {
702
        var newState = cloneState(state);
703
        messageIds = messageIds.map(function(id) {
704
            return "" + id;
705
        });
706
        newState.pendingDeleteMessageIds = newState.pendingDeleteMessageIds.filter(function(id) {
707
            return messageIds.indexOf(id) < 0;
708
        });
709
        return newState;
710
    };
711
 
712
    /**
713
     * Add messages to state selected messages.
714
     *
715
     * @param  {Object} state Current state.
716
     * @param  {Array} messageIds Messages that are selected.
717
     * @return {Object} New state with array of not blocked members.
718
     */
719
    var addSelectedMessagesById = function(state, messageIds) {
720
        var newState = cloneState(state);
721
        messageIds = messageIds.map(function(id) {
722
            return "" + id;
723
        });
724
        newState.selectedMessageIds = newState.selectedMessageIds.concat(messageIds);
725
        return newState;
726
    };
727
 
728
    /**
729
     * Remove messages from the state selected messages.
730
     *
731
     * @param  {Object} state Current state.
732
     * @param  {Array} messageIds Messages to remove from selected messages.
733
     * @return {Object} New state with array of selected messages.
734
     */
735
    var removeSelectedMessagesById = function(state, messageIds) {
736
        var newState = cloneState(state);
737
        messageIds = messageIds.map(function(id) {
738
            return "" + id;
739
        });
740
        newState.selectedMessageIds = newState.selectedMessageIds.filter(function(id) {
741
            return messageIds.indexOf(id) < 0;
742
        });
743
        return newState;
744
    };
745
 
746
    /**
747
     * Mark messages as read.
748
     *
749
     * @param  {Object} state Current state.
750
     * @param  {Array} readMessages Messages that are read.
751
     * @return {Object} New state with array of messages that have the isread attribute set.
752
     */
753
    var markMessagesAsRead = function(state, readMessages) {
754
        var newState = cloneState(state);
755
        var readMessageIds = readMessages.map(function(message) {
756
            return message.id;
757
        });
758
        newState.messages = newState.messages.map(function(message) {
759
            if (readMessageIds.indexOf(message.id) >= 0) {
760
                message.isRead = true;
761
            }
762
 
763
            return message;
764
        });
765
        return newState;
766
    };
767
 
768
    /**
769
     * Add a contact request to each of the members that the request is for.
770
     *
771
     * @param  {Object} state Current state.
772
     * @param  {Array} requests The contact requests
773
     * @return {Object} New state
774
     */
775
    var addContactRequests = function(state, requests) {
776
        var newState = cloneState(state);
777
 
778
        requests.forEach(function(request) {
779
            var fromUserId = request.userid;
780
            var toUserId = request.requesteduserid;
781
            newState.members[fromUserId].contactrequests.push(request);
782
            newState.members[toUserId].contactrequests.push(request);
783
        });
784
 
785
        return newState;
786
    };
787
 
788
    /**
789
     * Remove a contact request from the members of that request.
790
     *
791
     * @param  {Object} state Current state.
792
     * @param  {Array} requests The contact requests
793
     * @return {Object} New state
794
     */
795
    var removeContactRequests = function(state, requests) {
796
        var newState = cloneState(state);
797
        requests.forEach(function(request) {
798
            var fromUserId = request.userid;
799
            var toUserId = request.requesteduserid;
800
 
801
            newState.members[fromUserId].contactrequests = newState.members[fromUserId].contactrequests.filter(function(existing) {
802
                return existing.userid != fromUserId;
803
            });
804
            newState.members[toUserId].contactrequests = newState.members[toUserId].contactrequests.filter(function(existing) {
805
                return existing.requesteduserid != toUserId;
806
            });
807
        });
808
 
809
        return newState;
810
    };
811
 
812
    /**
813
     * Set wheter the message of the conversation can delete for all users.
814
     *
815
     * @param  {Object} state Current state.
816
     * @param  {Bool} value If it can delete for all users.
817
     * @return {Object} New state.
818
     */
819
    var setCanDeleteMessagesForAllUsers = function(state, value) {
820
        var newState = cloneState(state);
821
        newState.canDeleteMessagesForAllUsers = value;
822
        return newState;
823
    };
824
 
825
    /**
826
     * Set wheter the messages of the conversation delete for all users.
827
     *
828
     * @param  {Object} state Current state.
829
     * @param  {Bool} value Delete messages for all users.
830
     * @return {Object} New state.
831
     */
832
    var setDeleteMessagesForAllUsers = function(state, value) {
833
        var newState = cloneState(state);
834
        newState.deleteMessagesForAllUsers = value;
835
        return newState;
836
    };
837
 
838
    return {
839
        buildInitialState: buildInitialState,
840
        addMessages: addMessages,
841
        updateMessages: updateMessages,
842
        removeMessages: removeMessages,
843
        removeMessagesById: removeMessagesById,
844
        addMembers: addMembers,
845
        removeMembers: removeMembers,
846
        setLoadingMessages: setLoadingMessages,
847
        setLoadingMembers: setLoadingMembers,
848
        setId: setId,
849
        setName: setName,
850
        setSubname: setSubname,
851
        setType: setType,
852
        setIsFavourite: setIsFavourite,
853
        setIsMuted: setIsMuted,
854
        setCanDeleteMessagesForAllUsers: setCanDeleteMessagesForAllUsers,
855
        setDeleteMessagesForAllUsers: setDeleteMessagesForAllUsers,
856
        setTotalMemberCount: setTotalMemberCount,
857
        setImageUrl: setImageUrl,
858
        setLoadingConfirmAction: setLoadingConfirmAction,
859
        setPendingDeleteConversation: setPendingDeleteConversation,
860
        setMessagesSendPendingById: setMessagesSendPendingById,
861
        setMessagesSendSuccessById: setMessagesSendSuccessById,
862
        setMessagesSendFailById: setMessagesSendFailById,
863
        setShowEmojiAutoComplete: setShowEmojiAutoComplete,
864
        setShowEmojiPicker: setShowEmojiPicker,
865
        addPendingBlockUsersById: addPendingBlockUsersById,
866
        addPendingRemoveContactsById: addPendingRemoveContactsById,
867
        addPendingUnblockUsersById: addPendingUnblockUsersById,
868
        addPendingAddContactsById: addPendingAddContactsById,
869
        addPendingDeleteMessagesById: addPendingDeleteMessagesById,
870
        removePendingBlockUsersById: removePendingBlockUsersById,
871
        removePendingRemoveContactsById: removePendingRemoveContactsById,
872
        removePendingUnblockUsersById: removePendingUnblockUsersById,
873
        removePendingAddContactsById: removePendingAddContactsById,
874
        removePendingDeleteMessagesById: removePendingDeleteMessagesById,
875
        addSelectedMessagesById: addSelectedMessagesById,
876
        removeSelectedMessagesById: removeSelectedMessagesById,
877
        markMessagesAsRead: markMessagesAsRead,
878
        addContactRequests: addContactRequests,
879
        removeContactRequests: removeContactRequests
880
    };
881
});