summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/notes/stores/collapse_utils.js
blob: bee6d4f032956116910ed559d4f5588affc70cbf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import { n__, s__, sprintf } from '~/locale';
import { DESCRIPTION_TYPE } from '../constants';

/**
 * Changes the description from a note, returns 'changed the description n number of times'
 */
export const changeDescriptionNote = (note, descriptionChangedTimes, timeDifferenceMinutes) => {
  const descriptionNote = Object.assign({}, note);

  descriptionNote.note_html = sprintf(
    s__(`MergeRequest|
  %{paragraphStart}changed the description %{descriptionChangedTimes} times %{timeDifferenceMinutes}%{paragraphEnd}`),
    {
      paragraphStart: '<p dir="auto">',
      paragraphEnd: '</p>',
      descriptionChangedTimes,
      timeDifferenceMinutes: n__('within %d minute ', 'within %d minutes ', timeDifferenceMinutes),
    },
    false,
  );

  descriptionNote.times_updated = descriptionChangedTimes;

  return descriptionNote;
};

/**
 * Checks the time difference between two notes from their 'created_at' dates
 * returns an integer
 */

export const getTimeDifferenceMinutes = (noteBeggining, noteEnd) => {
  const descriptionNoteBegin = new Date(noteBeggining.created_at);
  const descriptionNoteEnd = new Date(noteEnd.created_at);
  const timeDifferenceMinutes = (descriptionNoteEnd - descriptionNoteBegin) / 1000 / 60;

  return Math.ceil(timeDifferenceMinutes);
};

/**
 * Checks if a note is a system note and if the content is description
 *
 * @param {Object} note
 * @returns {Boolean}
 */
export const isDescriptionSystemNote = note => note.system && note.note === DESCRIPTION_TYPE;

/**
 * Collapses the system notes of a description type, e.g. Changed the description, n minutes ago
 * the notes will collapse as long as they happen no more than 10 minutes away from each away
 * in between the notes can be anything, another type of system note
 * (such as 'changed the weight') or a comment.
 *
 * @param {Array} notes
 * @returns {Array}
 */
export const collapseSystemNotes = notes => {
  let lastDescriptionSystemNote = null;
  let lastDescriptionSystemNoteIndex = -1;
  let descriptionChangedTimes = 1;

  return notes.slice(0).reduce((acc, currentNote) => {
    const note = currentNote.notes[0];

    if (isDescriptionSystemNote(note)) {
      // is it the first one?
      if (!lastDescriptionSystemNote) {
        lastDescriptionSystemNote = note;
        lastDescriptionSystemNoteIndex = acc.length;
      } else if (lastDescriptionSystemNote) {
        const timeDifferenceMinutes = getTimeDifferenceMinutes(lastDescriptionSystemNote, note);

        // are they less than 10 minutes apart?
        if (timeDifferenceMinutes > 10) {
          // reset counter
          descriptionChangedTimes = 1;
          // update the previous system note
          lastDescriptionSystemNote = note;
          lastDescriptionSystemNoteIndex = acc.length;
        } else {
          // increase counter
          descriptionChangedTimes += 1;

          // delete the previous one
          acc.splice(lastDescriptionSystemNoteIndex, 1);

          // replace the text of the current system note with the collapsed note.
          currentNote.notes.splice(
            0,
            1,
            changeDescriptionNote(note, descriptionChangedTimes, timeDifferenceMinutes),
          );

          // update the previous system note index
          lastDescriptionSystemNoteIndex = acc.length;
        }
      }
    }
    acc.push(currentNote);
    return acc;
  }, []);
};

// for babel-rewire
export default {};